diff options
Diffstat (limited to 'arch/avr32/kernel/entry-avr32b.S')
| -rw-r--r-- | arch/avr32/kernel/entry-avr32b.S | 244 |
1 files changed, 150 insertions, 94 deletions
diff --git a/arch/avr32/kernel/entry-avr32b.S b/arch/avr32/kernel/entry-avr32b.S index 8cf16d7a704..7301f4806bb 100644 --- a/arch/avr32/kernel/entry-avr32b.S +++ b/arch/avr32/kernel/entry-avr32b.S @@ -74,50 +74,41 @@ exception_vectors: .align 2 bral do_dtlb_modified - /* - * r0 : PGD/PT/PTE - * r1 : Offending address - * r2 : Scratch register - * r3 : Cause (5, 12 or 13) - */ #define tlbmiss_save pushm r0-r3 #define tlbmiss_restore popm r0-r3 - .section .tlbx.ex.text,"ax",@progbits + .org 0x50 .global itlb_miss itlb_miss: tlbmiss_save rjmp tlb_miss_common - .section .tlbr.ex.text,"ax",@progbits + .org 0x60 dtlb_miss_read: tlbmiss_save rjmp tlb_miss_common - .section .tlbw.ex.text,"ax",@progbits + .org 0x70 dtlb_miss_write: tlbmiss_save .global tlb_miss_common + .align 2 tlb_miss_common: mfsr r0, SYSREG_TLBEAR mfsr r1, SYSREG_PTBR - /* Is it the vmalloc space? */ - bld r0, 31 - brcs handle_vmalloc_miss - - /* First level lookup */ + /* + * First level lookup: The PGD contains virtual pointers to + * the second-level page tables, but they may be NULL if not + * present. + */ pgtbl_lookup: lsr r2, r0, PGDIR_SHIFT ld.w r3, r1[r2 << 2] bfextu r1, r0, PAGE_SHIFT, PGDIR_SHIFT - PAGE_SHIFT - bld r3, _PAGE_BIT_PRESENT - brcc page_table_not_present - - /* Translate to virtual address in P1. */ - andl r3, 0xf000 - sbr r3, 31 + cp.w r3, 0 + breq page_table_not_present /* Second level lookup */ ld.w r2, r3[r1 << 2] @@ -148,16 +139,55 @@ pgtbl_lookup: tlbmiss_restore rete -handle_vmalloc_miss: - /* Simply do the lookup in init's page table */ + /* The slow path of the TLB miss handler */ + .align 2 +page_table_not_present: + /* Do we need to synchronize with swapper_pg_dir? */ + bld r0, 31 + brcs sync_with_swapper_pg_dir + +page_not_present: + tlbmiss_restore + sub sp, 4 + stmts --sp, r0-lr + call save_full_context_ex + mfsr r12, SYSREG_ECR + mov r11, sp + call do_page_fault + rjmp ret_from_exception + + .align 2 +sync_with_swapper_pg_dir: + /* + * If swapper_pg_dir contains a non-NULL second-level page + * table pointer, copy it into the current PGD. If not, we + * must handle it as a full-blown page fault. + * + * Jumping back to pgtbl_lookup causes an unnecessary lookup, + * but it is guaranteed to be a cache hit, it won't happen + * very often, and we absolutely do not want to sacrifice any + * performance in the fast path in order to improve this. + */ mov r1, lo(swapper_pg_dir) orh r1, hi(swapper_pg_dir) + ld.w r3, r1[r2 << 2] + cp.w r3, 0 + breq page_not_present + mfsr r1, SYSREG_PTBR + st.w r1[r2 << 2], r3 rjmp pgtbl_lookup + /* + * We currently have two bytes left at this point until we + * crash into the system call handler... + * + * Don't worry, the assembler will let us know. + */ + /* --- System Call --- */ - .section .scall.text,"ax",@progbits + .org 0x100 system_call: #ifdef CONFIG_PREEMPT mask_interrupts @@ -220,18 +250,20 @@ syscall_badsys: .global ret_from_fork ret_from_fork: - rcall schedule_tail + call schedule_tail + mov r12, 0 + rjmp syscall_return - /* check for syscall tracing */ - get_thread_info r0 - ld.w r1, r0[TI_flags] - andl r1, _TIF_ALLWORK_MASK, COH - brne syscall_exit_work - rjmp syscall_exit_cont + .global ret_from_kernel_thread +ret_from_kernel_thread: + call schedule_tail + mov r12, r0 + mov lr, r2 /* syscall_return */ + mov pc, r1 syscall_trace_enter: pushm r8-r12 - rcall syscall_trace + call syscall_trace popm r8-r12 rjmp syscall_trace_cont @@ -239,25 +271,25 @@ syscall_exit_work: bld r1, TIF_SYSCALL_TRACE brcc 1f unmask_interrupts - rcall syscall_trace + call syscall_trace mask_interrupts ld.w r1, r0[TI_flags] 1: bld r1, TIF_NEED_RESCHED brcc 2f unmask_interrupts - rcall schedule + call schedule mask_interrupts ld.w r1, r0[TI_flags] rjmp 1b -2: mov r2, _TIF_SIGPENDING | _TIF_RESTORE_SIGMASK +2: mov r2, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME tst r1, r2 breq 3f unmask_interrupts mov r12, sp mov r11, r0 - rcall do_notify_resume + call do_notify_resume mask_interrupts ld.w r1, r0[TI_flags] rjmp 1b @@ -266,18 +298,6 @@ syscall_exit_work: brcc syscall_exit_cont rjmp enter_monitor_mode - /* The slow path of the TLB miss handler */ -page_table_not_present: -page_not_present: - tlbmiss_restore - sub sp, 4 - stmts --sp, r0-lr - rcall save_full_context_ex - mfsr r12, SYSREG_ECR - mov r11, sp - rcall do_page_fault - rjmp ret_from_exception - /* This function expects to find offending PC in SYSREG_RAR_EX */ .type save_full_context_ex, @function .align 2 @@ -316,36 +336,92 @@ save_full_context_ex: /* Low-level exception handlers */ handle_critical: + /* + * AT32AP700x errata: + * + * After a Java stack overflow or underflow trap, any CPU + * memory access may cause erratic behavior. This will happen + * when the four least significant bits of the JOSP system + * register contains any value between 9 and 15 (inclusive). + * + * Possible workarounds: + * - Don't use the Java Extension Module + * - Ensure that the stack overflow and underflow trap + * handlers do not do any memory access or trigger any + * exceptions before the overflow/underflow condition is + * cleared (by incrementing or decrementing the JOSP) + * - Make sure that JOSP does not contain any problematic + * value before doing any exception or interrupt + * processing. + * - Set up a critical exception handler which writes a + * known-to-be-safe value, e.g. 4, to JOSP before doing + * any further processing. + * + * We'll use the last workaround for now since we cannot + * guarantee that user space processes don't use Java mode. + * Non-well-behaving userland will be terminated with extreme + * prejudice. + */ +#ifdef CONFIG_CPU_AT32AP700X + /* + * There's a chance we can't touch memory, so temporarily + * borrow PTBR to save the stack pointer while we fix things + * up... + */ + mtsr SYSREG_PTBR, sp + mov sp, 4 + mtsr SYSREG_JOSP, sp + mfsr sp, SYSREG_PTBR + sub pc, -2 + + /* Push most of pt_regs on stack. We'll do the rest later */ sub sp, 4 - stmts --sp, r0-lr - rcall save_full_context_ex + pushm r0-r12 + + /* PTBR mirrors current_thread_info()->task->active_mm->pgd */ + get_thread_info r0 + ld.w r1, r0[TI_task] + ld.w r2, r1[TSK_active_mm] + ld.w r3, r2[MM_pgd] + mtsr SYSREG_PTBR, r3 +#else + sub sp, 4 + pushm r0-r12 +#endif + sub r0, sp, -(14 * 4) + mov r1, lr + mfsr r2, SYSREG_RAR_EX + mfsr r3, SYSREG_RSR_EX + pushm r0-r3 + mfsr r12, SYSREG_ECR mov r11, sp - rcall do_critical_exception + call do_critical_exception /* We should never get here... */ bad_return: sub r12, pc, (. - 1f) - bral panic + lddpc pc, 2f .align 2 1: .asciz "Return from critical exception!" +2: .long panic .align 1 do_bus_error_write: sub sp, 4 stmts --sp, r0-lr - rcall save_full_context_ex + call save_full_context_ex mov r11, 1 rjmp 1f do_bus_error_read: sub sp, 4 stmts --sp, r0-lr - rcall save_full_context_ex + call save_full_context_ex mov r11, 0 1: mfsr r12, SYSREG_BEAR mov r10, sp - rcall do_bus_error + call do_bus_error rjmp ret_from_exception .align 1 @@ -360,7 +436,7 @@ do_nmi_ll: 1: pushm r8, r9 /* PC and SR */ mfsr r12, SYSREG_ECR mov r11, sp - rcall do_nmi + call do_nmi popm r8-r9 mtsr SYSREG_RAR_NMI, r8 tst r0, r0 @@ -384,29 +460,29 @@ do_nmi_ll: handle_address_fault: sub sp, 4 stmts --sp, r0-lr - rcall save_full_context_ex + call save_full_context_ex mfsr r12, SYSREG_ECR mov r11, sp - rcall do_address_exception + call do_address_exception rjmp ret_from_exception handle_protection_fault: sub sp, 4 stmts --sp, r0-lr - rcall save_full_context_ex + call save_full_context_ex mfsr r12, SYSREG_ECR mov r11, sp - rcall do_page_fault + call do_page_fault rjmp ret_from_exception .align 1 do_illegal_opcode_ll: sub sp, 4 stmts --sp, r0-lr - rcall save_full_context_ex + call save_full_context_ex mfsr r12, SYSREG_ECR mov r11, sp - rcall do_illegal_opcode + call do_illegal_opcode rjmp ret_from_exception do_dtlb_modified: @@ -440,11 +516,11 @@ do_dtlb_modified: do_fpe_ll: sub sp, 4 stmts --sp, r0-lr - rcall save_full_context_ex + call save_full_context_ex unmask_interrupts mov r12, 26 mov r11, sp - rcall do_fpe + call do_fpe rjmp ret_from_exception ret_from_exception: @@ -480,7 +556,7 @@ fault_resume_kernel: lddsp r4, sp[REG_SR] bld r4, SYSREG_GM_OFFSET brcs 1f - rcall preempt_schedule_irq + call preempt_schedule_irq 1: #endif @@ -509,18 +585,18 @@ fault_exit_work: bld r1, TIF_NEED_RESCHED brcc 1f unmask_interrupts - rcall schedule + call schedule mask_interrupts ld.w r1, r0[TI_flags] rjmp fault_exit_work -1: mov r2, _TIF_SIGPENDING | _TIF_RESTORE_SIGMASK +1: mov r2, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME tst r1, r2 breq 2f unmask_interrupts mov r12, sp mov r11, r0 - rcall do_notify_resume + call do_notify_resume mask_interrupts ld.w r1, r0[TI_flags] rjmp fault_exit_work @@ -543,10 +619,10 @@ handle_debug: .Ldebug_fixup_cont: #ifdef CONFIG_TRACE_IRQFLAGS - rcall trace_hardirqs_off + call trace_hardirqs_off #endif mov r12, sp - rcall do_debug + call do_debug mov sp, r12 lddsp r2, sp[REG_SR] @@ -570,7 +646,7 @@ handle_debug: mtsr SYSREG_RSR_DBG, r11 mtsr SYSREG_RAR_DBG, r10 #ifdef CONFIG_TRACE_IRQFLAGS - rcall trace_hardirqs_on + call trace_hardirqs_on 1: #endif ldmts sp++, r0-lr @@ -603,7 +679,7 @@ debug_resume_kernel: #ifdef CONFIG_TRACE_IRQFLAGS bld r11, SYSREG_GM_OFFSET brcc 1f - rcall trace_hardirqs_on + call trace_hardirqs_on 1: #endif mfsr r2, SYSREG_SR @@ -674,7 +750,7 @@ irq_level\level: mov r11, sp mov r12, \level - rcall do_IRQ + call do_IRQ lddsp r4, sp[REG_SR] bfextu r4, r4, SYSREG_M0_OFFSET, 3 @@ -694,7 +770,7 @@ irq_level\level: 1: #ifdef CONFIG_TRACE_IRQFLAGS - rcall trace_hardirqs_on + call trace_hardirqs_on #endif popm r8-r9 mtsr rar_int\level, r8 @@ -734,33 +810,13 @@ irq_level\level: lddsp r4, sp[REG_SR] bld r4, SYSREG_GM_OFFSET brcs 1b - rcall preempt_schedule_irq + call preempt_schedule_irq #endif rjmp 1b .endm .section .irq.text,"ax",@progbits -.global cpu_idle_sleep -cpu_idle_sleep: - mask_interrupts - get_thread_info r8 - ld.w r9, r8[TI_flags] - bld r9, TIF_NEED_RESCHED - brcs cpu_idle_enable_int_and_exit - sbr r9, TIF_CPU_GOING_TO_SLEEP - st.w r8[TI_flags], r9 - unmask_interrupts - sleep 0 -cpu_idle_skip_sleep: - mask_interrupts - ld.w r9, r8[TI_flags] - cbr r9, TIF_CPU_GOING_TO_SLEEP - st.w r8[TI_flags], r9 -cpu_idle_enable_int_and_exit: - unmask_interrupts - retal r12 - .global irq_level0 .global irq_level1 .global irq_level2 |
