diff options
Diffstat (limited to 'arch/arm')
-rw-r--r-- | arch/arm/kernel/entry-armv.S | 172 | ||||
-rw-r--r-- | arch/arm/kernel/setup.c | 52 |
2 files changed, 139 insertions, 85 deletions
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index cfb5cf5e48fc..78cf84cdc2ae 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S | |||
@@ -53,46 +53,62 @@ | |||
53 | /* | 53 | /* |
54 | * Invalid mode handlers | 54 | * Invalid mode handlers |
55 | */ | 55 | */ |
56 | .macro inv_entry, sym, reason | 56 | .macro inv_entry, reason |
57 | sub sp, sp, #S_FRAME_SIZE @ Allocate frame size in one go | 57 | sub sp, sp, #S_FRAME_SIZE |
58 | stmia sp, {r0 - lr} @ Save XXX r0 - lr | 58 | stmib sp, {r1 - lr} |
59 | ldr r4, .LC\sym | ||
60 | mov r1, #\reason | 59 | mov r1, #\reason |
61 | .endm | 60 | .endm |
62 | 61 | ||
63 | __pabt_invalid: | 62 | __pabt_invalid: |
64 | inv_entry abt, BAD_PREFETCH | 63 | inv_entry BAD_PREFETCH |
65 | b 1f | 64 | b common_invalid |
66 | 65 | ||
67 | __dabt_invalid: | 66 | __dabt_invalid: |
68 | inv_entry abt, BAD_DATA | 67 | inv_entry BAD_DATA |
69 | b 1f | 68 | b common_invalid |
70 | 69 | ||
71 | __irq_invalid: | 70 | __irq_invalid: |
72 | inv_entry irq, BAD_IRQ | 71 | inv_entry BAD_IRQ |
73 | b 1f | 72 | b common_invalid |
74 | 73 | ||
75 | __und_invalid: | 74 | __und_invalid: |
76 | inv_entry und, BAD_UNDEFINSTR | 75 | inv_entry BAD_UNDEFINSTR |
76 | |||
77 | @ | ||
78 | @ XXX fall through to common_invalid | ||
79 | @ | ||
80 | |||
81 | @ | ||
82 | @ common_invalid - generic code for failed exception (re-entrant version of handlers) | ||
83 | @ | ||
84 | common_invalid: | ||
85 | zero_fp | ||
86 | |||
87 | ldmia r0, {r4 - r6} | ||
88 | add r0, sp, #S_PC @ here for interlock avoidance | ||
89 | mov r7, #-1 @ "" "" "" "" | ||
90 | str r4, [sp] @ save preserved r0 | ||
91 | stmia r0, {r5 - r7} @ lr_<exception>, | ||
92 | @ cpsr_<exception>, "old_r0" | ||
77 | 93 | ||
78 | 1: zero_fp | ||
79 | ldmia r4, {r5 - r7} @ Get XXX pc, cpsr, old_r0 | ||
80 | add r4, sp, #S_PC | ||
81 | stmia r4, {r5 - r7} @ Save XXX pc, cpsr, old_r0 | ||
82 | mov r0, sp | 94 | mov r0, sp |
83 | and r2, r6, #31 @ int mode | 95 | and r2, r6, #0x1f |
84 | b bad_mode | 96 | b bad_mode |
85 | 97 | ||
86 | /* | 98 | /* |
87 | * SVC mode handlers | 99 | * SVC mode handlers |
88 | */ | 100 | */ |
89 | .macro svc_entry, sym | 101 | .macro svc_entry |
90 | sub sp, sp, #S_FRAME_SIZE | 102 | sub sp, sp, #S_FRAME_SIZE |
91 | stmia sp, {r0 - r12} @ save r0 - r12 | 103 | stmib sp, {r1 - r12} |
92 | ldr r2, .LC\sym | 104 | |
93 | add r0, sp, #S_FRAME_SIZE | 105 | ldmia r0, {r1 - r3} |
94 | ldmia r2, {r2 - r4} @ get pc, cpsr | 106 | add r5, sp, #S_SP @ here for interlock avoidance |
95 | add r5, sp, #S_SP | 107 | mov r4, #-1 @ "" "" "" "" |
108 | add r0, sp, #S_FRAME_SIZE @ "" "" "" "" | ||
109 | str r1, [sp] @ save the "real" r0 copied | ||
110 | @ from the exception stack | ||
111 | |||
96 | mov r1, lr | 112 | mov r1, lr |
97 | 113 | ||
98 | @ | 114 | @ |
@@ -109,7 +125,7 @@ __und_invalid: | |||
109 | 125 | ||
110 | .align 5 | 126 | .align 5 |
111 | __dabt_svc: | 127 | __dabt_svc: |
112 | svc_entry abt | 128 | svc_entry |
113 | 129 | ||
114 | @ | 130 | @ |
115 | @ get ready to re-enable interrupts if appropriate | 131 | @ get ready to re-enable interrupts if appropriate |
@@ -156,13 +172,15 @@ __dabt_svc: | |||
156 | 172 | ||
157 | .align 5 | 173 | .align 5 |
158 | __irq_svc: | 174 | __irq_svc: |
159 | svc_entry irq | 175 | svc_entry |
176 | |||
160 | #ifdef CONFIG_PREEMPT | 177 | #ifdef CONFIG_PREEMPT |
161 | get_thread_info tsk | 178 | get_thread_info tsk |
162 | ldr r8, [tsk, #TI_PREEMPT] @ get preempt count | 179 | ldr r8, [tsk, #TI_PREEMPT] @ get preempt count |
163 | add r7, r8, #1 @ increment it | 180 | add r7, r8, #1 @ increment it |
164 | str r7, [tsk, #TI_PREEMPT] | 181 | str r7, [tsk, #TI_PREEMPT] |
165 | #endif | 182 | #endif |
183 | |||
166 | irq_handler | 184 | irq_handler |
167 | #ifdef CONFIG_PREEMPT | 185 | #ifdef CONFIG_PREEMPT |
168 | ldr r0, [tsk, #TI_FLAGS] @ get flags | 186 | ldr r0, [tsk, #TI_FLAGS] @ get flags |
@@ -200,7 +218,7 @@ svc_preempt: | |||
200 | 218 | ||
201 | .align 5 | 219 | .align 5 |
202 | __und_svc: | 220 | __und_svc: |
203 | svc_entry und | 221 | svc_entry |
204 | 222 | ||
205 | @ | 223 | @ |
206 | @ call emulation code, which returns using r9 if it has emulated | 224 | @ call emulation code, which returns using r9 if it has emulated |
@@ -230,7 +248,7 @@ __und_svc: | |||
230 | 248 | ||
231 | .align 5 | 249 | .align 5 |
232 | __pabt_svc: | 250 | __pabt_svc: |
233 | svc_entry abt | 251 | svc_entry |
234 | 252 | ||
235 | @ | 253 | @ |
236 | @ re-enable interrupts if appropriate | 254 | @ re-enable interrupts if appropriate |
@@ -263,12 +281,6 @@ __pabt_svc: | |||
263 | ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr | 281 | ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr |
264 | 282 | ||
265 | .align 5 | 283 | .align 5 |
266 | .LCirq: | ||
267 | .word __temp_irq | ||
268 | .LCund: | ||
269 | .word __temp_und | ||
270 | .LCabt: | ||
271 | .word __temp_abt | ||
272 | .LCcralign: | 284 | .LCcralign: |
273 | .word cr_alignment | 285 | .word cr_alignment |
274 | #ifdef MULTI_ABORT | 286 | #ifdef MULTI_ABORT |
@@ -285,12 +297,16 @@ __pabt_svc: | |||
285 | /* | 297 | /* |
286 | * User mode handlers | 298 | * User mode handlers |
287 | */ | 299 | */ |
288 | .macro usr_entry, sym | 300 | .macro usr_entry |
289 | sub sp, sp, #S_FRAME_SIZE @ Allocate frame size in one go | 301 | sub sp, sp, #S_FRAME_SIZE |
290 | stmia sp, {r0 - r12} @ save r0 - r12 | 302 | stmib sp, {r1 - r12} |
291 | ldr r7, .LC\sym | 303 | |
292 | add r5, sp, #S_PC | 304 | ldmia r0, {r1 - r3} |
293 | ldmia r7, {r2 - r4} @ Get USR pc, cpsr | 305 | add r0, sp, #S_PC @ here for interlock avoidance |
306 | mov r4, #-1 @ "" "" "" "" | ||
307 | |||
308 | str r1, [sp] @ save the "real" r0 copied | ||
309 | @ from the exception stack | ||
294 | 310 | ||
295 | #if __LINUX_ARM_ARCH__ < 6 | 311 | #if __LINUX_ARM_ARCH__ < 6 |
296 | @ make sure our user space atomic helper is aborted | 312 | @ make sure our user space atomic helper is aborted |
@@ -307,8 +323,8 @@ __pabt_svc: | |||
307 | @ | 323 | @ |
308 | @ Also, separately save sp_usr and lr_usr | 324 | @ Also, separately save sp_usr and lr_usr |
309 | @ | 325 | @ |
310 | stmia r5, {r2 - r4} | 326 | stmia r0, {r2 - r4} |
311 | stmdb r5, {sp, lr}^ | 327 | stmdb r0, {sp, lr}^ |
312 | 328 | ||
313 | @ | 329 | @ |
314 | @ Enable the alignment trap while in kernel mode | 330 | @ Enable the alignment trap while in kernel mode |
@@ -323,7 +339,7 @@ __pabt_svc: | |||
323 | 339 | ||
324 | .align 5 | 340 | .align 5 |
325 | __dabt_usr: | 341 | __dabt_usr: |
326 | usr_entry abt | 342 | usr_entry |
327 | 343 | ||
328 | @ | 344 | @ |
329 | @ Call the processor-specific abort handler: | 345 | @ Call the processor-specific abort handler: |
@@ -352,7 +368,7 @@ __dabt_usr: | |||
352 | 368 | ||
353 | .align 5 | 369 | .align 5 |
354 | __irq_usr: | 370 | __irq_usr: |
355 | usr_entry irq | 371 | usr_entry |
356 | 372 | ||
357 | get_thread_info tsk | 373 | get_thread_info tsk |
358 | #ifdef CONFIG_PREEMPT | 374 | #ifdef CONFIG_PREEMPT |
@@ -360,6 +376,7 @@ __irq_usr: | |||
360 | add r7, r8, #1 @ increment it | 376 | add r7, r8, #1 @ increment it |
361 | str r7, [tsk, #TI_PREEMPT] | 377 | str r7, [tsk, #TI_PREEMPT] |
362 | #endif | 378 | #endif |
379 | |||
363 | irq_handler | 380 | irq_handler |
364 | #ifdef CONFIG_PREEMPT | 381 | #ifdef CONFIG_PREEMPT |
365 | ldr r0, [tsk, #TI_PREEMPT] | 382 | ldr r0, [tsk, #TI_PREEMPT] |
@@ -367,6 +384,7 @@ __irq_usr: | |||
367 | teq r0, r7 | 384 | teq r0, r7 |
368 | strne r0, [r0, -r0] | 385 | strne r0, [r0, -r0] |
369 | #endif | 386 | #endif |
387 | |||
370 | mov why, #0 | 388 | mov why, #0 |
371 | b ret_to_user | 389 | b ret_to_user |
372 | 390 | ||
@@ -374,7 +392,7 @@ __irq_usr: | |||
374 | 392 | ||
375 | .align 5 | 393 | .align 5 |
376 | __und_usr: | 394 | __und_usr: |
377 | usr_entry und | 395 | usr_entry |
378 | 396 | ||
379 | tst r3, #PSR_T_BIT @ Thumb mode? | 397 | tst r3, #PSR_T_BIT @ Thumb mode? |
380 | bne fpundefinstr @ ignore FP | 398 | bne fpundefinstr @ ignore FP |
@@ -490,7 +508,7 @@ fpundefinstr: | |||
490 | 508 | ||
491 | .align 5 | 509 | .align 5 |
492 | __pabt_usr: | 510 | __pabt_usr: |
493 | usr_entry abt | 511 | usr_entry |
494 | 512 | ||
495 | enable_irq @ Enable interrupts | 513 | enable_irq @ Enable interrupts |
496 | mov r0, r2 @ address (pc) | 514 | mov r0, r2 @ address (pc) |
@@ -749,29 +767,41 @@ __kuser_helper_end: | |||
749 | * | 767 | * |
750 | * Common stub entry macro: | 768 | * Common stub entry macro: |
751 | * Enter in IRQ mode, spsr = SVC/USR CPSR, lr = SVC/USR PC | 769 | * Enter in IRQ mode, spsr = SVC/USR CPSR, lr = SVC/USR PC |
770 | * | ||
771 | * SP points to a minimal amount of processor-private memory, the address | ||
772 | * of which is copied into r0 for the mode specific abort handler. | ||
752 | */ | 773 | */ |
753 | .macro vector_stub, name, sym, correction=0 | 774 | .macro vector_stub, name, correction=0 |
754 | .align 5 | 775 | .align 5 |
755 | 776 | ||
756 | vector_\name: | 777 | vector_\name: |
757 | ldr r13, .LCs\sym | ||
758 | .if \correction | 778 | .if \correction |
759 | sub lr, lr, #\correction | 779 | sub lr, lr, #\correction |
760 | .endif | 780 | .endif |
761 | str lr, [r13] @ save lr_IRQ | 781 | |
782 | @ | ||
783 | @ Save r0, lr_<exception> (parent PC) and spsr_<exception> | ||
784 | @ (parent CPSR) | ||
785 | @ | ||
786 | stmia sp, {r0, lr} @ save r0, lr | ||
762 | mrs lr, spsr | 787 | mrs lr, spsr |
763 | str lr, [r13, #4] @ save spsr_IRQ | 788 | str lr, [sp, #8] @ save spsr |
789 | |||
764 | @ | 790 | @ |
765 | @ now branch to the relevant MODE handling routine | 791 | @ Prepare for SVC32 mode. IRQs remain disabled. |
766 | @ | 792 | @ |
767 | mrs r13, cpsr | 793 | mrs r0, cpsr |
768 | bic r13, r13, #MODE_MASK | 794 | bic r0, r0, #MODE_MASK |
769 | orr r13, r13, #SVC_MODE | 795 | orr r0, r0, #SVC_MODE |
770 | msr spsr_cxsf, r13 @ switch to SVC_32 mode | 796 | msr spsr_cxsf, r0 |
771 | 797 | ||
772 | and lr, lr, #15 | 798 | @ |
799 | @ the branch table must immediately follow this code | ||
800 | @ | ||
801 | mov r0, sp | ||
802 | and lr, lr, #0x0f | ||
773 | ldr lr, [pc, lr, lsl #2] | 803 | ldr lr, [pc, lr, lsl #2] |
774 | movs pc, lr @ Changes mode and branches | 804 | movs pc, lr @ branch to handler in SVC mode |
775 | .endm | 805 | .endm |
776 | 806 | ||
777 | .globl __stubs_start | 807 | .globl __stubs_start |
@@ -779,7 +809,7 @@ __stubs_start: | |||
779 | /* | 809 | /* |
780 | * Interrupt dispatcher | 810 | * Interrupt dispatcher |
781 | */ | 811 | */ |
782 | vector_stub irq, irq, 4 | 812 | vector_stub irq, 4 |
783 | 813 | ||
784 | .long __irq_usr @ 0 (USR_26 / USR_32) | 814 | .long __irq_usr @ 0 (USR_26 / USR_32) |
785 | .long __irq_invalid @ 1 (FIQ_26 / FIQ_32) | 815 | .long __irq_invalid @ 1 (FIQ_26 / FIQ_32) |
@@ -802,7 +832,7 @@ __stubs_start: | |||
802 | * Data abort dispatcher | 832 | * Data abort dispatcher |
803 | * Enter in ABT mode, spsr = USR CPSR, lr = USR PC | 833 | * Enter in ABT mode, spsr = USR CPSR, lr = USR PC |
804 | */ | 834 | */ |
805 | vector_stub dabt, abt, 8 | 835 | vector_stub dabt, 8 |
806 | 836 | ||
807 | .long __dabt_usr @ 0 (USR_26 / USR_32) | 837 | .long __dabt_usr @ 0 (USR_26 / USR_32) |
808 | .long __dabt_invalid @ 1 (FIQ_26 / FIQ_32) | 838 | .long __dabt_invalid @ 1 (FIQ_26 / FIQ_32) |
@@ -825,7 +855,7 @@ __stubs_start: | |||
825 | * Prefetch abort dispatcher | 855 | * Prefetch abort dispatcher |
826 | * Enter in ABT mode, spsr = USR CPSR, lr = USR PC | 856 | * Enter in ABT mode, spsr = USR CPSR, lr = USR PC |
827 | */ | 857 | */ |
828 | vector_stub pabt, abt, 4 | 858 | vector_stub pabt, 4 |
829 | 859 | ||
830 | .long __pabt_usr @ 0 (USR_26 / USR_32) | 860 | .long __pabt_usr @ 0 (USR_26 / USR_32) |
831 | .long __pabt_invalid @ 1 (FIQ_26 / FIQ_32) | 861 | .long __pabt_invalid @ 1 (FIQ_26 / FIQ_32) |
@@ -848,7 +878,7 @@ __stubs_start: | |||
848 | * Undef instr entry dispatcher | 878 | * Undef instr entry dispatcher |
849 | * Enter in UND mode, spsr = SVC/USR CPSR, lr = SVC/USR PC | 879 | * Enter in UND mode, spsr = SVC/USR CPSR, lr = SVC/USR PC |
850 | */ | 880 | */ |
851 | vector_stub und, und | 881 | vector_stub und |
852 | 882 | ||
853 | .long __und_usr @ 0 (USR_26 / USR_32) | 883 | .long __und_usr @ 0 (USR_26 / USR_32) |
854 | .long __und_invalid @ 1 (FIQ_26 / FIQ_32) | 884 | .long __und_invalid @ 1 (FIQ_26 / FIQ_32) |
@@ -902,13 +932,6 @@ vector_addrexcptn: | |||
902 | .LCvswi: | 932 | .LCvswi: |
903 | .word vector_swi | 933 | .word vector_swi |
904 | 934 | ||
905 | .LCsirq: | ||
906 | .word __temp_irq | ||
907 | .LCsund: | ||
908 | .word __temp_und | ||
909 | .LCsabt: | ||
910 | .word __temp_abt | ||
911 | |||
912 | .globl __stubs_end | 935 | .globl __stubs_end |
913 | __stubs_end: | 936 | __stubs_end: |
914 | 937 | ||
@@ -930,23 +953,6 @@ __vectors_end: | |||
930 | 953 | ||
931 | .data | 954 | .data |
932 | 955 | ||
933 | /* | ||
934 | * Do not reorder these, and do not insert extra data between... | ||
935 | */ | ||
936 | |||
937 | __temp_irq: | ||
938 | .word 0 @ saved lr_irq | ||
939 | .word 0 @ saved spsr_irq | ||
940 | .word -1 @ old_r0 | ||
941 | __temp_und: | ||
942 | .word 0 @ Saved lr_und | ||
943 | .word 0 @ Saved spsr_und | ||
944 | .word -1 @ old_r0 | ||
945 | __temp_abt: | ||
946 | .word 0 @ Saved lr_abt | ||
947 | .word 0 @ Saved spsr_abt | ||
948 | .word -1 @ old_r0 | ||
949 | |||
950 | .globl cr_alignment | 956 | .globl cr_alignment |
951 | .globl cr_no_alignment | 957 | .globl cr_no_alignment |
952 | cr_alignment: | 958 | cr_alignment: |
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index c2a7da3ac0f1..7ecdda3f1253 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c | |||
@@ -92,6 +92,14 @@ struct cpu_user_fns cpu_user; | |||
92 | struct cpu_cache_fns cpu_cache; | 92 | struct cpu_cache_fns cpu_cache; |
93 | #endif | 93 | #endif |
94 | 94 | ||
95 | struct stack { | ||
96 | u32 irq[3]; | ||
97 | u32 abt[3]; | ||
98 | u32 und[3]; | ||
99 | } ____cacheline_aligned; | ||
100 | |||
101 | static struct stack stacks[NR_CPUS]; | ||
102 | |||
95 | char elf_platform[ELF_PLATFORM_SIZE]; | 103 | char elf_platform[ELF_PLATFORM_SIZE]; |
96 | EXPORT_SYMBOL(elf_platform); | 104 | EXPORT_SYMBOL(elf_platform); |
97 | 105 | ||
@@ -307,8 +315,6 @@ static void __init setup_processor(void) | |||
307 | cpu_name, processor_id, (int)processor_id & 15, | 315 | cpu_name, processor_id, (int)processor_id & 15, |
308 | proc_arch[cpu_architecture()]); | 316 | proc_arch[cpu_architecture()]); |
309 | 317 | ||
310 | dump_cpu_info(smp_processor_id()); | ||
311 | |||
312 | sprintf(system_utsname.machine, "%s%c", list->arch_name, ENDIANNESS); | 318 | sprintf(system_utsname.machine, "%s%c", list->arch_name, ENDIANNESS); |
313 | sprintf(elf_platform, "%s%c", list->elf_name, ENDIANNESS); | 319 | sprintf(elf_platform, "%s%c", list->elf_name, ENDIANNESS); |
314 | elf_hwcap = list->elf_hwcap; | 320 | elf_hwcap = list->elf_hwcap; |
@@ -316,6 +322,46 @@ static void __init setup_processor(void) | |||
316 | cpu_proc_init(); | 322 | cpu_proc_init(); |
317 | } | 323 | } |
318 | 324 | ||
325 | /* | ||
326 | * cpu_init - initialise one CPU. | ||
327 | * | ||
328 | * cpu_init dumps the cache information, initialises SMP specific | ||
329 | * information, and sets up the per-CPU stacks. | ||
330 | */ | ||
331 | void __init cpu_init(void) | ||
332 | { | ||
333 | unsigned int cpu = smp_processor_id(); | ||
334 | struct stack *stk = &stacks[cpu]; | ||
335 | |||
336 | if (cpu >= NR_CPUS) { | ||
337 | printk(KERN_CRIT "CPU%u: bad primary CPU number\n", cpu); | ||
338 | BUG(); | ||
339 | } | ||
340 | |||
341 | dump_cpu_info(cpu); | ||
342 | |||
343 | /* | ||
344 | * setup stacks for re-entrant exception handlers | ||
345 | */ | ||
346 | __asm__ ( | ||
347 | "msr cpsr_c, %1\n\t" | ||
348 | "add sp, %0, %2\n\t" | ||
349 | "msr cpsr_c, %3\n\t" | ||
350 | "add sp, %0, %4\n\t" | ||
351 | "msr cpsr_c, %5\n\t" | ||
352 | "add sp, %0, %6\n\t" | ||
353 | "msr cpsr_c, %7" | ||
354 | : | ||
355 | : "r" (stk), | ||
356 | "I" (PSR_F_BIT | PSR_I_BIT | IRQ_MODE), | ||
357 | "I" (offsetof(struct stack, irq[0])), | ||
358 | "I" (PSR_F_BIT | PSR_I_BIT | ABT_MODE), | ||
359 | "I" (offsetof(struct stack, abt[0])), | ||
360 | "I" (PSR_F_BIT | PSR_I_BIT | UND_MODE), | ||
361 | "I" (offsetof(struct stack, und[0])), | ||
362 | "I" (PSR_F_BIT | PSR_I_BIT | SVC_MODE)); | ||
363 | } | ||
364 | |||
319 | static struct machine_desc * __init setup_machine(unsigned int nr) | 365 | static struct machine_desc * __init setup_machine(unsigned int nr) |
320 | { | 366 | { |
321 | struct machine_desc *list; | 367 | struct machine_desc *list; |
@@ -715,6 +761,8 @@ void __init setup_arch(char **cmdline_p) | |||
715 | paging_init(&meminfo, mdesc); | 761 | paging_init(&meminfo, mdesc); |
716 | request_standard_resources(&meminfo, mdesc); | 762 | request_standard_resources(&meminfo, mdesc); |
717 | 763 | ||
764 | cpu_init(); | ||
765 | |||
718 | /* | 766 | /* |
719 | * Set up various architecture-specific pointers | 767 | * Set up various architecture-specific pointers |
720 | */ | 768 | */ |