aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/kernel/entry-armv.S172
-rw-r--r--arch/arm/kernel/setup.c52
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@
84common_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
781: 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
756vector_\name: 777vector_\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
952cr_alignment: 958cr_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;
92struct cpu_cache_fns cpu_cache; 92struct cpu_cache_fns cpu_cache;
93#endif 93#endif
94 94
95struct stack {
96 u32 irq[3];
97 u32 abt[3];
98 u32 und[3];
99} ____cacheline_aligned;
100
101static struct stack stacks[NR_CPUS];
102
95char elf_platform[ELF_PLATFORM_SIZE]; 103char elf_platform[ELF_PLATFORM_SIZE];
96EXPORT_SYMBOL(elf_platform); 104EXPORT_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 */
331void __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
319static struct machine_desc * __init setup_machine(unsigned int nr) 365static 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 */