📄 locore.s
字号:
ld [%l1 + %lo(_cpcb)], %l1 st %l0, [%l1 + PCB_WIM] ! cpcb->pcb_wim = cwp; save %g0, %g0, %g0 ! back to window I LOADWIN(%sp) save %g0, %g0, %g0 ! back to R save %g0, %g0, %g0 ! and then to T wr %l0, 0, %psr ! fix those cond codes.... nop ! (let them settle in) RETTwinuf_user: /* * Underflow from user mode. * * We cannot use rft_user (as noted above) because * we must re-execute the `restore' instruction. * Since it could be, e.g., `restore %l0,0,%l0', * it is not okay to touch R's registers either. * * We are now in window I. */ btst 7, %sp ! if unaligned, it is invalid bne winuf_invalid EMPTY PTE_OF_ADDR(%sp, %l7, winuf_invalid) CMP_PTE_USER_READ(%l7) ! if first page not readable, bne winuf_invalid ! it is invalid EMPTY SLT_IF_1PAGE_RW(%sp, %l7) ! first page is readable bl,a winuf_ok ! if only one page, enter window X restore %g0, 1, %l1 ! and goto ok, & set %l1 to 1 add %sp, 7*8, %l5 PTE_OF_ADDR(%l5, %l7, winuf_invalid) CMP_PTE_USER_READ(%l7) ! check second page too be,a winuf_ok ! enter window X and goto ok restore %g0, 1, %l1 ! (and then set %l1 to 1)winuf_invalid: /* * We were unable to restore the window because %sp * is invalid or paged out. Return to the trap window * and call trap(T_WINUF). This will save R to the user * stack, then load both R and I into the pcb rw[] area, * and return with pcb_nsaved set to -1 for success, 0 for * failure. `Failure' indicates that someone goofed with the * trap registers (e.g., signals), so that we need to return * from the trap as from a syscall (probably to a signal handler) * and let it retry the restore instruction later. Note that * window R will have been pushed out to user space, and thus * be the invalid window, by the time we get back here. (We * continue to label it R anyway.) We must also set %wim again, * and set pcb_uw to 1, before enabling traps. (Window R is the * only window, and it is a user window). */ save %g0, %g0, %g0 ! back to R#if 0 /* this gives `as' mild heartburn */ save %g0, 1, %l4 ! back to T, then %l4 = 1#else save %g0, %g0, %g0 ! back to T mov 1, %l4 ! and set %l4 = 1#endif sethi %hi(_cpcb), %l6 ld [%l6 + %lo(_cpcb)], %l6 st %l4, [%l6 + PCB_UW] ! pcb_uw = 1 ld [%l6 + PCB_WIM], %l5 ! get log2(%wim) sll %l4, %l5, %l4 ! %l4 = old %wim wr %l4, 0, %wim ! window I is now invalid again set UPAGES*NBPG-CCFSZ-80, %l5 add %l6, %l5, %sp ! get onto kernel stack CHECK_SP_REDZONE(%l6, %l5) /* * Okay, call trap(T_WINUF, psr, pc, &tf). * See `slowtrap' above for operation. */ wr %l0, PSR_ET, %psr std %l0, [%sp + CCFSZ + 0] ! tf.tf_psr, tf.tf_pc rd %y, %l3 std %l2, [%sp + CCFSZ + 8] ! tf.tf_npc, tf.tf_y mov T_WINUF, %o0 st %g1, [%sp + CCFSZ + 20] ! tf.tf_global[1] mov %l0, %o1 std %g2, [%sp + CCFSZ + 24] ! etc mov %l1, %o2 std %g4, [%sp + CCFSZ + 32] add %sp, CCFSZ, %o3 std %g6, [%sp + CCFSZ + 40] std %i0, [%sp + CCFSZ + 48] ! tf.tf_out[0], etc std %i2, [%sp + CCFSZ + 56] std %i4, [%sp + CCFSZ + 64] call _trap ! trap(T_WINUF, pc, psr, &tf) std %i6, [%sp + CCFSZ + 72] ! tf.tf_out[6] ldd [%sp + CCFSZ + 0], %l0 ! new psr, pc ldd [%sp + CCFSZ + 8], %l2 ! new npc, %y 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 ! %o0 for window R, etc ldd [%sp + CCFSZ + 56], %i2 ldd [%sp + CCFSZ + 64], %i4 wr %l0, 0, %psr ! disable traps: test must be atomic ldd [%sp + CCFSZ + 72], %i6 sethi %hi(_cpcb), %l6 ld [%l6 + %lo(_cpcb)], %l6 ld [%l6 + PCB_NSAVED], %l7 ! if nsaved is -1, we have our regs tst %l7 bl,a 1f ! got them wr %g0, 0, %wim ! allow us to enter windows R, I b,a return_from_trap /* * Got 'em. Load 'em up. */1: mov %g6, %l3 ! save %g6; set %g6 = cpcb mov %l6, %g6 st %g0, [%g6 + PCB_NSAVED] ! and clear magic flag restore ! from T to R restore ! from R to I restore %g0, 1, %l1 ! from I to X, then %l1 = 1 rd %psr, %l0 ! cwp = %psr; sll %l1, %l0, %l1 wr %l1, 0, %wim ! make window X invalid and %l0, 31, %l0 st %l0, [%g6 + PCB_WIM] ! cpcb->pcb_wim = cwp; nop ! unnecessary? old wim was 0... save %g0, %g0, %g0 ! back to I LOADWIN(%g6 + PCB_RW + 64) ! load from rw[1] save %g0, %g0, %g0 ! back to R LOADWIN(%g6 + PCB_RW) ! load from rw[0] save %g0, %g0, %g0 ! back to T wr %l0, 0, %psr ! restore condition codes mov %l3, %g6 ! fix %g6 RETT /* * Restoring from user stack, but everything has checked out * as good. We are now in window X, and %l1 = 1. Window R * is still valid and holds user values. */winuf_ok: rd %psr, %l0 sll %l1, %l0, %l1 wr %l1, 0, %wim ! make this one invalid sethi %hi(_cpcb), %l2 ld [%l2 + %lo(_cpcb)], %l2 and %l0, 31, %l0 st %l0, [%l2 + PCB_WIM] ! cpcb->pcb_wim = cwp; save %g0, %g0, %g0 ! back to I LOADWIN(%sp) save %g0, %g0, %g0 ! back to R save %g0, %g0, %g0 ! back to T wr %l0, 0, %psr ! restore condition codes nop ! it takes three to tangle RETT#endif /* end `real' version of window underflow trap handler *//* * Various return-from-trap routines (see return_from_trap). *//* * Return from trap, to kernel. * %l0 = %psr * %l1 = return pc * %l2 = return npc * %l4 = %wim * %l5 = bit for previous window */rft_kernel: btst %l5, %l4 ! if (wim & l5) bnz 1f ! goto reload; wr %l0, 0, %psr ! but first put !@#*% cond codes back /* previous window is valid; just rett */ nop ! wait for cond codes to settle in RETT /* * Previous window is invalid. * Update %wim and then reload l0..i7 from frame. * * T I X * 0 0 1 0 0 (%wim) * [see picture in window_uf handler] * * T is the current (Trap) window, I is the Invalid window, * and X is the window we want to make invalid. Window X * currently has no useful values. */1: wr %g0, 0, %wim ! allow us to enter window I nop; nop; nop ! (it takes a while) restore ! enter window I restore %g0, 1, %l1 ! enter window X, then %l1 = 1 rd %psr, %l0 ! CWP = %psr & 31; and %l0, 31, %l0 sll %l1, %l0, %l1 ! wim = 1 << CWP; wr %l1, 0, %wim ! setwim(wim); sethi %hi(_cpcb), %l1 ld [%l1 + %lo(_cpcb)], %l1 st %l0, [%l1 + PCB_WIM] ! cpcb->pcb_wim = l0 & 31; save %g0, %g0, %g0 ! back to window I LOADWIN(%sp) save %g0, %g0, %g0 ! back to window T /* * Note that the condition codes are still set from * the code at rft_kernel; we can simply return. */ RETT/* * Return from trap, to user. Checks for scheduling trap (`ast') first; * will re-enter trap() if set. Note that we may have to switch from * the interrupt stack to the kernel stack in this case. * %l0 = %psr * %l1 = return pc * %l2 = return npc * %l4 = %wim * %l5 = bit for previous window * %l6 = cpcb * If returning to a valid window, just set psr and return. */rft_user:! sethi %hi(_want_ast), %l7 ! (done below) ld [%l7 + %lo(_want_ast)], %l7 tst %l7 ! want AST trap? bne,a softtrap ! yes, re-enter trap with type T_AST mov T_AST, %o0 btst %l5, %l4 ! if (wim & l5) bnz 1f ! goto reload; wr %l0, 0, %psr ! restore cond codes nop ! (three instruction delay) RETT /* * Previous window is invalid. * Before we try to load it, we must verify its stack pointer. * This is much like the underflow handler, but a bit easier * since we can use our own local registers. */1: btst 7, %fp ! if unaligned, address is invalid bne rft_invalid EMPTY PTE_OF_ADDR(%fp, %l7, rft_invalid) CMP_PTE_USER_READ(%l7) ! try first page bne rft_invalid ! no good EMPTY SLT_IF_1PAGE_RW(%fp, %l7) bl,a rft_user_ok ! only 1 page: ok wr %g0, 0, %wim add %fp, 7*8, %l5 PTE_OF_ADDR(%l5, %l7, rft_invalid) CMP_PTE_USER_READ(%l7) ! check 2nd page too be,a rft_user_ok wr %g0, 0, %wim /* * The window we wanted to pull could not be pulled. Instead, * re-enter trap with type T_RWRET. This will pull the window * into cpcb->pcb_rw[0] and set cpcb->pcb_nsaved to -1, which we * will detect when we try to return again. */rft_invalid: b softtrap mov T_RWRET, %o0 /* * The window we want to pull can be pulled directly. */rft_user_ok:! wr %g0, 0, %wim ! allow us to get into it wr %l0, 0, %psr ! fix up the cond codes now nop; nop; nop restore ! enter window I restore %g0, 1, %l1 ! enter window X, then %l1 = 1 rd %psr, %l0 ! l0 = (junk << 5) + CWP; sll %l1, %l0, %l1 ! %wim = 1 << CWP; wr %l1, 0, %wim sethi %hi(_cpcb), %l1 ld [%l1 + %lo(_cpcb)], %l1 and %l0, 31, %l0 st %l0, [%l1 + PCB_WIM] ! cpcb->pcb_wim = l0 & 31; save %g0, %g0, %g0 ! back to window I LOADWIN(%sp) ! suck hard save %g0, %g0, %g0 ! back to window T RETT/* * Return from trap. Entered after a * wr %l0, 0, %psr * which disables traps so that we can rett; registers are: * * %l0 = %psr * %l1 = return pc * %l2 = return npc * * (%l3..%l7 anything). * * If we are returning to user code, we must: * 1. Check for register windows in the pcb that belong on the stack. * If there are any, reenter trap with type T_WINOF. * 2. Make sure the register windows will not underflow. This is * much easier in kernel mode.... */return_from_trap:! wr %l0, 0, %psr ! disable traps so we can rett! (someone else did this already) and %l0, 31, %l5 set wmask, %l6 ldub [%l6 + %l5], %l5 ! %l5 = 1 << ((CWP + 1) % nwindows) btst PSR_PS, %l0 ! returning to userland? bnz rft_kernel ! no, go return to kernel rd %wim, %l4 ! (read %wim in any case)rft_user_or_recover_pcb_windows: /* * (entered with %l4=%wim, %l5=wmask[cwp]; %l0..%l2 as usual) * * check cpcb->pcb_nsaved: * if 0, do a `normal' return to user (see rft_user); * if > 0, cpcb->pcb_rw[] holds registers to be copied to stack; * if -1, cpcb->pcb_rw[0] holds user registers for rett window * from an earlier T_RWRET pseudo-trap. */ sethi %hi(_cpcb), %l6 ld [%l6 + %lo(_cpcb)], %l6 ld [%l6 + PCB_NSAVED], %l7 tst %l7 bz,a rft_user sethi %hi(_want_ast), %l7 ! first instr of rft_user bg,a softtrap ! if (pcb_nsaved > 0) mov T_WINOF, %o0 ! trap(T_WINOF); /* * To get here, we must have tried to return from a previous * trap and discovered that it would cause a window underflow. * We then must have tried to pull the registers out of the * user stack (from the address in %fp==%i6) and discovered * that it was either unaligned or not loaded in memory, and * therefore we ran a trap(T_RWRET), which loaded one set of * registers into cpcb->pcb_pcb_rw[0] (if it had killed the * process due to a bad stack, we would not be here). * * We want to load pcb_rw[0] into the previous window, which * we know is currently invalid. In other words, we want * %wim to be 1 << ((cwp + 2) % nwindows). */ wr %g0, 0, %wim ! enable restores mov %g6, %l3 ! save g6 in l3 mov %l6, %g6 ! set g6 = &u st %g0, [%g6 + PCB_NSAVED] ! clear cpcb->pcb_nsaved restore ! enter window I restore %g0, 1, %l1 ! enter window X, then %l1 = 1 rd %psr, %l0 sll %l1, %l0, %l1 ! %wim = 1 << CWP; wr %l1, 0, %wim and %l0, 31, %l0 st %l0, [%g6 + PCB_WIM] ! cpcb->pcb_wim = CWP; nop ! unnecessary? old wim was 0... save %g0, %g0, %g0 ! back to window I LOADWIN(%g6 + PCB_RW) save %g0, %g0, %g0 ! back to window T (trap window) wr %l0, 0, %psr ! cond codes, cond codes everywhere mov %l3, %g6 ! restore g6 RETT! exported end marker for kernel gdb .globl _endtrapcode_endtrapcode:/* * init_tables(nwin) int nwin; * * Set up the uwtab and wmask tables. * We know nwin > 1. */init_tables: /* * for (i = -nwin, j = nwin - 2; ++i < 0; j--) * uwtab[i] = j; * (loop runs at least once) */ set uwtab, %o3 sub %g0, %o0, %o1 ! i = -nwin + 1 inc %o1 add %o0, -2, %o2 ! j = nwin - 2;0: stb %o2, [%o3 + %o1] ! uwtab[i] = j;1: inccc %o1 ! ++i < 0? bl 0b ! yes, continue loop dec %o2 ! in any case, j-- /* * (i now equals 0) * for (j = nwin - 1; i < nwin; i++, j--) * uwtab[i] = j; * (loop runs at least twice) */ sub %o0, 1, %o2 ! j = nwin - 10: stb %o2, [%o3 + %o1] ! uwtab[i] = j inc %o1 ! i++1: cmp %o1, %o0 ! i < nwin? bl 0b ! yes, continue dec %o2 ! in any case, j-- /* * We observe that, for i in 0..nwin-2, (i+1)%nwin == i+1; * for i==nwin-1, (i+1)%nwin == 0. * To avoid adding 1, we run i from 1 to nwin and set * wmask[i-1]. * * for (i = j = 1; i < nwin; i++) { * j <<= 1; (j now == 1 << i) * wmask[i - 1] = j; * } * (loop runs at least once) */ set wmask - 1, %o3 mov 1, %o1 ! i = 1; mov 2, %o2 ! j = 2;0: stb %o2, [%o3 + %o1] ! (wmask - 1)[i] = j; inc %o1 ! i++ cmp %o1, %o0 ! i < nwin? bl,a 0b ! yes, continue sll %o2, 1, %o2 ! (and j <<= 1) /* * Now i==nwin, so we want wmask[i-1] = 1. */ mov 1, %o2 ! j = 1; retl stb %o2, [%o3 + %o1] ! (wmask - 1)[i] = j;dostart: rd %psr, %l0 ! paranoia: make sure ... andn %l0, PSR_ET, %l0 ! we have traps off wr %l0, 0, %psr ! so that we can fiddle safely nop; nop; nop /* * Startup. * * W
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -