diff options
Diffstat (limited to 'arch/arm/kernel/entry-armv.S')
-rw-r--r-- | arch/arm/kernel/entry-armv.S | 111 |
1 files changed, 73 insertions, 38 deletions
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index a46d5b456765..7dca225752c1 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S | |||
@@ -166,12 +166,12 @@ __dabt_svc: | |||
166 | @ The abort handler must return the aborted address in r0, and | 166 | @ The abort handler must return the aborted address in r0, and |
167 | @ the fault status register in r1. r9 must be preserved. | 167 | @ the fault status register in r1. r9 must be preserved. |
168 | @ | 168 | @ |
169 | #ifdef MULTI_ABORT | 169 | #ifdef MULTI_DABORT |
170 | ldr r4, .LCprocfns | 170 | ldr r4, .LCprocfns |
171 | mov lr, pc | 171 | mov lr, pc |
172 | ldr pc, [r4] | 172 | ldr pc, [r4, #PROCESSOR_DABT_FUNC] |
173 | #else | 173 | #else |
174 | bl CPU_ABORT_HANDLER | 174 | bl CPU_DABORT_HANDLER |
175 | #endif | 175 | #endif |
176 | 176 | ||
177 | @ | 177 | @ |
@@ -209,14 +209,12 @@ __irq_svc: | |||
209 | 209 | ||
210 | irq_handler | 210 | irq_handler |
211 | #ifdef CONFIG_PREEMPT | 211 | #ifdef CONFIG_PREEMPT |
212 | str r8, [tsk, #TI_PREEMPT] @ restore preempt count | ||
212 | ldr r0, [tsk, #TI_FLAGS] @ get flags | 213 | ldr r0, [tsk, #TI_FLAGS] @ get flags |
214 | teq r8, #0 @ if preempt count != 0 | ||
215 | movne r0, #0 @ force flags to 0 | ||
213 | tst r0, #_TIF_NEED_RESCHED | 216 | tst r0, #_TIF_NEED_RESCHED |
214 | blne svc_preempt | 217 | blne svc_preempt |
215 | preempt_return: | ||
216 | ldr r0, [tsk, #TI_PREEMPT] @ read preempt value | ||
217 | str r8, [tsk, #TI_PREEMPT] @ restore preempt count | ||
218 | teq r0, r7 | ||
219 | strne r0, [r0, -r0] @ bug() | ||
220 | #endif | 218 | #endif |
221 | ldr r0, [sp, #S_PSR] @ irqs are already disabled | 219 | ldr r0, [sp, #S_PSR] @ irqs are already disabled |
222 | msr spsr_cxsf, r0 | 220 | msr spsr_cxsf, r0 |
@@ -230,19 +228,11 @@ preempt_return: | |||
230 | 228 | ||
231 | #ifdef CONFIG_PREEMPT | 229 | #ifdef CONFIG_PREEMPT |
232 | svc_preempt: | 230 | svc_preempt: |
233 | teq r8, #0 @ was preempt count = 0 | 231 | mov r8, lr |
234 | ldreq r6, .LCirq_stat | ||
235 | movne pc, lr @ no | ||
236 | ldr r0, [r6, #4] @ local_irq_count | ||
237 | ldr r1, [r6, #8] @ local_bh_count | ||
238 | adds r0, r0, r1 | ||
239 | movne pc, lr | ||
240 | mov r7, #0 @ preempt_schedule_irq | ||
241 | str r7, [tsk, #TI_PREEMPT] @ expects preempt_count == 0 | ||
242 | 1: bl preempt_schedule_irq @ irq en/disable is done inside | 232 | 1: bl preempt_schedule_irq @ irq en/disable is done inside |
243 | ldr r0, [tsk, #TI_FLAGS] @ get new tasks TI_FLAGS | 233 | ldr r0, [tsk, #TI_FLAGS] @ get new tasks TI_FLAGS |
244 | tst r0, #_TIF_NEED_RESCHED | 234 | tst r0, #_TIF_NEED_RESCHED |
245 | beq preempt_return @ go again | 235 | moveq pc, r8 @ go again |
246 | b 1b | 236 | b 1b |
247 | #endif | 237 | #endif |
248 | 238 | ||
@@ -293,7 +283,6 @@ __pabt_svc: | |||
293 | mrs r9, cpsr | 283 | mrs r9, cpsr |
294 | tst r3, #PSR_I_BIT | 284 | tst r3, #PSR_I_BIT |
295 | biceq r9, r9, #PSR_I_BIT | 285 | biceq r9, r9, #PSR_I_BIT |
296 | msr cpsr_c, r9 | ||
297 | 286 | ||
298 | @ | 287 | @ |
299 | @ set args, then call main handler | 288 | @ set args, then call main handler |
@@ -301,7 +290,15 @@ __pabt_svc: | |||
301 | @ r0 - address of faulting instruction | 290 | @ r0 - address of faulting instruction |
302 | @ r1 - pointer to registers on stack | 291 | @ r1 - pointer to registers on stack |
303 | @ | 292 | @ |
304 | mov r0, r2 @ address (pc) | 293 | #ifdef MULTI_PABORT |
294 | mov r0, r2 @ pass address of aborted instruction. | ||
295 | ldr r4, .LCprocfns | ||
296 | mov lr, pc | ||
297 | ldr pc, [r4, #PROCESSOR_PABT_FUNC] | ||
298 | #else | ||
299 | CPU_PABORT_HANDLER(r0, r2) | ||
300 | #endif | ||
301 | msr cpsr_c, r9 @ Maybe enable interrupts | ||
305 | mov r1, sp @ regs | 302 | mov r1, sp @ regs |
306 | bl do_PrefetchAbort @ call abort handler | 303 | bl do_PrefetchAbort @ call abort handler |
307 | 304 | ||
@@ -320,16 +317,12 @@ __pabt_svc: | |||
320 | .align 5 | 317 | .align 5 |
321 | .LCcralign: | 318 | .LCcralign: |
322 | .word cr_alignment | 319 | .word cr_alignment |
323 | #ifdef MULTI_ABORT | 320 | #ifdef MULTI_DABORT |
324 | .LCprocfns: | 321 | .LCprocfns: |
325 | .word processor | 322 | .word processor |
326 | #endif | 323 | #endif |
327 | .LCfp: | 324 | .LCfp: |
328 | .word fp_enter | 325 | .word fp_enter |
329 | #ifdef CONFIG_PREEMPT | ||
330 | .LCirq_stat: | ||
331 | .word irq_stat | ||
332 | #endif | ||
333 | 326 | ||
334 | /* | 327 | /* |
335 | * User mode handlers | 328 | * User mode handlers |
@@ -404,12 +397,12 @@ __dabt_usr: | |||
404 | @ The abort handler must return the aborted address in r0, and | 397 | @ The abort handler must return the aborted address in r0, and |
405 | @ the fault status register in r1. | 398 | @ the fault status register in r1. |
406 | @ | 399 | @ |
407 | #ifdef MULTI_ABORT | 400 | #ifdef MULTI_DABORT |
408 | ldr r4, .LCprocfns | 401 | ldr r4, .LCprocfns |
409 | mov lr, pc | 402 | mov lr, pc |
410 | ldr pc, [r4] | 403 | ldr pc, [r4, #PROCESSOR_DABT_FUNC] |
411 | #else | 404 | #else |
412 | bl CPU_ABORT_HANDLER | 405 | bl CPU_DABORT_HANDLER |
413 | #endif | 406 | #endif |
414 | 407 | ||
415 | @ | 408 | @ |
@@ -455,10 +448,6 @@ __irq_usr: | |||
455 | __und_usr: | 448 | __und_usr: |
456 | usr_entry | 449 | usr_entry |
457 | 450 | ||
458 | tst r3, #PSR_T_BIT @ Thumb mode? | ||
459 | bne __und_usr_unknown @ ignore FP | ||
460 | sub r4, r2, #4 | ||
461 | |||
462 | @ | 451 | @ |
463 | @ fall through to the emulation code, which returns using r9 if | 452 | @ fall through to the emulation code, which returns using r9 if |
464 | @ it has emulated the instruction, or the more conventional lr | 453 | @ it has emulated the instruction, or the more conventional lr |
@@ -468,7 +457,24 @@ __und_usr: | |||
468 | @ | 457 | @ |
469 | adr r9, ret_from_exception | 458 | adr r9, ret_from_exception |
470 | adr lr, __und_usr_unknown | 459 | adr lr, __und_usr_unknown |
471 | 1: ldrt r0, [r4] | 460 | tst r3, #PSR_T_BIT @ Thumb mode? |
461 | subeq r4, r2, #4 @ ARM instr at LR - 4 | ||
462 | subne r4, r2, #2 @ Thumb instr at LR - 2 | ||
463 | 1: ldreqt r0, [r4] | ||
464 | beq call_fpe | ||
465 | @ Thumb instruction | ||
466 | #if __LINUX_ARM_ARCH__ >= 7 | ||
467 | 2: ldrht r5, [r4], #2 | ||
468 | and r0, r5, #0xf800 @ mask bits 111x x... .... .... | ||
469 | cmp r0, #0xe800 @ 32bit instruction if xx != 0 | ||
470 | blo __und_usr_unknown | ||
471 | 3: ldrht r0, [r4] | ||
472 | add r2, r2, #2 @ r2 is PC + 2, make it PC + 4 | ||
473 | orr r0, r0, r5, lsl #16 | ||
474 | #else | ||
475 | b __und_usr_unknown | ||
476 | #endif | ||
477 | |||
472 | @ | 478 | @ |
473 | @ fallthrough to call_fpe | 479 | @ fallthrough to call_fpe |
474 | @ | 480 | @ |
@@ -477,10 +483,14 @@ __und_usr: | |||
477 | * The out of line fixup for the ldrt above. | 483 | * The out of line fixup for the ldrt above. |
478 | */ | 484 | */ |
479 | .section .fixup, "ax" | 485 | .section .fixup, "ax" |
480 | 2: mov pc, r9 | 486 | 4: mov pc, r9 |
481 | .previous | 487 | .previous |
482 | .section __ex_table,"a" | 488 | .section __ex_table,"a" |
483 | .long 1b, 2b | 489 | .long 1b, 4b |
490 | #if __LINUX_ARM_ARCH__ >= 7 | ||
491 | .long 2b, 4b | ||
492 | .long 3b, 4b | ||
493 | #endif | ||
484 | .previous | 494 | .previous |
485 | 495 | ||
486 | /* | 496 | /* |
@@ -507,9 +517,16 @@ __und_usr: | |||
507 | * r10 = this threads thread_info structure. | 517 | * r10 = this threads thread_info structure. |
508 | * lr = unrecognised instruction return address | 518 | * lr = unrecognised instruction return address |
509 | */ | 519 | */ |
520 | @ | ||
521 | @ Fall-through from Thumb-2 __und_usr | ||
522 | @ | ||
523 | #ifdef CONFIG_NEON | ||
524 | adr r6, .LCneon_thumb_opcodes | ||
525 | b 2f | ||
526 | #endif | ||
510 | call_fpe: | 527 | call_fpe: |
511 | #ifdef CONFIG_NEON | 528 | #ifdef CONFIG_NEON |
512 | adr r6, .LCneon_opcodes | 529 | adr r6, .LCneon_arm_opcodes |
513 | 2: | 530 | 2: |
514 | ldr r7, [r6], #4 @ mask value | 531 | ldr r7, [r6], #4 @ mask value |
515 | cmp r7, #0 @ end mask? | 532 | cmp r7, #0 @ end mask? |
@@ -526,6 +543,7 @@ call_fpe: | |||
526 | 1: | 543 | 1: |
527 | #endif | 544 | #endif |
528 | tst r0, #0x08000000 @ only CDP/CPRT/LDC/STC have bit 27 | 545 | tst r0, #0x08000000 @ only CDP/CPRT/LDC/STC have bit 27 |
546 | tstne r0, #0x04000000 @ bit 26 set on both ARM and Thumb-2 | ||
529 | #if defined(CONFIG_CPU_ARM610) || defined(CONFIG_CPU_ARM710) | 547 | #if defined(CONFIG_CPU_ARM610) || defined(CONFIG_CPU_ARM710) |
530 | and r8, r0, #0x0f000000 @ mask out op-code bits | 548 | and r8, r0, #0x0f000000 @ mask out op-code bits |
531 | teqne r8, #0x0f000000 @ SWI (ARM6/7 bug)? | 549 | teqne r8, #0x0f000000 @ SWI (ARM6/7 bug)? |
@@ -577,7 +595,7 @@ call_fpe: | |||
577 | #ifdef CONFIG_NEON | 595 | #ifdef CONFIG_NEON |
578 | .align 6 | 596 | .align 6 |
579 | 597 | ||
580 | .LCneon_opcodes: | 598 | .LCneon_arm_opcodes: |
581 | .word 0xfe000000 @ mask | 599 | .word 0xfe000000 @ mask |
582 | .word 0xf2000000 @ opcode | 600 | .word 0xf2000000 @ opcode |
583 | 601 | ||
@@ -586,6 +604,16 @@ call_fpe: | |||
586 | 604 | ||
587 | .word 0x00000000 @ mask | 605 | .word 0x00000000 @ mask |
588 | .word 0x00000000 @ opcode | 606 | .word 0x00000000 @ opcode |
607 | |||
608 | .LCneon_thumb_opcodes: | ||
609 | .word 0xef000000 @ mask | ||
610 | .word 0xef000000 @ opcode | ||
611 | |||
612 | .word 0xff100000 @ mask | ||
613 | .word 0xf9000000 @ opcode | ||
614 | |||
615 | .word 0x00000000 @ mask | ||
616 | .word 0x00000000 @ opcode | ||
589 | #endif | 617 | #endif |
590 | 618 | ||
591 | do_fpe: | 619 | do_fpe: |
@@ -619,8 +647,15 @@ __und_usr_unknown: | |||
619 | __pabt_usr: | 647 | __pabt_usr: |
620 | usr_entry | 648 | usr_entry |
621 | 649 | ||
650 | #ifdef MULTI_PABORT | ||
651 | mov r0, r2 @ pass address of aborted instruction. | ||
652 | ldr r4, .LCprocfns | ||
653 | mov lr, pc | ||
654 | ldr pc, [r4, #PROCESSOR_PABT_FUNC] | ||
655 | #else | ||
656 | CPU_PABORT_HANDLER(r0, r2) | ||
657 | #endif | ||
622 | enable_irq @ Enable interrupts | 658 | enable_irq @ Enable interrupts |
623 | mov r0, r2 @ address (pc) | ||
624 | mov r1, sp @ regs | 659 | mov r1, sp @ regs |
625 | bl do_PrefetchAbort @ call abort handler | 660 | bl do_PrefetchAbort @ call abort handler |
626 | /* fall through */ | 661 | /* fall through */ |