2 * Copyright (C) 2004-2006 Atmel Corporation
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
10 * This file contains the low-level entry-points into the kernel, that is,
11 * exception handlers, debug trap handlers, interrupt handlers and the
12 * system call handler.
14 #include <linux/errno.h>
17 #include <asm/hardirq.h>
21 #include <asm/pgtable.h>
22 #include <asm/ptrace.h>
23 #include <asm/sysreg.h>
24 #include <asm/thread_info.h>
25 #include <asm/unistd.h>
28 # define preempt_stop mask_interrupts
31 # define fault_resume_kernel fault_restore_all
34 #define __MASK(x) ((1 << (x)) - 1)
35 #define IRQ_MASK ((__MASK(SOFTIRQ_BITS) << SOFTIRQ_SHIFT) | \
36 (__MASK(HARDIRQ_BITS) << HARDIRQ_SHIFT))
38 .section .ex.text,"ax",@progbits
45 bral do_bus_error_write
47 bral do_bus_error_read
51 bral handle_address_fault
53 bral handle_protection_fault
57 bral do_illegal_opcode_ll
59 bral do_illegal_opcode_ll
61 bral do_illegal_opcode_ll
65 bral do_illegal_opcode_ll
67 bral handle_address_fault
69 bral handle_address_fault
71 bral handle_protection_fault
73 bral handle_protection_fault
79 * r1 : Offending address
80 * r2 : Scratch register
81 * r3 : Cause (5, 12 or 13)
83 #define tlbmiss_save pushm r0-r3
84 #define tlbmiss_restore popm r0-r3
86 .section .tlbx.ex.text,"ax",@progbits
92 .section .tlbr.ex.text,"ax",@progbits
97 .section .tlbw.ex.text,"ax",@progbits
101 .global tlb_miss_common
103 mfsr r0, SYSREG_TLBEAR
106 /* Is it the vmalloc space? */
108 brcs handle_vmalloc_miss
110 /* First level lookup */
112 lsr r2, r0, PGDIR_SHIFT
114 bfextu r1, r0, PAGE_SHIFT, PGDIR_SHIFT - PAGE_SHIFT
115 bld r3, _PAGE_BIT_PRESENT
116 brcc page_table_not_present
118 /* Translate to virtual address in P1. */
122 /* Second level lookup */
124 mfsr r0, SYSREG_TLBARLO
125 bld r2, _PAGE_BIT_PRESENT
126 brcc page_not_present
128 /* Mark the page as accessed */
129 sbr r2, _PAGE_BIT_ACCESSED
132 /* Drop software flags */
133 andl r2, _PAGE_FLAGS_HARDWARE_MASK & 0xffff
134 mtsr SYSREG_TLBELO, r2
136 /* Figure out which entry we want to replace */
137 mfsr r1, SYSREG_MMUCR
140 mov r3, -1 /* All entries have been accessed, */
141 mov r2, 0 /* so start at 0 */
142 mtsr SYSREG_TLBARLO, r3 /* and reset TLBAR */
144 1: bfins r1, r2, SYSREG_DRP_OFFSET, SYSREG_DRP_SIZE
145 mtsr SYSREG_MMUCR, r1
152 /* Simply do the lookup in init's page table */
153 mov r1, lo(swapper_pg_dir)
154 orh r1, hi(swapper_pg_dir)
158 /* --- System Call --- */
160 .section .scall.text,"ax",@progbits
162 #ifdef CONFIG_PREEMPT
165 pushm r12 /* r12_orig */
168 mfsr r0, SYSREG_RAR_SUP
169 mfsr r1, SYSREG_RSR_SUP
170 #ifdef CONFIG_PREEMPT
176 /* check for syscall tracing */
178 ld.w r1, r0[TI_flags]
179 bld r1, TIF_SYSCALL_TRACE
180 brcs syscall_trace_enter
186 lddpc lr, syscall_table_addr
188 mov r8, r5 /* 5th argument (6th is pushed by stub) */
191 .global syscall_return
194 mask_interrupts /* make sure we don't miss an interrupt
195 setting need_resched or sigpending
196 between sampling and the rets */
198 /* Store the return value so that the correct value is loaded below */
199 stdsp sp[REG_R12], r12
201 ld.w r1, r0[TI_flags]
202 andl r1, _TIF_ALLWORK_MASK, COH
203 brne syscall_exit_work
207 mtsr SYSREG_RAR_SUP, r8
208 mtsr SYSREG_RSR_SUP, r9
210 sub sp, -4 /* r12_orig */
221 .global ret_from_fork
225 /* check for syscall tracing */
227 ld.w r1, r0[TI_flags]
228 andl r1, _TIF_ALLWORK_MASK, COH
229 brne syscall_exit_work
230 rjmp syscall_exit_cont
236 rjmp syscall_trace_cont
239 bld r1, TIF_SYSCALL_TRACE
244 ld.w r1, r0[TI_flags]
246 1: bld r1, TIF_NEED_RESCHED
251 ld.w r1, r0[TI_flags]
254 2: mov r2, _TIF_SIGPENDING | _TIF_RESTORE_SIGMASK
260 rcall do_notify_resume
262 ld.w r1, r0[TI_flags]
265 3: bld r1, TIF_BREAKPOINT
266 brcc syscall_exit_cont
267 rjmp enter_monitor_mode
269 /* The slow path of the TLB miss handler */
270 page_table_not_present:
275 rcall save_full_context_ex
279 rjmp ret_from_exception
281 /* This function expects to find offending PC in SYSREG_RAR_EX */
282 .type save_full_context_ex, @function
284 save_full_context_ex:
285 mfsr r11, SYSREG_RAR_EX
286 sub r9, pc, . - debug_trampoline
287 mfsr r8, SYSREG_RSR_EX
291 andh r8, (MODE_MASK >> 16), COH
294 1: pushm r11, r12 /* PC and SR */
298 2: sub r10, sp, -(FRAME_SIZE_FULL - REG_LR)
299 stdsp sp[4], r10 /* replace saved SP */
303 * The debug handler set up a trampoline to make us
304 * automatically enter monitor mode upon return, but since
305 * we're saving the full context, we must assume that the
306 * exception handler might want to alter the return address
307 * and/or status register. So we need to restore the original
308 * context and enter monitor mode manually after the exception
311 3: get_thread_info r8
312 ld.w r11, r8[TI_rar_saved]
313 ld.w r12, r8[TI_rsr_saved]
315 .size save_full_context_ex, . - save_full_context_ex
317 /* Low-level exception handlers */
321 rcall save_full_context_ex
324 rcall do_critical_exception
326 /* We should never get here... */
328 sub r12, pc, (. - 1f)
331 1: .asciz "Return from critical exception!"
337 rcall save_full_context_ex
344 rcall save_full_context_ex
346 1: mfsr r12, SYSREG_BEAR
349 rjmp ret_from_exception
355 mfsr r9, SYSREG_RSR_NMI
356 mfsr r8, SYSREG_RAR_NMI
357 bfextu r0, r9, MODE_SHIFT, 3
360 1: pushm r8, r9 /* PC and SR */
365 mtsr SYSREG_RAR_NMI, r8
367 mtsr SYSREG_RSR_NMI, r9
371 sub sp, -4 /* skip r12_orig */
374 2: sub r10, sp, -(FRAME_SIZE_FULL - REG_LR)
375 stdsp sp[4], r10 /* replace saved SP */
379 sub sp, -4 /* skip sp */
381 sub sp, -4 /* skip r12_orig */
384 handle_address_fault:
387 rcall save_full_context_ex
390 rcall do_address_exception
391 rjmp ret_from_exception
393 handle_protection_fault:
396 rcall save_full_context_ex
400 rjmp ret_from_exception
403 do_illegal_opcode_ll:
406 rcall save_full_context_ex
409 rcall do_illegal_opcode
410 rjmp ret_from_exception
414 mfsr r1, SYSREG_TLBEAR
416 lsr r2, r1, PGDIR_SHIFT
418 lsl r1, (32 - PGDIR_SHIFT)
419 lsr r1, (32 - PGDIR_SHIFT) + PAGE_SHIFT
421 /* Translate to virtual address in P1 */
426 sbr r3, _PAGE_BIT_DIRTY
430 /* The page table is up-to-date. Update the TLB entry as well */
431 andl r0, lo(_PAGE_FLAGS_HARDWARE_MASK)
432 mtsr SYSREG_TLBELO, r0
434 /* MMUCR[DRP] is updated automatically, so let's go... */
443 rcall save_full_context_ex
448 rjmp ret_from_exception
454 andh r4, (MODE_MASK >> 16), COH
455 brne fault_resume_kernel
458 ld.w r1, r0[TI_flags]
459 andl r1, _TIF_WORK_MASK, COH
465 mtsr SYSREG_RAR_EX, r8
466 mtsr SYSREG_RSR_EX, r9
472 #ifdef CONFIG_PREEMPT
474 ld.w r2, r0[TI_preempt_count]
477 ld.w r1, r0[TI_flags]
478 bld r1, TIF_NEED_RESCHED
481 bld r4, SYSREG_GM_OFFSET
483 rcall preempt_schedule_irq
490 mtsr SYSREG_RAR_EX, r8
491 mtsr SYSREG_RSR_EX, r9
493 sub sp, -4 /* ignore SP */
495 sub sp, -4 /* ignore r12_orig */
499 /* Switch to exception mode so that we can share the same code. */
501 cbr r8, SYSREG_M0_OFFSET
502 orh r8, hi(SYSREG_BIT(M1) | SYSREG_BIT(M2))
506 ld.w r1, r0[TI_flags]
509 bld r1, TIF_NEED_RESCHED
514 ld.w r1, r0[TI_flags]
517 1: mov r2, _TIF_SIGPENDING | _TIF_RESTORE_SIGMASK
523 rcall do_notify_resume
525 ld.w r1, r0[TI_flags]
528 2: bld r1, TIF_BREAKPOINT
529 brcc fault_resume_user
530 rjmp enter_monitor_mode
532 .section .kprobes.text, "ax", @progbits
533 .type handle_debug, @function
535 sub sp, 4 /* r12_orig */
537 mfsr r8, SYSREG_RAR_DBG
538 mfsr r9, SYSREG_RSR_DBG
541 bfextu r9, r9, SYSREG_MODE_OFFSET, SYSREG_MODE_SIZE
542 brne debug_fixup_regs
545 #ifdef CONFIG_TRACE_IRQFLAGS
546 rcall trace_hardirqs_off
553 bfextu r3, r2, SYSREG_MODE_OFFSET, SYSREG_MODE_SIZE
554 brne debug_resume_kernel
557 ld.w r1, r0[TI_flags]
558 mov r2, _TIF_DBGWORK_MASK
562 bld r1, TIF_SINGLE_STEP
565 sbr r4, OCD_DC_SS_BIT
570 mtsr SYSREG_RSR_DBG, r11
571 mtsr SYSREG_RAR_DBG, r10
572 #ifdef CONFIG_TRACE_IRQFLAGS
573 rcall trace_hardirqs_on
579 .size handle_debug, . - handle_debug
581 /* Mode of the trapped context is in r9 */
582 .type debug_fixup_regs, @function
586 bfins r8, r9, SYSREG_MODE_OFFSET, SYSREG_MODE_SIZE
592 sub r8, sp, -FRAME_SIZE_FULL
594 rjmp .Ldebug_fixup_cont
595 .size debug_fixup_regs, . - debug_fixup_regs
597 .type debug_resume_kernel, @function
601 mtsr SYSREG_RAR_DBG, r10
602 mtsr SYSREG_RSR_DBG, r11
603 #ifdef CONFIG_TRACE_IRQFLAGS
604 bld r11, SYSREG_GM_OFFSET
606 rcall trace_hardirqs_on
611 bfins r2, r3, SYSREG_MODE_OFFSET, SYSREG_MODE_SIZE
617 sub sp, -4 /* skip SP */
621 .size debug_resume_kernel, . - debug_resume_kernel
623 .type debug_exit_work, @function
626 * We must return from Monitor Mode using a retd, and we must
627 * not schedule since that involves the D bit in SR getting
628 * cleared by something other than the debug hardware. This
629 * may cause undefined behaviour according to the Architecture
632 * So we fix up the return address and status and return to a
633 * stub below in Exception mode. From there, we can follow the
634 * normal exception return path.
636 * The real return address and status registers are stored on
637 * the stack in the way the exception return path understands,
638 * so no need to fix anything up there.
640 sub r8, pc, . - fault_exit_work
641 mtsr SYSREG_RAR_DBG, r8
643 orh r9, hi(SR_EM | SR_GM | MODE_EXCEPTION)
644 mtsr SYSREG_RSR_DBG, r9
647 .size debug_exit_work, . - debug_exit_work
649 .set rsr_int0, SYSREG_RSR_INT0
650 .set rsr_int1, SYSREG_RSR_INT1
651 .set rsr_int2, SYSREG_RSR_INT2
652 .set rsr_int3, SYSREG_RSR_INT3
653 .set rar_int0, SYSREG_RAR_INT0
654 .set rar_int1, SYSREG_RAR_INT1
655 .set rar_int2, SYSREG_RAR_INT2
656 .set rar_int3, SYSREG_RAR_INT3
658 .macro IRQ_LEVEL level
659 .type irq_level\level, @function
661 sub sp, 4 /* r12_orig */
663 mfsr r8, rar_int\level
664 mfsr r9, rsr_int\level
666 #ifdef CONFIG_PREEMPT
667 sub r11, pc, (. - system_call)
680 bfextu r4, r4, SYSREG_M0_OFFSET, 3
681 cp.w r4, MODE_SUPERVISOR >> SYSREG_M0_OFFSET
683 cp.w r4, MODE_USER >> SYSREG_M0_OFFSET
684 #ifdef CONFIG_PREEMPT
691 ld.w r1, r0[TI_flags]
692 andl r1, _TIF_WORK_MASK, COH
696 #ifdef CONFIG_TRACE_IRQFLAGS
697 rcall trace_hardirqs_on
700 mtsr rar_int\level, r8
701 mtsr rsr_int\level, r9
703 sub sp, -4 /* ignore r12_orig */
706 #ifdef CONFIG_PREEMPT
708 mfsr r8, rsr_int\level
710 mtsr rsr_int\level, r8
712 sub sp, -4 /* ignore r12_orig */
716 2: get_thread_info r0
717 ld.w r1, r0[TI_flags]
718 bld r1, TIF_CPU_GOING_TO_SLEEP
719 #ifdef CONFIG_PREEMPT
724 sub r1, pc, . - cpu_idle_skip_sleep
726 #ifdef CONFIG_PREEMPT
727 3: get_thread_info r0
728 ld.w r2, r0[TI_preempt_count]
731 ld.w r1, r0[TI_flags]
732 bld r1, TIF_NEED_RESCHED
735 bld r4, SYSREG_GM_OFFSET
737 rcall preempt_schedule_irq
742 .section .irq.text,"ax",@progbits
744 .global cpu_idle_sleep
748 ld.w r9, r8[TI_flags]
749 bld r9, TIF_NEED_RESCHED
750 brcs cpu_idle_enable_int_and_exit
751 sbr r9, TIF_CPU_GOING_TO_SLEEP
752 st.w r8[TI_flags], r9
757 ld.w r9, r8[TI_flags]
758 cbr r9, TIF_CPU_GOING_TO_SLEEP
759 st.w r8[TI_flags], r9
760 cpu_idle_enable_int_and_exit:
773 .section .kprobes.text, "ax", @progbits
774 .type enter_monitor_mode, @function
777 * We need to enter monitor mode to do a single step. The
778 * monitor code will alter the return address so that we
779 * return directly to the user instead of returning here.
782 rjmp breakpoint_failed
784 .size enter_monitor_mode, . - enter_monitor_mode
786 .type debug_trampoline, @function
787 .global debug_trampoline
790 * Save the registers on the stack so that the monitor code
791 * can find them easily.
793 sub sp, 4 /* r12_orig */
796 ld.w r8, r0[TI_rar_saved]
797 ld.w r9, r0[TI_rsr_saved]
801 * The monitor code will alter the return address so we don't
805 rjmp breakpoint_failed
806 .size debug_trampoline, . - debug_trampoline
808 .type breakpoint_failed, @function
811 * Something went wrong. Perhaps the debug hardware isn't
814 lda.w r12, msg_breakpoint_failed
816 mov r10, 9 /* SIGKILL */
820 msg_breakpoint_failed:
821 .asciz "Failed to enter Debug Mode"