plan 9 kernel history: overview | file list | diff list

1999/0819/pc/trap.c (diff list | history)

1999/0819/sys/src/9/pc/trap.c:1,8142000/0626/sys/src/9/pc/trap.c:1,808 (short | long | prev | next)
1991/0613    
#include	"u.h" 
1992/0321    
#include	"../port/lib.h" 
1991/0613    
#include	"mem.h" 
#include	"dat.h" 
#include	"fns.h" 
#include	"io.h" 
1991/0703    
#include	"ureg.h" 
1992/0111    
#include	"../port/error.h" 
1991/0613    
 
1991/0720    
void	noted(Ureg*, ulong); 
 
1997/0327    
static void debugbpt(Ureg*, void*); 
static void fault386(Ureg*, void*); 
1991/0731    
 
1998/0910    
static Lock vctllock; 
static Vctl *vctl[256]; 
1991/0709    
 
1991/0703    
void 
1999/0819    
intrenable(int irq, void (*f)(Ureg*, void*), void* a, int tbdf, char *name) 
1991/0613    
{ 
1998/0910    
	int vno; 
1999/0819    
	Vctl *v, *p; 
2000/0626    
	Vctl *v; 
1991/0614    
 
1998/0910    
	v = xalloc(sizeof(Vctl)); 
	v->isintr = 1; 
	v->irq = irq; 
	v->tbdf = tbdf; 
	v->f = f; 
	v->a = a; 
1999/0819    
	strncpy(v->name, name, NAMELEN-1); 
	v->name[NAMELEN-1] = 0; 
1998/0806    
 
1998/0910    
	ilock(&vctllock); 
	vno = arch->intrenable(v); 
	if(vno == -1){ 
		iunlock(&vctllock); 
1999/0819    
		print("intrenable: couldn't enable irq %d, tbdf 0x%uX for %s\n", 
			irq, tbdf, v->name); 
		if(p=vctl[vno]){ 
			print("intrenable: irq %d is already used by", irq); 
			for(; p; p=p->next) 
				print(" %s", p->name); 
			print("\n"); 
		} 
1998/0910    
		xfree(v); 
1998/0806    
		return; 
1991/0709    
	} 
1998/0910    
	if(vctl[vno]){ 
		if(vctl[vno]->isr != v->isr || vctl[vno]->eoi != v->eoi) 
1999/0819    
			panic("intrenable: handler: %s %s %luX %luX %luX %luX\n", 
				vctl[vno]->name, v->name, 
1998/0910    
				vctl[vno]->isr, v->isr, vctl[vno]->eoi, v->eoi); 
1998/1218    
		v->next = vctl[vno]; 
1998/0910    
	} 
	vctl[vno] = v; 
	iunlock(&vctllock); 
} 
1998/0806    
 
1999/0819    
int 
irqallocread(char *buf, long n, vlong offset) 
{ 
	int vno; 
	Vctl *v; 
	long oldn; 
	char str[11+1+NAMELEN+1], *p; 
	int m; 
 
	if(n < 0 || offset < 0) 
		error(Ebadarg); 
 
	oldn = n; 
	for(vno=0; vno<nelem(vctl); vno++){ 
		for(v=vctl[vno]; v; v=v->next){ 
			m = snprint(str, sizeof str, "%11d %11d %.*s\n", vno, v->irq, NAMELEN, v->name); 
			if(m <= offset)	/* if do not want this, skip entry */ 
				offset -= m; 
			else{ 
				/* skip offset bytes */ 
				m -= offset; 
				p = str+offset; 
				offset = 0; 
 
				/* write at most max(n,m) bytes */ 
				if(m > n) 
					m = n; 
				memmove(buf, p, m); 
				n -= m; 
				buf += m; 
 
				if(n == 0) 
					return oldn; 
			}	 
		} 
	} 
	return oldn - n; 
} 
 
1998/0910    
void 
1999/0819    
trapenable(int vno, void (*f)(Ureg*, void*), void* a, char *name) 
1998/0910    
{ 
	Vctl *v; 
 
	if(vno < 0 || vno >= VectorPIC) 
		panic("trapenable: vno %d\n", vno); 
	v = xalloc(sizeof(Vctl)); 
	v->tbdf = BUSUNKNOWN; 
	v->f = f; 
	v->a = a; 
1999/0819    
	strncpy(v->name, name, NAMELEN); 
	v->name[NAMELEN-1] = 0; 
1998/0910    
 
	lock(&vctllock); 
	if(vctl[vno]) 
		v->next = vctl[vno]->next; 
	vctl[vno] = v; 
	unlock(&vctllock); 
1991/0703    
} 
 
1997/0405    
static void 
nmienable(void) 
{ 
	int x; 
 
	/* 
	 * Hack: should be locked with NVRAM access. 
	 */ 
1998/0320    
	outb(0x70, 0x80);		/* NMI latch clear */ 
1997/0405    
	outb(0x70, 0); 
 
1998/0320    
	x = inb(0x61) & 0x07;		/* Enable NMI */ 
1997/0405    
	outb(0x61, 0x08|x); 
1998/0320    
	outb(0x61, x); 
1997/0405    
} 
 
1991/1112    
void 
1991/0703    
trapinit(void) 
{ 
1997/1101    
	int d1, v; 
1997/0327    
	ulong vaddr; 
	Segdesc *idt; 
1991/0614    
 
1997/0327    
	idt = (Segdesc*)IDTADDR; 
	vaddr = (ulong)vectortable; 
	for(v = 0; v < 256; v++){ 
1997/1101    
		d1 = (vaddr & 0xFFFF0000)|SEGP; 
		switch(v){ 
 
		case VectorBPT: 
			d1 |= SEGPL(3)|SEGIG; 
			break; 
 
		case VectorSYSCALL: 
1998/0401    
			d1 |= SEGPL(3)|SEGIG; 
1997/1101    
			break; 
 
		default: 
			d1 |= SEGPL(0)|SEGIG; 
			break; 
		} 
1997/0327    
		idt[v].d0 = (vaddr & 0xFFFF)|(KESEL<<16); 
1997/1101    
		idt[v].d1 = d1; 
1997/0327    
		vaddr += 6; 
	} 
1991/0731    
 
1997/1101    
	/* 
	 * Special traps. 
	 * Syscall() is called directly without going through trap(). 
	 */ 
1999/0819    
	trapenable(VectorBPT, debugbpt, 0, "debugpt"); 
	trapenable(VectorPF, fault386, 0, "fault386"); 
1997/0405    
 
	nmienable(); 
1991/0703    
} 
 
1998/0910    
static char* excname[32] = { 
	"divide error", 
	"debug exception", 
	"nonmaskable interrupt", 
	"breakpoint", 
	"overflow", 
	"bounds check", 
	"invalid opcode", 
	"coprocessor not available", 
	"double fault", 
	"coprocessor segment overrun", 
	"invalid TSS", 
	"segment not present", 
	"stack exception", 
	"general protection violation", 
	"page fault", 
	"15 (reserved)", 
	"coprocessor error", 
	"alignment check", 
	"machine check", 
	"19 (reserved)", 
	"20 (reserved)", 
	"21 (reserved)", 
	"22 (reserved)", 
	"23 (reserved)", 
	"24 (reserved)", 
	"25 (reserved)", 
	"26 (reserved)", 
	"27 (reserved)", 
	"28 (reserved)", 
	"29 (reserved)", 
	"30 (reserved)", 
	"31 (reserved)", 
1991/1113    
}; 
 
1991/0614    
/* 
1999/0301    
 *  All traps come here.  It is slower to have all traps call trap() 
 *  rather than directly vectoring the handler.  However, this avoids a 
 *  lot of code duplication and possible bugs.  The only exception is 
 *  VectorSYSCALL. 
1997/1101    
 *  Trap is called with interrupts disabled via interrupt-gates. 
1991/0614    
 */ 
1991/0710    
void 
1997/0327    
trap(Ureg* ureg) 
1991/0614    
{ 
1998/0910    
	int i, vno, user; 
1991/1113    
	char buf[ERRLEN]; 
1998/0910    
	Vctl *ctl, *v; 
1998/0115    
	Mach *mach; 
1991/0703    
 
1999/0701    
	m->intrts = fastticks(nil); 
1997/1101    
	user = 0; 
	if((ureg->cs & 0xFFFF) == UESEL){ 
		user = 1; 
1997/0327    
		up->dbgreg = ureg; 
1997/1101    
	} 
1991/1112    
 
1998/0910    
	vno = ureg->trap; 
	if(ctl = vctl[vno]){ 
1997/1101    
		if(ctl->isintr){ 
1997/0327    
			m->intr++; 
1998/0910    
			if(vno >= VectorPIC && vno != VectorSYSCALL) 
				m->lastintr = ctl->irq; 
1997/1101    
		} 
1991/1113    
 
1998/0910    
		if(ctl->isr) 
			ctl->isr(vno); 
		for(v = ctl; v != nil; v = v->next){ 
			if(v->f) 
				v->f(ureg, v->a); 
		} 
1997/0327    
		if(ctl->eoi) 
1998/0910    
			ctl->eoi(vno); 
1998/0401    
 
1998/0516    
		/*  
		 *  preemptive scheduling.  to limit stack depth, 
		 *  make sure process has a chance to return from 
		 *  the current interrupt before being preempted a 
		 *  second time. 
		 */ 
1998/0910    
		if(ctl->isintr && ctl->irq != IrqTIMER && ctl->irq != IrqCLOCK) 
1998/0512    
		if(up && up->state == Running) 
		if(anyhigher()) 
1998/0516    
		if(up->preempted == 0) 
		if(!active.exiting){ 
			up->preempted = 1; 
1998/0512    
			sched(); 
1998/0516    
			splhi(); 
			up->preempted = 0; 
1998/0605    
			return; 
1998/0516    
		} 
1991/0731    
	} 
1998/0910    
	else if(vno <= nelem(excname) && user){ 
1997/0327    
		spllo(); 
1998/0910    
		sprint(buf, "sys: trap: %s", excname[vno]); 
1997/0327    
		postnote(up, 1, buf, NDebug); 
	} 
1998/0910    
	else if(vno >= VectorPIC && vno != VectorSYSCALL){ 
1997/0327    
		/* 
		 * An unknown interrupt. 
		 * Check for a default IRQ7. This can happen when 
		 * the IRQ input goes away before the acknowledge. 
		 * In this case, a 'default IRQ7' is generated, but 
		 * the corresponding bit in the ISR isn't set. 
		 * In fact, just ignore all such interrupts. 
		 */ 
1998/0115    
		print("cpu%d: spurious interrupt %d, last %d", 
1998/0910    
			m->machno, vno, m->lastintr); 
1998/0115    
		for(i = 0; i < 32; i++){ 
			if(!(active.machs & (1<<i))) 
				continue; 
			mach = MACHP(i); 
			if(m->machno == mach->machno) 
				continue; 
			print(": cpu%d: last %d", mach->machno, mach->lastintr); 
		} 
		print("\n"); 
		m->spuriousintr++; 
1997/0327    
		return; 
	} 
	else{ 
1998/0910    
		if(vno == VectorNMI){ 
1998/0401    
			nmienable(); 
			if(m->machno != 0){ 
1999/0301    
				print("cpu%d: PC %8.8luX\n", 
					m->machno, ureg->pc); 
1997/0405    
				for(;;); 
1998/0401    
			} 
1997/0405    
		} 
1997/0327    
		dumpregs(ureg); 
1998/0910    
		if(vno < nelem(excname)) 
			panic("%s", excname[vno]); 
		panic("unknown trap/intr: %d\n", vno); 
1997/0327    
	} 
1991/0801    
 
1997/1101    
	if(user && (up->procctl || up->nnote)){ 
		splhi(); 
1997/0327    
		notify(ureg); 
1997/1101    
	} 
1991/0806    
} 
 
/* 
1991/0718    
 *  dump registers 
 */ 
void 
1997/0327    
dumpregs2(Ureg* ureg) 
1991/0718    
{ 
1993/0915    
	if(up) 
1999/0301    
		print("cpu%d: registers for %s %lud\n", 
			m->machno, up->text, up->pid); 
1991/0718    
	else 
1997/0327    
		print("cpu%d: registers for kernel\n", m->machno); 
1999/0301    
	print("FLAGS=%luX TRAP=%luX ECODE=%luX PC=%luX", 
		ureg->flags, ureg->trap, ureg->ecode, ureg->pc); 
1998/0825    
	print(" SS=%4.4luX USP=%luX\n", ureg->ss & 0xFFFF, ureg->usp); 
	print("  AX %8.8luX  BX %8.8luX  CX %8.8luX  DX %8.8luX\n", 
1997/0327    
		ureg->ax, ureg->bx, ureg->cx, ureg->dx); 
1998/0825    
	print("  SI %8.8luX  DI %8.8luX  BP %8.8luX\n", 
1997/0327    
		ureg->si, ureg->di, ureg->bp); 
1998/0825    
	print("  CS %4.4luX  DS %4.4luX  ES %4.4luX  FS %4.4luX  GS %4.4luX\n", 
1997/1101    
		ureg->cs & 0xFFFF, ureg->ds & 0xFFFF, ureg->es & 0xFFFF, 
		ureg->fs & 0xFFFF, ureg->gs & 0xFFFF); 
1991/0718    
} 
 
1991/0720    
void 
1997/0327    
dumpregs(Ureg* ureg) 
1993/0915    
{ 
1994/0813    
	extern ulong etext; 
1998/0401    
	vlong mca, mct; 
1993/1113    
 
1997/0327    
	dumpregs2(ureg); 
1994/0813    
 
1997/0327    
	/* 
	 * Processor control registers. 
1999/0301    
	 * If machine check exception, time stamp counter, page size extensions 
	 * or enhanced virtual 8086 mode extensions are supported, there is a 
	 * CR4. If there is a CR4 and machine check extensions, read the machine 
	 * check address and machine check type registers if RDMSR supported. 
1997/0327    
	 */ 
1999/0301    
	print("  CR0 %8.8lux CR2 %8.8lux CR3 %8.8lux", 
		getcr0(), getcr2(), getcr3()); 
1997/0327    
	if(m->cpuiddx & 0x9A){ 
1998/0811    
		print(" CR4 %8.8lux", getcr4()); 
1997/0327    
		if((m->cpuiddx & 0xA0) == 0xA0){ 
1998/0401    
			rdmsr(0x00, &mca); 
			rdmsr(0x01, &mct); 
1998/0811    
			print("\n  MCA %8.8llux MCT %8.8llux", mca, mct); 
1997/0327    
		} 
	} 
1998/0811    
	print("\n  ur %lux up %lux\n", ureg, up); 
1993/0915    
} 
 
1999/0721    
 
/* 
 * Fill in enough of Ureg to get a stack trace, and call a function. 
 * Used by debugging interface rdb. 
 */ 
1993/0915    
void 
1999/0721    
callwithureg(void (*fn)(Ureg*)) 
1999/0720    
{ 
1999/0721    
	Ureg ureg; 
	ureg.pc = getcallerpc(&fn); 
	ureg.sp = (ulong)&fn; 
	fn(&ureg); 
1999/0720    
} 
 
1999/0721    
static void 
_dumpstack(Ureg *ureg) 
1991/0720    
{ 
1992/0804    
	ulong l, v, i; 
1997/0327    
	uchar *p; 
1992/0804    
	extern ulong etext; 
 
1993/0915    
	if(up == 0) 
1992/0804    
		return; 
 
1999/0721    
	print("ktrace /kernel/path %.8lux %.8lux\n", ureg->pc, ureg->sp); 
1992/0804    
	i = 0; 
1994/0816    
	for(l=(ulong)&l; l<(ulong)(up->kstack+KSTACK); l+=4){ 
1992/0804    
		v = *(ulong*)l; 
		if(KTZERO < v && v < (ulong)&etext){ 
1997/1101    
			/* 
			 * Pick off general CALL (0xE8) and CALL indirect 
			 * through AX (0xFFD0). 
			 */ 
1997/0327    
			p = (uchar*)v; 
1999/0301    
			if(*(p-5) == 0xE8 
			|| (*(p-2) == 0xFF && *(p-1) == 0xD0)){ 
1999/0720    
				print("%.8lux=%.8lux ", l, v); 
1997/0327    
				i++; 
			} 
1992/0804    
		} 
1999/0720    
		if(i == 4){ 
1992/0804    
			i = 0; 
			print("\n"); 
		} 
	} 
1999/0720    
	if(i) 
		print("\n"); 
1999/0721    
} 
 
void 
dumpstack(void) 
{ 
	callwithureg(_dumpstack); 
1991/0720    
} 
 
1997/0327    
static void 
debugbpt(Ureg* ureg, void*) 
{ 
	char buf[ERRLEN]; 
 
	if(up == 0) 
		panic("kernel bpt"); 
	/* restore pc to instruction that caused the trap */ 
	ureg->pc--; 
	sprint(buf, "sys: breakpoint"); 
	postnote(up, 1, buf, NDebug); 
} 
 
static void 
fault386(Ureg* ureg, void*) 
{ 
	ulong addr; 
	int read, user, n, insyscall; 
	char buf[ERRLEN]; 
 
	addr = getcr2(); 
1998/0731    
	user = (ureg->cs & 0xFFFF) == UESEL; 
	if(!user && mmukmapsync(addr)) 
		return; 
1997/0327    
	read = !(ureg->ecode & 2); 
1998/0731    
	insyscall = up->insyscall; 
	up->insyscall = 1; 
1997/0327    
	n = fault(addr, read); 
	if(n < 0){ 
1998/0910    
		if(!user){ 
			dumpregs(ureg); 
			panic("fault: 0x%lux\n", addr); 
1997/0327    
		} 
1998/0910    
		sprint(buf, "sys: trap: fault %s addr=0x%lux", 
			read? "read" : "write", addr); 
		postnote(up, 1, buf, NDebug); 
1997/0327    
	} 
	up->insyscall = insyscall; 
} 
 
1991/0718    
/* 
1991/0710    
 *  system calls 
 */ 
1991/0731    
#include "../port/systab.h" 
1991/0720    
 
1992/0103    
/* 
1997/1101    
 *  Syscall is called directly from assembler without going through trap(). 
1992/0103    
 */ 
1997/1101    
void 
syscall(Ureg* ureg) 
1991/0710    
{ 
1991/0720    
	ulong	sp; 
	long	ret; 
1997/1101    
	int	i, scallnr; 
1991/0720    
 
1997/1101    
	if((ureg->cs & 0xFFFF) != UESEL) 
		panic("syscall: cs 0x%4.4uX\n", ureg->cs); 
 
1997/0327    
	m->syscall++; 
1993/0915    
	up->insyscall = 1; 
1997/0327    
	up->pc = ureg->pc; 
	up->dbgreg = ureg; 
1993/1225    
 
1997/1101    
	scallnr = ureg->ax; 
	up->scallnr = scallnr; 
	if(scallnr == RFORK && up->fpstate == FPactive){ 
		fpsave(&up->fpsave); 
		up->fpstate = FPinactive; 
1992/0805    
	} 
1998/0401    
	spllo(); 
1994/0715    
 
1997/0327    
	sp = ureg->usp; 
1993/0915    
	up->nerrlab = 0; 
1991/0720    
	ret = -1; 
	if(!waserror()){ 
1997/1101    
		if(scallnr >= nsyscall){ 
1999/0301    
			pprint("bad sys call number %d pc %lux\n", 
				scallnr, ureg->pc); 
1993/1013    
			postnote(up, 1, "sys: bad sys call", NDebug); 
1991/0720    
			error(Ebadarg); 
		} 
1992/0625    
 
1997/1101    
		if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)-BY2WD)) 
			validaddr(sp, sizeof(Sargs)+BY2WD, 0); 
1992/0625    
 
1997/1101    
		up->s = *((Sargs*)(sp+BY2WD)); 
		up->psstate = sysctab[scallnr]; 
1992/0625    
 
1997/1101    
		ret = systab[scallnr](up->s.args); 
1991/0720    
		poperror(); 
	} 
1993/0915    
	if(up->nerrlab){ 
1997/1101    
		print("bad errstack [%d]: %d extra\n", scallnr, up->nerrlab); 
1991/0720    
		for(i = 0; i < NERR; i++) 
1999/0301    
			print("sp=%lux pc=%lux\n", 
				up->errlab[i].sp, up->errlab[i].pc); 
1991/0720    
		panic("error stack"); 
	} 
1991/1114    
 
1993/0915    
	up->insyscall = 0; 
	up->psstate = 0; 
1992/0609    
 
	/* 
1997/1101    
	 *  Put return value in frame.  On the x86 the syscall is 
1992/0609    
	 *  just another trap and the return value from syscall is 
	 *  ignored.  On other machines the return value is put into 
	 *  the results register by caller of syscall. 
	 */ 
1997/0327    
	ureg->ax = ret; 
1992/0609    
 
1997/1101    
	if(scallnr == NOTED) 
1997/0327    
		noted(ureg, *(ulong*)(sp+BY2WD)); 
1991/1114    
 
1997/1101    
	if(scallnr!=RFORK && (up->procctl || up->nnote)){ 
		splhi(); 
1997/0327    
		notify(ureg); 
1998/0605    
	} 
1991/0710    
} 
 
1991/0720    
/* 
 *  Call user, if necessary, with note. 
 *  Pass user the Ureg struct and the note on his stack. 
 */ 
1992/0108    
int 
1997/0327    
notify(Ureg* ureg) 
1991/0710    
{ 
1995/0202    
	int l; 
1991/1114    
	ulong s, sp; 
1991/1218    
	Note *n; 
1991/0720    
 
1993/0915    
	if(up->procctl) 
1993/1013    
		procctl(up); 
1993/0915    
	if(up->nnote == 0) 
1992/0108    
		return 0; 
1991/1114    
 
	s = spllo(); 
1993/0915    
	qlock(&up->debug); 
	up->notepending = 0; 
	n = &up->note[0]; 
1991/1218    
	if(strncmp(n->msg, "sys:", 4) == 0){ 
		l = strlen(n->msg); 
		if(l > ERRLEN-15)	/* " pc=0x12345678\0" */ 
			l = ERRLEN-15; 
1997/0327    
		sprint(n->msg+l, " pc=0x%.8lux", ureg->pc); 
1991/1218    
	} 
1995/0202    
 
1993/0915    
	if(n->flag!=NUser && (up->notified || up->notify==0)){ 
1992/0714    
		if(n->flag == NDebug) 
1991/1218    
			pprint("suicide: %s\n", n->msg); 
1996/0626    
		qunlock(&up->debug); 
1991/1218    
		pexit(n->msg, n->flag!=NDebug); 
1991/0720    
	} 
1995/0202    
 
	if(up->notified) { 
		qunlock(&up->debug); 
		splhi(); 
		return 0; 
1991/0720    
	} 
1995/0202    
		 
	if(!up->notify){ 
		qunlock(&up->debug); 
		pexit(n->msg, n->flag!=NDebug); 
	} 
1997/0327    
	sp = ureg->usp; 
1995/0202    
	sp -= sizeof(Ureg); 
 
	if(!okaddr((ulong)up->notify, 1, 0) 
1995/02021    
	|| !okaddr(sp-ERRLEN-4*BY2WD, sizeof(Ureg)+ERRLEN+4*BY2WD, 1)){ 
1995/0202    
		pprint("suicide: bad address in notify\n"); 
		qunlock(&up->debug); 
		pexit("Suicide", 0); 
	} 
 
	up->ureg = (void*)sp; 
1997/0327    
	memmove((Ureg*)sp, ureg, sizeof(Ureg)); 
1995/0202    
	*(Ureg**)(sp-BY2WD) = up->ureg;	/* word under Ureg is old up->ureg */ 
	up->ureg = (void*)sp; 
	sp -= BY2WD+ERRLEN; 
	memmove((char*)sp, up->note[0].msg, ERRLEN); 
	sp -= 3*BY2WD; 
	*(ulong*)(sp+2*BY2WD) = sp+3*BY2WD;	/* arg 2 is string */ 
	*(ulong*)(sp+1*BY2WD) = (ulong)up->ureg;	/* arg 1 is ureg* */ 
	*(ulong*)(sp+0*BY2WD) = 0;		/* arg 0 is pc */ 
1997/0327    
	ureg->usp = sp; 
	ureg->pc = (ulong)up->notify; 
1995/0202    
	up->notified = 1; 
	up->nnote--; 
	memmove(&up->lastnote, &up->note[0], sizeof(Note)); 
	memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note)); 
 
1993/0915    
	qunlock(&up->debug); 
1991/1114    
	splx(s); 
1995/0202    
	return 1; 
1991/0710    
} 
 
1991/0720    
/* 
 *   Return user to state before notify() 
 */ 
1991/0710    
void 
1997/0327    
noted(Ureg* ureg, ulong arg0) 
1991/0710    
{ 
1997/0327    
	Ureg *nureg; 
1995/0202    
	ulong oureg, sp; 
1991/0720    
 
1993/0915    
	qlock(&up->debug); 
1995/0202    
	if(arg0!=NRSTR && !up->notified) { 
1993/0915    
		qunlock(&up->debug); 
1994/0513    
		pprint("call to noted() when not notified\n"); 
1995/0105    
		pexit("Suicide", 0); 
1991/0720    
	} 
1993/0915    
	up->notified = 0; 
1994/0513    
 
1999/0301    
	nureg = up->ureg;	/* pointer to user returned Ureg struct */ 
1995/0202    
 
	/* sanity clause */ 
1997/0327    
	oureg = (ulong)nureg; 
1995/02021    
	if(!okaddr((ulong)oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){ 
1997/0520    
		pprint("bad ureg in noted or call to noted when not notified\n"); 
1994/0513    
		qunlock(&up->debug); 
1995/0202    
		pexit("Suicide", 0); 
1994/0513    
	} 
 
1997/0520    
	/* 
	 * Check the segment selectors are all valid, otherwise 
	 * a fault will be taken on attempting to return to the 
	 * user process. 
1997/1003    
	 * Take care with the comparisons as different processor 
	 * generations push segment descriptors in different ways. 
1997/0520    
	 */ 
1997/1003    
	if((nureg->cs & 0xFFFF) != UESEL || (nureg->ss & 0xFFFF) != UDSEL 
	  || (nureg->ds & 0xFFFF) != UDSEL || (nureg->es & 0xFFFF) != UDSEL 
	  || (nureg->fs & 0xFFFF) != UDSEL || (nureg->gs & 0xFFFF) != UDSEL){ 
		pprint("bad segment selector in noted\n"); 
1997/0520    
		qunlock(&up->debug); 
		pexit("Suicide", 0); 
	} 
1995/0202    
 
	/* don't let user change system flags */ 
1997/0327    
	nureg->flags = (ureg->flags & ~0xCD5) | (nureg->flags & 0xCD5); 
1995/0202    
 
1997/0327    
	memmove(ureg, nureg, sizeof(Ureg)); 
1995/0105    
 
1991/0720    
	switch(arg0){ 
	case NCONT: 
1995/0202    
	case NRSTR: 
1997/0327    
		if(!okaddr(nureg->pc, 1, 0) || !okaddr(nureg->usp, BY2WD, 0)){ 
1995/0202    
			qunlock(&up->debug); 
1999/0604    
			pprint("suicide: trap in noted\n"); 
1994/0513    
			pexit("Suicide", 0); 
1991/0814    
		} 
1995/0202    
		up->ureg = (Ureg*)(*(ulong*)(oureg-BY2WD)); 
		qunlock(&up->debug); 
1995/0105    
		break; 
1991/0720    
 
1995/0202    
	case NSAVE: 
1999/0301    
		if(!okaddr(nureg->pc, BY2WD, 0) 
		|| !okaddr(nureg->usp, BY2WD, 0)){ 
1995/0202    
			qunlock(&up->debug); 
1999/0604    
			pprint("suicide: trap in noted\n"); 
1995/0202    
			pexit("Suicide", 0); 
		} 
		qunlock(&up->debug); 
		sp = oureg-4*BY2WD-ERRLEN; 
		splhi(); 
1997/0327    
		ureg->sp = sp; 
1995/0202    
		((ulong*)sp)[1] = oureg;	/* arg 1 0(FP) is ureg* */ 
		((ulong*)sp)[0] = 0;		/* arg 0 is pc */ 
		break; 
 
1991/0720    
	default: 
		pprint("unknown noted arg 0x%lux\n", arg0); 
1993/0915    
		up->lastnote.flag = NDebug; 
1991/0720    
		/* fall through */ 
		 
	case NDFLT: 
1999/0604    
		if(up->lastnote.flag == NDebug){  
			qunlock(&up->debug); 
1993/0915    
			pprint("suicide: %s\n", up->lastnote.msg); 
1999/0604    
		} else 
			qunlock(&up->debug); 
1993/0915    
		pexit(up->lastnote.msg, up->lastnote.flag!=NDebug); 
1991/0720    
	} 
1991/1112    
} 
 
1993/1113    
long 
execregs(ulong entry, ulong ssize, ulong nargs) 
{ 
	ulong *sp; 
1997/0327    
	Ureg *ureg; 
1993/1113    
 
	sp = (ulong*)(USTKTOP - ssize); 
	*--sp = nargs; 
 
1997/0327    
	ureg = up->dbgreg; 
	ureg->usp = (ulong)sp; 
	ureg->pc = entry; 
1994/0513    
	return USTKTOP-BY2WD;		/* address of user-level clock */ 
1993/1113    
} 
 
ulong 
userpc(void) 
{ 
1997/0327    
	Ureg *ureg; 
1993/1113    
 
1997/0327    
	ureg = (Ureg*)up->dbgreg; 
	return ureg->pc; 
1993/1113    
} 
 
1999/0301    
/* This routine must save the values of registers the user is not permitted 
 * to write from devproc and then restore the saved values before returning. 
1991/1112    
 */ 
void 
1997/0327    
setregisters(Ureg* ureg, char* pureg, char* uva, int n) 
1991/1112    
{ 
	ulong flags; 
	ulong cs; 
	ulong ss; 
 
1997/0327    
	flags = ureg->flags; 
	cs = ureg->cs; 
	ss = ureg->ss; 
1991/1112    
	memmove(pureg, uva, n); 
1997/0327    
	ureg->flags = (ureg->flags & 0x00FF) | (flags & 0xFF00); 
	ureg->cs = cs; 
	ureg->ss = ss; 
1993/1113    
} 
 
static void 
linkproc(void) 
{ 
	spllo(); 
1997/0327    
	up->kpfun(up->kparg); 
1993/1113    
} 
 
void 
1997/0327    
kprocchild(Proc* p, void (*func)(void*), void* arg) 
1993/1113    
{ 
1999/0517    
	/* 
	 * gotolabel() needs a word on the stack in 
	 * which to place the return PC used to jump 
	 * to linkproc(). 
	 */ 
1993/1113    
	p->sched.pc = (ulong)linkproc; 
1999/0517    
	p->sched.sp = (ulong)p->kstack+KSTACK-BY2WD; 
1993/1113    
 
	p->kpfun = func; 
	p->kparg = arg; 
} 
 
void 
1997/0327    
forkchild(Proc *p, Ureg *ureg) 
1993/1113    
{ 
1997/0327    
	Ureg *cureg; 
1993/1113    
 
	/* 
1997/0327    
	 * Add 2*BY2WD to the stack to account for 
1993/1113    
	 *  - the return PC 
	 *  - trap's argument (ur) 
	 */ 
	p->sched.sp = (ulong)p->kstack+KSTACK-(sizeof(Ureg)+2*BY2WD); 
	p->sched.pc = (ulong)forkret; 
 
1997/0327    
	cureg = (Ureg*)(p->sched.sp+2*BY2WD); 
	memmove(cureg, ureg, sizeof(Ureg)); 
1999/0301    
	/* return value of syscall in child */ 
	cureg->ax = 0; 
1993/1113    
 
1997/0327    
	/* Things from bottom of syscall which were never executed */ 
1993/1113    
	p->psstate = 0; 
	p->insyscall = 0; 
1991/0614    
} 
1993/1022    
 
/* Give enough context in the ureg to produce a kernel stack for 
 * a sleeping process 
 */ 
void 
1997/0327    
setkernur(Ureg* ureg, Proc* p) 
1993/1022    
{ 
1997/0327    
	ureg->pc = p->sched.pc; 
	ureg->sp = p->sched.sp+4; 
1993/1022    
} 
1995/1024    
 
ulong 
dbgpc(Proc *p) 
{ 
1997/0327    
	Ureg *ureg; 
1995/1024    
 
1997/0327    
	ureg = p->dbgreg; 
	if(ureg == 0) 
1995/1024    
		return 0; 
 
1997/0327    
	return ureg->pc; 
1995/1024    
} 


source code copyright © 1990-2005 Lucent Technologies; see license
Plan 9 distribution
comments to russ cox (rsc@swtch.com)