aboutsummaryrefslogtreecommitdiff
path: root/arch/avr32/kernel/entry-avr32b.S
diff options
context:
space:
mode:
Diffstat (limited to 'arch/avr32/kernel/entry-avr32b.S')
-rw-r--r--arch/avr32/kernel/entry-avr32b.S244
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