xref: /plan9/sys/src/9/pc/trap.c (revision edc15dd6d93c9a1b27df91ec433ef75c20e7345d)
13e12c5d1SDavid du Colombier #include	"u.h"
2e288d156SDavid du Colombier #include	"tos.h"
33e12c5d1SDavid du Colombier #include	"../port/lib.h"
43e12c5d1SDavid du Colombier #include	"mem.h"
53e12c5d1SDavid du Colombier #include	"dat.h"
63e12c5d1SDavid du Colombier #include	"fns.h"
73e12c5d1SDavid du Colombier #include	"io.h"
83e12c5d1SDavid du Colombier #include	"ureg.h"
93e12c5d1SDavid du Colombier #include	"../port/error.h"
10179dd269SDavid du Colombier #include	<trace.h>
113e12c5d1SDavid du Colombier 
124de34a7eSDavid du Colombier static int trapinited;
134de34a7eSDavid du Colombier 
143e12c5d1SDavid du Colombier void	noted(Ureg*, ulong);
153e12c5d1SDavid du Colombier 
167dd7cddfSDavid du Colombier static void debugbpt(Ureg*, void*);
177dd7cddfSDavid du Colombier static void fault386(Ureg*, void*);
18e288d156SDavid du Colombier static void doublefault(Ureg*, void*);
19fe853e23SDavid du Colombier static void unexpected(Ureg*, void*);
20fe853e23SDavid du Colombier static void _dumpstack(Ureg*);
213e12c5d1SDavid du Colombier 
227dd7cddfSDavid du Colombier static Lock vctllock;
237dd7cddfSDavid du Colombier static Vctl *vctl[256];
243ff48bf5SDavid du Colombier 
253ff48bf5SDavid du Colombier enum
263ff48bf5SDavid du Colombier {
270701b922SDavid du Colombier 	Ntimevec = 20		/* number of time buckets for each intr */
283ff48bf5SDavid du Colombier };
29e288d156SDavid du Colombier ulong intrtimes[256][Ntimevec];
303e12c5d1SDavid du Colombier 
313e12c5d1SDavid du Colombier void
327dd7cddfSDavid du Colombier intrenable(int irq, void (*f)(Ureg*, void*), void* a, int tbdf, char *name)
333e12c5d1SDavid du Colombier {
347dd7cddfSDavid du Colombier 	int vno;
3559cc4ca5SDavid du Colombier 	Vctl *v;
367dd7cddfSDavid du Colombier 
379a747e4fSDavid du Colombier 	if(f == nil){
389a747e4fSDavid du Colombier 		print("intrenable: nil handler for %d, tbdf 0x%uX for %s\n",
399a747e4fSDavid du Colombier 			irq, tbdf, name);
409a747e4fSDavid du Colombier 		return;
419a747e4fSDavid du Colombier 	}
429a747e4fSDavid du Colombier 
437dd7cddfSDavid du Colombier 	v = xalloc(sizeof(Vctl));
447dd7cddfSDavid du Colombier 	v->isintr = 1;
457dd7cddfSDavid du Colombier 	v->irq = irq;
467dd7cddfSDavid du Colombier 	v->tbdf = tbdf;
477dd7cddfSDavid du Colombier 	v->f = f;
487dd7cddfSDavid du Colombier 	v->a = a;
499a747e4fSDavid du Colombier 	strncpy(v->name, name, KNAMELEN-1);
509a747e4fSDavid du Colombier 	v->name[KNAMELEN-1] = 0;
517dd7cddfSDavid du Colombier 
527dd7cddfSDavid du Colombier 	ilock(&vctllock);
537dd7cddfSDavid du Colombier 	vno = arch->intrenable(v);
547dd7cddfSDavid du Colombier 	if(vno == -1){
557dd7cddfSDavid du Colombier 		iunlock(&vctllock);
567dd7cddfSDavid du Colombier 		print("intrenable: couldn't enable irq %d, tbdf 0x%uX for %s\n",
577dd7cddfSDavid du Colombier 			irq, tbdf, v->name);
587dd7cddfSDavid du Colombier 		xfree(v);
597dd7cddfSDavid du Colombier 		return;
607dd7cddfSDavid du Colombier 	}
617dd7cddfSDavid du Colombier 	if(vctl[vno]){
627dd7cddfSDavid du Colombier 		if(vctl[vno]->isr != v->isr || vctl[vno]->eoi != v->eoi)
637dd7cddfSDavid du Colombier 			panic("intrenable: handler: %s %s %luX %luX %luX %luX\n",
647dd7cddfSDavid du Colombier 				vctl[vno]->name, v->name,
657dd7cddfSDavid du Colombier 				vctl[vno]->isr, v->isr, vctl[vno]->eoi, v->eoi);
667dd7cddfSDavid du Colombier 		v->next = vctl[vno];
677dd7cddfSDavid du Colombier 	}
687dd7cddfSDavid du Colombier 	vctl[vno] = v;
697dd7cddfSDavid du Colombier 	iunlock(&vctllock);
707dd7cddfSDavid du Colombier }
717dd7cddfSDavid du Colombier 
7207a38badSDavid du Colombier int
739a747e4fSDavid du Colombier intrdisable(int irq, void (*f)(Ureg *, void *), void *a, int tbdf, char *name)
749a747e4fSDavid du Colombier {
759a747e4fSDavid du Colombier 	Vctl **pv, *v;
769a747e4fSDavid du Colombier 	int vno;
779a747e4fSDavid du Colombier 
789a747e4fSDavid du Colombier 	/*
799a747e4fSDavid du Colombier 	 * For now, none of this will work with the APIC code,
809a747e4fSDavid du Colombier 	 * there is no mapping between irq and vector as the IRQ
819a747e4fSDavid du Colombier 	 * is pretty meaningless.
829a747e4fSDavid du Colombier 	 */
839a747e4fSDavid du Colombier 	if(arch->intrvecno == nil)
8407a38badSDavid du Colombier 		return -1;
859a747e4fSDavid du Colombier 	vno = arch->intrvecno(irq);
869a747e4fSDavid du Colombier 	ilock(&vctllock);
879a747e4fSDavid du Colombier 	pv = &vctl[vno];
889a747e4fSDavid du Colombier 	while (*pv &&
899a747e4fSDavid du Colombier 		  ((*pv)->irq != irq || (*pv)->tbdf != tbdf || (*pv)->f != f || (*pv)->a != a ||
909a747e4fSDavid du Colombier 		   strcmp((*pv)->name, name)))
919a747e4fSDavid du Colombier 		pv = &((*pv)->next);
929a747e4fSDavid du Colombier 	assert(*pv);
939a747e4fSDavid du Colombier 
949a747e4fSDavid du Colombier 	v = *pv;
959a747e4fSDavid du Colombier 	*pv = (*pv)->next;	/* Link out the entry */
969a747e4fSDavid du Colombier 
979a747e4fSDavid du Colombier 	if(vctl[vno] == nil && arch->intrdisable != nil)
989a747e4fSDavid du Colombier 		arch->intrdisable(irq);
999a747e4fSDavid du Colombier 	iunlock(&vctllock);
1009a747e4fSDavid du Colombier 	xfree(v);
10107a38badSDavid du Colombier 	return 0;
1029a747e4fSDavid du Colombier }
1039a747e4fSDavid du Colombier 
10480ee5cbfSDavid du Colombier static long
10580ee5cbfSDavid du Colombier irqallocread(Chan*, void *vbuf, long n, vlong offset)
1067dd7cddfSDavid du Colombier {
1073ff48bf5SDavid du Colombier 	char *buf, *p, str[2*(11+1)+KNAMELEN+1+1];
10880ee5cbfSDavid du Colombier 	int m, vno;
1097dd7cddfSDavid du Colombier 	long oldn;
11080ee5cbfSDavid du Colombier 	Vctl *v;
1117dd7cddfSDavid du Colombier 
1127dd7cddfSDavid du Colombier 	if(n < 0 || offset < 0)
1137dd7cddfSDavid du Colombier 		error(Ebadarg);
1147dd7cddfSDavid du Colombier 
1157dd7cddfSDavid du Colombier 	oldn = n;
11680ee5cbfSDavid du Colombier 	buf = vbuf;
1177dd7cddfSDavid du Colombier 	for(vno=0; vno<nelem(vctl); vno++){
1187dd7cddfSDavid du Colombier 		for(v=vctl[vno]; v; v=v->next){
1199a747e4fSDavid du Colombier 			m = snprint(str, sizeof str, "%11d %11d %.*s\n", vno, v->irq, KNAMELEN, v->name);
1207dd7cddfSDavid du Colombier 			if(m <= offset)	/* if do not want this, skip entry */
1217dd7cddfSDavid du Colombier 				offset -= m;
1227dd7cddfSDavid du Colombier 			else{
1237dd7cddfSDavid du Colombier 				/* skip offset bytes */
1247dd7cddfSDavid du Colombier 				m -= offset;
1257dd7cddfSDavid du Colombier 				p = str+offset;
1267dd7cddfSDavid du Colombier 				offset = 0;
1277dd7cddfSDavid du Colombier 
1287dd7cddfSDavid du Colombier 				/* write at most max(n,m) bytes */
1297dd7cddfSDavid du Colombier 				if(m > n)
1307dd7cddfSDavid du Colombier 					m = n;
1317dd7cddfSDavid du Colombier 				memmove(buf, p, m);
1327dd7cddfSDavid du Colombier 				n -= m;
1337dd7cddfSDavid du Colombier 				buf += m;
1347dd7cddfSDavid du Colombier 
1357dd7cddfSDavid du Colombier 				if(n == 0)
1367dd7cddfSDavid du Colombier 					return oldn;
1377dd7cddfSDavid du Colombier 			}
1387dd7cddfSDavid du Colombier 		}
1397dd7cddfSDavid du Colombier 	}
1407dd7cddfSDavid du Colombier 	return oldn - n;
1413e12c5d1SDavid du Colombier }
1423e12c5d1SDavid du Colombier 
1433e12c5d1SDavid du Colombier void
1447dd7cddfSDavid du Colombier trapenable(int vno, void (*f)(Ureg*, void*), void* a, char *name)
1453e12c5d1SDavid du Colombier {
1467dd7cddfSDavid du Colombier 	Vctl *v;
147219b2ee8SDavid du Colombier 
1487dd7cddfSDavid du Colombier 	if(vno < 0 || vno >= VectorPIC)
1497dd7cddfSDavid du Colombier 		panic("trapenable: vno %d\n", vno);
1507dd7cddfSDavid du Colombier 	v = xalloc(sizeof(Vctl));
1517dd7cddfSDavid du Colombier 	v->tbdf = BUSUNKNOWN;
1527dd7cddfSDavid du Colombier 	v->f = f;
1537dd7cddfSDavid du Colombier 	v->a = a;
1549a747e4fSDavid du Colombier 	strncpy(v->name, name, KNAMELEN);
1559a747e4fSDavid du Colombier 	v->name[KNAMELEN-1] = 0;
1567dd7cddfSDavid du Colombier 
157061a3f44SDavid du Colombier 	ilock(&vctllock);
1587dd7cddfSDavid du Colombier 	if(vctl[vno])
1597dd7cddfSDavid du Colombier 		v->next = vctl[vno]->next;
1607dd7cddfSDavid du Colombier 	vctl[vno] = v;
161061a3f44SDavid du Colombier 	iunlock(&vctllock);
1627dd7cddfSDavid du Colombier }
1637dd7cddfSDavid du Colombier 
1647dd7cddfSDavid du Colombier static void
1657dd7cddfSDavid du Colombier nmienable(void)
1667dd7cddfSDavid du Colombier {
1677dd7cddfSDavid du Colombier 	int x;
1683e12c5d1SDavid du Colombier 
1693e12c5d1SDavid du Colombier 	/*
1707dd7cddfSDavid du Colombier 	 * Hack: should be locked with NVRAM access.
1713e12c5d1SDavid du Colombier 	 */
1727dd7cddfSDavid du Colombier 	outb(0x70, 0x80);		/* NMI latch clear */
1737dd7cddfSDavid du Colombier 	outb(0x70, 0);
1747dd7cddfSDavid du Colombier 
1757dd7cddfSDavid du Colombier 	x = inb(0x61) & 0x07;		/* Enable NMI */
1767dd7cddfSDavid du Colombier 	outb(0x61, 0x08|x);
1777dd7cddfSDavid du Colombier 	outb(0x61, x);
1783e12c5d1SDavid du Colombier }
1793e12c5d1SDavid du Colombier 
1804de34a7eSDavid du Colombier /*
1814de34a7eSDavid du Colombier  * Minimal trap setup.  Just enough so that we can panic
1824de34a7eSDavid du Colombier  * on traps (bugs) during kernel initialization.
1834de34a7eSDavid du Colombier  * Called very early - malloc is not yet available.
1844de34a7eSDavid du Colombier  */
1853e12c5d1SDavid du Colombier void
1864de34a7eSDavid du Colombier trapinit0(void)
1873e12c5d1SDavid du Colombier {
1887dd7cddfSDavid du Colombier 	int d1, v;
1897dd7cddfSDavid du Colombier 	ulong vaddr;
1907dd7cddfSDavid du Colombier 	Segdesc *idt;
1913e12c5d1SDavid du Colombier 
1927dd7cddfSDavid du Colombier 	idt = (Segdesc*)IDTADDR;
1937dd7cddfSDavid du Colombier 	vaddr = (ulong)vectortable;
1947dd7cddfSDavid du Colombier 	for(v = 0; v < 256; v++){
1957dd7cddfSDavid du Colombier 		d1 = (vaddr & 0xFFFF0000)|SEGP;
1967dd7cddfSDavid du Colombier 		switch(v){
1973e12c5d1SDavid du Colombier 
1987dd7cddfSDavid du Colombier 		case VectorBPT:
1997dd7cddfSDavid du Colombier 			d1 |= SEGPL(3)|SEGIG;
2007dd7cddfSDavid du Colombier 			break;
2013e12c5d1SDavid du Colombier 
2027dd7cddfSDavid du Colombier 		case VectorSYSCALL:
2037dd7cddfSDavid du Colombier 			d1 |= SEGPL(3)|SEGIG;
2047dd7cddfSDavid du Colombier 			break;
2053e12c5d1SDavid du Colombier 
2067dd7cddfSDavid du Colombier 		default:
2077dd7cddfSDavid du Colombier 			d1 |= SEGPL(0)|SEGIG;
2087dd7cddfSDavid du Colombier 			break;
2097dd7cddfSDavid du Colombier 		}
2107dd7cddfSDavid du Colombier 		idt[v].d0 = (vaddr & 0xFFFF)|(KESEL<<16);
2117dd7cddfSDavid du Colombier 		idt[v].d1 = d1;
2127dd7cddfSDavid du Colombier 		vaddr += 6;
2133e12c5d1SDavid du Colombier 	}
2144de34a7eSDavid du Colombier }
2153e12c5d1SDavid du Colombier 
2164de34a7eSDavid du Colombier void
2174de34a7eSDavid du Colombier trapinit(void)
2184de34a7eSDavid du Colombier {
2197dd7cddfSDavid du Colombier 	/*
2207dd7cddfSDavid du Colombier 	 * Special traps.
2217dd7cddfSDavid du Colombier 	 * Syscall() is called directly without going through trap().
2227dd7cddfSDavid du Colombier 	 */
2237dd7cddfSDavid du Colombier 	trapenable(VectorBPT, debugbpt, 0, "debugpt");
2247dd7cddfSDavid du Colombier 	trapenable(VectorPF, fault386, 0, "fault386");
225e288d156SDavid du Colombier 	trapenable(Vector2F, doublefault, 0, "doublefault");
226fe853e23SDavid du Colombier 	trapenable(Vector15, unexpected, 0, "unexpected");
2277dd7cddfSDavid du Colombier 	nmienable();
22880ee5cbfSDavid du Colombier 
22980ee5cbfSDavid du Colombier 	addarchfile("irqalloc", 0444, irqallocread, nil);
2304de34a7eSDavid du Colombier 	trapinited = 1;
2317dd7cddfSDavid du Colombier }
2327dd7cddfSDavid du Colombier 
2337dd7cddfSDavid du Colombier static char* excname[32] = {
2347dd7cddfSDavid du Colombier 	"divide error",
2357dd7cddfSDavid du Colombier 	"debug exception",
2367dd7cddfSDavid du Colombier 	"nonmaskable interrupt",
2377dd7cddfSDavid du Colombier 	"breakpoint",
2387dd7cddfSDavid du Colombier 	"overflow",
2397dd7cddfSDavid du Colombier 	"bounds check",
2407dd7cddfSDavid du Colombier 	"invalid opcode",
2417dd7cddfSDavid du Colombier 	"coprocessor not available",
2427dd7cddfSDavid du Colombier 	"double fault",
2437dd7cddfSDavid du Colombier 	"coprocessor segment overrun",
2447dd7cddfSDavid du Colombier 	"invalid TSS",
2457dd7cddfSDavid du Colombier 	"segment not present",
2467dd7cddfSDavid du Colombier 	"stack exception",
2477dd7cddfSDavid du Colombier 	"general protection violation",
2487dd7cddfSDavid du Colombier 	"page fault",
2497dd7cddfSDavid du Colombier 	"15 (reserved)",
2507dd7cddfSDavid du Colombier 	"coprocessor error",
2517dd7cddfSDavid du Colombier 	"alignment check",
2527dd7cddfSDavid du Colombier 	"machine check",
2537dd7cddfSDavid du Colombier 	"19 (reserved)",
2547dd7cddfSDavid du Colombier 	"20 (reserved)",
2557dd7cddfSDavid du Colombier 	"21 (reserved)",
2567dd7cddfSDavid du Colombier 	"22 (reserved)",
2577dd7cddfSDavid du Colombier 	"23 (reserved)",
2587dd7cddfSDavid du Colombier 	"24 (reserved)",
2597dd7cddfSDavid du Colombier 	"25 (reserved)",
2607dd7cddfSDavid du Colombier 	"26 (reserved)",
2617dd7cddfSDavid du Colombier 	"27 (reserved)",
2627dd7cddfSDavid du Colombier 	"28 (reserved)",
2637dd7cddfSDavid du Colombier 	"29 (reserved)",
2647dd7cddfSDavid du Colombier 	"30 (reserved)",
2657dd7cddfSDavid du Colombier 	"31 (reserved)",
2663e12c5d1SDavid du Colombier };
2673e12c5d1SDavid du Colombier 
2683e12c5d1SDavid du Colombier /*
2693ff48bf5SDavid du Colombier  *  keep histogram of interrupt service times
2703ff48bf5SDavid du Colombier  */
2713ff48bf5SDavid du Colombier void
2723ff48bf5SDavid du Colombier intrtime(Mach*, int vno)
2733ff48bf5SDavid du Colombier {
2743ff48bf5SDavid du Colombier 	ulong diff;
275e288d156SDavid du Colombier 	ulong x;
2763ff48bf5SDavid du Colombier 
277e288d156SDavid du Colombier 	x = perfticks();
2783ff48bf5SDavid du Colombier 	diff = x - m->perf.intrts;
2793ff48bf5SDavid du Colombier 	m->perf.intrts = x;
2803ff48bf5SDavid du Colombier 
2813ff48bf5SDavid du Colombier 	m->perf.inintr += diff;
2823ff48bf5SDavid du Colombier 	if(up == nil && m->perf.inidle > diff)
2833ff48bf5SDavid du Colombier 		m->perf.inidle -= diff;
2843ff48bf5SDavid du Colombier 
28541dd6b47SDavid du Colombier 	diff /= m->cpumhz*100;		/* quantum = 100µsec */
286e288d156SDavid du Colombier 	if(diff >= Ntimevec)
2873ff48bf5SDavid du Colombier 		diff = Ntimevec-1;
2883ff48bf5SDavid du Colombier 	intrtimes[vno][diff]++;
2893ff48bf5SDavid du Colombier }
2903ff48bf5SDavid du Colombier 
291e288d156SDavid du Colombier /* go to user space */
292e288d156SDavid du Colombier void
293e288d156SDavid du Colombier kexit(Ureg*)
294e288d156SDavid du Colombier {
295e288d156SDavid du Colombier 	uvlong t;
296e288d156SDavid du Colombier 	Tos *tos;
297e288d156SDavid du Colombier 
298e288d156SDavid du Colombier 	/* precise time accounting, kernel exit */
299e288d156SDavid du Colombier 	tos = (Tos*)(USTKTOP-sizeof(Tos));
300e288d156SDavid du Colombier 	cycles(&t);
301e288d156SDavid du Colombier 	tos->kcycles += t - up->kentry;
302e288d156SDavid du Colombier 	tos->pcycles = up->pcycles;
303e288d156SDavid du Colombier 	tos->pid = up->pid;
304e288d156SDavid du Colombier }
305e288d156SDavid du Colombier 
3063ff48bf5SDavid du Colombier /*
3077dd7cddfSDavid du Colombier  *  All traps come here.  It is slower to have all traps call trap()
3087dd7cddfSDavid du Colombier  *  rather than directly vectoring the handler.  However, this avoids a
3097dd7cddfSDavid du Colombier  *  lot of code duplication and possible bugs.  The only exception is
3107dd7cddfSDavid du Colombier  *  VectorSYSCALL.
3117dd7cddfSDavid du Colombier  *  Trap is called with interrupts disabled via interrupt-gates.
3123e12c5d1SDavid du Colombier  */
3133e12c5d1SDavid du Colombier void
3147dd7cddfSDavid du Colombier trap(Ureg* ureg)
3153e12c5d1SDavid du Colombier {
3162009dc88SDavid du Colombier 	int clockintr, i, vno, user;
3179a747e4fSDavid du Colombier 	char buf[ERRMAX];
3187dd7cddfSDavid du Colombier 	Vctl *ctl, *v;
3197dd7cddfSDavid du Colombier 	Mach *mach;
3203e12c5d1SDavid du Colombier 
3214de34a7eSDavid du Colombier 	if(!trapinited){
3224de34a7eSDavid du Colombier 		/* fault386 can give a better error message */
3234de34a7eSDavid du Colombier 		if(ureg->trap == VectorPF)
3244de34a7eSDavid du Colombier 			fault386(ureg, nil);
3254de34a7eSDavid du Colombier 		panic("trap %lud: not ready", ureg->trap);
3264de34a7eSDavid du Colombier 	}
3274de34a7eSDavid du Colombier 
3283ff48bf5SDavid du Colombier 	m->perf.intrts = perfticks();
329e288d156SDavid du Colombier 	user = (ureg->cs & 0xFFFF) == UESEL;
330e288d156SDavid du Colombier 	if(user){
3317dd7cddfSDavid du Colombier 		up->dbgreg = ureg;
332e288d156SDavid du Colombier 		cycles(&up->kentry);
333219b2ee8SDavid du Colombier 	}
3347dd7cddfSDavid du Colombier 
3353cf081f0SDavid du Colombier 	clockintr = 0;
3363cf081f0SDavid du Colombier 
3377dd7cddfSDavid du Colombier 	vno = ureg->trap;
3387dd7cddfSDavid du Colombier 	if(ctl = vctl[vno]){
3397dd7cddfSDavid du Colombier 		if(ctl->isintr){
3407dd7cddfSDavid du Colombier 			m->intr++;
3417dd7cddfSDavid du Colombier 			if(vno >= VectorPIC && vno != VectorSYSCALL)
3427dd7cddfSDavid du Colombier 				m->lastintr = ctl->irq;
3437dd7cddfSDavid du Colombier 		}
3447dd7cddfSDavid du Colombier 
3457dd7cddfSDavid du Colombier 		if(ctl->isr)
3467dd7cddfSDavid du Colombier 			ctl->isr(vno);
3477dd7cddfSDavid du Colombier 		for(v = ctl; v != nil; v = v->next){
3480701b922SDavid du Colombier 			if(v->f)
3497dd7cddfSDavid du Colombier 				v->f(ureg, v->a);
3507dd7cddfSDavid du Colombier 		}
3517dd7cddfSDavid du Colombier 		if(ctl->eoi)
3527dd7cddfSDavid du Colombier 			ctl->eoi(vno);
3533e12c5d1SDavid du Colombier 
354a6a9e072SDavid du Colombier 		if(ctl->isintr){
3553ff48bf5SDavid du Colombier 			intrtime(m, vno);
356179dd269SDavid du Colombier 
3572009dc88SDavid du Colombier 			if(ctl->irq == IrqCLOCK || ctl->irq == IrqTIMER)
3582009dc88SDavid du Colombier 				clockintr = 1;
3592009dc88SDavid du Colombier 
3602009dc88SDavid du Colombier 			if(up && !clockintr)
361a6a9e072SDavid du Colombier 				preempted();
3623e12c5d1SDavid du Colombier 		}
3633e12c5d1SDavid du Colombier 	}
3647dd7cddfSDavid du Colombier 	else if(vno <= nelem(excname) && user){
3657dd7cddfSDavid du Colombier 		spllo();
3667dd7cddfSDavid du Colombier 		sprint(buf, "sys: trap: %s", excname[vno]);
3677dd7cddfSDavid du Colombier 		postnote(up, 1, buf, NDebug);
3687dd7cddfSDavid du Colombier 	}
3697dd7cddfSDavid du Colombier 	else if(vno >= VectorPIC && vno != VectorSYSCALL){
370219b2ee8SDavid du Colombier 		/*
3717dd7cddfSDavid du Colombier 		 * An unknown interrupt.
372219b2ee8SDavid du Colombier 		 * Check for a default IRQ7. This can happen when
373219b2ee8SDavid du Colombier 		 * the IRQ input goes away before the acknowledge.
374219b2ee8SDavid du Colombier 		 * In this case, a 'default IRQ7' is generated, but
375219b2ee8SDavid du Colombier 		 * the corresponding bit in the ISR isn't set.
376219b2ee8SDavid du Colombier 		 * In fact, just ignore all such interrupts.
377219b2ee8SDavid du Colombier 		 */
3789a747e4fSDavid du Colombier 
3799a747e4fSDavid du Colombier 		/* call all interrupt routines, just in case */
3809a747e4fSDavid du Colombier 		for(i = VectorPIC; i <= MaxIrqLAPIC; i++){
3819a747e4fSDavid du Colombier 			ctl = vctl[i];
3829a747e4fSDavid du Colombier 			if(ctl == nil)
3839a747e4fSDavid du Colombier 				continue;
3849a747e4fSDavid du Colombier 			if(!ctl->isintr)
3859a747e4fSDavid du Colombier 				continue;
3869a747e4fSDavid du Colombier 			for(v = ctl; v != nil; v = v->next){
3879a747e4fSDavid du Colombier 				if(v->f)
3889a747e4fSDavid du Colombier 					v->f(ureg, v->a);
3899a747e4fSDavid du Colombier 			}
3909a747e4fSDavid du Colombier 			/* should we do this? */
3919a747e4fSDavid du Colombier 			if(ctl->eoi)
3929a747e4fSDavid du Colombier 				ctl->eoi(i);
3939a747e4fSDavid du Colombier 		}
3949a747e4fSDavid du Colombier 
3959a747e4fSDavid du Colombier 		/* clear the interrupt */
3969a747e4fSDavid du Colombier 		i8259isr(vno);
3979a747e4fSDavid du Colombier 
398da51d93aSDavid du Colombier 		if(0)print("cpu%d: spurious interrupt %d, last %d\n",
3997dd7cddfSDavid du Colombier 			m->machno, vno, m->lastintr);
400da51d93aSDavid du Colombier 		if(0)if(conf.nmach > 1){
4019a747e4fSDavid du Colombier 			for(i = 0; i < 32; i++){
4027dd7cddfSDavid du Colombier 				if(!(active.machs & (1<<i)))
4037dd7cddfSDavid du Colombier 					continue;
4047dd7cddfSDavid du Colombier 				mach = MACHP(i);
4057dd7cddfSDavid du Colombier 				if(m->machno == mach->machno)
4067dd7cddfSDavid du Colombier 					continue;
407da51d93aSDavid du Colombier 				print(" cpu%d: last %d",
408da51d93aSDavid du Colombier 					mach->machno, mach->lastintr);
409219b2ee8SDavid du Colombier 			}
4107dd7cddfSDavid du Colombier 			print("\n");
411e288d156SDavid du Colombier 		}
412da51d93aSDavid du Colombier 		m->spuriousintr++;
413da51d93aSDavid du Colombier 		if(user)
414da51d93aSDavid du Colombier 			kexit(ureg);
4153e12c5d1SDavid du Colombier 		return;
4163e12c5d1SDavid du Colombier 	}
4177dd7cddfSDavid du Colombier 	else{
4187dd7cddfSDavid du Colombier 		if(vno == VectorNMI){
419208510e1SDavid du Colombier 			/*
420208510e1SDavid du Colombier 			 * Don't re-enable, it confuses the crash dumps.
4217dd7cddfSDavid du Colombier 			nmienable();
422208510e1SDavid du Colombier 			 */
423208510e1SDavid du Colombier 			iprint("cpu%d: PC %#8.8lux\n", m->machno, ureg->pc);
424208510e1SDavid du Colombier 			while(m->machno != 0)
425208510e1SDavid du Colombier 				;
4267dd7cddfSDavid du Colombier 		}
4277dd7cddfSDavid du Colombier 		dumpregs(ureg);
428fe853e23SDavid du Colombier 		if(!user){
429fe853e23SDavid du Colombier 			ureg->sp = (ulong)&ureg->sp;
430fe853e23SDavid du Colombier 			_dumpstack(ureg);
431fe853e23SDavid du Colombier 		}
4327dd7cddfSDavid du Colombier 		if(vno < nelem(excname))
4337dd7cddfSDavid du Colombier 			panic("%s", excname[vno]);
4347dd7cddfSDavid du Colombier 		panic("unknown trap/intr: %d\n", vno);
4357dd7cddfSDavid du Colombier 	}
436da51d93aSDavid du Colombier 	splhi();
437da51d93aSDavid du Colombier 
438da51d93aSDavid du Colombier 	/* delaysched set because we held a lock or because our quantum ended */
4392009dc88SDavid du Colombier 	if(up && up->delaysched && clockintr){
440da51d93aSDavid du Colombier 		sched();
441da51d93aSDavid du Colombier 		splhi();
442da51d93aSDavid du Colombier 	}
4433e12c5d1SDavid du Colombier 
444e288d156SDavid du Colombier 	if(user){
445da51d93aSDavid du Colombier 		if(up->procctl || up->nnote)
4467dd7cddfSDavid du Colombier 			notify(ureg);
447e288d156SDavid du Colombier 		kexit(ureg);
448e288d156SDavid du Colombier 	}
4493e12c5d1SDavid du Colombier }
4503e12c5d1SDavid du Colombier 
4513e12c5d1SDavid du Colombier /*
4523e12c5d1SDavid du Colombier  *  dump registers
4533e12c5d1SDavid du Colombier  */
4543e12c5d1SDavid du Colombier void
4557dd7cddfSDavid du Colombier dumpregs2(Ureg* ureg)
4563e12c5d1SDavid du Colombier {
4577dd7cddfSDavid du Colombier 	if(up)
458208510e1SDavid du Colombier 		iprint("cpu%d: registers for %s %lud\n",
4597dd7cddfSDavid du Colombier 			m->machno, up->text, up->pid);
4603e12c5d1SDavid du Colombier 	else
461208510e1SDavid du Colombier 		iprint("cpu%d: registers for kernel\n", m->machno);
462208510e1SDavid du Colombier 	iprint("FLAGS=%luX TRAP=%luX ECODE=%luX PC=%luX",
4637dd7cddfSDavid du Colombier 		ureg->flags, ureg->trap, ureg->ecode, ureg->pc);
464208510e1SDavid du Colombier 	iprint(" SS=%4.4luX USP=%luX\n", ureg->ss & 0xFFFF, ureg->usp);
465208510e1SDavid du Colombier 	iprint("  AX %8.8luX  BX %8.8luX  CX %8.8luX  DX %8.8luX\n",
4667dd7cddfSDavid du Colombier 		ureg->ax, ureg->bx, ureg->cx, ureg->dx);
467208510e1SDavid du Colombier 	iprint("  SI %8.8luX  DI %8.8luX  BP %8.8luX\n",
4687dd7cddfSDavid du Colombier 		ureg->si, ureg->di, ureg->bp);
469208510e1SDavid du Colombier 	iprint("  CS %4.4luX  DS %4.4luX  ES %4.4luX  FS %4.4luX  GS %4.4luX\n",
4707dd7cddfSDavid du Colombier 		ureg->cs & 0xFFFF, ureg->ds & 0xFFFF, ureg->es & 0xFFFF,
4717dd7cddfSDavid du Colombier 		ureg->fs & 0xFFFF, ureg->gs & 0xFFFF);
472219b2ee8SDavid du Colombier }
473219b2ee8SDavid du Colombier 
474219b2ee8SDavid du Colombier void
4757dd7cddfSDavid du Colombier dumpregs(Ureg* ureg)
476219b2ee8SDavid du Colombier {
4777dd7cddfSDavid du Colombier 	vlong mca, mct;
4787dd7cddfSDavid du Colombier 
4797dd7cddfSDavid du Colombier 	dumpregs2(ureg);
4807dd7cddfSDavid du Colombier 
4817dd7cddfSDavid du Colombier 	/*
4827dd7cddfSDavid du Colombier 	 * Processor control registers.
4837dd7cddfSDavid du Colombier 	 * If machine check exception, time stamp counter, page size extensions
4847dd7cddfSDavid du Colombier 	 * or enhanced virtual 8086 mode extensions are supported, there is a
4857dd7cddfSDavid du Colombier 	 * CR4. If there is a CR4 and machine check extensions, read the machine
4867dd7cddfSDavid du Colombier 	 * check address and machine check type registers if RDMSR supported.
4877dd7cddfSDavid du Colombier 	 */
488208510e1SDavid du Colombier 	iprint("  CR0 %8.8lux CR2 %8.8lux CR3 %8.8lux",
4897dd7cddfSDavid du Colombier 		getcr0(), getcr2(), getcr3());
4907dd7cddfSDavid du Colombier 	if(m->cpuiddx & 0x9A){
491208510e1SDavid du Colombier 		iprint(" CR4 %8.8lux", getcr4());
4927dd7cddfSDavid du Colombier 		if((m->cpuiddx & 0xA0) == 0xA0){
4937dd7cddfSDavid du Colombier 			rdmsr(0x00, &mca);
4947dd7cddfSDavid du Colombier 			rdmsr(0x01, &mct);
495208510e1SDavid du Colombier 			iprint("\n  MCA %8.8llux MCT %8.8llux", mca, mct);
4967dd7cddfSDavid du Colombier 		}
4977dd7cddfSDavid du Colombier 	}
498208510e1SDavid du Colombier 	iprint("\n  ur %lux up %lux\n", ureg, up);
4993e12c5d1SDavid du Colombier }
5003e12c5d1SDavid du Colombier 
5017dd7cddfSDavid du Colombier 
5027dd7cddfSDavid du Colombier /*
5037dd7cddfSDavid du Colombier  * Fill in enough of Ureg to get a stack trace, and call a function.
5047dd7cddfSDavid du Colombier  * Used by debugging interface rdb.
5057dd7cddfSDavid du Colombier  */
5063e12c5d1SDavid du Colombier void
5077dd7cddfSDavid du Colombier callwithureg(void (*fn)(Ureg*))
5087dd7cddfSDavid du Colombier {
5097dd7cddfSDavid du Colombier 	Ureg ureg;
5107dd7cddfSDavid du Colombier 	ureg.pc = getcallerpc(&fn);
5117dd7cddfSDavid du Colombier 	ureg.sp = (ulong)&fn;
5127dd7cddfSDavid du Colombier 	fn(&ureg);
5137dd7cddfSDavid du Colombier }
5147dd7cddfSDavid du Colombier 
5157dd7cddfSDavid du Colombier static void
5167dd7cddfSDavid du Colombier _dumpstack(Ureg *ureg)
5173e12c5d1SDavid du Colombier {
518208510e1SDavid du Colombier 	uintptr l, v, i, estack;
5193e12c5d1SDavid du Colombier 	extern ulong etext;
520fe853e23SDavid du Colombier 	int x;
521*edc15dd6SDavid du Colombier 	char *s;
5223e12c5d1SDavid du Colombier 
523*edc15dd6SDavid du Colombier 	if((s = getconf("*nodumpstack")) != nil && strcmp(s, "0") != 0){
52482cf11d1SDavid du Colombier 		iprint("dumpstack disabled\n");
52582cf11d1SDavid du Colombier 		return;
52682cf11d1SDavid du Colombier 	}
527fe853e23SDavid du Colombier 	iprint("dumpstack\n");
52882cf11d1SDavid du Colombier 
529fe853e23SDavid du Colombier 	x = 0;
530208510e1SDavid du Colombier 	x += iprint("ktrace /kernel/path %.8lux %.8lux <<EOF\n", ureg->pc, ureg->sp);
5313e12c5d1SDavid du Colombier 	i = 0;
5329a747e4fSDavid du Colombier 	if(up
533208510e1SDavid du Colombier 	&& (uintptr)&l >= (uintptr)up->kstack
534208510e1SDavid du Colombier 	&& (uintptr)&l <= (uintptr)up->kstack+KSTACK)
535208510e1SDavid du Colombier 		estack = (uintptr)up->kstack+KSTACK;
536208510e1SDavid du Colombier 	else if((uintptr)&l >= (uintptr)m->stack
537208510e1SDavid du Colombier 	&& (uintptr)&l <= (uintptr)m+MACHSIZE)
538208510e1SDavid du Colombier 		estack = (uintptr)m+MACHSIZE;
5399a747e4fSDavid du Colombier 	else
5409a747e4fSDavid du Colombier 		return;
541208510e1SDavid du Colombier 	x += iprint("estackx %p\n", estack);
5429a747e4fSDavid du Colombier 
543208510e1SDavid du Colombier 	for(l = (uintptr)&l; l < estack; l += sizeof(uintptr)){
544208510e1SDavid du Colombier 		v = *(uintptr*)l;
545208510e1SDavid du Colombier 		if((KTZERO < v && v < (uintptr)&etext) || estack-l < 32){
5467dd7cddfSDavid du Colombier 			/*
547208510e1SDavid du Colombier 			 * Could Pick off general CALL (((uchar*)v)[-5] == 0xE8)
548208510e1SDavid du Colombier 			 * and CALL indirect through AX
549208510e1SDavid du Colombier 			 * (((uchar*)v)[-2] == 0xFF && ((uchar*)v)[-2] == 0xD0),
5509a747e4fSDavid du Colombier 			 * but this is too clever and misses faulting address.
5517dd7cddfSDavid du Colombier 			 */
552208510e1SDavid du Colombier 			x += iprint("%.8p=%.8p ", l, v);
5533e12c5d1SDavid du Colombier 			i++;
5543e12c5d1SDavid du Colombier 		}
5553e12c5d1SDavid du Colombier 		if(i == 4){
5563e12c5d1SDavid du Colombier 			i = 0;
557208510e1SDavid du Colombier 			x += iprint("\n");
5583e12c5d1SDavid du Colombier 		}
5593e12c5d1SDavid du Colombier 	}
5607dd7cddfSDavid du Colombier 	if(i)
561208510e1SDavid du Colombier 		iprint("\n");
562208510e1SDavid du Colombier 	iprint("EOF\n");
563208510e1SDavid du Colombier 
564208510e1SDavid du Colombier 	if(ureg->trap != VectorNMI)
565208510e1SDavid du Colombier 		return;
566208510e1SDavid du Colombier 
567208510e1SDavid du Colombier 	i = 0;
568208510e1SDavid du Colombier 	for(l = (uintptr)&l; l < estack; l += sizeof(uintptr)){
569208510e1SDavid du Colombier 		iprint("%.8p ", *(uintptr*)l);
570208510e1SDavid du Colombier 		if(++i == 8){
571208510e1SDavid du Colombier 			i = 0;
572208510e1SDavid du Colombier 			iprint("\n");
573208510e1SDavid du Colombier 		}
574208510e1SDavid du Colombier 	}
575208510e1SDavid du Colombier 	if(i)
576208510e1SDavid du Colombier 		iprint("\n");
5773e12c5d1SDavid du Colombier }
5783e12c5d1SDavid du Colombier 
5797dd7cddfSDavid du Colombier void
5807dd7cddfSDavid du Colombier dumpstack(void)
5813e12c5d1SDavid du Colombier {
5827dd7cddfSDavid du Colombier 	callwithureg(_dumpstack);
5833e12c5d1SDavid du Colombier }
5843e12c5d1SDavid du Colombier 
5857dd7cddfSDavid du Colombier static void
5867dd7cddfSDavid du Colombier debugbpt(Ureg* ureg, void*)
5873e12c5d1SDavid du Colombier {
5889a747e4fSDavid du Colombier 	char buf[ERRMAX];
5897dd7cddfSDavid du Colombier 
5907dd7cddfSDavid du Colombier 	if(up == 0)
5917dd7cddfSDavid du Colombier 		panic("kernel bpt");
5927dd7cddfSDavid du Colombier 	/* restore pc to instruction that caused the trap */
5937dd7cddfSDavid du Colombier 	ureg->pc--;
5947dd7cddfSDavid du Colombier 	sprint(buf, "sys: breakpoint");
5957dd7cddfSDavid du Colombier 	postnote(up, 1, buf, NDebug);
5967dd7cddfSDavid du Colombier }
5977dd7cddfSDavid du Colombier 
5987dd7cddfSDavid du Colombier static void
599e288d156SDavid du Colombier doublefault(Ureg*, void*)
600e288d156SDavid du Colombier {
601e288d156SDavid du Colombier 	panic("double fault");
602e288d156SDavid du Colombier }
603e288d156SDavid du Colombier 
604fe853e23SDavid du Colombier static void
605fe853e23SDavid du Colombier unexpected(Ureg* ureg, void*)
606fe853e23SDavid du Colombier {
607fe853e23SDavid du Colombier 	print("unexpected trap %lud; ignoring\n", ureg->trap);
608fe853e23SDavid du Colombier }
609e288d156SDavid du Colombier 
610e862f8a5SDavid du Colombier extern void checkpages(void);
611be704722SDavid du Colombier extern void checkfault(ulong, ulong);
612e288d156SDavid du Colombier static void
6137dd7cddfSDavid du Colombier fault386(Ureg* ureg, void*)
6147dd7cddfSDavid du Colombier {
6157dd7cddfSDavid du Colombier 	ulong addr;
6167dd7cddfSDavid du Colombier 	int read, user, n, insyscall;
6179a747e4fSDavid du Colombier 	char buf[ERRMAX];
6187dd7cddfSDavid du Colombier 
6197dd7cddfSDavid du Colombier 	addr = getcr2();
6207dd7cddfSDavid du Colombier 	read = !(ureg->ecode & 2);
6214de34a7eSDavid du Colombier 
6224de34a7eSDavid du Colombier 	user = (ureg->cs & 0xFFFF) == UESEL;
6234de34a7eSDavid du Colombier 	if(!user){
6244de34a7eSDavid du Colombier 		if(vmapsync(addr))
6254de34a7eSDavid du Colombier 			return;
6264de34a7eSDavid du Colombier 		if(addr >= USTKTOP)
6274de34a7eSDavid du Colombier 			panic("kernel fault: bad address pc=0x%.8lux addr=0x%.8lux", ureg->pc, addr);
6289a747e4fSDavid du Colombier 		if(up == nil)
6294de34a7eSDavid du Colombier 			panic("kernel fault: no user process pc=0x%.8lux addr=0x%.8lux", ureg->pc, addr);
6304de34a7eSDavid du Colombier 	}
6314de34a7eSDavid du Colombier 	if(up == nil)
6324de34a7eSDavid du Colombier 		panic("user fault: up=0 pc=0x%.8lux addr=0x%.8lux", ureg->pc, addr);
6334de34a7eSDavid du Colombier 
6347dd7cddfSDavid du Colombier 	insyscall = up->insyscall;
6357dd7cddfSDavid du Colombier 	up->insyscall = 1;
6367dd7cddfSDavid du Colombier 	n = fault(addr, read);
6377dd7cddfSDavid du Colombier 	if(n < 0){
6387dd7cddfSDavid du Colombier 		if(!user){
6397dd7cddfSDavid du Colombier 			dumpregs(ureg);
6407dd7cddfSDavid du Colombier 			panic("fault: 0x%lux\n", addr);
6417dd7cddfSDavid du Colombier 		}
642d717568cSDavid du Colombier 		checkpages();
643be704722SDavid du Colombier 		checkfault(addr, ureg->pc);
6447dd7cddfSDavid du Colombier 		sprint(buf, "sys: trap: fault %s addr=0x%lux",
6457dd7cddfSDavid du Colombier 			read ? "read" : "write", addr);
6467dd7cddfSDavid du Colombier 		postnote(up, 1, buf, NDebug);
6477dd7cddfSDavid du Colombier 	}
6487dd7cddfSDavid du Colombier 	up->insyscall = insyscall;
6493e12c5d1SDavid du Colombier }
6503e12c5d1SDavid du Colombier 
6513e12c5d1SDavid du Colombier /*
6523e12c5d1SDavid du Colombier  *  system calls
6533e12c5d1SDavid du Colombier  */
6543e12c5d1SDavid du Colombier #include "../port/systab.h"
6553e12c5d1SDavid du Colombier 
6563e12c5d1SDavid du Colombier /*
6577dd7cddfSDavid du Colombier  *  Syscall is called directly from assembler without going through trap().
6583e12c5d1SDavid du Colombier  */
6597dd7cddfSDavid du Colombier void
6607dd7cddfSDavid du Colombier syscall(Ureg* ureg)
6613e12c5d1SDavid du Colombier {
6629a747e4fSDavid du Colombier 	char *e;
6633e12c5d1SDavid du Colombier 	ulong	sp;
6643e12c5d1SDavid du Colombier 	long	ret;
665e288d156SDavid du Colombier 	int	i, s;
6669a747e4fSDavid du Colombier 	ulong scallnr;
6673e12c5d1SDavid du Colombier 
6687dd7cddfSDavid du Colombier 	if((ureg->cs & 0xFFFF) != UESEL)
6699a747e4fSDavid du Colombier 		panic("syscall: cs 0x%4.4luX\n", ureg->cs);
670219b2ee8SDavid du Colombier 
671e288d156SDavid du Colombier 	cycles(&up->kentry);
672e288d156SDavid du Colombier 
6737dd7cddfSDavid du Colombier 	m->syscall++;
6747dd7cddfSDavid du Colombier 	up->insyscall = 1;
6757dd7cddfSDavid du Colombier 	up->pc = ureg->pc;
6767dd7cddfSDavid du Colombier 	up->dbgreg = ureg;
6773e12c5d1SDavid du Colombier 
678e288d156SDavid du Colombier 	if(up->procctl == Proc_tracesyscall){
679e288d156SDavid du Colombier 		up->procctl = Proc_stopme;
680e288d156SDavid du Colombier 		procctl(up);
681e288d156SDavid du Colombier 	}
682e288d156SDavid du Colombier 
6837dd7cddfSDavid du Colombier 	scallnr = ureg->ax;
6847dd7cddfSDavid du Colombier 	up->scallnr = scallnr;
6857dd7cddfSDavid du Colombier 	if(scallnr == RFORK && up->fpstate == FPactive){
6867dd7cddfSDavid du Colombier 		fpsave(&up->fpsave);
6877dd7cddfSDavid du Colombier 		up->fpstate = FPinactive;
6883e12c5d1SDavid du Colombier 	}
6893e12c5d1SDavid du Colombier 	spllo();
6907dd7cddfSDavid du Colombier 
6917dd7cddfSDavid du Colombier 	sp = ureg->usp;
6927dd7cddfSDavid du Colombier 	up->nerrlab = 0;
6933e12c5d1SDavid du Colombier 	ret = -1;
6943e12c5d1SDavid du Colombier 	if(!waserror()){
6959a747e4fSDavid du Colombier 		if(scallnr >= nsyscall || systab[scallnr] == 0){
6967dd7cddfSDavid du Colombier 			pprint("bad sys call number %d pc %lux\n",
6977dd7cddfSDavid du Colombier 				scallnr, ureg->pc);
6987dd7cddfSDavid du Colombier 			postnote(up, 1, "sys: bad sys call", NDebug);
6993e12c5d1SDavid du Colombier 			error(Ebadarg);
7003e12c5d1SDavid du Colombier 		}
7013e12c5d1SDavid du Colombier 
7027dd7cddfSDavid du Colombier 		if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)-BY2WD))
7037dd7cddfSDavid du Colombier 			validaddr(sp, sizeof(Sargs)+BY2WD, 0);
7043e12c5d1SDavid du Colombier 
7057dd7cddfSDavid du Colombier 		up->s = *((Sargs*)(sp+BY2WD));
7067dd7cddfSDavid du Colombier 		up->psstate = sysctab[scallnr];
7073e12c5d1SDavid du Colombier 
7087dd7cddfSDavid du Colombier 		ret = systab[scallnr](up->s.args);
7093e12c5d1SDavid du Colombier 		poperror();
7109a747e4fSDavid du Colombier 	}else{
7119a747e4fSDavid du Colombier 		/* failure: save the error buffer for errstr */
7129a747e4fSDavid du Colombier 		e = up->syserrstr;
7139a747e4fSDavid du Colombier 		up->syserrstr = up->errstr;
7149a747e4fSDavid du Colombier 		up->errstr = e;
71503172982SDavid du Colombier 		if(0 && up->pid == 1)
71603172982SDavid du Colombier 			print("syscall %lud error %s\n", scallnr, up->syserrstr);
7173e12c5d1SDavid du Colombier 	}
7187dd7cddfSDavid du Colombier 	if(up->nerrlab){
719e288d156SDavid du Colombier 		print("bad errstack [%lud]: %d extra\n", scallnr, up->nerrlab);
7203e12c5d1SDavid du Colombier 		for(i = 0; i < NERR; i++)
7217dd7cddfSDavid du Colombier 			print("sp=%lux pc=%lux\n",
7227dd7cddfSDavid du Colombier 				up->errlab[i].sp, up->errlab[i].pc);
7233e12c5d1SDavid du Colombier 		panic("error stack");
7243e12c5d1SDavid du Colombier 	}
7253e12c5d1SDavid du Colombier 
7263e12c5d1SDavid du Colombier 	/*
7277dd7cddfSDavid du Colombier 	 *  Put return value in frame.  On the x86 the syscall is
7283e12c5d1SDavid du Colombier 	 *  just another trap and the return value from syscall is
7293e12c5d1SDavid du Colombier 	 *  ignored.  On other machines the return value is put into
7303e12c5d1SDavid du Colombier 	 *  the results register by caller of syscall.
7313e12c5d1SDavid du Colombier 	 */
7327dd7cddfSDavid du Colombier 	ureg->ax = ret;
7333e12c5d1SDavid du Colombier 
734e288d156SDavid du Colombier 	if(up->procctl == Proc_tracesyscall){
735e288d156SDavid du Colombier 		up->procctl = Proc_stopme;
736e288d156SDavid du Colombier 		s = splhi();
737e288d156SDavid du Colombier 		procctl(up);
738e288d156SDavid du Colombier 		splx(s);
739e288d156SDavid du Colombier 	}
740e288d156SDavid du Colombier 
741e288d156SDavid du Colombier 	up->insyscall = 0;
742e288d156SDavid du Colombier 	up->psstate = 0;
743e288d156SDavid du Colombier 
7447dd7cddfSDavid du Colombier 	if(scallnr == NOTED)
7457dd7cddfSDavid du Colombier 		noted(ureg, *(ulong*)(sp+BY2WD));
7463e12c5d1SDavid du Colombier 
7477dd7cddfSDavid du Colombier 	if(scallnr!=RFORK && (up->procctl || up->nnote)){
7487dd7cddfSDavid du Colombier 		splhi();
7497dd7cddfSDavid du Colombier 		notify(ureg);
7507dd7cddfSDavid du Colombier 	}
751e288d156SDavid du Colombier 	/* if we delayed sched because we held a lock, sched now */
752e288d156SDavid du Colombier 	if(up->delaysched)
753e288d156SDavid du Colombier 		sched();
754e288d156SDavid du Colombier 	kexit(ureg);
7553e12c5d1SDavid du Colombier }
7563e12c5d1SDavid du Colombier 
7573e12c5d1SDavid du Colombier /*
7583e12c5d1SDavid du Colombier  *  Call user, if necessary, with note.
7593e12c5d1SDavid du Colombier  *  Pass user the Ureg struct and the note on his stack.
7603e12c5d1SDavid du Colombier  */
7613e12c5d1SDavid du Colombier int
7627dd7cddfSDavid du Colombier notify(Ureg* ureg)
7633e12c5d1SDavid du Colombier {
764219b2ee8SDavid du Colombier 	int l;
7653e12c5d1SDavid du Colombier 	ulong s, sp;
7663e12c5d1SDavid du Colombier 	Note *n;
7673e12c5d1SDavid du Colombier 
7687dd7cddfSDavid du Colombier 	if(up->procctl)
7697dd7cddfSDavid du Colombier 		procctl(up);
7707dd7cddfSDavid du Colombier 	if(up->nnote == 0)
7713e12c5d1SDavid du Colombier 		return 0;
7723e12c5d1SDavid du Colombier 
7733ff48bf5SDavid du Colombier 	if(up->fpstate == FPactive){
7743ff48bf5SDavid du Colombier 		fpsave(&up->fpsave);
7753ff48bf5SDavid du Colombier 		up->fpstate = FPinactive;
7763ff48bf5SDavid du Colombier 	}
7773ff48bf5SDavid du Colombier 	up->fpstate |= FPillegal;
7783ff48bf5SDavid du Colombier 
7793e12c5d1SDavid du Colombier 	s = spllo();
7807dd7cddfSDavid du Colombier 	qlock(&up->debug);
7817dd7cddfSDavid du Colombier 	up->notepending = 0;
7827dd7cddfSDavid du Colombier 	n = &up->note[0];
7833e12c5d1SDavid du Colombier 	if(strncmp(n->msg, "sys:", 4) == 0){
7843e12c5d1SDavid du Colombier 		l = strlen(n->msg);
7859a747e4fSDavid du Colombier 		if(l > ERRMAX-15)	/* " pc=0x12345678\0" */
7869a747e4fSDavid du Colombier 			l = ERRMAX-15;
7877dd7cddfSDavid du Colombier 		sprint(n->msg+l, " pc=0x%.8lux", ureg->pc);
7883e12c5d1SDavid du Colombier 	}
789219b2ee8SDavid du Colombier 
7907dd7cddfSDavid du Colombier 	if(n->flag!=NUser && (up->notified || up->notify==0)){
7917dd7cddfSDavid du Colombier 		if(n->flag == NDebug)
7923e12c5d1SDavid du Colombier 			pprint("suicide: %s\n", n->msg);
7937dd7cddfSDavid du Colombier 		qunlock(&up->debug);
7943e12c5d1SDavid du Colombier 		pexit(n->msg, n->flag!=NDebug);
7953e12c5d1SDavid du Colombier 	}
796219b2ee8SDavid du Colombier 
7977dd7cddfSDavid du Colombier 	if(up->notified){
7987dd7cddfSDavid du Colombier 		qunlock(&up->debug);
799219b2ee8SDavid du Colombier 		splhi();
800219b2ee8SDavid du Colombier 		return 0;
801219b2ee8SDavid du Colombier 	}
802219b2ee8SDavid du Colombier 
8037dd7cddfSDavid du Colombier 	if(!up->notify){
8047dd7cddfSDavid du Colombier 		qunlock(&up->debug);
805bd389b36SDavid du Colombier 		pexit(n->msg, n->flag!=NDebug);
806bd389b36SDavid du Colombier 	}
8077dd7cddfSDavid du Colombier 	sp = ureg->usp;
808208510e1SDavid du Colombier 	sp -= 256;	/* debugging: preserve context causing problem */
8093e12c5d1SDavid du Colombier 	sp -= sizeof(Ureg);
810208510e1SDavid du Colombier if(0) print("%s %lud: notify %.8lux %.8lux %.8lux %s\n",
811208510e1SDavid du Colombier 	up->text, up->pid, ureg->pc, ureg->usp, sp, n->msg);
812219b2ee8SDavid du Colombier 
8137dd7cddfSDavid du Colombier 	if(!okaddr((ulong)up->notify, 1, 0)
8149a747e4fSDavid du Colombier 	|| !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)){
815219b2ee8SDavid du Colombier 		pprint("suicide: bad address in notify\n");
8167dd7cddfSDavid du Colombier 		qunlock(&up->debug);
8173e12c5d1SDavid du Colombier 		pexit("Suicide", 0);
8183e12c5d1SDavid du Colombier 	}
819219b2ee8SDavid du Colombier 
8207dd7cddfSDavid du Colombier 	up->ureg = (void*)sp;
8217dd7cddfSDavid du Colombier 	memmove((Ureg*)sp, ureg, sizeof(Ureg));
8227dd7cddfSDavid du Colombier 	*(Ureg**)(sp-BY2WD) = up->ureg;	/* word under Ureg is old up->ureg */
8237dd7cddfSDavid du Colombier 	up->ureg = (void*)sp;
8249a747e4fSDavid du Colombier 	sp -= BY2WD+ERRMAX;
8259a747e4fSDavid du Colombier 	memmove((char*)sp, up->note[0].msg, ERRMAX);
8263e12c5d1SDavid du Colombier 	sp -= 3*BY2WD;
8273e12c5d1SDavid du Colombier 	*(ulong*)(sp+2*BY2WD) = sp+3*BY2WD;		/* arg 2 is string */
8287dd7cddfSDavid du Colombier 	*(ulong*)(sp+1*BY2WD) = (ulong)up->ureg;	/* arg 1 is ureg* */
8293e12c5d1SDavid du Colombier 	*(ulong*)(sp+0*BY2WD) = 0;			/* arg 0 is pc */
8307dd7cddfSDavid du Colombier 	ureg->usp = sp;
8317dd7cddfSDavid du Colombier 	ureg->pc = (ulong)up->notify;
8327dd7cddfSDavid du Colombier 	up->notified = 1;
8337dd7cddfSDavid du Colombier 	up->nnote--;
8347dd7cddfSDavid du Colombier 	memmove(&up->lastnote, &up->note[0], sizeof(Note));
8357dd7cddfSDavid du Colombier 	memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note));
836219b2ee8SDavid du Colombier 
8377dd7cddfSDavid du Colombier 	qunlock(&up->debug);
8383e12c5d1SDavid du Colombier 	splx(s);
839219b2ee8SDavid du Colombier 	return 1;
8403e12c5d1SDavid du Colombier }
8413e12c5d1SDavid du Colombier 
8423e12c5d1SDavid du Colombier /*
8433e12c5d1SDavid du Colombier  *   Return user to state before notify()
8443e12c5d1SDavid du Colombier  */
8453e12c5d1SDavid du Colombier void
8467dd7cddfSDavid du Colombier noted(Ureg* ureg, ulong arg0)
8473e12c5d1SDavid du Colombier {
8487dd7cddfSDavid du Colombier 	Ureg *nureg;
849219b2ee8SDavid du Colombier 	ulong oureg, sp;
8503e12c5d1SDavid du Colombier 
8517dd7cddfSDavid du Colombier 	qlock(&up->debug);
8527dd7cddfSDavid du Colombier 	if(arg0!=NRSTR && !up->notified) {
8537dd7cddfSDavid du Colombier 		qunlock(&up->debug);
854219b2ee8SDavid du Colombier 		pprint("call to noted() when not notified\n");
8553e12c5d1SDavid du Colombier 		pexit("Suicide", 0);
8563e12c5d1SDavid du Colombier 	}
8577dd7cddfSDavid du Colombier 	up->notified = 0;
858219b2ee8SDavid du Colombier 
8597dd7cddfSDavid du Colombier 	nureg = up->ureg;	/* pointer to user returned Ureg struct */
860219b2ee8SDavid du Colombier 
8613ff48bf5SDavid du Colombier 	up->fpstate &= ~FPillegal;
8623ff48bf5SDavid du Colombier 
863219b2ee8SDavid du Colombier 	/* sanity clause */
8647dd7cddfSDavid du Colombier 	oureg = (ulong)nureg;
865219b2ee8SDavid du Colombier 	if(!okaddr((ulong)oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){
8667dd7cddfSDavid du Colombier 		pprint("bad ureg in noted or call to noted when not notified\n");
8677dd7cddfSDavid du Colombier 		qunlock(&up->debug);
868219b2ee8SDavid du Colombier 		pexit("Suicide", 0);
869219b2ee8SDavid du Colombier 	}
870219b2ee8SDavid du Colombier 
8717dd7cddfSDavid du Colombier 	/*
8727dd7cddfSDavid du Colombier 	 * Check the segment selectors are all valid, otherwise
8737dd7cddfSDavid du Colombier 	 * a fault will be taken on attempting to return to the
8747dd7cddfSDavid du Colombier 	 * user process.
8757dd7cddfSDavid du Colombier 	 * Take care with the comparisons as different processor
8767dd7cddfSDavid du Colombier 	 * generations push segment descriptors in different ways.
8777dd7cddfSDavid du Colombier 	 */
8787dd7cddfSDavid du Colombier 	if((nureg->cs & 0xFFFF) != UESEL || (nureg->ss & 0xFFFF) != UDSEL
8797dd7cddfSDavid du Colombier 	  || (nureg->ds & 0xFFFF) != UDSEL || (nureg->es & 0xFFFF) != UDSEL
8807dd7cddfSDavid du Colombier 	  || (nureg->fs & 0xFFFF) != UDSEL || (nureg->gs & 0xFFFF) != UDSEL){
8817dd7cddfSDavid du Colombier 		pprint("bad segment selector in noted\n");
8827dd7cddfSDavid du Colombier 		qunlock(&up->debug);
8837dd7cddfSDavid du Colombier 		pexit("Suicide", 0);
8847dd7cddfSDavid du Colombier 	}
885219b2ee8SDavid du Colombier 
886219b2ee8SDavid du Colombier 	/* don't let user change system flags */
8877dd7cddfSDavid du Colombier 	nureg->flags = (ureg->flags & ~0xCD5) | (nureg->flags & 0xCD5);
888219b2ee8SDavid du Colombier 
8897dd7cddfSDavid du Colombier 	memmove(ureg, nureg, sizeof(Ureg));
890219b2ee8SDavid du Colombier 
8913e12c5d1SDavid du Colombier 	switch(arg0){
8923e12c5d1SDavid du Colombier 	case NCONT:
893219b2ee8SDavid du Colombier 	case NRSTR:
894208510e1SDavid du Colombier if(0) print("%s %lud: noted %.8lux %.8lux\n",
895208510e1SDavid du Colombier 	up->text, up->pid, nureg->pc, nureg->usp);
8967dd7cddfSDavid du Colombier 		if(!okaddr(nureg->pc, 1, 0) || !okaddr(nureg->usp, BY2WD, 0)){
8977dd7cddfSDavid du Colombier 			qunlock(&up->debug);
898219b2ee8SDavid du Colombier 			pprint("suicide: trap in noted\n");
899219b2ee8SDavid du Colombier 			pexit("Suicide", 0);
900219b2ee8SDavid du Colombier 		}
9017dd7cddfSDavid du Colombier 		up->ureg = (Ureg*)(*(ulong*)(oureg-BY2WD));
9027dd7cddfSDavid du Colombier 		qunlock(&up->debug);
903219b2ee8SDavid du Colombier 		break;
904219b2ee8SDavid du Colombier 
905219b2ee8SDavid du Colombier 	case NSAVE:
9067dd7cddfSDavid du Colombier 		if(!okaddr(nureg->pc, BY2WD, 0)
9077dd7cddfSDavid du Colombier 		|| !okaddr(nureg->usp, BY2WD, 0)){
9087dd7cddfSDavid du Colombier 			qunlock(&up->debug);
909219b2ee8SDavid du Colombier 			pprint("suicide: trap in noted\n");
910219b2ee8SDavid du Colombier 			pexit("Suicide", 0);
9113e12c5d1SDavid du Colombier 		}
9127dd7cddfSDavid du Colombier 		qunlock(&up->debug);
9139a747e4fSDavid du Colombier 		sp = oureg-4*BY2WD-ERRMAX;
914219b2ee8SDavid du Colombier 		splhi();
9157dd7cddfSDavid du Colombier 		ureg->sp = sp;
916219b2ee8SDavid du Colombier 		((ulong*)sp)[1] = oureg;	/* arg 1 0(FP) is ureg* */
917219b2ee8SDavid du Colombier 		((ulong*)sp)[0] = 0;		/* arg 0 is pc */
918219b2ee8SDavid du Colombier 		break;
9193e12c5d1SDavid du Colombier 
9203e12c5d1SDavid du Colombier 	default:
921219b2ee8SDavid du Colombier 		pprint("unknown noted arg 0x%lux\n", arg0);
9227dd7cddfSDavid du Colombier 		up->lastnote.flag = NDebug;
9237dd7cddfSDavid du Colombier 		/* fall through */
9243e12c5d1SDavid du Colombier 
9253e12c5d1SDavid du Colombier 	case NDFLT:
9267dd7cddfSDavid du Colombier 		if(up->lastnote.flag == NDebug){
9277dd7cddfSDavid du Colombier 			qunlock(&up->debug);
9287dd7cddfSDavid du Colombier 			pprint("suicide: %s\n", up->lastnote.msg);
929219b2ee8SDavid du Colombier 		} else
9307dd7cddfSDavid du Colombier 			qunlock(&up->debug);
9317dd7cddfSDavid du Colombier 		pexit(up->lastnote.msg, up->lastnote.flag!=NDebug);
9323e12c5d1SDavid du Colombier 	}
9333e12c5d1SDavid du Colombier }
9343e12c5d1SDavid du Colombier 
9357dd7cddfSDavid du Colombier long
9367dd7cddfSDavid du Colombier execregs(ulong entry, ulong ssize, ulong nargs)
9377dd7cddfSDavid du Colombier {
9387dd7cddfSDavid du Colombier 	ulong *sp;
9397dd7cddfSDavid du Colombier 	Ureg *ureg;
9407dd7cddfSDavid du Colombier 
9414de34a7eSDavid du Colombier 	up->fpstate = FPinit;
9424de34a7eSDavid du Colombier 	fpoff();
9434de34a7eSDavid du Colombier 
9447dd7cddfSDavid du Colombier 	sp = (ulong*)(USTKTOP - ssize);
9457dd7cddfSDavid du Colombier 	*--sp = nargs;
9467dd7cddfSDavid du Colombier 
9477dd7cddfSDavid du Colombier 	ureg = up->dbgreg;
9487dd7cddfSDavid du Colombier 	ureg->usp = (ulong)sp;
9497dd7cddfSDavid du Colombier 	ureg->pc = entry;
950e288d156SDavid du Colombier 	return USTKTOP-sizeof(Tos);		/* address of kernel/user shared data */
9517dd7cddfSDavid du Colombier }
9527dd7cddfSDavid du Colombier 
95359cc4ca5SDavid du Colombier /*
95459cc4ca5SDavid du Colombier  *  return the userpc the last exception happened at
95559cc4ca5SDavid du Colombier  */
9567dd7cddfSDavid du Colombier ulong
9577dd7cddfSDavid du Colombier userpc(void)
9587dd7cddfSDavid du Colombier {
9597dd7cddfSDavid du Colombier 	Ureg *ureg;
9607dd7cddfSDavid du Colombier 
9617dd7cddfSDavid du Colombier 	ureg = (Ureg*)up->dbgreg;
9627dd7cddfSDavid du Colombier 	return ureg->pc;
9637dd7cddfSDavid du Colombier }
9647dd7cddfSDavid du Colombier 
9657dd7cddfSDavid du Colombier /* This routine must save the values of registers the user is not permitted
9667dd7cddfSDavid du Colombier  * to write from devproc and then restore the saved values before returning.
9673e12c5d1SDavid du Colombier  */
9683e12c5d1SDavid du Colombier void
9697dd7cddfSDavid du Colombier setregisters(Ureg* ureg, char* pureg, char* uva, int n)
9703e12c5d1SDavid du Colombier {
9713e12c5d1SDavid du Colombier 	ulong flags;
9723e12c5d1SDavid du Colombier 	ulong cs;
9733e12c5d1SDavid du Colombier 	ulong ss;
9743e12c5d1SDavid du Colombier 
9757dd7cddfSDavid du Colombier 	flags = ureg->flags;
9767dd7cddfSDavid du Colombier 	cs = ureg->cs;
9777dd7cddfSDavid du Colombier 	ss = ureg->ss;
9783e12c5d1SDavid du Colombier 	memmove(pureg, uva, n);
9797dd7cddfSDavid du Colombier 	ureg->flags = (ureg->flags & 0x00FF) | (flags & 0xFF00);
9807dd7cddfSDavid du Colombier 	ureg->cs = cs;
9817dd7cddfSDavid du Colombier 	ureg->ss = ss;
9827dd7cddfSDavid du Colombier }
9837dd7cddfSDavid du Colombier 
9847dd7cddfSDavid du Colombier static void
9857dd7cddfSDavid du Colombier linkproc(void)
9867dd7cddfSDavid du Colombier {
9877dd7cddfSDavid du Colombier 	spllo();
9887dd7cddfSDavid du Colombier 	up->kpfun(up->kparg);
9893ff48bf5SDavid du Colombier 	pexit("kproc dying", 0);
9907dd7cddfSDavid du Colombier }
9917dd7cddfSDavid du Colombier 
9927dd7cddfSDavid du Colombier void
9937dd7cddfSDavid du Colombier kprocchild(Proc* p, void (*func)(void*), void* arg)
9947dd7cddfSDavid du Colombier {
9957dd7cddfSDavid du Colombier 	/*
9967dd7cddfSDavid du Colombier 	 * gotolabel() needs a word on the stack in
9977dd7cddfSDavid du Colombier 	 * which to place the return PC used to jump
9987dd7cddfSDavid du Colombier 	 * to linkproc().
9997dd7cddfSDavid du Colombier 	 */
10007dd7cddfSDavid du Colombier 	p->sched.pc = (ulong)linkproc;
10017dd7cddfSDavid du Colombier 	p->sched.sp = (ulong)p->kstack+KSTACK-BY2WD;
10027dd7cddfSDavid du Colombier 
10037dd7cddfSDavid du Colombier 	p->kpfun = func;
10047dd7cddfSDavid du Colombier 	p->kparg = arg;
10057dd7cddfSDavid du Colombier }
10067dd7cddfSDavid du Colombier 
10077dd7cddfSDavid du Colombier void
10087dd7cddfSDavid du Colombier forkchild(Proc *p, Ureg *ureg)
10097dd7cddfSDavid du Colombier {
10107dd7cddfSDavid du Colombier 	Ureg *cureg;
10117dd7cddfSDavid du Colombier 
10127dd7cddfSDavid du Colombier 	/*
10137dd7cddfSDavid du Colombier 	 * Add 2*BY2WD to the stack to account for
10147dd7cddfSDavid du Colombier 	 *  - the return PC
10157dd7cddfSDavid du Colombier 	 *  - trap's argument (ur)
10167dd7cddfSDavid du Colombier 	 */
10177dd7cddfSDavid du Colombier 	p->sched.sp = (ulong)p->kstack+KSTACK-(sizeof(Ureg)+2*BY2WD);
10187dd7cddfSDavid du Colombier 	p->sched.pc = (ulong)forkret;
10197dd7cddfSDavid du Colombier 
10207dd7cddfSDavid du Colombier 	cureg = (Ureg*)(p->sched.sp+2*BY2WD);
10217dd7cddfSDavid du Colombier 	memmove(cureg, ureg, sizeof(Ureg));
10227dd7cddfSDavid du Colombier 	/* return value of syscall in child */
10237dd7cddfSDavid du Colombier 	cureg->ax = 0;
10247dd7cddfSDavid du Colombier 
10257dd7cddfSDavid du Colombier 	/* Things from bottom of syscall which were never executed */
10267dd7cddfSDavid du Colombier 	p->psstate = 0;
10277dd7cddfSDavid du Colombier 	p->insyscall = 0;
10287dd7cddfSDavid du Colombier }
10297dd7cddfSDavid du Colombier 
10307dd7cddfSDavid du Colombier /* Give enough context in the ureg to produce a kernel stack for
10317dd7cddfSDavid du Colombier  * a sleeping process
10327dd7cddfSDavid du Colombier  */
10337dd7cddfSDavid du Colombier void
10347dd7cddfSDavid du Colombier setkernur(Ureg* ureg, Proc* p)
10357dd7cddfSDavid du Colombier {
10367dd7cddfSDavid du Colombier 	ureg->pc = p->sched.pc;
10377dd7cddfSDavid du Colombier 	ureg->sp = p->sched.sp+4;
10387dd7cddfSDavid du Colombier }
10397dd7cddfSDavid du Colombier 
10407dd7cddfSDavid du Colombier ulong
10417dd7cddfSDavid du Colombier dbgpc(Proc *p)
10427dd7cddfSDavid du Colombier {
10437dd7cddfSDavid du Colombier 	Ureg *ureg;
10447dd7cddfSDavid du Colombier 
10457dd7cddfSDavid du Colombier 	ureg = p->dbgreg;
10467dd7cddfSDavid du Colombier 	if(ureg == 0)
10477dd7cddfSDavid du Colombier 		return 0;
10487dd7cddfSDavid du Colombier 
10497dd7cddfSDavid du Colombier 	return ureg->pc;
10503e12c5d1SDavid du Colombier }
1051