⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 trap.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 2 页
字号:
	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 + -