/* * linux/arch/unicore32/kernel/entry.S * * Code specific to PKUnity SoC and UniCore ISA * * Copyright (C) 2001-2010 GUAN Xue-tao * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Low-level vector interface routines */#include <linux/init.h>#include <linux/linkage.h>#include <asm/assembler.h>#include <asm/errno.h>#include <asm/thread_info.h>#include <asm/memory.h>#include <asm/unistd.h>#include <generated/asm-offsets.h>#include "debug-macro.S" @@ Most of the stack format comes from struct pt_regs, but with@ the addition of 8 bytes for storing syscall args 5 and 6.@#define S_OFF 8 /* * The SWI code relies on the fact that R0 is at the bottom of the stack * (due to slow/fast restore user regs). */#if S_R0 != 0#error "Please fix"#endif .macro zero_fp#ifdef CONFIG_FRAME_POINTER mov fp, #0#endif .endm .macro alignment_trap, rtemp#ifdef CONFIG_ALIGNMENT_TRAP ldw \rtemp, .LCcralign ldw \rtemp, [\rtemp] movc p0.c1, \rtemp, #0#endif .endm .macro load_user_sp_lr, rd, rtemp, offset = 0 mov \rtemp, asr xor \rtemp, \rtemp, #(PRIV_MODE ^ SUSR_MODE) mov.a asr, \rtemp @ switch to the SUSR mode ldw sp, [\rd+], #\offset @ load sp_user ldw lr, [\rd+], #\offset + 4 @ load lr_user xor \rtemp, \rtemp, #(PRIV_MODE ^ SUSR_MODE) mov.a asr, \rtemp @ switch back to the PRIV mode .endm .macro priv_exit, rpsr mov.a bsr, \rpsr ldm.w (r0 - r15), [sp]+ ldm.b (r16 - pc), [sp]+ @ load r0 - pc, asr .endm .macro restore_user_regs, fast = 0, offset = 0 ldw r1, [sp+], #\offset + S_PSR @ get calling asr ldw lr, [sp+], #\offset + S_PC @ get pc mov.a bsr, r1 @ save in bsr_priv .if \fast add sp, sp, #\offset + S_R1 @ r0 is syscall return value ldm.w (r1 - r15), [sp]+ @ get calling r1 - r15 ldur (r16 - lr), [sp]+ @ get calling r16 - lr .else ldm.w (r0 - r15), [sp]+ @ get calling r0 - r15 ldur (r16 - lr), [sp]+ @ get calling r16 - lr .endif nop add sp, sp, #S_FRAME_SIZE - S_R16 mov.a pc, lr @ return @ and move bsr_priv into asr .endm .macro get_thread_info, rd mov \rd, sp >> #13 mov \rd, \rd << #13 .endm .macro get_irqnr_and_base, irqnr, irqstat, base, tmp ldw \base, =(PKUNITY_INTC_BASE) ldw \irqstat, [\base+], #0xC @ INTC_ICIP ldw \tmp, [\base+], #0x4 @ INTC_ICMR and.a \irqstat, \irqstat, \tmp beq 1001f cntlz \irqnr, \irqstat rsub \irqnr, \irqnr, #311001: /* EQ will be set if no irqs pending */ .endm #ifdef CONFIG_DEBUG_LL .macro printreg, reg, temp adr \temp, 901f stm (r0-r3), [\temp]+ stw lr, [\temp+], #0x10 mov r0, \reg b.l printhex8 mov r0, #':' b.l printch mov r0, pc b.l printhex8 adr r0, 902f b.l printascii adr \temp, 901f ldm (r0-r3), [\temp]+ ldw lr, [\temp+], #0x10 b 903f901: .word 0, 0, 0, 0, 0 @ r0-r3, lr902: .asciz ": epip4d\n" .align903: .endm#endif /* * These are the registers used in the syscall handler, and allow us to * have in theory up to 7 arguments to a function - r0 to r6. * * Note that tbl == why is intentional. * * We must set at least "tsk" and "why" when calling ret_with_reschedule. */scno .req r21 @ syscall numbertbl .req r22 @ syscall table pointerwhy .req r22 @ Linux syscall (!= 0)tsk .req r23 @ current thread_info /* * Interrupt handling. Preserves r17, r18, r19 */ .macro intr_handler1: get_irqnr_and_base r0, r6, r5, lr beq 2f mov r1, sp @ @ routine called with r0 = irq number, r1 = struct pt_regs * @ adr lr, 1b b asm_do_IRQ2: .endm /* * PRIV mode handlers */ .macro priv_entry sub sp, sp, #(S_FRAME_SIZE - 4) stm (r1 - r15), [sp]+ add r5, sp, #S_R15 stm (r16 - r28), [r5]+ ldm (r1 - r3), [r0]+ add r5, sp, #S_SP - 4 @ here for interlock avoidance mov r4, #-1 @ "" "" "" "" add r0, sp, #(S_FRAME_SIZE - 4) stw.w r1, [sp+], #-4 @ save the "real" r0 copied @ from the exception stack mov r1, lr @ @ We are now ready to fill in the remaining blanks on the stack: @ @ r0 - sp_priv @ r1 - lr_priv @ r2 - lr_<exception>, already fixed up for correct return/restart @ r3 - bsr_<exception> @ r4 - orig_r0 (see pt_regs definition in ptrace.h) @ stm (r0 - r4), [r5]+ .endm /* * User mode handlers * */ .macro user_entry sub sp, sp, #S_FRAME_SIZE stm (r1 - r15), [sp+] add r4, sp, #S_R16 stm (r16 - r28), [r4]+ ldm (r1 - r3), [r0]+ add r0, sp, #S_PC @ here for interlock avoidance mov r4, #-1 @ "" "" "" "" stw r1, [sp] @ save the "real" r0 copied @ from the exception stack @ @ We are now ready to fill in the remaining blanks on the stack: @ @ r2 - lr_<exception>, already fixed up for correct return/restart @ r3 - bsr_<exception> @ r4 - orig_r0 (see pt_regs definition in ptrace.h) @ @ Also, separately save sp_user and lr_user @ stm (r2 - r4), [r0]+ stur (sp, lr), [r0-] @ @ Enable the alignment trap while in kernel mode @ alignment_trap r0 @ @ Clear FP to mark the first stack frame @ zero_fp .endm .text @@ __invalid - generic code for failed exception@ (re-entrant version of handlers)@__invalid: sub sp, sp, #S_FRAME_SIZE stm (r1 - r15), [sp+] add r1, sp, #S_R16 stm (r16 - r28, sp, lr), [r1]+ zero_fp ldm (r4 - r6), [r0]+ add r0, sp, #S_PC @ here for interlock avoidance mov r7, #-1 @ "" "" "" "" stw r4, [sp] @ save preserved r0 stm (r5 - r7), [r0]+ @ lr_<exception>, @ asr_<exception>, "old_r0" mov r0, sp mov r1, asr b bad_modeENDPROC(__invalid) .align 5__dabt_priv: priv_entry @ @ get ready to re-enable interrupts if appropriate @ mov r17, asr cand.a r3, #PSR_I_BIT bne 1f andn r17, r17, #PSR_I_BIT1: @ @ Call the processor-specific abort handler: @ @ r2 - aborted context pc @ r3 - aborted context asr @ @ The abort handler must return the aborted address in r0, and @ the fault status register in r1. @ movc r1, p0.c3, #0 @ get FSR movc r0, p0.c4, #0 @ get FAR @ @ set desired INTR state, then call main handler @ mov.a asr, r17 mov r2, sp b.l do_DataAbort @ @ INTRs off again before pulling preserved data off the stack @ disable_irq r0 @ @ restore BSR and restart the instruction @ ldw r2, [sp+], #S_PSR priv_exit r2 @ return from exceptionENDPROC(__dabt_priv) .align 5__intr_priv: priv_entry intr_handler mov r0, #0 @ epip4d movc p0.c5, r0, #14 nop; nop; nop; nop; nop; nop; nop; nop ldw r4, [sp+], #S_PSR @ irqs are already disabled priv_exit r4 @ return from exceptionENDPROC(__intr_priv) .ltorg .align 5__extn_priv: priv_entry mov r0, sp @ struct pt_regs *regs mov r1, asr b bad_mode @ not supportedENDPROC(__extn_priv) .align 5__pabt_priv: priv_entry @ @ re-enable interrupts if appropriate @ mov r17, asr cand.a r3, #PSR_I_BIT bne 1f andn r17, r17, #PSR_I_BIT1: @ @ set args, then call main handler @ @ r0 - address of faulting instruction @ r1 - pointer to registers on stack @ mov r0, r2 @ pass address of aborted instruction mov r1, #5 mov.a asr, r17 mov r2, sp @ regs b.l do_PrefetchAbort @ call abort handler @ @ INTRs off again before pulling preserved data off the stack @ disable_irq r0 @ @ restore BSR and restart the instruction @ ldw r2, [sp+], #S_PSR priv_exit r2 @ return from exceptionENDPROC(__pabt_priv) .align 5.LCcralign: .word cr_alignment .align 5__dabt_user: user_entry #ifdef CONFIG_UNICORE_FPU_F64 cff ip, s31 cand.a ip, #0x08000000 @ FPU execption traps? beq 209f ldw ip, [sp+], #S_PC add ip, ip, #4 stw ip, [sp+], #S_PC @ @ fall through to the emulation code, which returns using r19 if @ it has emulated the instruction, or the more conventional lr @ if we are to treat this as a real extended instruction @ @ r0 - instruction @1: ldw.u r0, [r2] adr r19, ret_from_exception adr lr, 209f @ @ fallthrough to call do_uc_f64 @/* * Check whether the instruction is a co-processor instruction. * If yes, we need to call the relevant co-processor handler. * * Note that we don't do a full check here for the co-processor * instructions; all instructions with bit 27 set are well * defined. The only instructions that should fault are the * co-processor instructions. * * Emulators may wish to make use of the following registers: * r0 = instruction opcode. * r2 = PC * r19 = normal "successful" return address * r20 = this threads thread_info structure. * lr = unrecognised instruction return address */ get_thread_info r20 @ get current thread and r8, r0, #0x00003c00 @ mask out CP number mov r7, #1 stb r7, [r20+], #TI_USED_CP + 2 @ set appropriate used_cp[] @ F64 hardware support entry point. @ r0 = faulted instruction @ r19 = return address @ r20 = fp_state enable_irq r4 add r20, r20, #TI_FPSTATE @ r20 = workspace cff r1, s31 @ get fpu FPSCR andn r2, r1, #0x08000000 ctf r2, s31 @ clear 27 bit mov r2, sp @ nothing stacked - regdump is at TOS mov lr, r19 @ setup for a return to the user code @ Now call the C code to package up the bounce to the support code @ r0 holds the trigger instruction @ r1 holds the FPSCR value @ r2 pointer to register dump b ucf64_exchandler209:#endif @ @ Call the processor-specific abort handler: @ @ r2 - aborted context pc @ r3 - aborted context asr @ @ The abort handler must return the aborted address in r0, and @ the fault status register in r1. @ movc r1, p0.c3, #0 @ get FSR movc r0, p0.c4, #0 @ get FAR @ @ INTRs on, then call the main handler @ enable_irq r2 mov r2, sp adr lr, ret_from_exception b do_DataAbortENDPROC(__dabt_user) .align 5__intr_user: user_entry get_thread_info tsk intr_handler mov why, #0 b ret_to_userENDPROC(__intr_user) .ltorg .align 5__extn_user: user_entry mov r0, sp mov r1, asr b bad_modeENDPROC(__extn_user) .align 5__pabt_user: user_entry mov r0, r2 @ pass address of aborted instruction. mov r1, #5 enable_irq r1 @ Enable interrupts mov r2, sp @ regs b.l do_PrefetchAbort @ call abort handler /* fall through *//* * This is the return code to user mode for abort handlers */ENTRY(ret_from_exception) get_thread_info tsk mov why, #0 b ret_to_userENDPROC(__pabt_user)ENDPROC(ret_from_exception) /* * Register switch for UniCore V2 processors * r0 = previous task_struct, r1 = previous thread_info, r2 = next thread_info * previous and next are guaranteed not to be the same. */ENTRY(__switch_to) add ip, r1, #TI_CPU_SAVE stm.w (r4 - r15), [ip]+ stm.w (r16 - r27, sp, lr), [ip]+Lines 1–500 of 805. Load more
/* * linux/arch/unicore32/kernel/entry.S * * Code specific to PKUnity SoC and UniCore ISA * * Copyright (C) 2001-2010 GUAN Xue-tao * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Low-level vector interface routines */ #include <linux/init.h> #include <linux/linkage.h> #include <asm/assembler.h> #include <asm/errno.h> #include <asm/thread_info.h> #include <asm/memory.h> #include <asm/unistd.h> #include <generated/asm-offsets.h> #include "debug-macro.S" @ @ Most of the stack format comes from struct pt_regs, but with @ the addition of 8 bytes for storing syscall args 5 and 6. @ #define S_OFF 8 /* * The SWI code relies on the fact that R0 is at the bottom of the stack * (due to slow/fast restore user regs). */ #if S_R0 != 0 #error "Please fix" #endif .macro zero_fp #ifdef CONFIG_FRAME_POINTER mov fp, #0 #endif .endm .macro alignment_trap, rtemp #ifdef CONFIG_ALIGNMENT_TRAP ldw \rtemp, .LCcralign ldw \rtemp, [\rtemp] movc p0.c1, \rtemp, #0 #endif .endm .macro load_user_sp_lr, rd, rtemp, offset = 0 mov \rtemp, asr xor \rtemp, \rtemp, #(PRIV_MODE ^ SUSR_MODE) mov.a asr, \rtemp @ switch to the SUSR mode ldw sp, [\rd+], #\offset @ load sp_user ldw lr, [\rd+], #\offset + 4 @ load lr_user xor \rtemp, \rtemp, #(PRIV_MODE ^ SUSR_MODE) mov.a asr, \rtemp @ switch back to the PRIV mode .endm .macro priv_exit, rpsr mov.a bsr, \rpsr ldm.w (r0 - r15), [sp]+ ldm.b (r16 - pc), [sp]+ @ load r0 - pc, asr .endm .macro restore_user_regs, fast = 0, offset = 0 ldw r1, [sp+], #\offset + S_PSR @ get calling asr ldw lr, [sp+], #\offset + S_PC @ get pc mov.a bsr, r1 @ save in bsr_priv .if \fast add sp, sp, #\offset + S_R1 @ r0 is syscall return value ldm.w (r1 - r15), [sp]+ @ get calling r1 - r15 ldur (r16 - lr), [sp]+ @ get calling r16 - lr .else ldm.w (r0 - r15), [sp]+ @ get calling r0 - r15 ldur (r16 - lr), [sp]+ @ get calling r16 - lr .endif nop add sp, sp, #S_FRAME_SIZE - S_R16 mov.a pc, lr @ return @ and move bsr_priv into asr .endm .macro get_thread_info, rd mov \rd, sp >> #13 mov \rd, \rd << #13 .endm .macro get_irqnr_and_base, irqnr, irqstat, base, tmp ldw \base, =(PKUNITY_INTC_BASE) ldw \irqstat, [\base+], #0xC @ INTC_ICIP ldw \tmp, [\base+], #0x4 @ INTC_ICMR and.a \irqstat, \irqstat, \tmp beq 1001f cntlz \irqnr, \irqstat rsub \irqnr, \irqnr, #31 1001: /* EQ will be set if no irqs pending */ .endm #ifdef CONFIG_DEBUG_LL .macro printreg, reg, temp adr \temp, 901f stm (r0-r3), [\temp]+ stw lr, [\temp+], #0x10 mov r0, \reg b.l printhex8 mov r0, #':' b.l printch mov r0, pc b.l printhex8 adr r0, 902f b.l printascii adr \temp, 901f ldm (r0-r3), [\temp]+ ldw lr, [\temp+], #0x10 b 903f 901: .word 0, 0, 0, 0, 0 @ r0-r3, lr 902: .asciz ": epip4d\n" .align 903: .endm #endif /* * These are the registers used in the syscall handler, and allow us to * have in theory up to 7 arguments to a function - r0 to r6. * * Note that tbl == why is intentional. * * We must set at least "tsk" and "why" when calling ret_with_reschedule. */ scno .req r21 @ syscall number tbl .req r22 @ syscall table pointer why .req r22 @ Linux syscall (!= 0) tsk .req r23 @ current thread_info /* * Interrupt handling. Preserves r17, r18, r19 */ .macro intr_handler 1: get_irqnr_and_base r0, r6, r5, lr beq 2f mov r1, sp @ @ routine called with r0 = irq number, r1 = struct pt_regs * @ adr lr, 1b b asm_do_IRQ 2: .endm /* * PRIV mode handlers */ .macro priv_entry sub sp, sp, #(S_FRAME_SIZE - 4) stm (r1 - r15), [sp]+ add r5, sp, #S_R15 stm (r16 - r28), [r5]+ ldm (r1 - r3), [r0]+ add r5, sp, #S_SP - 4 @ here for interlock avoidance mov r4, #-1 @ "" "" "" "" add r0, sp, #(S_FRAME_SIZE - 4) stw.w r1, [sp+], #-4 @ save the "real" r0 copied @ from the exception stack mov r1, lr @ @ We are now ready to fill in the remaining blanks on the stack: @ @ r0 - sp_priv @ r1 - lr_priv @ r2 - lr_<exception>, already fixed up for correct return/restart @ r3 - bsr_<exception> @ r4 - orig_r0 (see pt_regs definition in ptrace.h) @ stm (r0 - r4), [r5]+ .endm /* * User mode handlers * */ .macro user_entry sub sp, sp, #S_FRAME_SIZE stm (r1 - r15), [sp+] add r4, sp, #S_R16 stm (r16 - r28), [r4]+ ldm (r1 - r3), [r0]+ add r0, sp, #S_PC @ here for interlock avoidance mov r4, #-1 @ "" "" "" "" stw r1, [sp] @ save the "real" r0 copied @ from the exception stack @ @ We are now ready to fill in the remaining blanks on the stack: @ @ r2 - lr_<exception>, already fixed up for correct return/restart @ r3 - bsr_<exception> @ r4 - orig_r0 (see pt_regs definition in ptrace.h) @ @ Also, separately save sp_user and lr_user @ stm (r2 - r4), [r0]+ stur (sp, lr), [r0-] @ @ Enable the alignment trap while in kernel mode @ alignment_trap r0 @ @ Clear FP to mark the first stack frame @ zero_fp .endm .text @ @ __invalid - generic code for failed exception @ (re-entrant version of handlers) @ __invalid: sub sp, sp, #S_FRAME_SIZE stm (r1 - r15), [sp+] add r1, sp, #S_R16 stm (r16 - r28, sp, lr), [r1]+ zero_fp ldm (r4 - r6), [r0]+ add r0, sp, #S_PC @ here for interlock avoidance mov r7, #-1 @ "" "" "" "" stw r4, [sp] @ save preserved r0 stm (r5 - r7), [r0]+ @ lr_<exception>, @ asr_<exception>, "old_r0" mov r0, sp mov r1, asr b bad_mode ENDPROC(__invalid) .align 5 __dabt_priv: priv_entry @ @ get ready to re-enable interrupts if appropriate @ mov r17, asr cand.a r3, #PSR_I_BIT bne 1f andn r17, r17, #PSR_I_BIT 1: @ @ Call the processor-specific abort handler: @ @ r2 - aborted context pc @ r3 - aborted context asr @ @ The abort handler must return the aborted address in r0, and @ the fault status register in r1. @ movc r1, p0.c3, #0 @ get FSR movc r0, p0.c4, #0 @ get FAR @ @ set desired INTR state, then call main handler @ mov.a asr, r17 mov r2, sp b.l do_DataAbort @ @ INTRs off again before pulling preserved data off the stack @ disable_irq r0 @ @ restore BSR and restart the instruction @ ldw r2, [sp+], #S_PSR priv_exit r2 @ return from exception ENDPROC(__dabt_priv) .align 5 __intr_priv: priv_entry intr_handler mov r0, #0 @ epip4d movc p0.c5, r0, #14 nop; nop; nop; nop; nop; nop; nop; nop ldw r4, [sp+], #S_PSR @ irqs are already disabled priv_exit r4 @ return from exception ENDPROC(__intr_priv) .ltorg .align 5 __extn_priv: priv_entry mov r0, sp @ struct pt_regs *regs mov r1, asr b bad_mode @ not supported ENDPROC(__extn_priv) .align 5 __pabt_priv: priv_entry @ @ re-enable interrupts if appropriate @ mov r17, asr cand.a r3, #PSR_I_BIT bne 1f andn r17, r17, #PSR_I_BIT 1: @ @ set args, then call main handler @ @ r0 - address of faulting instruction @ r1 - pointer to registers on stack @ mov r0, r2 @ pass address of aborted instruction mov r1, #5 mov.a asr, r17 mov r2, sp @ regs b.l do_PrefetchAbort @ call abort handler @ @ INTRs off again before pulling preserved data off the stack @ disable_irq r0 @ @ restore BSR and restart the instruction @ ldw r2, [sp+], #S_PSR priv_exit r2 @ return from exception ENDPROC(__pabt_priv) .align 5 .LCcralign: .word cr_alignment .align 5 __dabt_user: user_entry #ifdef CONFIG_UNICORE_FPU_F64 cff ip, s31 cand.a ip, #0x08000000 @ FPU execption traps? beq 209f ldw ip, [sp+], #S_PC add ip, ip, #4 stw ip, [sp+], #S_PC @ @ fall through to the emulation code, which returns using r19 if @ it has emulated the instruction, or the more conventional lr @ if we are to treat this as a real extended instruction @ @ r0 - instruction @ 1: ldw.u r0, [r2] adr r19, ret_from_exception adr lr, 209f @ @ fallthrough to call do_uc_f64 @ /* * Check whether the instruction is a co-processor instruction. * If yes, we need to call the relevant co-processor handler. * * Note that we don't do a full check here for the co-processor * instructions; all instructions with bit 27 set are well * defined. The only instructions that should fault are the * co-processor instructions. * * Emulators may wish to make use of the following registers: * r0 = instruction opcode. * r2 = PC * r19 = normal "successful" return address * r20 = this threads thread_info structure. * lr = unrecognised instruction return address */ get_thread_info r20 @ get current thread and r8, r0, #0x00003c00 @ mask out CP number mov r7, #1 stb r7, [r20+], #TI_USED_CP + 2 @ set appropriate used_cp[] @ F64 hardware support entry point. @ r0 = faulted instruction @ r19 = return address @ r20 = fp_state enable_irq r4 add r20, r20, #TI_FPSTATE @ r20 = workspace cff r1, s31 @ get fpu FPSCR andn r2, r1, #0x08000000 ctf r2, s31 @ clear 27 bit mov r2, sp @ nothing stacked - regdump is at TOS mov lr, r19 @ setup for a return to the user code @ Now call the C code to package up the bounce to the support code @ r0 holds the trigger instruction @ r1 holds the FPSCR value @ r2 pointer to register dump b ucf64_exchandler 209: #endif @ @ Call the processor-specific abort handler: @ @ r2 - aborted context pc @ r3 - aborted context asr @ @ The abort handler must return the aborted address in r0, and @ the fault status register in r1. @ movc r1, p0.c3, #0 @ get FSR movc r0, p0.c4, #0 @ get FAR @ @ INTRs on, then call the main handler @ enable_irq r2 mov r2, sp adr lr, ret_from_exception b do_DataAbort ENDPROC(__dabt_user) .align 5 __intr_user: user_entry get_thread_info tsk intr_handler mov why, #0 b ret_to_user ENDPROC(__intr_user) .ltorg .align 5 __extn_user: user_entry mov r0, sp mov r1, asr b bad_mode ENDPROC(__extn_user) .align 5 __pabt_user: user_entry mov r0, r2 @ pass address of aborted instruction. mov r1, #5 enable_irq r1 @ Enable interrupts mov r2, sp @ regs b.l do_PrefetchAbort @ call abort handler /* fall through */ /* * This is the return code to user mode for abort handlers */ ENTRY(ret_from_exception) get_thread_info tsk mov why, #0 b ret_to_user ENDPROC(__pabt_user) ENDPROC(ret_from_exception) /* * Register switch for UniCore V2 processors * r0 = previous task_struct, r1 = previous thread_info, r2 = next thread_info * previous and next are guaranteed not to be the same. */ ENTRY(__switch_to) add ip, r1, #TI_CPU_SAVE stm.w (r4 - r15), [ip]+ stm.w (r16 - r27, sp, lr), [ip]+