📄 locore.s
字号:
* Handle an interrupt from kernel mode. * Interrupts use the standard kernel stack. * switch_exit sets up a kernel stack after exit so interrupts won't fail. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------------- */#define KINTR_REG_OFFSET (STAND_FRAME_SIZE)#define KINTR_SR_OFFSET (STAND_FRAME_SIZE + KERN_REG_SIZE)#define KINTR_MULT_LO_OFFSET (STAND_FRAME_SIZE + KERN_REG_SIZE + 4)#define KINTR_MULT_HI_OFFSET (STAND_FRAME_SIZE + KERN_REG_SIZE + 8)#define KINTR_FRAME_SIZE (STAND_FRAME_SIZE + KERN_REG_SIZE + 12)NNON_LEAF(MachKernIntr, KINTR_FRAME_SIZE, ra) .set noat subu sp, sp, KINTR_FRAME_SIZE # allocate stack frame .mask 0x80000000, (STAND_RA_OFFSET - KINTR_FRAME_SIZE)/* * Save the relevant kernel registers onto the stack. * We don't need to save s0 - s8, sp and gp because * the compiler does it for us. */ sw AT, KINTR_REG_OFFSET + 0(sp) sw v0, KINTR_REG_OFFSET + 4(sp) sw v1, KINTR_REG_OFFSET + 8(sp) sw a0, KINTR_REG_OFFSET + 12(sp) mflo v0 mfhi v1 sw a1, KINTR_REG_OFFSET + 16(sp) sw a2, KINTR_REG_OFFSET + 20(sp) sw a3, KINTR_REG_OFFSET + 24(sp) sw t0, KINTR_REG_OFFSET + 28(sp) mfc0 a0, MACH_COP_0_STATUS_REG # First arg is the status reg. sw t1, KINTR_REG_OFFSET + 32(sp) sw t2, KINTR_REG_OFFSET + 36(sp) sw t3, KINTR_REG_OFFSET + 40(sp) sw t4, KINTR_REG_OFFSET + 44(sp) mfc0 a1, MACH_COP_0_CAUSE_REG # Second arg is the cause reg. sw t5, KINTR_REG_OFFSET + 48(sp) sw t6, KINTR_REG_OFFSET + 52(sp) sw t7, KINTR_REG_OFFSET + 56(sp) sw t8, KINTR_REG_OFFSET + 60(sp) mfc0 a2, MACH_COP_0_EXC_PC # Third arg is the pc. sw t9, KINTR_REG_OFFSET + 64(sp) sw ra, KINTR_REG_OFFSET + 68(sp) sw v0, KINTR_MULT_LO_OFFSET(sp) sw v1, KINTR_MULT_HI_OFFSET(sp) sw a0, KINTR_SR_OFFSET(sp)/* * Call the interrupt handler. */ jal interrupt sw a2, STAND_RA_OFFSET(sp) # for debugging/* * Restore registers and return from the interrupt. */ lw a0, KINTR_SR_OFFSET(sp) lw t0, KINTR_MULT_LO_OFFSET(sp) lw t1, KINTR_MULT_HI_OFFSET(sp) mtc0 a0, MACH_COP_0_STATUS_REG # Restore the SR, disable intrs mtlo t0 mthi t1 lw k0, STAND_RA_OFFSET(sp) lw AT, KINTR_REG_OFFSET + 0(sp) lw v0, KINTR_REG_OFFSET + 4(sp) lw v1, KINTR_REG_OFFSET + 8(sp) lw a0, KINTR_REG_OFFSET + 12(sp) lw a1, KINTR_REG_OFFSET + 16(sp) lw a2, KINTR_REG_OFFSET + 20(sp) lw a3, KINTR_REG_OFFSET + 24(sp) lw t0, KINTR_REG_OFFSET + 28(sp) lw t1, KINTR_REG_OFFSET + 32(sp) lw t2, KINTR_REG_OFFSET + 36(sp) lw t3, KINTR_REG_OFFSET + 40(sp) lw t4, KINTR_REG_OFFSET + 44(sp) lw t5, KINTR_REG_OFFSET + 48(sp) lw t6, KINTR_REG_OFFSET + 52(sp) lw t7, KINTR_REG_OFFSET + 56(sp) lw t8, KINTR_REG_OFFSET + 60(sp) lw t9, KINTR_REG_OFFSET + 64(sp) lw ra, KINTR_REG_OFFSET + 68(sp) addu sp, sp, KINTR_FRAME_SIZE j k0 # Now return from the rfe # interrupt. .set atEND(MachKernIntr)/*---------------------------------------------------------------------------- * * MachUserIntr -- * * Handle an interrupt from user mode. * Note: we save minimal state in the u.u_pcb struct and use the standard * kernel stack since there has to be a u page if we came from user mode. * If there is a pending software interrupt, then save the remaining state * and call softintr(). This is all because if we call switch() inside * interrupt(), not all the user registers have been saved in u.u_pcb. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------------- */NNON_LEAF(MachUserIntr, STAND_FRAME_SIZE, ra) .set noat .mask 0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)/* * Save the relevant user registers into the u.u_pcb struct. * We don't need to save s0 - s8 because * the compiler does it for us. */ sw AT, UADDR+U_PCB_REGS+(AST * 4) sw v0, UADDR+U_PCB_REGS+(V0 * 4) sw v1, UADDR+U_PCB_REGS+(V1 * 4) sw a0, UADDR+U_PCB_REGS+(A0 * 4) mflo v0 mfhi v1 sw a1, UADDR+U_PCB_REGS+(A1 * 4) sw a2, UADDR+U_PCB_REGS+(A2 * 4) sw a3, UADDR+U_PCB_REGS+(A3 * 4) sw t0, UADDR+U_PCB_REGS+(T0 * 4) mfc0 a0, MACH_COP_0_STATUS_REG # First arg is the status reg. sw t1, UADDR+U_PCB_REGS+(T1 * 4) sw t2, UADDR+U_PCB_REGS+(T2 * 4) sw t3, UADDR+U_PCB_REGS+(T3 * 4) sw t4, UADDR+U_PCB_REGS+(T4 * 4) mfc0 a1, MACH_COP_0_CAUSE_REG # Second arg is the cause reg. sw t5, UADDR+U_PCB_REGS+(T5 * 4) sw t6, UADDR+U_PCB_REGS+(T6 * 4) sw t7, UADDR+U_PCB_REGS+(T7 * 4) sw t8, UADDR+U_PCB_REGS+(T8 * 4) mfc0 a2, MACH_COP_0_EXC_PC # Third arg is the pc. sw t9, UADDR+U_PCB_REGS+(T9 * 4) sw gp, UADDR+U_PCB_REGS+(GP * 4) sw sp, UADDR+U_PCB_REGS+(SP * 4) sw ra, UADDR+U_PCB_REGS+(RA * 4) li sp, KERNELSTACK - STAND_FRAME_SIZE # switch to kernel SP sw v0, UADDR+U_PCB_REGS+(MULLO * 4) sw v1, UADDR+U_PCB_REGS+(MULHI * 4) sw a0, UADDR+U_PCB_REGS+(SR * 4) sw a2, UADDR+U_PCB_REGS+(PC * 4) # la gp, _gp # switch to kernel GP .set at and t0, a0, ~MACH_SR_COP_1_BIT # Turn off the FPU. .set noat mtc0 t0, MACH_COP_0_STATUS_REG/* * Call the interrupt handler. */ jal interrupt sw a2, STAND_RA_OFFSET(sp) # for debugging/* * Restore registers and return from the interrupt. */ lw a0, UADDR+U_PCB_REGS+(SR * 4) lw v0, astpending # any pending interrupts? mtc0 a0, MACH_COP_0_STATUS_REG # Restore the SR, disable intrs bne v0, zero, 1f # dont restore, call softintr lw t0, UADDR+U_PCB_REGS+(MULLO * 4) lw t1, UADDR+U_PCB_REGS+(MULHI * 4) lw k0, UADDR+U_PCB_REGS+(PC * 4) lw AT, UADDR+U_PCB_REGS+(AST * 4) lw v0, UADDR+U_PCB_REGS+(V0 * 4) lw v1, UADDR+U_PCB_REGS+(V1 * 4) lw a0, UADDR+U_PCB_REGS+(A0 * 4) lw a1, UADDR+U_PCB_REGS+(A1 * 4) lw a2, UADDR+U_PCB_REGS+(A2 * 4) lw a3, UADDR+U_PCB_REGS+(A3 * 4) mtlo t0 mthi t1 lw t0, UADDR+U_PCB_REGS+(T0 * 4) lw t1, UADDR+U_PCB_REGS+(T1 * 4) lw t2, UADDR+U_PCB_REGS+(T2 * 4) lw t3, UADDR+U_PCB_REGS+(T3 * 4) lw t4, UADDR+U_PCB_REGS+(T4 * 4) lw t5, UADDR+U_PCB_REGS+(T5 * 4) lw t6, UADDR+U_PCB_REGS+(T6 * 4) lw t7, UADDR+U_PCB_REGS+(T7 * 4) lw t8, UADDR+U_PCB_REGS+(T8 * 4) lw t9, UADDR+U_PCB_REGS+(T9 * 4) lw gp, UADDR+U_PCB_REGS+(GP * 4) lw sp, UADDR+U_PCB_REGS+(SP * 4) lw ra, UADDR+U_PCB_REGS+(RA * 4) j k0 # Now return from the rfe # interrupt.1:/* * We have pending software interrupts; save remaining user state in u.u_pcb. */ sw s0, UADDR+U_PCB_REGS+(S0 * 4) sw s1, UADDR+U_PCB_REGS+(S1 * 4) sw s2, UADDR+U_PCB_REGS+(S2 * 4) sw s3, UADDR+U_PCB_REGS+(S3 * 4) sw s4, UADDR+U_PCB_REGS+(S4 * 4) sw s5, UADDR+U_PCB_REGS+(S5 * 4) sw s6, UADDR+U_PCB_REGS+(S6 * 4) sw s7, UADDR+U_PCB_REGS+(S7 * 4) sw s8, UADDR+U_PCB_REGS+(S8 * 4) li t0, MACH_HARD_INT_MASK | MACH_SR_INT_ENA_CUR/* * Call the software interrupt handler. */ jal softintr mtc0 t0, MACH_COP_0_STATUS_REG # enable interrupts (spl0)/* * Restore user registers and return. NOTE: interrupts are enabled. */ lw a0, UADDR+U_PCB_REGS+(SR * 4) lw t0, UADDR+U_PCB_REGS+(MULLO * 4) lw t1, UADDR+U_PCB_REGS+(MULHI * 4) mtc0 a0, MACH_COP_0_STATUS_REG # this should disable interrupts mtlo t0 mthi t1 lw k0, UADDR+U_PCB_REGS+(PC * 4) lw AT, UADDR+U_PCB_REGS+(AST * 4) lw v0, UADDR+U_PCB_REGS+(V0 * 4) lw v1, UADDR+U_PCB_REGS+(V1 * 4) lw a0, UADDR+U_PCB_REGS+(A0 * 4) lw a1, UADDR+U_PCB_REGS+(A1 * 4) lw a2, UADDR+U_PCB_REGS+(A2 * 4) lw a3, UADDR+U_PCB_REGS+(A3 * 4) lw t0, UADDR+U_PCB_REGS+(T0 * 4) lw t1, UADDR+U_PCB_REGS+(T1 * 4) lw t2, UADDR+U_PCB_REGS+(T2 * 4) lw t3, UADDR+U_PCB_REGS+(T3 * 4) lw t4, UADDR+U_PCB_REGS+(T4 * 4) lw t5, UADDR+U_PCB_REGS+(T5 * 4) lw t6, UADDR+U_PCB_REGS+(T6 * 4) lw t7, UADDR+U_PCB_REGS+(T7 * 4) lw s0, UADDR+U_PCB_REGS+(S0 * 4) lw s1, UADDR+U_PCB_REGS+(S1 * 4) lw s2, UADDR+U_PCB_REGS+(S2 * 4) lw s3, UADDR+U_PCB_REGS+(S3 * 4) lw s4, UADDR+U_PCB_REGS+(S4 * 4) lw s5, UADDR+U_PCB_REGS+(S5 * 4) lw s6, UADDR+U_PCB_REGS+(S6 * 4) lw s7, UADDR+U_PCB_REGS+(S7 * 4) lw t8, UADDR+U_PCB_REGS+(T8 * 4) lw t9, UADDR+U_PCB_REGS+(T9 * 4) lw gp, UADDR+U_PCB_REGS+(GP * 4) lw sp, UADDR+U_PCB_REGS+(SP * 4) lw s8, UADDR+U_PCB_REGS+(S8 * 4) lw ra, UADDR+U_PCB_REGS+(RA * 4) j k0 rfe .set atEND(MachUserIntr)#if 0/*---------------------------------------------------------------------------- * * MachTLBModException -- * * Handle a TLB modified exception. * The BaddVAddr, Context, and EntryHi registers contain the failed * virtual address. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------------- */NLEAF(MachTLBModException) .set noat tlbp # find the TLB entry mfc0 k0, MACH_COP_0_TLB_LOW # get the physical address mfc0 k1, MACH_COP_0_TLB_INDEX # check to be sure its valid or k0, k0, VMMACH_TLB_MOD_BIT # update TLB blt k1, zero, 4f # not found!!! mtc0 k0, MACH_COP_0_TLB_LOW li k1, MACH_CACHED_MEMORY_ADDR subu k0, k0, k1 srl k0, k0, VMMACH_TLB_PHYS_PAGE_SHIFT la k1, pmap_attributes addu k0, k0, k1 lbu k1, 0(k0) # fetch old value nop or k1, k1, 1 # set modified bit sb k1, 0(k0) # save new value mfc0 k0, MACH_COP_0_EXC_PC # get return address nop j k0 rfe4: break 0 # panic .set atEND(MachTLBModException)#endif/*---------------------------------------------------------------------------- * * MachTLBMissException -- * * Handle a TLB miss exception from kernel mode. * The BaddVAddr, Context, and EntryHi registers contain the failed * virtual address. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------------- */NLEAF(MachTLBMissException) .set noat mfc0 k0, MACH_COP_0_BAD_VADDR # get the fault address li k1, VM_MIN_KERNEL_ADDRESS # compute index subu k0, k0, k1 lw k1, Sysmapsize # index within range? srl k0, k0, PGSHIFT sltu k1, k0, k1 beq k1, zero, 1f # No. check for valid stack nop lw k1, Sysmap sll k0, k0, 2 # compute offset from index addu k1, k1, k0 lw k0, 0(k1) # get PTE entry mfc0 k1, MACH_COP_0_EXC_PC # get return address mtc0 k0, MACH_COP_0_TLB_LOW # save PTE entry and k0, k0, PG_V # check for valid entry beq k0, zero, MachKernGenException # PTE invalid nop tlbwr # update TLB j k1 rfe1: subu k0, sp, UADDR + 0x200 # check to see if we have a sltiu k0, UPAGES*NBPG - 0x200 # valid kernel stack bne k0, zero, MachKernGenException # Go panic nop la a0, start - START_FRAME - 8 # set sp to a valid place sw sp, 24(a0) move sp, a0 la a0, 1f mfc0 a2, MACH_COP_0_STATUS_REG mfc0 a3, MACH_COP_0_CAUSE_REG mfc0 a1, MACH_COP_0_EXC_PC sw a2, 16(sp) sw a3, 20(sp) sw sp, 24(sp) move a2, ra jal printf mfc0 a3, MACH_COP_0_BAD_VADDR .data1: .asciiz "ktlbmiss: PC %x RA %x ADR %x\nSR %x CR %x SP %x\n" .text la sp, start - START_FRAME # set sp to a valid place PANIC("kernel stack overflow") .set atEND(MachTLBMissException)/* * Set/clear software interrupt routines. */LEAF(setsoftclock) mfc0 v0, MACH_COP_0_CAUSE_REG # read cause register nop or v0, v0, MACH_SOFT_INT_MASK_0 # set soft clock interrupt mtc0 v0, MACH_COP_0_CAUSE_REG # save it j ra nopEND(setsoftclock)LEAF(clearsoftclock) mfc0 v0, MACH_COP_0_CAUSE_REG # read cause register nop and v0, v0, ~MACH_SOFT_INT_MASK_0 # clear soft clock interrupt mtc0 v0, MACH_COP_0_CAUSE_REG # save it j ra nopEND(clearsoftclock)LEAF(setsoftnet) mfc0 v0, MACH_COP_0_CAUSE_REG # read cause register nop or v0, v0, MACH_SOFT_INT_MASK_1 # set soft net interrupt mtc0 v0, MACH_COP_0_CAUSE_REG # save it j ra nopEND(setsoftnet)LEAF(clearsoftnet) mfc0 v0, MACH_COP_0_CAUSE_REG # read cause register nop and v0, v0, ~MACH_SOFT_INT_MASK_1 # clear soft net interrupt mtc0 v0, MACH_COP_0_CAUSE_REG # save it j ra nopEND(clearsoftnet)/* * Set/change interrupt priority routines. */LEAF(MachEnableIntr) mfc0 v0, MACH_COP_0_STATUS_REG # read status register nop or v0, v0, MACH_SR_INT_ENA_CUR mtc0 v0, MACH_COP_0_STATUS_REG # enable all interrupts j ra nopEND(MachEnableIntr)LEAF(spl0) mfc0 v0, MACH_COP_0_STATUS_REG # read status register nop or t0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR) mtc0 t0, MACH_COP_0_STATUS_REG # enable all interrupts j ra and v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR)END(spl0)LEAF(splsoftclock) mfc0 v0, MACH_COP_0_STATUS_REG # read status register li t0, ~MACH_SOFT_INT_MASK_0 # disable soft clock and t0, t0, v0 mtc0 t0, MACH_COP_0_STATUS_REG # save it j ra and v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR)END(splsoftclock)LEAF(Mach_spl0) mfc0 v0, MACH_COP_0_STATUS_REG # read status register li t0, ~(MACH_INT_MASK_0|MACH_SOFT_INT_MASK_1|MACH_SOFT_INT_MASK_0) and t0, t0, v0 mtc0 t0, MACH_COP_0_STATUS_REG # save it j ra and v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR)END(Mach_spl0)LEAF(Mach_spl1) mfc0 v0, MACH_COP_0_STATUS_REG # read status register li t0, ~(MACH_INT_MASK_1|MACH_SOFT_INT_MASK_0|MACH_SOFT_INT_MASK_1) and t0, t0, v0 mtc0 t0, MACH_COP_0_STATUS_REG # save it j ra and v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR)END(Mach_spl1)LEAF(Mach_spl2) mfc0 v0, MACH_COP_0_STATUS_REG # read status register li t0, ~(MACH_INT_MASK_2|MACH_SOFT_INT_MASK_1|MACH_SOFT_INT_MASK_0) and t0, t0, v0 mtc0 t0, MACH_COP_0_STATUS_REG # save it j ra and v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR)END(Mach_spl2)LEAF(Mach_spl3) mfc0 v0, MACH_COP_0_STATUS_REG # read status register li t0, ~(MACH_INT_MASK_3|MACH_SOFT_INT_MASK_1|MACH_SOFT_INT_MASK_0) and t0, t0, v0 mtc0 t0, MACH_COP_0_STATUS_REG # save it j ra and v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR)END(Mach_spl3)/* * We define an alternate entry point after mcount is called so it * can be used in mcount without causeing a recursive loop. */LEAF(splhigh)ALEAF(_splhigh) mfc0 v0, MACH_COP_0_STATUS_REG # read status register li t0, ~MACH_SR_INT_ENA_CUR # disable all interrupts and t0, t0, v0 mtc0 t0, MACH_COP_0_STATUS_REG # save it j ra and v0, v0, (MACH_INT_MASK | MACH_SR_INT_ENA_CUR)END(splhigh)/*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -