aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/kernel/head.S
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/kernel/head.S')
-rw-r--r--arch/arm/kernel/head.S251
1 files changed, 196 insertions, 55 deletions
diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S
index f17d9a09e8fb..c9173cfbbc74 100644
--- a/arch/arm/kernel/head.S
+++ b/arch/arm/kernel/head.S
@@ -26,14 +26,6 @@
26#include <mach/debug-macro.S> 26#include <mach/debug-macro.S>
27#endif 27#endif
28 28
29#if (PHYS_OFFSET & 0x001fffff)
30#error "PHYS_OFFSET must be at an even 2MiB boundary!"
31#endif
32
33#define KERNEL_RAM_VADDR (PAGE_OFFSET + TEXT_OFFSET)
34#define KERNEL_RAM_PADDR (PHYS_OFFSET + TEXT_OFFSET)
35
36
37/* 29/*
38 * swapper_pg_dir is the virtual address of the initial page table. 30 * swapper_pg_dir is the virtual address of the initial page table.
39 * We place the page tables 16K below KERNEL_RAM_VADDR. Therefore, we must 31 * We place the page tables 16K below KERNEL_RAM_VADDR. Therefore, we must
@@ -41,6 +33,7 @@
41 * the least significant 16 bits to be 0x8000, but we could probably 33 * the least significant 16 bits to be 0x8000, but we could probably
42 * relax this restriction to KERNEL_RAM_VADDR >= PAGE_OFFSET + 0x4000. 34 * relax this restriction to KERNEL_RAM_VADDR >= PAGE_OFFSET + 0x4000.
43 */ 35 */
36#define KERNEL_RAM_VADDR (PAGE_OFFSET + TEXT_OFFSET)
44#if (KERNEL_RAM_VADDR & 0xffff) != 0x8000 37#if (KERNEL_RAM_VADDR & 0xffff) != 0x8000
45#error KERNEL_RAM_VADDR must start at 0xXXXX8000 38#error KERNEL_RAM_VADDR must start at 0xXXXX8000
46#endif 39#endif
@@ -48,8 +41,8 @@
48 .globl swapper_pg_dir 41 .globl swapper_pg_dir
49 .equ swapper_pg_dir, KERNEL_RAM_VADDR - 0x4000 42 .equ swapper_pg_dir, KERNEL_RAM_VADDR - 0x4000
50 43
51 .macro pgtbl, rd 44 .macro pgtbl, rd, phys
52 ldr \rd, =(KERNEL_RAM_PADDR - 0x4000) 45 add \rd, \phys, #TEXT_OFFSET - 0x4000
53 .endm 46 .endm
54 47
55#ifdef CONFIG_XIP_KERNEL 48#ifdef CONFIG_XIP_KERNEL
@@ -87,25 +80,33 @@ ENTRY(stext)
87 movs r10, r5 @ invalid processor (r5=0)? 80 movs r10, r5 @ invalid processor (r5=0)?
88 THUMB( it eq ) @ force fixup-able long branch encoding 81 THUMB( it eq ) @ force fixup-able long branch encoding
89 beq __error_p @ yes, error 'p' 82 beq __error_p @ yes, error 'p'
90 bl __lookup_machine_type @ r5=machinfo 83
91 movs r8, r5 @ invalid machine (r5=0)? 84#ifndef CONFIG_XIP_KERNEL
92 THUMB( it eq ) @ force fixup-able long branch encoding 85 adr r3, 2f
93 beq __error_a @ yes, error 'a' 86 ldmia r3, {r4, r8}
87 sub r4, r3, r4 @ (PHYS_OFFSET - PAGE_OFFSET)
88 add r8, r8, r4 @ PHYS_OFFSET
89#else
90 ldr r8, =PLAT_PHYS_OFFSET
91#endif
94 92
95 /* 93 /*
96 * r1 = machine no, r2 = atags, 94 * r1 = machine no, r2 = atags,
97 * r8 = machinfo, r9 = cpuid, r10 = procinfo 95 * r8 = phys_offset, r9 = cpuid, r10 = procinfo
98 */ 96 */
99 bl __vet_atags 97 bl __vet_atags
100#ifdef CONFIG_SMP_ON_UP 98#ifdef CONFIG_SMP_ON_UP
101 bl __fixup_smp 99 bl __fixup_smp
102#endif 100#endif
101#ifdef CONFIG_ARM_PATCH_PHYS_VIRT
102 bl __fixup_pv_table
103#endif
103 bl __create_page_tables 104 bl __create_page_tables
104 105
105 /* 106 /*
106 * The following calls CPU specific code in a position independent 107 * The following calls CPU specific code in a position independent
107 * manner. See arch/arm/mm/proc-*.S for details. r10 = base of 108 * manner. See arch/arm/mm/proc-*.S for details. r10 = base of
108 * xxx_proc_info structure selected by __lookup_machine_type 109 * xxx_proc_info structure selected by __lookup_processor_type
109 * above. On return, the CPU will be ready for the MMU to be 110 * above. On return, the CPU will be ready for the MMU to be
110 * turned on, and r0 will hold the CPU control register value. 111 * turned on, and r0 will hold the CPU control register value.
111 */ 112 */
@@ -118,22 +119,24 @@ ENTRY(stext)
1181: b __enable_mmu 1191: b __enable_mmu
119ENDPROC(stext) 120ENDPROC(stext)
120 .ltorg 121 .ltorg
122#ifndef CONFIG_XIP_KERNEL
1232: .long .
124 .long PAGE_OFFSET
125#endif
121 126
122/* 127/*
123 * Setup the initial page tables. We only setup the barest 128 * Setup the initial page tables. We only setup the barest
124 * amount which are required to get the kernel running, which 129 * amount which are required to get the kernel running, which
125 * generally means mapping in the kernel code. 130 * generally means mapping in the kernel code.
126 * 131 *
127 * r8 = machinfo 132 * r8 = phys_offset, r9 = cpuid, r10 = procinfo
128 * r9 = cpuid
129 * r10 = procinfo
130 * 133 *
131 * Returns: 134 * Returns:
132 * r0, r3, r5-r7 corrupted 135 * r0, r3, r5-r7 corrupted
133 * r4 = physical page table address 136 * r4 = physical page table address
134 */ 137 */
135__create_page_tables: 138__create_page_tables:
136 pgtbl r4 @ page table address 139 pgtbl r4, r8 @ page table address
137 140
138 /* 141 /*
139 * Clear the 16K level 1 swapper page table 142 * Clear the 16K level 1 swapper page table
@@ -189,10 +192,8 @@ __create_page_tables:
189 /* 192 /*
190 * Map some ram to cover our .data and .bss areas. 193 * Map some ram to cover our .data and .bss areas.
191 */ 194 */
192 orr r3, r7, #(KERNEL_RAM_PADDR & 0xff000000) 195 add r3, r8, #TEXT_OFFSET
193 .if (KERNEL_RAM_PADDR & 0x00f00000) 196 orr r3, r3, r7
194 orr r3, r3, #(KERNEL_RAM_PADDR & 0x00f00000)
195 .endif
196 add r0, r4, #(KERNEL_RAM_VADDR & 0xff000000) >> 18 197 add r0, r4, #(KERNEL_RAM_VADDR & 0xff000000) >> 18
197 str r3, [r0, #(KERNEL_RAM_VADDR & 0x00f00000) >> 18]! 198 str r3, [r0, #(KERNEL_RAM_VADDR & 0x00f00000) >> 18]!
198 ldr r6, =(_end - 1) 199 ldr r6, =(_end - 1)
@@ -205,14 +206,17 @@ __create_page_tables:
205#endif 206#endif
206 207
207 /* 208 /*
208 * Then map first 1MB of ram in case it contains our boot params. 209 * Then map boot params address in r2 or
210 * the first 1MB of ram if boot params address is not specified.
209 */ 211 */
210 add r0, r4, #PAGE_OFFSET >> 18 212 mov r0, r2, lsr #20
211 orr r6, r7, #(PHYS_OFFSET & 0xff000000) 213 movs r0, r0, lsl #20
212 .if (PHYS_OFFSET & 0x00f00000) 214 moveq r0, r8
213 orr r6, r6, #(PHYS_OFFSET & 0x00f00000) 215 sub r3, r0, r8
214 .endif 216 add r3, r3, #PAGE_OFFSET
215 str r6, [r0] 217 add r3, r4, r3, lsr #18
218 orr r6, r7, r0
219 str r6, [r3]
216 220
217#ifdef CONFIG_DEBUG_LL 221#ifdef CONFIG_DEBUG_LL
218#ifndef CONFIG_DEBUG_ICEDCC 222#ifndef CONFIG_DEBUG_ICEDCC
@@ -391,25 +395,24 @@ ENDPROC(__turn_mmu_on)
391 395
392 396
393#ifdef CONFIG_SMP_ON_UP 397#ifdef CONFIG_SMP_ON_UP
398 __INIT
394__fixup_smp: 399__fixup_smp:
395 mov r4, #0x00070000 400 and r3, r9, #0x000f0000 @ architecture version
396 orr r3, r4, #0xff000000 @ mask 0xff070000 401 teq r3, #0x000f0000 @ CPU ID supported?
397 orr r4, r4, #0x41000000 @ val 0x41070000
398 and r0, r9, r3
399 teq r0, r4 @ ARM CPU and ARMv6/v7?
400 bne __fixup_smp_on_up @ no, assume UP 402 bne __fixup_smp_on_up @ no, assume UP
401 403
402 orr r3, r3, #0x0000ff00 404 bic r3, r9, #0x00ff0000
403 orr r3, r3, #0x000000f0 @ mask 0xff07fff0 405 bic r3, r3, #0x0000000f @ mask 0xff00fff0
406 mov r4, #0x41000000
404 orr r4, r4, #0x0000b000 407 orr r4, r4, #0x0000b000
405 orr r4, r4, #0x00000020 @ val 0x4107b020 408 orr r4, r4, #0x00000020 @ val 0x4100b020
406 and r0, r9, r3 409 teq r3, r4 @ ARM 11MPCore?
407 teq r0, r4 @ ARM 11MPCore?
408 moveq pc, lr @ yes, assume SMP 410 moveq pc, lr @ yes, assume SMP
409 411
410 mrc p15, 0, r0, c0, c0, 5 @ read MPIDR 412 mrc p15, 0, r0, c0, c0, 5 @ read MPIDR
411 tst r0, #1 << 31 413 and r0, r0, #0xc0000000 @ multiprocessing extensions and
412 movne pc, lr @ bit 31 => SMP 414 teq r0, #0x80000000 @ not part of a uniprocessor system?
415 moveq pc, lr @ yes, assume SMP
413 416
414__fixup_smp_on_up: 417__fixup_smp_on_up:
415 adr r0, 1f 418 adr r0, 1f
@@ -417,18 +420,7 @@ __fixup_smp_on_up:
417 sub r3, r0, r3 420 sub r3, r0, r3
418 add r4, r4, r3 421 add r4, r4, r3
419 add r5, r5, r3 422 add r5, r5, r3
4202: cmp r4, r5 423 b __do_fixup_smp_on_up
421 movhs pc, lr
422 ldmia r4!, {r0, r6}
423 ARM( str r6, [r0, r3] )
424 THUMB( add r0, r0, r3 )
425#ifdef __ARMEB__
426 THUMB( mov r6, r6, ror #16 ) @ Convert word order for big-endian.
427#endif
428 THUMB( strh r6, [r0], #2 ) @ For Thumb-2, store as two halfwords
429 THUMB( mov r6, r6, lsr #16 ) @ to be robust against misaligned r3.
430 THUMB( strh r6, [r0] )
431 b 2b
432ENDPROC(__fixup_smp) 424ENDPROC(__fixup_smp)
433 425
434 .align 426 .align
@@ -442,7 +434,156 @@ smp_on_up:
442 ALT_SMP(.long 1) 434 ALT_SMP(.long 1)
443 ALT_UP(.long 0) 435 ALT_UP(.long 0)
444 .popsection 436 .popsection
437#endif
438
439 .text
440__do_fixup_smp_on_up:
441 cmp r4, r5
442 movhs pc, lr
443 ldmia r4!, {r0, r6}
444 ARM( str r6, [r0, r3] )
445 THUMB( add r0, r0, r3 )
446#ifdef __ARMEB__
447 THUMB( mov r6, r6, ror #16 ) @ Convert word order for big-endian.
448#endif
449 THUMB( strh r6, [r0], #2 ) @ For Thumb-2, store as two halfwords
450 THUMB( mov r6, r6, lsr #16 ) @ to be robust against misaligned r3.
451 THUMB( strh r6, [r0] )
452 b __do_fixup_smp_on_up
453ENDPROC(__do_fixup_smp_on_up)
454
455ENTRY(fixup_smp)
456 stmfd sp!, {r4 - r6, lr}
457 mov r4, r0
458 add r5, r0, r1
459 mov r3, #0
460 bl __do_fixup_smp_on_up
461 ldmfd sp!, {r4 - r6, pc}
462ENDPROC(fixup_smp)
463
464#ifdef CONFIG_ARM_PATCH_PHYS_VIRT
445 465
466/* __fixup_pv_table - patch the stub instructions with the delta between
467 * PHYS_OFFSET and PAGE_OFFSET, which is assumed to be 16MiB aligned and
468 * can be expressed by an immediate shifter operand. The stub instruction
469 * has a form of '(add|sub) rd, rn, #imm'.
470 */
471 __HEAD
472__fixup_pv_table:
473 adr r0, 1f
474 ldmia r0, {r3-r5, r7}
475 sub r3, r0, r3 @ PHYS_OFFSET - PAGE_OFFSET
476 add r4, r4, r3 @ adjust table start address
477 add r5, r5, r3 @ adjust table end address
478 add r7, r7, r3 @ adjust __pv_phys_offset address
479 str r8, [r7] @ save computed PHYS_OFFSET to __pv_phys_offset
480#ifndef CONFIG_ARM_PATCH_PHYS_VIRT_16BIT
481 mov r6, r3, lsr #24 @ constant for add/sub instructions
482 teq r3, r6, lsl #24 @ must be 16MiB aligned
483#else
484 mov r6, r3, lsr #16 @ constant for add/sub instructions
485 teq r3, r6, lsl #16 @ must be 64kiB aligned
486#endif
487THUMB( it ne @ cross section branch )
488 bne __error
489 str r6, [r7, #4] @ save to __pv_offset
490 b __fixup_a_pv_table
491ENDPROC(__fixup_pv_table)
492
493 .align
4941: .long .
495 .long __pv_table_begin
496 .long __pv_table_end
4972: .long __pv_phys_offset
498
499 .text
500__fixup_a_pv_table:
501#ifdef CONFIG_THUMB2_KERNEL
502#ifdef CONFIG_ARM_PATCH_PHYS_VIRT_16BIT
503 lsls r0, r6, #24
504 lsr r6, #8
505 beq 1f
506 clz r7, r0
507 lsr r0, #24
508 lsl r0, r7
509 bic r0, 0x0080
510 lsrs r7, #1
511 orrcs r0, #0x0080
512 orr r0, r0, r7, lsl #12
513#endif
5141: lsls r6, #24
515 beq 4f
516 clz r7, r6
517 lsr r6, #24
518 lsl r6, r7
519 bic r6, #0x0080
520 lsrs r7, #1
521 orrcs r6, #0x0080
522 orr r6, r6, r7, lsl #12
523 orr r6, #0x4000
524 b 4f
5252: @ at this point the C flag is always clear
526 add r7, r3
527#ifdef CONFIG_ARM_PATCH_PHYS_VIRT_16BIT
528 ldrh ip, [r7]
529 tst ip, 0x0400 @ the i bit tells us LS or MS byte
530 beq 3f
531 cmp r0, #0 @ set C flag, and ...
532 biceq ip, 0x0400 @ immediate zero value has a special encoding
533 streqh ip, [r7] @ that requires the i bit cleared
534#endif
5353: ldrh ip, [r7, #2]
536 and ip, 0x8f00
537 orrcc ip, r6 @ mask in offset bits 31-24
538 orrcs ip, r0 @ mask in offset bits 23-16
539 strh ip, [r7, #2]
5404: cmp r4, r5
541 ldrcc r7, [r4], #4 @ use branch for delay slot
542 bcc 2b
543 bx lr
544#else
545#ifdef CONFIG_ARM_PATCH_PHYS_VIRT_16BIT
546 and r0, r6, #255 @ offset bits 23-16
547 mov r6, r6, lsr #8 @ offset bits 31-24
548#else
549 mov r0, #0 @ just in case...
550#endif
551 b 3f
5522: ldr ip, [r7, r3]
553 bic ip, ip, #0x000000ff
554 tst ip, #0x400 @ rotate shift tells us LS or MS byte
555 orrne ip, ip, r6 @ mask in offset bits 31-24
556 orreq ip, ip, r0 @ mask in offset bits 23-16
557 str ip, [r7, r3]
5583: cmp r4, r5
559 ldrcc r7, [r4], #4 @ use branch for delay slot
560 bcc 2b
561 mov pc, lr
562#endif
563ENDPROC(__fixup_a_pv_table)
564
565ENTRY(fixup_pv_table)
566 stmfd sp!, {r4 - r7, lr}
567 ldr r2, 2f @ get address of __pv_phys_offset
568 mov r3, #0 @ no offset
569 mov r4, r0 @ r0 = table start
570 add r5, r0, r1 @ r1 = table size
571 ldr r6, [r2, #4] @ get __pv_offset
572 bl __fixup_a_pv_table
573 ldmfd sp!, {r4 - r7, pc}
574ENDPROC(fixup_pv_table)
575
576 .align
5772: .long __pv_phys_offset
578
579 .data
580 .globl __pv_phys_offset
581 .type __pv_phys_offset, %object
582__pv_phys_offset:
583 .long 0
584 .size __pv_phys_offset, . - __pv_phys_offset
585__pv_offset:
586 .long 0
446#endif 587#endif
447 588
448#include "head-common.S" 589#include "head-common.S"