Path: blob/master/arch/avr32/kernel/entry-avr32b.S
10817 views
/*1* Copyright (C) 2004-2006 Atmel Corporation2*3* This program is free software; you can redistribute it and/or modify4* it under the terms of the GNU General Public License version 2 as5* published by the Free Software Foundation.6*/78/*9* This file contains the low-level entry-points into the kernel, that is,10* exception handlers, debug trap handlers, interrupt handlers and the11* system call handler.12*/13#include <linux/errno.h>1415#include <asm/asm.h>16#include <asm/hardirq.h>17#include <asm/irq.h>18#include <asm/ocd.h>19#include <asm/page.h>20#include <asm/pgtable.h>21#include <asm/ptrace.h>22#include <asm/sysreg.h>23#include <asm/thread_info.h>24#include <asm/unistd.h>2526#ifdef CONFIG_PREEMPT27# define preempt_stop mask_interrupts28#else29# define preempt_stop30# define fault_resume_kernel fault_restore_all31#endif3233#define __MASK(x) ((1 << (x)) - 1)34#define IRQ_MASK ((__MASK(SOFTIRQ_BITS) << SOFTIRQ_SHIFT) | \35(__MASK(HARDIRQ_BITS) << HARDIRQ_SHIFT))3637.section .ex.text,"ax",@progbits38.align 239exception_vectors:40bral handle_critical41.align 242bral handle_critical43.align 244bral do_bus_error_write45.align 246bral do_bus_error_read47.align 248bral do_nmi_ll49.align 250bral handle_address_fault51.align 252bral handle_protection_fault53.align 254bral handle_debug55.align 256bral do_illegal_opcode_ll57.align 258bral do_illegal_opcode_ll59.align 260bral do_illegal_opcode_ll61.align 262bral do_fpe_ll63.align 264bral do_illegal_opcode_ll65.align 266bral handle_address_fault67.align 268bral handle_address_fault69.align 270bral handle_protection_fault71.align 272bral handle_protection_fault73.align 274bral do_dtlb_modified7576#define tlbmiss_save pushm r0-r377#define tlbmiss_restore popm r0-r37879.org 0x5080.global itlb_miss81itlb_miss:82tlbmiss_save83rjmp tlb_miss_common8485.org 0x6086dtlb_miss_read:87tlbmiss_save88rjmp tlb_miss_common8990.org 0x7091dtlb_miss_write:92tlbmiss_save9394.global tlb_miss_common95.align 296tlb_miss_common:97mfsr r0, SYSREG_TLBEAR98mfsr r1, SYSREG_PTBR99100/*101* First level lookup: The PGD contains virtual pointers to102* the second-level page tables, but they may be NULL if not103* present.104*/105pgtbl_lookup:106lsr r2, r0, PGDIR_SHIFT107ld.w r3, r1[r2 << 2]108bfextu r1, r0, PAGE_SHIFT, PGDIR_SHIFT - PAGE_SHIFT109cp.w r3, 0110breq page_table_not_present111112/* Second level lookup */113ld.w r2, r3[r1 << 2]114mfsr r0, SYSREG_TLBARLO115bld r2, _PAGE_BIT_PRESENT116brcc page_not_present117118/* Mark the page as accessed */119sbr r2, _PAGE_BIT_ACCESSED120st.w r3[r1 << 2], r2121122/* Drop software flags */123andl r2, _PAGE_FLAGS_HARDWARE_MASK & 0xffff124mtsr SYSREG_TLBELO, r2125126/* Figure out which entry we want to replace */127mfsr r1, SYSREG_MMUCR128clz r2, r0129brcc 1f130mov r3, -1 /* All entries have been accessed, */131mov r2, 0 /* so start at 0 */132mtsr SYSREG_TLBARLO, r3 /* and reset TLBAR */1331341: bfins r1, r2, SYSREG_DRP_OFFSET, SYSREG_DRP_SIZE135mtsr SYSREG_MMUCR, r1136tlbw137138tlbmiss_restore139rete140141/* The slow path of the TLB miss handler */142.align 2143page_table_not_present:144/* Do we need to synchronize with swapper_pg_dir? */145bld r0, 31146brcs sync_with_swapper_pg_dir147148page_not_present:149tlbmiss_restore150sub sp, 4151stmts --sp, r0-lr152call save_full_context_ex153mfsr r12, SYSREG_ECR154mov r11, sp155call do_page_fault156rjmp ret_from_exception157158.align 2159sync_with_swapper_pg_dir:160/*161* If swapper_pg_dir contains a non-NULL second-level page162* table pointer, copy it into the current PGD. If not, we163* must handle it as a full-blown page fault.164*165* Jumping back to pgtbl_lookup causes an unnecessary lookup,166* but it is guaranteed to be a cache hit, it won't happen167* very often, and we absolutely do not want to sacrifice any168* performance in the fast path in order to improve this.169*/170mov r1, lo(swapper_pg_dir)171orh r1, hi(swapper_pg_dir)172ld.w r3, r1[r2 << 2]173cp.w r3, 0174breq page_not_present175mfsr r1, SYSREG_PTBR176st.w r1[r2 << 2], r3177rjmp pgtbl_lookup178179/*180* We currently have two bytes left at this point until we181* crash into the system call handler...182*183* Don't worry, the assembler will let us know.184*/185186187/* --- System Call --- */188189.org 0x100190system_call:191#ifdef CONFIG_PREEMPT192mask_interrupts193#endif194pushm r12 /* r12_orig */195stmts --sp, r0-lr196197mfsr r0, SYSREG_RAR_SUP198mfsr r1, SYSREG_RSR_SUP199#ifdef CONFIG_PREEMPT200unmask_interrupts201#endif202zero_fp203stm --sp, r0-r1204205/* check for syscall tracing */206get_thread_info r0207ld.w r1, r0[TI_flags]208bld r1, TIF_SYSCALL_TRACE209brcs syscall_trace_enter210211syscall_trace_cont:212cp.w r8, NR_syscalls213brhs syscall_badsys214215lddpc lr, syscall_table_addr216ld.w lr, lr[r8 << 2]217mov r8, r5 /* 5th argument (6th is pushed by stub) */218icall lr219220.global syscall_return221syscall_return:222get_thread_info r0223mask_interrupts /* make sure we don't miss an interrupt224setting need_resched or sigpending225between sampling and the rets */226227/* Store the return value so that the correct value is loaded below */228stdsp sp[REG_R12], r12229230ld.w r1, r0[TI_flags]231andl r1, _TIF_ALLWORK_MASK, COH232brne syscall_exit_work233234syscall_exit_cont:235popm r8-r9236mtsr SYSREG_RAR_SUP, r8237mtsr SYSREG_RSR_SUP, r9238ldmts sp++, r0-lr239sub sp, -4 /* r12_orig */240rets241242.align 2243syscall_table_addr:244.long sys_call_table245246syscall_badsys:247mov r12, -ENOSYS248rjmp syscall_return249250.global ret_from_fork251ret_from_fork:252call schedule_tail253254/* check for syscall tracing */255get_thread_info r0256ld.w r1, r0[TI_flags]257andl r1, _TIF_ALLWORK_MASK, COH258brne syscall_exit_work259rjmp syscall_exit_cont260261syscall_trace_enter:262pushm r8-r12263call syscall_trace264popm r8-r12265rjmp syscall_trace_cont266267syscall_exit_work:268bld r1, TIF_SYSCALL_TRACE269brcc 1f270unmask_interrupts271call syscall_trace272mask_interrupts273ld.w r1, r0[TI_flags]2742751: bld r1, TIF_NEED_RESCHED276brcc 2f277unmask_interrupts278call schedule279mask_interrupts280ld.w r1, r0[TI_flags]281rjmp 1b2822832: mov r2, _TIF_SIGPENDING | _TIF_RESTORE_SIGMASK | _TIF_NOTIFY_RESUME284tst r1, r2285breq 3f286unmask_interrupts287mov r12, sp288mov r11, r0289call do_notify_resume290mask_interrupts291ld.w r1, r0[TI_flags]292rjmp 1b2932943: bld r1, TIF_BREAKPOINT295brcc syscall_exit_cont296rjmp enter_monitor_mode297298/* This function expects to find offending PC in SYSREG_RAR_EX */299.type save_full_context_ex, @function300.align 2301save_full_context_ex:302mfsr r11, SYSREG_RAR_EX303sub r9, pc, . - debug_trampoline304mfsr r8, SYSREG_RSR_EX305cp.w r9, r11306breq 3f307mov r12, r8308andh r8, (MODE_MASK >> 16), COH309brne 2f3103111: pushm r11, r12 /* PC and SR */312unmask_exceptions313ret r123143152: sub r10, sp, -(FRAME_SIZE_FULL - REG_LR)316stdsp sp[4], r10 /* replace saved SP */317rjmp 1b318319/*320* The debug handler set up a trampoline to make us321* automatically enter monitor mode upon return, but since322* we're saving the full context, we must assume that the323* exception handler might want to alter the return address324* and/or status register. So we need to restore the original325* context and enter monitor mode manually after the exception326* has been handled.327*/3283: get_thread_info r8329ld.w r11, r8[TI_rar_saved]330ld.w r12, r8[TI_rsr_saved]331rjmp 1b332.size save_full_context_ex, . - save_full_context_ex333334/* Low-level exception handlers */335handle_critical:336/*337* AT32AP700x errata:338*339* After a Java stack overflow or underflow trap, any CPU340* memory access may cause erratic behavior. This will happen341* when the four least significant bits of the JOSP system342* register contains any value between 9 and 15 (inclusive).343*344* Possible workarounds:345* - Don't use the Java Extension Module346* - Ensure that the stack overflow and underflow trap347* handlers do not do any memory access or trigger any348* exceptions before the overflow/underflow condition is349* cleared (by incrementing or decrementing the JOSP)350* - Make sure that JOSP does not contain any problematic351* value before doing any exception or interrupt352* processing.353* - Set up a critical exception handler which writes a354* known-to-be-safe value, e.g. 4, to JOSP before doing355* any further processing.356*357* We'll use the last workaround for now since we cannot358* guarantee that user space processes don't use Java mode.359* Non-well-behaving userland will be terminated with extreme360* prejudice.361*/362#ifdef CONFIG_CPU_AT32AP700X363/*364* There's a chance we can't touch memory, so temporarily365* borrow PTBR to save the stack pointer while we fix things366* up...367*/368mtsr SYSREG_PTBR, sp369mov sp, 4370mtsr SYSREG_JOSP, sp371mfsr sp, SYSREG_PTBR372sub pc, -2373374/* Push most of pt_regs on stack. We'll do the rest later */375sub sp, 4376pushm r0-r12377378/* PTBR mirrors current_thread_info()->task->active_mm->pgd */379get_thread_info r0380ld.w r1, r0[TI_task]381ld.w r2, r1[TSK_active_mm]382ld.w r3, r2[MM_pgd]383mtsr SYSREG_PTBR, r3384#else385sub sp, 4386pushm r0-r12387#endif388sub r0, sp, -(14 * 4)389mov r1, lr390mfsr r2, SYSREG_RAR_EX391mfsr r3, SYSREG_RSR_EX392pushm r0-r3393394mfsr r12, SYSREG_ECR395mov r11, sp396call do_critical_exception397398/* We should never get here... */399bad_return:400sub r12, pc, (. - 1f)401bral panic402.align 24031: .asciz "Return from critical exception!"404405.align 1406do_bus_error_write:407sub sp, 4408stmts --sp, r0-lr409call save_full_context_ex410mov r11, 1411rjmp 1f412413do_bus_error_read:414sub sp, 4415stmts --sp, r0-lr416call save_full_context_ex417mov r11, 04181: mfsr r12, SYSREG_BEAR419mov r10, sp420call do_bus_error421rjmp ret_from_exception422423.align 1424do_nmi_ll:425sub sp, 4426stmts --sp, r0-lr427mfsr r9, SYSREG_RSR_NMI428mfsr r8, SYSREG_RAR_NMI429bfextu r0, r9, MODE_SHIFT, 3430brne 2f4314321: pushm r8, r9 /* PC and SR */433mfsr r12, SYSREG_ECR434mov r11, sp435call do_nmi436popm r8-r9437mtsr SYSREG_RAR_NMI, r8438tst r0, r0439mtsr SYSREG_RSR_NMI, r9440brne 3f441442ldmts sp++, r0-lr443sub sp, -4 /* skip r12_orig */444rete4454462: sub r10, sp, -(FRAME_SIZE_FULL - REG_LR)447stdsp sp[4], r10 /* replace saved SP */448rjmp 1b4494503: popm lr451sub sp, -4 /* skip sp */452popm r0-r12453sub sp, -4 /* skip r12_orig */454rete455456handle_address_fault:457sub sp, 4458stmts --sp, r0-lr459call save_full_context_ex460mfsr r12, SYSREG_ECR461mov r11, sp462call do_address_exception463rjmp ret_from_exception464465handle_protection_fault:466sub sp, 4467stmts --sp, r0-lr468call save_full_context_ex469mfsr r12, SYSREG_ECR470mov r11, sp471call do_page_fault472rjmp ret_from_exception473474.align 1475do_illegal_opcode_ll:476sub sp, 4477stmts --sp, r0-lr478call save_full_context_ex479mfsr r12, SYSREG_ECR480mov r11, sp481call do_illegal_opcode482rjmp ret_from_exception483484do_dtlb_modified:485pushm r0-r3486mfsr r1, SYSREG_TLBEAR487mfsr r0, SYSREG_PTBR488lsr r2, r1, PGDIR_SHIFT489ld.w r0, r0[r2 << 2]490lsl r1, (32 - PGDIR_SHIFT)491lsr r1, (32 - PGDIR_SHIFT) + PAGE_SHIFT492493/* Translate to virtual address in P1 */494andl r0, 0xf000495sbr r0, 31496add r2, r0, r1 << 2497ld.w r3, r2[0]498sbr r3, _PAGE_BIT_DIRTY499mov r0, r3500st.w r2[0], r3501502/* The page table is up-to-date. Update the TLB entry as well */503andl r0, lo(_PAGE_FLAGS_HARDWARE_MASK)504mtsr SYSREG_TLBELO, r0505506/* MMUCR[DRP] is updated automatically, so let's go... */507tlbw508509popm r0-r3510rete511512do_fpe_ll:513sub sp, 4514stmts --sp, r0-lr515call save_full_context_ex516unmask_interrupts517mov r12, 26518mov r11, sp519call do_fpe520rjmp ret_from_exception521522ret_from_exception:523mask_interrupts524lddsp r4, sp[REG_SR]525526andh r4, (MODE_MASK >> 16), COH527brne fault_resume_kernel528529get_thread_info r0530ld.w r1, r0[TI_flags]531andl r1, _TIF_WORK_MASK, COH532brne fault_exit_work533534fault_resume_user:535popm r8-r9536mask_exceptions537mtsr SYSREG_RAR_EX, r8538mtsr SYSREG_RSR_EX, r9539ldmts sp++, r0-lr540sub sp, -4541rete542543fault_resume_kernel:544#ifdef CONFIG_PREEMPT545get_thread_info r0546ld.w r2, r0[TI_preempt_count]547cp.w r2, 0548brne 1f549ld.w r1, r0[TI_flags]550bld r1, TIF_NEED_RESCHED551brcc 1f552lddsp r4, sp[REG_SR]553bld r4, SYSREG_GM_OFFSET554brcs 1f555call preempt_schedule_irq5561:557#endif558559popm r8-r9560mask_exceptions561mfsr r1, SYSREG_SR562mtsr SYSREG_RAR_EX, r8563mtsr SYSREG_RSR_EX, r9564popm lr565sub sp, -4 /* ignore SP */566popm r0-r12567sub sp, -4 /* ignore r12_orig */568rete569570irq_exit_work:571/* Switch to exception mode so that we can share the same code. */572mfsr r8, SYSREG_SR573cbr r8, SYSREG_M0_OFFSET574orh r8, hi(SYSREG_BIT(M1) | SYSREG_BIT(M2))575mtsr SYSREG_SR, r8576sub pc, -2577get_thread_info r0578ld.w r1, r0[TI_flags]579580fault_exit_work:581bld r1, TIF_NEED_RESCHED582brcc 1f583unmask_interrupts584call schedule585mask_interrupts586ld.w r1, r0[TI_flags]587rjmp fault_exit_work5885891: mov r2, _TIF_SIGPENDING | _TIF_RESTORE_SIGMASK590tst r1, r2591breq 2f592unmask_interrupts593mov r12, sp594mov r11, r0595call do_notify_resume596mask_interrupts597ld.w r1, r0[TI_flags]598rjmp fault_exit_work5996002: bld r1, TIF_BREAKPOINT601brcc fault_resume_user602rjmp enter_monitor_mode603604.section .kprobes.text, "ax", @progbits605.type handle_debug, @function606handle_debug:607sub sp, 4 /* r12_orig */608stmts --sp, r0-lr609mfsr r8, SYSREG_RAR_DBG610mfsr r9, SYSREG_RSR_DBG611unmask_exceptions612pushm r8-r9613bfextu r9, r9, SYSREG_MODE_OFFSET, SYSREG_MODE_SIZE614brne debug_fixup_regs615616.Ldebug_fixup_cont:617#ifdef CONFIG_TRACE_IRQFLAGS618call trace_hardirqs_off619#endif620mov r12, sp621call do_debug622mov sp, r12623624lddsp r2, sp[REG_SR]625bfextu r3, r2, SYSREG_MODE_OFFSET, SYSREG_MODE_SIZE626brne debug_resume_kernel627628get_thread_info r0629ld.w r1, r0[TI_flags]630mov r2, _TIF_DBGWORK_MASK631tst r1, r2632brne debug_exit_work633634bld r1, TIF_SINGLE_STEP635brcc 1f636mfdr r4, OCD_DC637sbr r4, OCD_DC_SS_BIT638mtdr OCD_DC, r46396401: popm r10,r11641mask_exceptions642mtsr SYSREG_RSR_DBG, r11643mtsr SYSREG_RAR_DBG, r10644#ifdef CONFIG_TRACE_IRQFLAGS645call trace_hardirqs_on6461:647#endif648ldmts sp++, r0-lr649sub sp, -4650retd651.size handle_debug, . - handle_debug652653/* Mode of the trapped context is in r9 */654.type debug_fixup_regs, @function655debug_fixup_regs:656mfsr r8, SYSREG_SR657mov r10, r8658bfins r8, r9, SYSREG_MODE_OFFSET, SYSREG_MODE_SIZE659mtsr SYSREG_SR, r8660sub pc, -2661stdsp sp[REG_LR], lr662mtsr SYSREG_SR, r10663sub pc, -2664sub r8, sp, -FRAME_SIZE_FULL665stdsp sp[REG_SP], r8666rjmp .Ldebug_fixup_cont667.size debug_fixup_regs, . - debug_fixup_regs668669.type debug_resume_kernel, @function670debug_resume_kernel:671mask_exceptions672popm r10, r11673mtsr SYSREG_RAR_DBG, r10674mtsr SYSREG_RSR_DBG, r11675#ifdef CONFIG_TRACE_IRQFLAGS676bld r11, SYSREG_GM_OFFSET677brcc 1f678call trace_hardirqs_on6791:680#endif681mfsr r2, SYSREG_SR682mov r1, r2683bfins r2, r3, SYSREG_MODE_OFFSET, SYSREG_MODE_SIZE684mtsr SYSREG_SR, r2685sub pc, -2686popm lr687mtsr SYSREG_SR, r1688sub pc, -2689sub sp, -4 /* skip SP */690popm r0-r12691sub sp, -4692retd693.size debug_resume_kernel, . - debug_resume_kernel694695.type debug_exit_work, @function696debug_exit_work:697/*698* We must return from Monitor Mode using a retd, and we must699* not schedule since that involves the D bit in SR getting700* cleared by something other than the debug hardware. This701* may cause undefined behaviour according to the Architecture702* manual.703*704* So we fix up the return address and status and return to a705* stub below in Exception mode. From there, we can follow the706* normal exception return path.707*708* The real return address and status registers are stored on709* the stack in the way the exception return path understands,710* so no need to fix anything up there.711*/712sub r8, pc, . - fault_exit_work713mtsr SYSREG_RAR_DBG, r8714mov r9, 0715orh r9, hi(SR_EM | SR_GM | MODE_EXCEPTION)716mtsr SYSREG_RSR_DBG, r9717sub pc, -2718retd719.size debug_exit_work, . - debug_exit_work720721.set rsr_int0, SYSREG_RSR_INT0722.set rsr_int1, SYSREG_RSR_INT1723.set rsr_int2, SYSREG_RSR_INT2724.set rsr_int3, SYSREG_RSR_INT3725.set rar_int0, SYSREG_RAR_INT0726.set rar_int1, SYSREG_RAR_INT1727.set rar_int2, SYSREG_RAR_INT2728.set rar_int3, SYSREG_RAR_INT3729730.macro IRQ_LEVEL level731.type irq_level\level, @function732irq_level\level:733sub sp, 4 /* r12_orig */734stmts --sp,r0-lr735mfsr r8, rar_int\level736mfsr r9, rsr_int\level737738#ifdef CONFIG_PREEMPT739sub r11, pc, (. - system_call)740cp.w r11, r8741breq 4f742#endif743744pushm r8-r9745746mov r11, sp747mov r12, \level748749call do_IRQ750751lddsp r4, sp[REG_SR]752bfextu r4, r4, SYSREG_M0_OFFSET, 3753cp.w r4, MODE_SUPERVISOR >> SYSREG_M0_OFFSET754breq 2f755cp.w r4, MODE_USER >> SYSREG_M0_OFFSET756#ifdef CONFIG_PREEMPT757brne 3f758#else759brne 1f760#endif761762get_thread_info r0763ld.w r1, r0[TI_flags]764andl r1, _TIF_WORK_MASK, COH765brne irq_exit_work7667671:768#ifdef CONFIG_TRACE_IRQFLAGS769call trace_hardirqs_on770#endif771popm r8-r9772mtsr rar_int\level, r8773mtsr rsr_int\level, r9774ldmts sp++,r0-lr775sub sp, -4 /* ignore r12_orig */776rete777778#ifdef CONFIG_PREEMPT7794: mask_interrupts780mfsr r8, rsr_int\level781sbr r8, 16782mtsr rsr_int\level, r8783ldmts sp++, r0-lr784sub sp, -4 /* ignore r12_orig */785rete786#endif7877882: get_thread_info r0789ld.w r1, r0[TI_flags]790bld r1, TIF_CPU_GOING_TO_SLEEP791#ifdef CONFIG_PREEMPT792brcc 3f793#else794brcc 1b795#endif796sub r1, pc, . - cpu_idle_skip_sleep797stdsp sp[REG_PC], r1798#ifdef CONFIG_PREEMPT7993: get_thread_info r0800ld.w r2, r0[TI_preempt_count]801cp.w r2, 0802brne 1b803ld.w r1, r0[TI_flags]804bld r1, TIF_NEED_RESCHED805brcc 1b806lddsp r4, sp[REG_SR]807bld r4, SYSREG_GM_OFFSET808brcs 1b809call preempt_schedule_irq810#endif811rjmp 1b812.endm813814.section .irq.text,"ax",@progbits815816.global irq_level0817.global irq_level1818.global irq_level2819.global irq_level3820IRQ_LEVEL 0821IRQ_LEVEL 1822IRQ_LEVEL 2823IRQ_LEVEL 3824825.section .kprobes.text, "ax", @progbits826.type enter_monitor_mode, @function827enter_monitor_mode:828/*829* We need to enter monitor mode to do a single step. The830* monitor code will alter the return address so that we831* return directly to the user instead of returning here.832*/833breakpoint834rjmp breakpoint_failed835836.size enter_monitor_mode, . - enter_monitor_mode837838.type debug_trampoline, @function839.global debug_trampoline840debug_trampoline:841/*842* Save the registers on the stack so that the monitor code843* can find them easily.844*/845sub sp, 4 /* r12_orig */846stmts --sp, r0-lr847get_thread_info r0848ld.w r8, r0[TI_rar_saved]849ld.w r9, r0[TI_rsr_saved]850pushm r8-r9851852/*853* The monitor code will alter the return address so we don't854* return here.855*/856breakpoint857rjmp breakpoint_failed858.size debug_trampoline, . - debug_trampoline859860.type breakpoint_failed, @function861breakpoint_failed:862/*863* Something went wrong. Perhaps the debug hardware isn't864* enabled?865*/866lda.w r12, msg_breakpoint_failed867mov r11, sp868mov r10, 9 /* SIGKILL */869call die8701: rjmp 1b871872msg_breakpoint_failed:873.asciz "Failed to enter Debug Mode"874875876