📄 trap.c
字号:
case T_BREAKPOINT: trapsignal(p, SIGTRAP, 0); break; case T_DIV0: ADVANCE; trapsignal(p, SIGFPE, FPE_INTDIV_TRAP); break; case T_FLUSHWIN: write_user_windows();#ifdef probably_slower_since_this_is_usually_false if (pcb->pcb_nsaved && rwindow_save(p)) sigexit(p, SIGILL);#endif ADVANCE; break; case T_CLEANWIN: uprintf("T_CLEANWIN\n"); /* XXX */ ADVANCE; break; case T_RANGECHECK: uprintf("T_RANGECHECK\n"); /* XXX */ ADVANCE; trapsignal(p, SIGILL, 0); /* XXX code?? */ break; case T_FIXALIGN: uprintf("T_FIXALIGN\n"); /* XXX */ ADVANCE; break; case T_INTOF: uprintf("T_INTOF\n"); /* XXX */ ADVANCE; trapsignal(p, SIGFPE, FPE_INTOVF_TRAP); break; } userret(p, pc, sticks); share_fpu(p, tf);#undef ADVANCE}/* * Save windows from PCB into user stack, and return 0. This is used on * window overflow pseudo-traps (from locore.s, just before returning to * user mode) and when ptrace or sendsig needs a consistent state. * As a side effect, rwindow_save() always sets pcb_nsaved to 0, * clobbering the `underflow restore' indicator if it was -1. * * If the windows cannot be saved, pcb_nsaved is restored and we return -1. */intrwindow_save(p) register struct proc *p;{ register struct pcb *pcb = &p->p_addr->u_pcb; register struct rwindow *rw = &pcb->pcb_rw[0]; register int i; i = pcb->pcb_nsaved; if (i < 0) { pcb->pcb_nsaved = 0; return (0); } if (i == 0) return (0);if(rwindow_debug)printf("%s[%d]: rwindow: pcb->stack:", p->p_comm, p->p_pid); do {if(rwindow_debug)printf(" %x", rw[1].rw_in[6]); if (copyout((caddr_t)rw, (caddr_t)rw[1].rw_in[6], sizeof *rw)) return (-1); rw++; } while (--i > 0);if(rwindow_debug)printf("\n"); pcb->pcb_nsaved = 0; return (0);}/* * Kill user windows (before exec) by writing back to stack or pcb * and then erasing any pcb tracks. Otherwise we might try to write * the registers into the new process after the exec. */kill_user_windows(p) struct proc *p;{ write_user_windows(); p->p_addr->u_pcb.pcb_nsaved = 0;}/* * Called from locore.s trap handling, for synchronous memory faults. * * This duplicates a lot of logic in trap() and perhaps should be * moved there; but the bus-error-register parameters are unique to * this routine. * * Since synchronous errors accumulate during prefetch, we can have * more than one `cause'. But we do not care what the cause, here; * we just want to page in the page and try again. */mem_access_fault(type, ser, v, pc, psr, tf) register unsigned type; register int ser; register u_int v; register int pc, psr; register struct trapframe *tf;{ register struct proc *p; register struct vmspace *vm; register vm_offset_t va; register int i, rv, sig = SIGBUS; vm_prot_t ftype; int onfault, mmucode; u_quad_t sticks; cnt.v_trap++; if ((p = curproc) == NULL) /* safety check */ p = &proc0; sticks = p->p_sticks; /* * Figure out what to pass the VM code, and ignore the sva register * value in v on text faults (text faults are always at pc). * Kernel faults are somewhat different: text faults are always * illegal, and data faults are extra complex. User faults must * set p->p_md.md_tf, in case we decide to deliver a signal. Check * for illegal virtual addresses early since those can induce more * faults. */ if (type == T_TEXTFAULT) v = pc; i = (int)v >> PG_VSHIFT; if (i != 0 && i != -1) goto fault; ftype = ser & SER_WRITE ? VM_PROT_READ|VM_PROT_WRITE : VM_PROT_READ; va = trunc_page(v); if (psr & PSR_PS) { extern char Lfsbail[]; if (type == T_TEXTFAULT) { (void) splhigh(); printf("text fault: pc=%x ser=%b\n", pc, ser, SER_BITS); panic("kernel fault"); /* NOTREACHED */ } /* * If this was an access that we shouldn't try to page in, * resume at the fault handler without any action. */ if (p->p_addr && p->p_addr->u_pcb.pcb_onfault == Lfsbail) goto kfault; /* * During autoconfiguration, faults are never OK unless * pcb_onfault is set. Once running normally we must allow * exec() to cause copy-on-write faults to kernel addresses. */ if (cold) goto kfault; if (va >= KERNBASE) { if (vm_fault(kernel_map, va, ftype, 0) == KERN_SUCCESS) return; goto kfault; } } else p->p_md.md_tf = tf; /* * mmu_pagein returns -1 if the page is already valid, in which * case we have a hard fault; it returns 1 if it loads a segment * that got bumped out via LRU replacement. */ vm = p->p_vmspace; rv = mmu_pagein(&vm->vm_pmap, va, ser & SER_WRITE ? PG_V|PG_W : PG_V); if (rv < 0) goto fault; if (rv > 0) goto out; /* alas! must call the horrible vm code */ rv = vm_fault(&vm->vm_map, (vm_offset_t)va, ftype, FALSE); /* * If this was a stack access we keep track of the maximum * accessed stack size. Also, if vm_fault gets a protection * failure it is due to accessing the stack region outside * the current limit and we need to reflect that as an access * error. */ if ((caddr_t)va >= vm->vm_maxsaddr) { if (rv == KERN_SUCCESS) { unsigned nss = clrnd(btoc(USRSTACK - va)); if (nss > vm->vm_ssize) vm->vm_ssize = nss; } else if (rv == KERN_PROTECTION_FAILURE) rv = KERN_INVALID_ADDRESS; } if (rv == KERN_SUCCESS) { /* * pmap_enter() does not enter all requests made from * vm_fault into the MMU (as that causes unnecessary * entries for `wired' pages). Instead, we call * mmu_pagein here to make sure the new PTE gets installed. */ (void) mmu_pagein(&vm->vm_pmap, va, 0); } else { /* * Pagein failed. If doing copyin/out, return to onfault * address. Any other page fault in kernel, die; if user * fault, deliver SIGBUS or SIGSEGV. */ if (rv != KERN_PROTECTION_FAILURE) sig = SIGSEGV;fault: if (psr & PSR_PS) {kfault: onfault = p->p_addr ? (int)p->p_addr->u_pcb.pcb_onfault : 0; if (!onfault) { (void) splhigh(); printf("data fault: pc=%x addr=%x ser=%b\n", pc, v, ser, SER_BITS); panic("kernel fault"); /* NOTREACHED */ } tf->tf_pc = onfault; tf->tf_npc = onfault + 4; return; } trapsignal(p, sig, (u_int)v); }out: if ((psr & PSR_PS) == 0) { userret(p, pc, sticks); share_fpu(p, tf); }}/* * System calls. `pc' is just a copy of tf->tf_pc. * * Note that the things labelled `out' registers in the trapframe were the * `in' registers within the syscall trap code (because of the automatic * `save' effect of each trap). They are, however, the %o registers of the * thing that made the system call, and are named that way here. * * The `suncompat' parameter actually only exists if COMPAT_SUNOS is defined. */syscall(code, tf, pc, suncompat) register u_int code; register struct trapframe *tf; int pc, suncompat;{ register int i, nsys, *ap, nap; register struct sysent *callp; register struct proc *p; int error, new; struct args { int i[8]; } args; int rval[2]; u_quad_t sticks; extern int nsysent; extern struct pcb *cpcb; cnt.v_syscall++; p = curproc;#ifdef DIAGNOSTIC if (tf->tf_psr & PSR_PS) panic("syscall"); if (cpcb != &p->p_addr->u_pcb) panic("syscall cpcb/ppcb"); if (tf != (struct trapframe *)((caddr_t)cpcb + UPAGES * NBPG) - 1) panic("syscall trapframe");#endif sticks = p->p_sticks; p->p_md.md_tf = tf; new = code & (SYSCALL_G7RFLAG | SYSCALL_G2RFLAG); code &= ~(SYSCALL_G7RFLAG | SYSCALL_G2RFLAG);#ifdef COMPAT_SUNOS if (suncompat) { extern int nsunsys; extern struct sysent sunsys[]; callp = sunsys, nsys = nsunsys; } else#endif callp = sysent, nsys = nsysent; /* * The first six system call arguments are in the six %o registers. * Any arguments beyond that are in the `argument extension' area * of the user's stack frame (see <machine/frame.h>). * * Check for ``special'' codes that alter this, namely syscall and * __syscall. The latter takes a quad syscall number, so that other * arguments are at their natural alignments. Adjust the number * of ``easy'' arguments as appropriate; we will copy the hard * ones later as needed. */ ap = &tf->tf_out[0]; nap = 6; switch (code) { case SYS_syscall: code = *ap++; nap--; break; case SYS___syscall:#ifdef COMPAT_SUNOS if (suncompat) break;#endif code = ap[_QUAD_LOWWORD]; ap += 2; nap -= 2; break; } /* Callp currently points to syscall, which returns ENOSYS. */ if (code < nsys) { callp += code; i = callp->sy_narg; if (i > nap) { /* usually false */ if (i > 8) panic("syscall nargs"); error = copyin((caddr_t)tf->tf_out[6] + offsetof(struct frame, fr_argx), (caddr_t)&args.i[nap], (i - nap) * sizeof(int)); if (error) {#ifdef KTRACE if (KTRPOINT(p, KTR_SYSCALL)) ktrsyscall(p->p_tracep, code, callp->sy_narg, args.i);#endif goto bad; } i = nap; } copywords(ap, args.i, i * 4); } rval[0] = 0; rval[1] = tf->tf_out[1]; error = (*callp->sy_call)(p, &args, rval); if (error == 0) { /* * If fork succeeded and we are the child, our stack * has moved and the pointer tf is no longer valid, * and p is wrong. Compute the new trapframe pointer. * (The trap frame invariably resides at the * tippity-top of the u. area.) */ p = curproc; tf = (struct trapframe *) ((caddr_t)p->p_addr + UPAGES * NBPG - sizeof(*tf));/* this is done earlier: *//* p->p_md.md_tf = tf; */ tf->tf_out[0] = rval[0]; tf->tf_out[1] = rval[1]; if (new) { /* jmp %g2 (or %g7, deprecated) on success */ i = tf->tf_global[new & SYSCALL_G2RFLAG ? 2 : 7]; if (i & 3) { error = EINVAL; goto bad; } } else { /* old system call convention: clear C on success */ tf->tf_psr &= ~PSR_C; /* success */ i = tf->tf_npc; } tf->tf_pc = i; tf->tf_npc = i + 4; } else if (error > 0 /*error != ERESTART && error != EJUSTRETURN*/) {bad: tf->tf_out[0] = error; tf->tf_psr |= PSR_C; /* fail */ i = tf->tf_npc; tf->tf_pc = i; tf->tf_npc = i + 4; } /* else if (error == ERESTART || error == EJUSTRETURN) */ /* nothing to do */ userret(p, pc, sticks);#ifdef KTRACE if (KTRPOINT(p, KTR_SYSRET)) ktrsysret(p->p_tracep, code, error, rval[0]);#endif share_fpu(p, tf);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -