📄 locore.s
字号:
/* * The window we wanted to push could not be pushed. * Instead, save ALL user windows into the pcb. * We will notice later that we did this, when we * get ready to return from our trap or syscall. * * The code here is run rarely and need not be optimal. */ctw_invalid: /* * Reread cpcb->pcb_uw. We decremented this earlier, * so it is off by one. */ ld [%g6 + PCB_UW], %g7 ! (number of user windows) - 1 add %g6, PCB_RW, %g5 /* save g7+1 windows, starting with the current one */1: ! do { std %l0, [%g5 + (0*8)] ! rw->rw_local[0] = l0; std %l2, [%g5 + (1*8)] ! ... std %l4, [%g5 + (2*8)] std %l6, [%g5 + (3*8)] std %i0, [%g5 + (4*8)] std %i2, [%g5 + (5*8)] std %i4, [%g5 + (6*8)] std %i6, [%g5 + (7*8)] deccc %g7 ! if (n > 0) save(), rw++; bge,a 1b ! } while (--n >= 0); save %g5, 64, %g5 /* stash sp for bottommost window */ st %sp, [%g5 + 64 + (7*8)] /* set up new wim */ rd %psr, %g7 ! g7 = (junk << 5) + new_cwp; mov 1, %g5 ! g5 = 1 << new_cwp; sll %g5, %g7, %g5 wr %g5, 0, %wim ! wim = g5; and %g7, 31, %g7 st %g7, [%g6 + PCB_WIM] ! cpcb->pcb_wim = new_cwp; /* fix up pcb fields */ ld [%g6 + PCB_UW], %g7 ! n = cpcb->pcb_uw; add %g7, 1, %g5 st %g5, [%g6 + PCB_NSAVED] ! cpcb->pcb_nsaved = n + 1; st %g0, [%g6 + PCB_UW] ! cpcb->pcb_uw = 0; /* return to trap window */1: deccc %g7 ! do { bge 1b ! restore(); restore ! } while (--n >= 0); mov %l5, %g5 ! restore g5, g6, & g7, and return mov %l6, %g6 jmp %l4 + 8 mov %l7, %g7 /* NOTREACHED *//* * Each memory access (text or data) fault, from user or kernel mode, * comes here. We read the error register and figure out what has * happened. * * This cannot be done from C code since we must not enable traps (and * hence may not use the `save' instruction) until we have decided that * the error is or is not an asynchronous one that showed up after a * synchronous error, but which must be handled before the sync err. * * Most memory faults are user mode text or data faults, which can cause * signal delivery or ptracing, for which we must build a full trapframe. * It does not seem worthwhile to work to avoid this in the other cases, * so we store all the %g registers on the stack immediately. * * On entry: * %l0 = %psr * %l1 = return pc * %l2 = return npc * %l3 = T_TEXTFAULT or T_DATAFAULT * * Internal: * %l4 = %y, until we call mem_access_fault (then onto trapframe) * %l5 = IE_reg_addr, if async mem error * * We know about the layout of the error registers here. * addr reg * ---- --- * a AC_SYNC_ERR * a+4 AC_SYNC_VA * a+8 AC_ASYNC_ERR * a+12 AC_ASYNC_VA */memfault: TRAP_SETUP(-CCFSZ-80) INCR(_cnt+V_FAULTS) ! cnt.v_faults++ (clobbers %o0,%o1) st %g1, [%sp + CCFSZ + 20] ! save g1 rd %y, %l4 ! save y#if AC_SYNC_ERR + 4 != AC_SYNC_VA || \ AC_SYNC_ERR + 8 != AC_ASYNC_ERR || AC_SYNC_ERR + 12 != AC_ASYNC_VA help help help ! I, I, I wanna be a lifeguard#endif set AC_SYNC_ERR, %o0 std %g2, [%sp + CCFSZ + 24] ! save g2, g3 lda [%o0] ASI_CONTROL, %o1 ! sync err reg inc 4, %o0 std %g4, [%sp + CCFSZ + 32] ! (sneak g4,g5 in here) lda [%o0] ASI_CONTROL, %o2 ! sync virt addr btst SER_MEMERR, %o1 ! memory error? std %g6, [%sp + CCFSZ + 40] bz,a normal_mem_fault ! no, just a regular fault wr %l0, PSR_ET, %psr ! (and reenable traps) /* * We got a synchronous memory error. It could be one that * happened because there were two stores in a row, and the * first went into the write buffer, and the second caused this * synchronous trap; so there could now be a pending async error. * This is in fact the case iff the two va's differ. */ inc 4, %o0 lda [%o0] ASI_CONTROL, %o3 ! async err reg inc 4, %o0 lda [%o0] ASI_CONTROL, %o4 ! async virt addr cmp %o2, %o4 be,a 1f ! no, not an async err wr %l0, PSR_ET, %psr ! (and reenable traps) /* * Handle the async error; ignore the sync error for now * (we may end up getting it again, but so what?). * This code is essentially the same as that at `nmi' below, * but the register usage is different and we cannot merge. */ sethi %hi(IE_reg_addr), %l5 ! ienab_bic(IE_ALLIE); ldub [%l5 + %lo(IE_reg_addr)], %o0 andn %o0, IE_ALLIE, %o0 stb %o0, [%l5 + %lo(IE_reg_addr)] /* * Now reenable traps and call C code. * %o1 through %o4 still hold the error reg contents. * If memerr() returns, return from the trap. */ wr %l0, PSR_ET, %psr call _memerr ! memerr(0, ser, sva, aer, ava) clr %o0 ld [%sp + CCFSZ + 20], %g1 ! restore g1 through g7 wr %l0, 0, %psr ! and disable traps, 3 instr delay ldd [%sp + CCFSZ + 24], %g2 ldd [%sp + CCFSZ + 32], %g4 ldd [%sp + CCFSZ + 40], %g6 /* now safe to set IE_ALLIE again */ ldub [%l5 + %lo(IE_reg_addr)], %o1 or %o1, IE_ALLIE, %o1 stb %o1, [%l5 + %lo(IE_reg_addr)] b return_from_trap wr %l4, 0, %y ! restore y /* * Trap was a synchronous memory error. * %o1 through %o4 still hold the error reg contents. */1: call _memerr ! memerr(1, ser, sva, aer, ava) mov 1, %o0 ld [%sp + CCFSZ + 20], %g1 ! restore g1 through g7 ldd [%sp + CCFSZ + 24], %g2 ldd [%sp + CCFSZ + 32], %g4 ldd [%sp + CCFSZ + 40], %g6 wr %l4, 0, %y ! restore y b return_from_trap wr %l0, 0, %psr /* NOTREACHED */normal_mem_fault: /* * Trap was some other error; call C code to deal with it. * Must finish trap frame (psr,pc,npc,%y,%o0..%o7) in case * we decide to deliver a signal or ptrace the process. * %g1..%g7 were already set up above. */ std %l0, [%sp + CCFSZ + 0] ! set tf.tf_psr, tf.tf_pc mov %l3, %o0 ! (argument: type) st %l2, [%sp + CCFSZ + 8] ! set tf.tf_npc st %l4, [%sp + CCFSZ + 12] ! set tf.tf_y mov %l1, %o3 ! (argument: pc) std %i0, [%sp + CCFSZ + 48] ! tf.tf_out[0], etc std %i2, [%sp + CCFSZ + 56] mov %l0, %o4 ! (argument: psr) std %i4, [%sp + CCFSZ + 64] std %i6, [%sp + CCFSZ + 72] call _mem_access_fault ! mem_access_fault(type, ser, sva, ! pc, psr, &tf); add %sp, CCFSZ, %o5 ! (argument: &tf) ldd [%sp + CCFSZ + 0], %l0 ! load new values ldd [%sp + CCFSZ + 8], %l2 wr %l3, 0, %y ld [%sp + CCFSZ + 20], %g1 ldd [%sp + CCFSZ + 24], %g2 ldd [%sp + CCFSZ + 32], %g4 ldd [%sp + CCFSZ + 40], %g6 ldd [%sp + CCFSZ + 48], %i0 ldd [%sp + CCFSZ + 56], %i2 ldd [%sp + CCFSZ + 64], %i4 ldd [%sp + CCFSZ + 72], %i6 b return_from_trap ! go return wr %l0, 0, %psr ! (but first disable traps again)/* * fp_exception has to check to see if we are trying to save * the FP state, and if so, continue to save the FP state. * * We do not even bother checking to see if we were in kernel mode, * since users have no access to the special_fp_store instruction. * * This whole idea was stolen from Sprite. */fp_exception: set special_fp_store, %l4 ! see if we came from the special one cmp %l1, %l4 ! pc == special_fp_store? bne slowtrap ! no, go handle per usual EMPTY sethi %hi(savefpcont), %l4 ! yes, "return" to the special code or %lo(savefpcont), %l4, %l4 jmp %l4 rett %l4 + 4/* * slowtrap() builds a trap frame and calls trap(). * This is called `slowtrap' because it *is*.... * We have to build a full frame for ptrace(), for instance. * * Registers: * %l0 = %psr * %l1 = return pc * %l2 = return npc * %l3 = trap code */slowtrap: TRAP_SETUP(-CCFSZ-80) /* * Phew, ready to enable traps and call C code. */ mov %l3, %o0 ! put type in %o0 for laterLslowtrap_reenter: wr %l0, PSR_ET, %psr ! traps on again std %l0, [%sp + CCFSZ] ! tf.tf_psr = psr; tf.tf_pc = ret_pc; rd %y, %l3 std %l2, [%sp + CCFSZ + 8] ! tf.tf_npc = return_npc; tf.tf_y = %y; st %g1, [%sp + CCFSZ + 20] std %g2, [%sp + CCFSZ + 24] std %g4, [%sp + CCFSZ + 32] std %g6, [%sp + CCFSZ + 40] std %i0, [%sp + CCFSZ + 48] mov %l0, %o1 ! (psr) std %i2, [%sp + CCFSZ + 56] mov %l1, %o2 ! (pc) std %i4, [%sp + CCFSZ + 64] add %sp, CCFSZ, %o3 ! (&tf) call _trap ! trap(type, psr, pc, &tf) std %i6, [%sp + CCFSZ + 72] ldd [%sp + CCFSZ], %l0 ! load new values ldd [%sp + CCFSZ + 8], %l2 wr %l3, 0, %y ld [%sp + CCFSZ + 20], %g1 ldd [%sp + CCFSZ + 24], %g2 ldd [%sp + CCFSZ + 32], %g4 ldd [%sp + CCFSZ + 40], %g6 ldd [%sp + CCFSZ + 48], %i0 ldd [%sp + CCFSZ + 56], %i2 ldd [%sp + CCFSZ + 64], %i4 ldd [%sp + CCFSZ + 72], %i6 b return_from_trap wr %l0, 0, %psr/* * Do a `software' trap by re-entering the trap code, possibly first * switching from interrupt stack to kernel stack. This is used for * scheduling and signal ASTs (which generally occur from softclock or * tty or net interrupts) and register window saves (which might occur * from anywhere). * * The current window is the trap window, and it is by definition clean. * We enter with the trap type in %o0. All we have to do is jump to * Lslowtrap_reenter above, but maybe after switching stacks.... */softtrap: sethi %hi(_eintstack), %l7 cmp %sp, %l7 bge Lslowtrap_reenter EMPTY sethi %hi(_cpcb), %l6 ld [%l6 + %lo(_cpcb)], %l6 set UPAGES*NBPG - CCFSZ - 80, %l5 add %l6, %l5, %l7 SET_SP_REDZONE(%l6, %l5) b Lslowtrap_reenter mov %l7, %sp#ifdef KGDB/* * bpt is entered on all breakpoint traps. * If this is a kernel breakpoint, we do not want to call trap(). * Among other reasons, this way we can set breakpoints in trap(). */bpt: btst PSR_PS, %l0 ! breakpoint from kernel? bz slowtrap ! no, go do regular trap nop /* * Build a trap frame for kgdb_trap_glue to copy. * Enable traps but set ipl high so that we will not * see interrupts from within breakpoints. */ TRAP_SETUP(-CCFSZ-80) or %l0, PSR_PIL, %l4 ! splhigh() wr %l4, 0, %psr ! the manual claims that this wr %l4, PSR_ET, %psr ! song and dance is necessary std %l0, [%sp + CCFSZ + 0] ! tf.tf_psr, tf.tf_pc mov %l3, %o0 ! trap type arg for kgdb_trap_glue rd %y, %l3 std %l2, [%sp + CCFSZ + 8] ! tf.tf_npc, tf.tf_y rd %wim, %l3 st %l3, [%sp + CCFSZ + 16] ! tf.tf_wim (a kgdb-only r/o field) st %g1, [%sp + CCFSZ + 20] ! tf.tf_global[1] std %g2, [%sp + CCFSZ + 24] ! etc std %g4, [%sp + CCFSZ + 32] std %g6, [%sp + CCFSZ + 40] std %i0, [%sp + CCFSZ + 48] ! tf.tf_in[0..1] std %i2, [%sp + CCFSZ + 56] ! etc std %i4, [%sp + CCFSZ + 64] std %i6, [%sp + CCFSZ + 72] /* * Now call kgdb_trap_glue(); if it returns, call trap(). */ mov %o0, %l3 ! gotta save trap type call _kgdb_trap_glue ! kgdb_trap_glue(type, &trapframe) add %sp, CCFSZ, %o1 ! (&trapframe) /* * Use slowtrap to call trap---but first erase our tracks * (put the registers back the way they were). */ mov %l3, %o0 ! slowtrap will need trap type ld [%sp + CCFSZ + 12], %l3 wr %l3, 0, %y ld [%sp + CCFSZ + 20], %g1 ldd [%sp + CCFSZ + 24], %g2 ldd [%sp + CCFSZ + 32], %g4 b Lslowtrap_reenter ldd [%sp + CCFSZ + 40], %g6/* * Enter kernel breakpoint. Write all the windows (not including the * current window) into the stack, so that backtrace works. Copy the * supplied trap frame to the kgdb stack and switch stacks. * * kgdb_trap_glue(type, tf0) * int type; * struct trapframe *tf0; */ .globl _kgdb_trap_glue_kgdb_trap_glue: save %sp, -CCFSZ, %sp call _write_all_windows mov %sp, %l4 ! %l4 = current %sp /* copy trapframe to top of kgdb stack */ set _kgdb_stack + KGDB_STACK_SIZE - 80, %l0 ! %l0 = tfcopy -> end_of_kgdb_stack mov 80, %l11: ldd [%i1], %l2 inc 8, %i1 deccc 8, %l1 std %l2, [%l0] bg 1b inc 8, %l0#ifdef DEBUG /* save old red zone and then turn it off */ sethi %hi(_redzone), %l7 ld [%l7 + %lo(_redzone)], %l6 st %g0, [%l7 + %lo(_redzone)]#endif /* switch to kgdb stack */ add %l0, -CCFSZ-80, %sp /* if (kgdb_trap(type, tfcopy)) kgdb_rett(tfcopy); */ mov %i0, %o0 call _kgdb_trap add %l0, -80, %o1 tst %o0 bnz,a kgdb_rett add %l0, -80, %g1 /* * kgdb_trap() did not handle the trap at all so the stack is * still intact. A simple `restore' will put everything back, * after we reset the stack pointer. */ mov %l4, %sp#ifdef DEBUG st %l6, [%l7 + %lo(_redzone)] ! restore red zone#endif ret restore/* * Return from kgdb trap. This is sort of special. * * We know that kgdb_trap_glue wrote the window above it, so that we will * be able to (and are sure to have to) load it up. We also know that we * came from kernel land and can assume that the %fp (%i6) we load here * is proper. We must also be sure not to lower ipl (it is at splhigh()) * until we have traps disabled, due to the SPARC taking traps at the * new ipl before noticing that PSR_ET has been turned off. We are on * the kgdb stack, so this could be disastrous. * * Note that the trapframe argument in %g1 points into the current stack * frame (current window). We abandon this window when we move %g1->tf_psr * into %psr, but we will not have loaded the new %sp yet, so again traps * must be disabled. */kgdb_rett: rd %psr, %g4 ! turn off traps wr %g4, PSR_ET, %psr /* use the three-instruction delay to do something useful */ ld [%g1], %g2 ! pick up new %psr ld [%g1 + 12], %g3 ! set %y wr %g3, 0, %y#ifdef DEBUG st %l6, [%l7 + %lo(_redzone)] ! and restore red zone#endif wr %g0, 0, %wim ! enable window changes nop; nop; nop /* now safe to set the new psr (changes CWP, leaves traps disabled) */ wr %g2, 0, %psr ! set rett psr (including cond codes) /* 3 instruction delay before we can use the new window *//*1*/ ldd [%g1 + 24], %g2 ! set new %g2, %g3/*2*/ ldd [%g1 + 32], %g4 ! set new %g4, %g5/*3*/ ldd [%g1 + 40], %g6 ! set new %g6, %g7 /* now we can use the new window */ mov %g1, %l4 ld [%l4 + 4], %l1 ! get new pc ld [%l4 + 8], %l2 ! get new npc
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -