diff options
Diffstat (limited to 'arch/arm/kernel/entry-armv.S')
| -rw-r--r-- | arch/arm/kernel/entry-armv.S | 172 |
1 files changed, 89 insertions, 83 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: |
