📄 locore.s
字号:
ld [%l4 + 20], %g1 ! set new %g1 /* set up returnee's out registers, including its %sp */ ldd [%l4 + 48], %i0 ldd [%l4 + 56], %i2 ldd [%l4 + 64], %i4 ldd [%l4 + 72], %i6 /* load returnee's window, making the window above it be invalid */ restore restore %g0, 1, %l1 ! move to inval window and set %l1 = 1 rd %psr, %l0 sll %l1, %l0, %l1 wr %l1, 0, %wim ! %wim = 1 << (%psr & 31) sethi %hi(_cpcb), %l1 ld [%l1 + %lo(_cpcb)], %l1 and %l0, 31, %l0 ! CWP = %psr & 31; st %l0, [%l1 + PCB_WIM] ! cpcb->pcb_wim = CWP; save %g0, %g0, %g0 ! back to window to reload LOADWIN(%sp) save %g0, %g0, %g0 ! back to trap window /* note, we have not altered condition codes; safe to just rett */ RETT#endif/* * syscall() builds a trap frame and calls syscall(). * sun_syscall is same but delivers sun system call number * XXX should not have to save&reload ALL the registers just for * ptrace... */#ifdef COMPAT_SUNOSsun_syscall: TRAP_SETUP(-CCFSZ-80) b sys_merge mov 1, %o3 ! third arg to syscall: sun compatsyscall: TRAP_SETUP(-CCFSZ-80) clr %o3 ! third arg to syscall: native bsdsys_merge:#elsesyscall: TRAP_SETUP(-CCFSZ-80)#endif wr %l0, PSR_ET, %psr std %l0, [%sp + CCFSZ + 0] ! tf_psr, tf_pc rd %y, %l3 std %l2, [%sp + CCFSZ + 8] ! tf_npc, tf_y st %g1, [%sp + CCFSZ + 20] ! tf_g[1] std %g2, [%sp + CCFSZ + 24] ! tf_g[2], tf_g[3] std %g4, [%sp + CCFSZ + 32] ! etc std %g6, [%sp + CCFSZ + 40] mov %g1, %o0 ! (code) std %i0, [%sp + CCFSZ + 48] add %sp, CCFSZ, %o1 ! (&tf) std %i2, [%sp + CCFSZ + 56] mov %l1, %o2 ! (pc) std %i4, [%sp + CCFSZ + 64] call _syscall ! syscall(code, &tf, pc, suncompat) std %i6, [%sp + CCFSZ + 72] ! now load em all up again, sigh ldd [%sp + CCFSZ + 0], %l0 ! new %psr, new pc ldd [%sp + CCFSZ + 8], %l2 ! new npc, new %y wr %l3, 0, %y /* see `dostart' for the reason for this label */init_syscall_ret: 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/* * Interrupts. Software interrupts must be cleared from the software * interrupt enable register. Rather than calling ienab_bic for each, * we do them in-line before enabling traps. * * After preliminary setup work, the interrupt is passed to each * registered handler in turn. These are expected to return nonzero if * they took care of the interrupt. If a handler claims the interrupt, * we exit (hardware interrupts are latched in the requestor so we'll * just take another interrupt in the unlikely event of simultaneous * interrupts from two different devices at the same level). If we go * through all the registered handlers and no one claims it, we report a * stray interrupt. This is more or less done as: * * for (ih = intrhand[intlev]; ih; ih = ih->ih_next) * if ((*ih->ih_fun)(ih->ih_arg ? ih->ih_arg : &frame)) * return; * strayintr(&frame); * * Software interrupts are almost the same with three exceptions: * (1) we clear the interrupt from the software interrupt enable * register before calling any handler (we have to clear it first * to avoid an interrupt-losing race), * (2) we always call all the registered handlers (there is no way * to tell if the single bit in the software interrupt register * represents one or many requests) * (3) we never announce a stray interrupt (because of (1), another * interrupt request can come in while we're in the handler. If * the handler deal with everything for both the original & the * new request, we'll erroneously report a stray interrupt when * we take the software interrupt for the new request. * * Inputs: * %l0 = %psr * %l1 = return pc * %l2 = return npc * %l3 = interrupt level * (software interrupt only) %l4 = bits to clear in interrupt register * * Internal: * %l4, %l5: local variables * %l6 = %y * %l7 = %g1 * %g2..%g7 go to stack * * An interrupt frame is built in the space for a full trapframe; * this contains the psr, pc, npc, and interrupt level. */ .comm _intrhand, 15 * 8 ! intrhand[0..14]; 0 => errorsoftintr: sethi %hi(IE_reg_addr), %l6 ldub [%l6 + %lo(IE_reg_addr)], %l5 andn %l5, %l4, %l5 stb %l5, [%l6 + %lo(IE_reg_addr)] INTR_SETUP(-CCFSZ-80) std %g2, [%sp + CCFSZ + 24] ! save registers INCR(_cnt+V_INTR) ! cnt.v_intr++; (clobbers %o0,%o1) mov %g1, %l7 rd %y, %l6 std %g4, [%sp + CCFSZ + 32] andn %l0, PSR_PIL, %l4 ! %l4 = psr & ~PSR_PIL | sll %l3, 8, %l5 ! intlev << IPLSHIFT std %g6, [%sp + CCFSZ + 40] or %l5, %l4, %l4 ! ; wr %l4, 0, %psr ! the manual claims this wr %l4, PSR_ET, %psr ! song and dance is necessary std %l0, [%sp + CCFSZ + 0] ! set up intrframe/clockframe sll %l3, 2, %l5 set _intrcnt, %l4 ! intrcnt[intlev]++; ld [%l4 + %l5], %o0 std %l2, [%sp + CCFSZ + 8] inc %o0 st %o0, [%l4 + %l5] set _intrhand, %l4 ! %l4 = intrhand[intlev]; ld [%l4 + %l5], %l4 b 3f st %fp, [%sp + CCFSZ + 16]1: ld [%l4], %o1 ld [%l4 + 4], %o0 tst %o0 bz,a 2f add %sp, CCFSZ, %o02: jmpl %o1, %o7 ! (void)(*ih->ih_fun)(...) ld [%l4 + 8], %l4 ! and ih = ih->ih_next3: tst %l4 ! while ih != NULL bnz 1b nop mov %l7, %g1 wr %l6, 0, %y ldd [%sp + CCFSZ + 24], %g2 ldd [%sp + CCFSZ + 32], %g4 ldd [%sp + CCFSZ + 40], %g6 b return_from_trap wr %l0, 0, %psr /* * _sparc_interrupt is exported for paranoia checking (see intr.c). */ .globl _sparc_interrupt_sparc_interrupt: INTR_SETUP(-CCFSZ-80) std %g2, [%sp + CCFSZ + 24] ! save registers INCR(_cnt+V_INTR) ! cnt.v_intr++; (clobbers %o0,%o1) mov %g1, %l7 rd %y, %l6 std %g4, [%sp + CCFSZ + 32] andn %l0, PSR_PIL, %l4 ! %l4 = psr & ~PSR_PIL | sll %l3, 8, %l5 ! intlev << IPLSHIFT std %g6, [%sp + CCFSZ + 40] or %l5, %l4, %l4 ! ; wr %l4, 0, %psr ! the manual claims this wr %l4, PSR_ET, %psr ! song and dance is necessary std %l0, [%sp + CCFSZ + 0] ! set up intrframe/clockframe sll %l3, 2, %l5 set _intrcnt, %l4 ! intrcnt[intlev]++; ld [%l4 + %l5], %o0 std %l2, [%sp + CCFSZ + 8] ! set up intrframe/clockframe inc %o0 st %o0, [%l4 + %l5] set _intrhand, %l4 ! %l4 = intrhand[intlev]; ld [%l4 + %l5], %l4 b 3f st %fp, [%sp + CCFSZ + 16]1: ld [%l4], %o1 ld [%l4 + 4], %o0 tst %o0 bz,a 2f add %sp, CCFSZ, %o02: jmpl %o1, %o7 ! handled = (*ih->ih_fun)(...) ld [%l4 + 8], %l4 ! and ih = ih->ih_next tst %o0 bnz 4f ! if (handled) break nop3: tst %l4 bnz 1b ! while (ih) nop call _strayintr ! strayintr(&intrframe) add %sp, CCFSZ, %o0 /* all done: restore registers and go return */4: mov %l7, %g1 wr %l6, 0, %y ldd [%sp + CCFSZ + 24], %g2 ldd [%sp + CCFSZ + 32], %g4 ldd [%sp + CCFSZ + 40], %g6 b return_from_trap wr %l0, 0, %psr#ifdef notyet/* * Level 12 (ZS serial) interrupt. Handle it quickly, schedule a * software interrupt, and get out. Do the software interrupt directly * if we would just take it on the way out. * * Input: * %l0 = %psr * %l1 = return pc * %l2 = return npc * Internal: * %l3 = zs device * %l4, %l5 = temporary * %l6 = rr3 (or temporary data) + 0x100 => need soft int * %l7 = zs soft status */zshard:#endif /* notyet *//* * Level 15 interrupt. An async memory error has occurred; * take care of it (typically by panicking, but hey...). * %l0 = %psr * %l1 = return pc * %l2 = return npc * %l3 = 15 * 4 (why? just because!) * * Internal: * %l4 = %y * %l5 = %g1 * %l6 = %g6 * %l7 = %g7 * g2, g3, g4, g5 go to stack * * This code is almost the same as that in mem_access_fault, * except that we already know the problem is not a `normal' fault, * and that we must be extra-careful with interrupt enables. */nmi: INTR_SETUP(-CCFSZ-80) INCR(_cnt+V_INTR) ! cnt.v_intr++; (clobbers %o0,%o1) /* * Level 15 interrupts are nonmaskable, so with traps off, * disable all interrupts to prevent recursion. */ sethi %hi(IE_reg_addr), %o0 ldub [%o0 + %lo(IE_reg_addr)], %o1 andn %o1, IE_ALLIE, %o1 stb %o1, [%o0 + %lo(IE_reg_addr)] wr %l0, PSR_ET, %psr ! okay, turn traps on again std %g2, [%sp + CCFSZ + 0] ! save g2, g3 rd %y, %l4 ! save y ! must read the sync error register too. set AC_SYNC_ERR, %o0 lda [%o0] ASI_CONTROL, %o1 ! sync err reg inc 4, %o0 lda [%o0] ASI_CONTROL, %o2 ! sync virt addr std %g4, [%sp + CCFSZ + 8] ! save g4,g5 mov %g1, %l5 ! save g1,g6,g7 mov %g6, %l6 mov %g7, %l7 inc 4, %o0 lda [%o0] ASI_CONTROL, %o3 ! async err reg inc 4, %o0 lda [%o0] ASI_CONTROL, %o4 ! async virt addr ! and call C code call _memerr ! memerr(0, ser, sva, aer, ava) clr %o0 mov %l5, %g1 ! restore g1 through g7 ldd [%sp + CCFSZ + 0], %g2 ldd [%sp + CCFSZ + 8], %g4 wr %l0, 0, %psr ! re-disable traps mov %l6, %g6 mov %l7, %g7 ! set IE_ALLIE again (safe, we disabled traps again above) sethi %hi(IE_reg_addr), %o0 ldub [%o0 + %lo(IE_reg_addr)], %o1 or %o1, IE_ALLIE, %o1 stb %o1, [%o0 + %lo(IE_reg_addr)] b return_from_trap wr %l4, 0, %y ! restore y/* * Window overflow trap handler. * %l0 = %psr * %l1 = return pc * %l2 = return npc */window_of:#ifdef TRIVIAL_WINDOW_OVERFLOW_HANDLER /* a trivial version that assumes %sp is ok */ /* (for testing only!) */ save %g0, %g0, %g0 std %l0, [%sp + (0*8)] rd %psr, %l0 mov 1, %l1 sll %l1, %l0, %l0 wr %l0, 0, %wim std %l2, [%sp + (1*8)] std %l4, [%sp + (2*8)] std %l6, [%sp + (3*8)] std %i0, [%sp + (4*8)] std %i2, [%sp + (5*8)] std %i4, [%sp + (6*8)] std %i6, [%sp + (7*8)] restore RETT#else /* * This is similar to TRAP_SETUP, but we do not want to spend * a lot of time, so we have separate paths for kernel and user. * We also know for sure that the window has overflowed. */ btst PSR_PS, %l0 bz winof_user sethi %hi(clean_trap_window), %l7 /* * Overflow from kernel mode. Call clean_trap_window to * do the dirty work, then just return, since we know prev * window is valid. clean_trap_windows might dump all *user* * windows into the pcb, but we do not care: there is at * least one kernel window (a trap or interrupt frame!) * above us. */ jmpl %l7 + %lo(clean_trap_window), %l4 mov %g7, %l7 ! for clean_trap_window wr %l0, 0, %psr ! put back the @%*! cond. codes nop ! (let them settle in) RETTwinof_user: /* * Overflow from user mode. * If clean_trap_window dumps the registers into the pcb, * rft_user will need to call trap(), so we need space for * a trap frame. We also have to compute pcb_nw. * * SHOULD EXPAND IN LINE TO AVOID BUILDING TRAP FRAME ON * `EASY' SAVES */ sethi %hi(_cpcb), %l6 ld [%l6 + %lo(_cpcb)], %l6 ld [%l6 + PCB_WIM], %l5 and %l0, 31, %l3 sub %l3, %l5, %l5 /* l5 = CWP - pcb_wim */ set uwtab, %l4 ldub [%l4 + %l5], %l5 /* l5 = uwtab[l5] */ st %l5, [%l6 + PCB_UW] jmpl %l7 + %lo(clean_trap_window), %l4 mov %g7, %l7 ! for clean_trap_window sethi %hi(_cpcb), %l6 ld [%l6 + %lo(_cpcb)], %l6 set UPAGES*NBPG-CCFSZ-80, %l5 add %l6, %l5, %sp /* over to kernel stack */ CHECK_SP_REDZONE(%l6, %l5) /* * Copy return_from_trap far enough to allow us * to jump directly to rft_user_or_recover_pcb_windows * (since we know that is where we are headed). */! and %l0, 31, %l3 ! still set (clean_trap_window ! leaves this register alone) set wmask, %l6 ldub [%l6 + %l3], %l5 ! %l5 = 1 << ((CWP + 1) % nwindows) b rft_user_or_recover_pcb_windows rd %wim, %l4 ! (read %wim first)#endif /* end `real' version of window overflow trap handler *//* * Window underflow trap handler. * %l0 = %psr * %l1 = return pc * %l2 = return npc * * A picture: * * T R I X * 0 0 0 1 0 0 0 (%wim) * [bit numbers increase towards the right; * `restore' moves right & `save' moves left] * * T is the current (Trap) window, R is the window that attempted * a `Restore' instruction, I is the Invalid window, and X is the * window we want to make invalid before we return. * * Since window R is valid, we cannot use rft_user to restore stuff * for us. We have to duplicate its logic. YUCK. * * Incidentally, TRIX are for kids. Silly rabbit! */window_uf:#ifdef TRIVIAL_WINDOW_UNDERFLOW_HANDLER wr %g0, 0, %wim ! allow us to enter I restore ! to R nop nop restore ! to I restore %g0, 1, %l1 ! to X rd %psr, %l0 sll %l1, %l0, %l0 wr %l0, 0, %wim save %g0, %g0, %g0 ! back to I LOADWIN(%sp) save %g0, %g0, %g0 ! back to R save %g0, %g0, %g0 ! back to T RETT#else wr %g0, 0, %wim ! allow us to enter I btst PSR_PS, %l0 restore ! enter window R bz winuf_user restore ! enter window I /* * Underflow from kernel mode. Just recover the * registers and go (except that we have to update * the blasted user pcb fields). */ restore %g0, 1, %l1 ! enter window X, then set %l1 to 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -