📄 entry.s
字号:
/* * arch/v850/kernel/entry.S -- Low-level system-call handling, trap handlers, * and context-switching * * Copyright (C) 2001,2002 NEC Corporation * Copyright (C) 2001,2002 Miles Bader <miles@gnu.org> * * This file is subject to the terms and conditions of the GNU General * Public License. See the file COPYING in the main directory of this * archive for more details. * * Written by Miles Bader <miles@gnu.org> */#include <linux/sys.h>#include <asm/entry.h>#include <asm/current.h>#include <asm/clinkage.h>#include <asm/processor.h>#include <asm/irq.h>#include "v850_defs.h"/* Make a slightly more convenient alias for C_SYMBOL_NAME. */#define CSYM C_SYMBOL_NAME/* The offset of the struct pt_regs in a `state save frame' on the stack. */#define PTO STATE_SAVE_PT_OFFSET/* Save argument registers to the struct pt_regs pointed to by EP. */#define SAVE_ARG_REGS \ sst.w r6, PTO+PT_GPR(6)[ep]; \ sst.w r7, PTO+PT_GPR(7)[ep]; \ sst.w r8, PTO+PT_GPR(8)[ep]; \ sst.w r9, PTO+PT_GPR(9)[ep];/* Restore argument registers from the struct pt_regs pointed to by EP. */#define RESTORE_ARG_REGS \ sld.w PTO+PT_GPR(6)[ep], r6; \ sld.w PTO+PT_GPR(7)[ep], r7; \ sld.w PTO+PT_GPR(8)[ep], r8; \ sld.w PTO+PT_GPR(9)[ep], r9;/* Save value return registers to the struct pt_regs pointed to by EP. */#define SAVE_RVAL_REGS \ sst.w r10, PTO+PT_GPR(10)[ep]; \ sst.w r11, PTO+PT_GPR(11)[ep];/* Restore value return registers from the struct pt_regs pointed to by EP. */#define RESTORE_RVAL_REGS \ sld.w PTO+PT_GPR(10)[ep], r10; \ sld.w PTO+PT_GPR(11)[ep], r11;#define SAVE_CALL_CLOBBERED_REGS_BEFORE_ARGS \ sst.w r1, PTO+PT_GPR(1)[ep]; \ sst.w r5, PTO+PT_GPR(5)[ep];#define SAVE_CALL_CLOBBERED_REGS_AFTER_RVAL \ sst.w r12, PTO+PT_GPR(12)[ep]; \ sst.w r13, PTO+PT_GPR(13)[ep]; \ sst.w r14, PTO+PT_GPR(14)[ep]; \ sst.w r15, PTO+PT_GPR(15)[ep]; \ sst.w r16, PTO+PT_GPR(16)[ep]; \ sst.w r17, PTO+PT_GPR(17)[ep]; \ sst.w r18, PTO+PT_GPR(18)[ep]; \ sst.w r19, PTO+PT_GPR(19)[ep];#define RESTORE_CALL_CLOBBERED_REGS_BEFORE_ARGS \ sld.w PTO+PT_GPR(1)[ep], r1; \ sld.w PTO+PT_GPR(5)[ep], r5;#define RESTORE_CALL_CLOBBERED_REGS_AFTER_RVAL \ sld.w PTO+PT_GPR(12)[ep], r12; \ sld.w PTO+PT_GPR(13)[ep], r13; \ sld.w PTO+PT_GPR(14)[ep], r14; \ sld.w PTO+PT_GPR(15)[ep], r15; \ sld.w PTO+PT_GPR(16)[ep], r16; \ sld.w PTO+PT_GPR(17)[ep], r17; \ sld.w PTO+PT_GPR(18)[ep], r18; \ sld.w PTO+PT_GPR(19)[ep], r19;/* Save `call clobbered' registers to the struct pt_regs pointed to by EP. */#define SAVE_CALL_CLOBBERED_REGS \ SAVE_CALL_CLOBBERED_REGS_BEFORE_ARGS; \ SAVE_ARG_REGS; \ SAVE_RVAL_REGS; \ SAVE_CALL_CLOBBERED_REGS_AFTER_RVAL;/* Restore `call clobbered' registers from the struct pt_regs pointed to by EP. */#define RESTORE_CALL_CLOBBERED_REGS \ RESTORE_CALL_CLOBBERED_REGS_BEFORE_ARGS; \ RESTORE_ARG_REGS; \ RESTORE_RVAL_REGS; \ RESTORE_CALL_CLOBBERED_REGS_AFTER_RVAL;/* Save `call clobbered' registers except for the return-value registers to the struct pt_regs pointed to by EP. */#define SAVE_CALL_CLOBBERED_REGS_NO_RVAL \ SAVE_CALL_CLOBBERED_REGS_BEFORE_ARGS; \ SAVE_ARG_REGS; \ SAVE_CALL_CLOBBERED_REGS_AFTER_RVAL;/* Restore `call clobbered' registers except for the return-value registers from the struct pt_regs pointed to by EP. */#define RESTORE_CALL_CLOBBERED_REGS_NO_RVAL \ RESTORE_CALL_CLOBBERED_REGS_BEFORE_ARGS; \ RESTORE_ARG_REGS; \ RESTORE_CALL_CLOBBERED_REGS_AFTER_RVAL;/* Zero `call clobbered' registers except for the return-value registers. */#define ZERO_CALL_CLOBBERED_REGS_NO_RVAL \ mov r0, r1; mov r0, r5; \ mov r0, r12; mov r0, r13; mov r0, r14; mov r0, r15; \ mov r0, r16; mov r0, r17; mov r0, r18; mov r0, r19;/* Save `call saved' registers to the struct pt_regs pointed to by EP. */#define SAVE_CALL_SAVED_REGS \ sst.w r2, PTO+PT_GPR(2)[ep]; \ sst.w r20, PTO+PT_GPR(20)[ep]; \ sst.w r21, PTO+PT_GPR(21)[ep]; \ sst.w r22, PTO+PT_GPR(22)[ep]; \ sst.w r23, PTO+PT_GPR(23)[ep]; \ sst.w r24, PTO+PT_GPR(24)[ep]; \ sst.w r25, PTO+PT_GPR(25)[ep]; \ sst.w r26, PTO+PT_GPR(26)[ep]; \ sst.w r27, PTO+PT_GPR(27)[ep]; \ sst.w r28, PTO+PT_GPR(28)[ep]; \ sst.w r29, PTO+PT_GPR(29)[ep];/* Restore `call saved' registers from the struct pt_regs pointed to by EP. */#define RESTORE_CALL_SAVED_REGS \ sld.w PTO+PT_GPR(2)[ep], r2; \ sld.w PTO+PT_GPR(20)[ep], r20; \ sld.w PTO+PT_GPR(21)[ep], r21; \ sld.w PTO+PT_GPR(22)[ep], r22; \ sld.w PTO+PT_GPR(23)[ep], r23; \ sld.w PTO+PT_GPR(24)[ep], r24; \ sld.w PTO+PT_GPR(25)[ep], r25; \ sld.w PTO+PT_GPR(26)[ep], r26; \ sld.w PTO+PT_GPR(27)[ep], r27; \ sld.w PTO+PT_GPR(28)[ep], r28; \ sld.w PTO+PT_GPR(29)[ep], r29;/* Save system registers to the struct pt_regs pointed to by REG. r19 is clobbered. */#define SAVE_SYS_REGS \ stsr SR_EIPC, r19; /* user's PC, before interrupt */ \ sst.w r19, PTO+PT_PC[ep]; \ stsr SR_EIPSW, r19; /* & PSW (XXX save this?) */ \ sst.w r19, PTO+PT_PSW[ep]; \ stsr SR_CTPC, r19; /* (XXX maybe not used in kernel?) */ \ sst.w r19, PTO+PT_CTPC[ep]; \ stsr SR_CTPSW, r19; /* " */ \ sst.w r19, PTO+PT_CTPSW[ep]; \ stsr SR_CTBP, r19; /* " */ \ sst.w r19, PTO+PT_CTBP[ep];/* Restore system registers from the struct pt_regs pointed to by EP. LP is clobbered (it is used as a scratch register because the POP_STATE macro restores it, and this macro is usually used inside POP_STATE). */#define RESTORE_SYS_REGS \ sld.w PTO+PT_PC[ep], lp; \ ldsr lp, SR_EIPC; /* user's PC, before interrupt */ \ sld.w PTO+PT_PSW[ep], lp; \ ldsr lp, SR_EIPSW; /* & PSW (XXX save this?) */ \ sld.w PTO+PT_CTPC[ep], lp; \ ldsr lp, SR_CTPC; /* (XXX maybe not used in kernel?) */ \ sld.w PTO+PT_CTPSW[ep], lp; \ ldsr lp, SR_CTPSW; /* " */ \ sld.w PTO+PT_CTBP[ep], lp; \ ldsr lp, SR_CTBP; /* " *//* Save system registers to the struct pt_regs pointed to by REG. This is a NMI-specific version, because NMIs save the PC/PSW in a different place than other interrupt requests. r19 is clobbered. */#define SAVE_SYS_REGS_FOR_NMI \ stsr SR_FEPC, r19; /* user's PC, before NMI */ \ sst.w r19, PTO+PT_PC[ep]; \ stsr SR_FEPSW, r19; /* & PSW (XXX save this?) */ \ sst.w r19, PTO+PT_PSW[ep]; \ stsr SR_CTPC, r19; /* (XXX maybe not used in kernel?) */ \ sst.w r19, PTO+PT_CTPC[ep]; \ stsr SR_CTPSW, r19; /* " */ \ sst.w r19, PTO+PT_CTPSW[ep]; \ stsr SR_CTBP, r19; /* " */ \ sst.w r19, PTO+PT_CTBP[ep];/* Restore system registers from the struct pt_regs pointed to by EP. This is a NMI-specific version, because NMIs save the PC/PSW in a different place than other interrupt requests. LP is clobbered (it is used as a scratch register because the POP_STATE macro restores it, and this macro is usually used inside POP_STATE). */#define RESTORE_SYS_REGS_FOR_NMI \ ldsr lp, SR_FEPC; /* user's PC, before NMI */ \ sld.w PTO+PT_PC[ep], lp; \ ldsr lp, SR_FEPSW; /* & PSW (XXX save this?) */ \ sld.w PTO+PT_PSW[ep], lp; \ ldsr lp, SR_CTPC; /* (XXX maybe not used in kernel?) */ \ sld.w PTO+PT_CTPC[ep], lp; \ ldsr lp, SR_CTPSW; /* " */ \ sld.w PTO+PT_CTPSW[ep], lp; \ ldsr lp, SR_CTBP; /* " */ \ sld.w PTO+PT_CTBP[ep], lp;/* Push register state, except for the stack pointer, on the stack in the form of a struct pt_regs, in preparation for a system call. This macro makes sure that `special' registers, system registers; TYPE identifies the set of extra registers to be saved as well. EP is clobbered. */#define PUSH_STATE(type) \ addi -STATE_SAVE_SIZE, sp, sp; /* Make room on the stack. */ \ st.w ep, PTO+PT_GPR(GPR_EP)[sp]; \ mov sp, ep; \ sst.w gp, PTO+PT_GPR(GPR_GP)[ep]; \ sst.w lp, PTO+PT_GPR(GPR_LP)[ep]; \ type ## _STATE_SAVER;/* Pop a register state, except for the stack pointer, from the struct pt_regs on the stack. */#define POP_STATE(type) \ mov sp, ep; \ type ## _STATE_RESTORER; \ sld.w PTO+PT_GPR(GPR_GP)[ep], gp; \ sld.w PTO+PT_GPR(GPR_LP)[ep], lp; \ sld.w PTO+PT_GPR(GPR_EP)[ep], ep; \ addi STATE_SAVE_SIZE, sp, sp; /* Clean up our stack space. *//* Switch to the kernel stack if necessary, and push register state on the stack in the form of a struct pt_regs. Also load the current task pointer if switching from user mode. The stack-pointer (r3) should have already been saved to the memory location SP_SAVE_LOC (the reason for this is that the interrupt vectors may be beyond a 22-bit signed offset jump from the actual interrupt handler, and this allows them to save the stack-pointer and use that register to do an indirect jump). This macro makes sure that `special' registers, system registers, and the stack pointer are saved; TYPE identifies the set of extra registers to be saved as well. SYSCALL_NUM is the register in which the system-call number this state is for is stored (r0 if this isn't a system call). Interrupts should already be disabled when calling this. */#define SAVE_STATE(type, syscall_num, sp_save_loc) \ tst1 0, KM; /* See if already in kernel mode. */ \ bz 1f; \ /* Kernel-mode state save. */ \ ld.w sp_save_loc, sp; /* Reload kernel stack-pointer. */ \ st.w sp, (PT_GPR(GPR_SP)-PT_SIZE)[sp]; /* Save original SP. */ \ PUSH_STATE(type); \ mov 1, r19; /* Was in kernel-mode. */ \ sst.w r19, PTO+PT_KERNEL_MODE[ep]; /* [ep is set by PUSH_STATE] */ \ br 2f; \1: /* User-mode state save. */ \ ld.w KSP, sp; /* Switch to kernel stack. */ \ PUSH_STATE(type); \ sst.w r0, PTO+PT_KERNEL_MODE[ep]; /* Was in user-mode. */ \ ld.w sp_save_loc, r19; \ sst.w r19, PTO+PT_GPR(GPR_SP)[ep]; /* Store user SP. */ \ mov 1, r19; \ st.b r19, KM; /* Now we're in kernel-mode. */ \ GET_CURRENT_TASK(CURRENT_TASK); /* Fetch the current task pointer. */ \2: /* Save away the syscall number. */ \ sst.w syscall_num, PTO+PT_SYSCALL[ep]/* Save register state not normally saved by PUSH_STATE for TYPE. */#define SAVE_EXTRA_STATE(type) \ mov sp, ep; \ type ## _EXTRA_STATE_SAVER;/* Restore register state not normally restored by POP_STATE for TYPE. */#define RESTORE_EXTRA_STATE(type) \ mov sp, ep; \ type ## _EXTRA_STATE_RESTORER;/* Save any call-clobbered registers not normally saved by PUSH_STATE for TYPE. */#define SAVE_EXTRA_STATE_FOR_FUNCALL(type) \ mov sp, ep; \ type ## _FUNCALL_EXTRA_STATE_SAVER;/* Restore any call-clobbered registers not normally restored by POP_STATE for TYPE. */#define RESTORE_EXTRA_STATE_FOR_FUNCALL(type) \ mov sp, ep; \ type ## _FUNCALL_EXTRA_STATE_RESTORER;/* These are extra_state_saver/restorer values for a user trap. Note that we save the argument registers so that restarted syscalls will function properly (otherwise it wouldn't be necessary), and we must _not_ restore the return-value registers (so that traps can return a value!), but there are various options for what happens to other call-clobbered registers, selected by preprocessor conditionals. */#if TRAPS_PRESERVE_CALL_CLOBBERED_REGS /* Traps save/restore all call-clobbered registers (except for rval regs). */#define TRAP_STATE_SAVER \ SAVE_CALL_CLOBBERED_REGS_NO_RVAL; \ SAVE_SYS_REGS#define TRAP_STATE_RESTORER \ RESTORE_CALL_CLOBBERED_REGS_NO_RVAL; \ RESTORE_SYS_REGS#else /* !TRAPS_PRESERVE_CALL_CLOBBERED_REGS *//* Traps don't save call-clobbered registers (but do still save arg regs). */#define TRAP_STATE_SAVER \ SAVE_ARG_REGS; \ SAVE_SYS_REGS#if TRAPS_ZERO_CALL_CLOBBERED_REGS /* Traps zero call-clobbered registers (except for arg/rval regs) before returning from a system call, to avoid any internal values from leaking out of the kernel. */#define TRAP_STATE_RESTORER \ ZERO_CALL_CLOBBERED_REGS_NO_ARGS_NO_RVAL; \ RESTORE_ARG_REGS; \ RESTORE_SYS_REGS#else /* !TRAPS_ZERO_CALL_CLOBBERED_REGS */ /* When traps return, they just leave call-clobbered registers (except for arg regs) with whatever value they have from the kernel. */#define TRAP_STATE_RESTORER \ RESTORE_ARG_REGS; \ RESTORE_SYS_REGS#endif /* TRAPS_ZERO_CALL_CLOBBERED_REGS */#endif /* TRAPS_PRESERVE_CALL_CLOBBERED_REGS *//* Save registers not normally saved by traps. */#define TRAP_EXTRA_STATE_SAVER \ SAVE_RVAL_REGS; \ SAVE_CALL_SAVED_REGS#define TRAP_EXTRA_STATE_RESTORER \ RESTORE_RVAL_REGS; \ RESTORE_CALL_SAVED_REGS#define TRAP_FUNCALL_EXTRA_STATE_SAVER \ SAVE_RVAL_REGS#define TRAP_FUNCALL_EXTRA_STATE_RESTORER \ RESTORE_RVAL_REGS/* Register saving/restoring for maskable interrupts. */#define IRQ_STATE_SAVER \ SAVE_CALL_CLOBBERED_REGS; \ SAVE_SYS_REGS
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -