xref: /plan9-contrib/sys/src/9/loongson/trap.c (revision a81c3ea0c7f009a3088ab7fe55ea9013d9d77a74)
1*a81c3ea0SDavid du Colombier #include	"u.h"
2*a81c3ea0SDavid du Colombier #include	"../port/lib.h"
3*a81c3ea0SDavid du Colombier #include	"mem.h"
4*a81c3ea0SDavid du Colombier #include	"dat.h"
5*a81c3ea0SDavid du Colombier #include	"fns.h"
6*a81c3ea0SDavid du Colombier #include	"ureg.h"
7*a81c3ea0SDavid du Colombier #include	"io.h"
8*a81c3ea0SDavid du Colombier #include	<tos.h>
9*a81c3ea0SDavid du Colombier #include	"../port/error.h"
10*a81c3ea0SDavid du Colombier 
11*a81c3ea0SDavid du Colombier #define setstatus(v)	/* experiment: delete this to enable recursive traps */
12*a81c3ea0SDavid du Colombier 
13*a81c3ea0SDavid du Colombier typedef struct Handler Handler;
14*a81c3ea0SDavid du Colombier 
15*a81c3ea0SDavid du Colombier struct Handler {
16*a81c3ea0SDavid du Colombier 	void	(*handler)(Ureg*, void*);
17*a81c3ea0SDavid du Colombier 	void	*arg;
18*a81c3ea0SDavid du Colombier 	Handler	*next;			/* at this interrupt level */
19*a81c3ea0SDavid du Colombier 	ulong	intrs;
20*a81c3ea0SDavid du Colombier };
21*a81c3ea0SDavid du Colombier 
22*a81c3ea0SDavid du Colombier ulong offintrs;
23*a81c3ea0SDavid du Colombier ulong intrcauses[ILmax+1];
24*a81c3ea0SDavid du Colombier 
25*a81c3ea0SDavid du Colombier int	intr(Ureg*);
26*a81c3ea0SDavid du Colombier void	kernfault(Ureg*, int);
27*a81c3ea0SDavid du Colombier void	noted(Ureg*, Ureg**, ulong);
28*a81c3ea0SDavid du Colombier void	rfnote(Ureg**);
29*a81c3ea0SDavid du Colombier 
30*a81c3ea0SDavid du Colombier char *excname[] =
31*a81c3ea0SDavid du Colombier {
32*a81c3ea0SDavid du Colombier 	"trap: external interrupt",
33*a81c3ea0SDavid du Colombier 	"trap: TLB modification (store to unwritable)",
34*a81c3ea0SDavid du Colombier 	"trap: TLB miss (load or fetch)",
35*a81c3ea0SDavid du Colombier 	"trap: TLB miss (store)",
36*a81c3ea0SDavid du Colombier 	"trap: address error (load or fetch)",
37*a81c3ea0SDavid du Colombier 	"trap: address error (store)",
38*a81c3ea0SDavid du Colombier 	"trap: bus error (fetch)",
39*a81c3ea0SDavid du Colombier 	"trap: bus error (data load or store)",
40*a81c3ea0SDavid du Colombier 	"trap: system call",
41*a81c3ea0SDavid du Colombier 	"breakpoint",
42*a81c3ea0SDavid du Colombier 	"trap: reserved instruction",
43*a81c3ea0SDavid du Colombier 	"trap: coprocessor unusable",
44*a81c3ea0SDavid du Colombier 	"trap: arithmetic overflow",
45*a81c3ea0SDavid du Colombier 	"trap: TRAP exception",
46*a81c3ea0SDavid du Colombier 	"trap: VCE (instruction)",
47*a81c3ea0SDavid du Colombier 	"trap: floating-point exception",
48*a81c3ea0SDavid du Colombier 	"trap: coprocessor 2 implementation-specific", /* used as sys call for debugger */
49*a81c3ea0SDavid du Colombier 	"trap: corextend unusable",
50*a81c3ea0SDavid du Colombier 	"trap: precise coprocessor 2 exception",
51*a81c3ea0SDavid du Colombier 	"trap: TLB read-inhibit",
52*a81c3ea0SDavid du Colombier 	"trap: TLB execute-inhibit",
53*a81c3ea0SDavid du Colombier 	"trap: undefined 21",
54*a81c3ea0SDavid du Colombier 	"trap: undefined 22",
55*a81c3ea0SDavid du Colombier 	"trap: WATCH exception",
56*a81c3ea0SDavid du Colombier 	"trap: machine checkcore",
57*a81c3ea0SDavid du Colombier 	"trap: undefined 25",
58*a81c3ea0SDavid du Colombier 	"trap: undefined 26",
59*a81c3ea0SDavid du Colombier 	"trap: undefined 27",
60*a81c3ea0SDavid du Colombier 	"trap: undefined 28",
61*a81c3ea0SDavid du Colombier 	"trap: undefined 29",
62*a81c3ea0SDavid du Colombier 	"trap: cache error",
63*a81c3ea0SDavid du Colombier 	"trap: VCE (data)",
64*a81c3ea0SDavid du Colombier };
65*a81c3ea0SDavid du Colombier 
66*a81c3ea0SDavid du Colombier char *fpcause[] =
67*a81c3ea0SDavid du Colombier {
68*a81c3ea0SDavid du Colombier 	"inexact operation",
69*a81c3ea0SDavid du Colombier 	"underflow",
70*a81c3ea0SDavid du Colombier 	"overflow",
71*a81c3ea0SDavid du Colombier 	"division by zero",
72*a81c3ea0SDavid du Colombier 	"invalid operation",
73*a81c3ea0SDavid du Colombier };
74*a81c3ea0SDavid du Colombier 
75*a81c3ea0SDavid du Colombier struct {
76*a81c3ea0SDavid du Colombier 	char	*name;
77*a81c3ea0SDavid du Colombier 	uint	off;
78*a81c3ea0SDavid du Colombier } regname[] = {
79*a81c3ea0SDavid du Colombier 	"STATUS", Ureg_status,
80*a81c3ea0SDavid du Colombier 	"PC",	Ureg_pc,
81*a81c3ea0SDavid du Colombier 	"SP",	Ureg_sp,
82*a81c3ea0SDavid du Colombier 	"CAUSE",Ureg_cause,
83*a81c3ea0SDavid du Colombier 	"BADADDR", Ureg_badvaddr,
84*a81c3ea0SDavid du Colombier 	"TLBVIRT", Ureg_tlbvirt,
85*a81c3ea0SDavid du Colombier 	"HI",	Ureg_hi,
86*a81c3ea0SDavid du Colombier 	"LO",	Ureg_lo,
87*a81c3ea0SDavid du Colombier 	"R31",	Ureg_r31,
88*a81c3ea0SDavid du Colombier 	"R30",	Ureg_r30,
89*a81c3ea0SDavid du Colombier 	"R28",	Ureg_r28,
90*a81c3ea0SDavid du Colombier 	"R27",	Ureg_r27,
91*a81c3ea0SDavid du Colombier 	"R26",	Ureg_r26,
92*a81c3ea0SDavid du Colombier 	"R25",	Ureg_r25,
93*a81c3ea0SDavid du Colombier 	"R24",	Ureg_r24,
94*a81c3ea0SDavid du Colombier 	"R23",	Ureg_r23,
95*a81c3ea0SDavid du Colombier 	"R22",	Ureg_r22,
96*a81c3ea0SDavid du Colombier 	"R21",	Ureg_r21,
97*a81c3ea0SDavid du Colombier 	"R20",	Ureg_r20,
98*a81c3ea0SDavid du Colombier 	"R19",	Ureg_r19,
99*a81c3ea0SDavid du Colombier 	"R18",	Ureg_r18,
100*a81c3ea0SDavid du Colombier 	"R17",	Ureg_r17,
101*a81c3ea0SDavid du Colombier 	"R16",	Ureg_r16,
102*a81c3ea0SDavid du Colombier 	"R15",	Ureg_r15,
103*a81c3ea0SDavid du Colombier 	"R14",	Ureg_r14,
104*a81c3ea0SDavid du Colombier 	"R13",	Ureg_r13,
105*a81c3ea0SDavid du Colombier 	"R12",	Ureg_r12,
106*a81c3ea0SDavid du Colombier 	"R11",	Ureg_r11,
107*a81c3ea0SDavid du Colombier 	"R10",	Ureg_r10,
108*a81c3ea0SDavid du Colombier 	"R9",	Ureg_r9,
109*a81c3ea0SDavid du Colombier 	"R8",	Ureg_r8,
110*a81c3ea0SDavid du Colombier 	"R7",	Ureg_r7,
111*a81c3ea0SDavid du Colombier 	"R6",	Ureg_r6,
112*a81c3ea0SDavid du Colombier 	"R5",	Ureg_r5,
113*a81c3ea0SDavid du Colombier 	"R4",	Ureg_r4,
114*a81c3ea0SDavid du Colombier 	"R3",	Ureg_r3,
115*a81c3ea0SDavid du Colombier 	"R2",	Ureg_r2,
116*a81c3ea0SDavid du Colombier 	"R1",	Ureg_r1,
117*a81c3ea0SDavid du Colombier };
118*a81c3ea0SDavid du Colombier 
119*a81c3ea0SDavid du Colombier static Lock intrlock;
120*a81c3ea0SDavid du Colombier static Handler handlers[ILmax+1];
121*a81c3ea0SDavid du Colombier static ulong pciintrmask;
122*a81c3ea0SDavid du Colombier static ulong i8259intrmask;
123*a81c3ea0SDavid du Colombier 
124*a81c3ea0SDavid du Colombier static char *
ptlb(ulong phys)125*a81c3ea0SDavid du Colombier ptlb(ulong phys)
126*a81c3ea0SDavid du Colombier {
127*a81c3ea0SDavid du Colombier 	static char buf[4][32];
128*a81c3ea0SDavid du Colombier 	static int k;
129*a81c3ea0SDavid du Colombier 	char *p;
130*a81c3ea0SDavid du Colombier 
131*a81c3ea0SDavid du Colombier 	k = (k+1)&3;
132*a81c3ea0SDavid du Colombier 	p = buf[k];
133*a81c3ea0SDavid du Colombier 	p += snprint(p, sizeof buf[k] - (p - buf[k]), "(%#lux %lud ",
134*a81c3ea0SDavid du Colombier 		(phys<<6) & ~(BY2PG-1), (phys>>3)&7);
135*a81c3ea0SDavid du Colombier 	if(phys & 4)
136*a81c3ea0SDavid du Colombier 		*p++ = 'd';
137*a81c3ea0SDavid du Colombier 	if(phys & 2)
138*a81c3ea0SDavid du Colombier 		*p++ = 'v';
139*a81c3ea0SDavid du Colombier 	if(phys & 1)
140*a81c3ea0SDavid du Colombier 		*p++ = 'g';
141*a81c3ea0SDavid du Colombier 	*p++ = ')';
142*a81c3ea0SDavid du Colombier 	*p = 0;
143*a81c3ea0SDavid du Colombier 	return buf[k];
144*a81c3ea0SDavid du Colombier }
145*a81c3ea0SDavid du Colombier 
146*a81c3ea0SDavid du Colombier static void
kpteprint(Ureg * ur)147*a81c3ea0SDavid du Colombier kpteprint(Ureg *ur)
148*a81c3ea0SDavid du Colombier {
149*a81c3ea0SDavid du Colombier 	ulong i, tlbstuff[3];
150*a81c3ea0SDavid du Colombier 	KMap *k;
151*a81c3ea0SDavid du Colombier 
152*a81c3ea0SDavid du Colombier 	i = (ur->badvaddr & ~(2*BY2PG-1)) | TLBPID(tlbvirt());
153*a81c3ea0SDavid du Colombier 	print("tlbvirt=%#lux\n", i);
154*a81c3ea0SDavid du Colombier 	i = gettlbp(i, tlbstuff);
155*a81c3ea0SDavid du Colombier 	print("i=%lud v=%#lux p0=%s p1=%s\n",
156*a81c3ea0SDavid du Colombier 		i, tlbstuff[0], ptlb(tlbstuff[1]), ptlb(tlbstuff[2]));
157*a81c3ea0SDavid du Colombier 
158*a81c3ea0SDavid du Colombier 	i = (ur->badvaddr & ~KMAPADDR)>>15;
159*a81c3ea0SDavid du Colombier 	if(i > KPTESIZE){
160*a81c3ea0SDavid du Colombier 		print("kpte index = %lud ?\n", i);
161*a81c3ea0SDavid du Colombier 		return;
162*a81c3ea0SDavid du Colombier 	}
163*a81c3ea0SDavid du Colombier 	k = &kpte[i];
164*a81c3ea0SDavid du Colombier 	print("i=%lud, &k=%#p, k={v=%#lux, p0=%s, p1=%s, pg=%#p}\n",
165*a81c3ea0SDavid du Colombier 		i, k, k->virt, ptlb(k->phys0), ptlb(k->phys1), k->pg);
166*a81c3ea0SDavid du Colombier 	print("pg={pa=%#lux, va=%#lux}\n", k->pg->pa, k->pg->va);
167*a81c3ea0SDavid du Colombier }
168*a81c3ea0SDavid du Colombier 
169*a81c3ea0SDavid du Colombier void
kvce(Ureg * ur,int ecode)170*a81c3ea0SDavid du Colombier kvce(Ureg *ur, int ecode)
171*a81c3ea0SDavid du Colombier {
172*a81c3ea0SDavid du Colombier 	char c;
173*a81c3ea0SDavid du Colombier 	Pte **p;
174*a81c3ea0SDavid du Colombier 	Page **pg;
175*a81c3ea0SDavid du Colombier 	Segment *s;
176*a81c3ea0SDavid du Colombier 	ulong addr, soff;
177*a81c3ea0SDavid du Colombier 
178*a81c3ea0SDavid du Colombier 	c = 'D';
179*a81c3ea0SDavid du Colombier 	if(ecode == CVCEI)
180*a81c3ea0SDavid du Colombier 		c = 'I';
181*a81c3ea0SDavid du Colombier 	print("Trap: VCE%c: addr=%#lux\n", c, ur->badvaddr);
182*a81c3ea0SDavid du Colombier 	if((ur->badvaddr & KSEGM) == KSEG3) {
183*a81c3ea0SDavid du Colombier 		kpteprint(ur);
184*a81c3ea0SDavid du Colombier 		return;
185*a81c3ea0SDavid du Colombier 	}
186*a81c3ea0SDavid du Colombier 	if(up && !(ur->badvaddr & KSEGM)) {
187*a81c3ea0SDavid du Colombier 		addr = ur->badvaddr;
188*a81c3ea0SDavid du Colombier 		s = seg(up, addr, 0);
189*a81c3ea0SDavid du Colombier 		if(s == 0){
190*a81c3ea0SDavid du Colombier 			print("kvce: no seg for %#lux\n", addr);
191*a81c3ea0SDavid du Colombier 			for(;;)
192*a81c3ea0SDavid du Colombier 				;
193*a81c3ea0SDavid du Colombier 		}
194*a81c3ea0SDavid du Colombier 		addr &= ~(BY2PG-1);
195*a81c3ea0SDavid du Colombier 		soff = addr - s->base;
196*a81c3ea0SDavid du Colombier 		p = &s->map[soff/PTEMAPMEM];
197*a81c3ea0SDavid du Colombier 		if(*p){
198*a81c3ea0SDavid du Colombier 			pg = &(*p)->pages[(soff&(PTEMAPMEM-1))/BY2PG];
199*a81c3ea0SDavid du Colombier 			if(*pg)
200*a81c3ea0SDavid du Colombier 				print("kvce: pa=%#lux, va=%#lux\n",
201*a81c3ea0SDavid du Colombier 					(*pg)->pa, (*pg)->va);
202*a81c3ea0SDavid du Colombier 			else
203*a81c3ea0SDavid du Colombier 				print("kvce: no *pg\n");
204*a81c3ea0SDavid du Colombier 		}else
205*a81c3ea0SDavid du Colombier 			print("kvce: no *p\n");
206*a81c3ea0SDavid du Colombier 	}
207*a81c3ea0SDavid du Colombier }
208*a81c3ea0SDavid du Colombier 
209*a81c3ea0SDavid du Colombier /* prepare to go to user space */
210*a81c3ea0SDavid du Colombier void
kexit(Ureg *)211*a81c3ea0SDavid du Colombier kexit(Ureg*)
212*a81c3ea0SDavid du Colombier {
213*a81c3ea0SDavid du Colombier 	Tos *tos;
214*a81c3ea0SDavid du Colombier 
215*a81c3ea0SDavid du Colombier 	/* precise time accounting, kernel exit */
216*a81c3ea0SDavid du Colombier 	tos = (Tos*)(USTKTOP-sizeof(Tos));
217*a81c3ea0SDavid du Colombier 	tos->kcycles += fastticks(&tos->cyclefreq) - up->kentry;
218*a81c3ea0SDavid du Colombier 	tos->pcycles = up->pcycles;
219*a81c3ea0SDavid du Colombier 	tos->pid = up->pid;
220*a81c3ea0SDavid du Colombier }
221*a81c3ea0SDavid du Colombier 
222*a81c3ea0SDavid du Colombier char*
fpexcname(Ureg * ur,ulong fcr31,char * buf,uint size)223*a81c3ea0SDavid du Colombier fpexcname(Ureg *ur, ulong fcr31, char *buf, uint size)
224*a81c3ea0SDavid du Colombier {
225*a81c3ea0SDavid du Colombier 	int i;
226*a81c3ea0SDavid du Colombier 	char *s;
227*a81c3ea0SDavid du Colombier 	ulong fppc;
228*a81c3ea0SDavid du Colombier 
229*a81c3ea0SDavid du Colombier 	fppc = ur->pc;
230*a81c3ea0SDavid du Colombier 	if(ur->cause & BD)	/* branch delay */
231*a81c3ea0SDavid du Colombier 		fppc += 4;
232*a81c3ea0SDavid du Colombier 	s = 0;
233*a81c3ea0SDavid du Colombier 	if(fcr31 & FPUNIMP)
234*a81c3ea0SDavid du Colombier 		s = "unimplemented operation";
235*a81c3ea0SDavid du Colombier 	else {
236*a81c3ea0SDavid du Colombier 		fcr31 >>= 7;		/* trap enable bits */
237*a81c3ea0SDavid du Colombier 		fcr31 &= (fcr31>>5);	/* anded with exceptions */
238*a81c3ea0SDavid du Colombier 		for(i=0; i<5; i++)
239*a81c3ea0SDavid du Colombier 			if(fcr31 & (1<<i))
240*a81c3ea0SDavid du Colombier 				s = fpcause[i];
241*a81c3ea0SDavid du Colombier 	}
242*a81c3ea0SDavid du Colombier 
243*a81c3ea0SDavid du Colombier 	if(s == 0)
244*a81c3ea0SDavid du Colombier 		return "no floating point exception";
245*a81c3ea0SDavid du Colombier 
246*a81c3ea0SDavid du Colombier 	snprint(buf, size, "%s fppc=%#lux", s, fppc);
247*a81c3ea0SDavid du Colombier 	return buf;
248*a81c3ea0SDavid du Colombier }
249*a81c3ea0SDavid du Colombier 
250*a81c3ea0SDavid du Colombier void
trap(Ureg * ur)251*a81c3ea0SDavid du Colombier trap(Ureg *ur)
252*a81c3ea0SDavid du Colombier {
253*a81c3ea0SDavid du Colombier 	int ecode, clockintr, user, cop, x, fpchk;
254*a81c3ea0SDavid du Colombier 	ulong fpfcr31;
255*a81c3ea0SDavid du Colombier 	char buf[2*ERRMAX], buf1[ERRMAX], *fpexcep;
256*a81c3ea0SDavid du Colombier 	static int dumps;
257*a81c3ea0SDavid du Colombier 
258*a81c3ea0SDavid du Colombier 	ecode = (ur->cause>>2)&EXCMASK;
259*a81c3ea0SDavid du Colombier 	user = ur->status&KUSER;
260*a81c3ea0SDavid du Colombier 	if (ur->cause & TS)
261*a81c3ea0SDavid du Colombier 		panic("trap: tlb shutdown");
262*a81c3ea0SDavid du Colombier 
263*a81c3ea0SDavid du Colombier 	fpchk = 0;
264*a81c3ea0SDavid du Colombier 	if(user){
265*a81c3ea0SDavid du Colombier 		up->dbgreg = ur;
266*a81c3ea0SDavid du Colombier 		cycles(&up->kentry);
267*a81c3ea0SDavid du Colombier 		if(up && up->fpstate == FPactive) {
268*a81c3ea0SDavid du Colombier 			if((ur->status & CU1) == 0)
269*a81c3ea0SDavid du Colombier 				panic("FPactive but no CU1");
270*a81c3ea0SDavid du Colombier 			ur->status &= ~CU1;
271*a81c3ea0SDavid du Colombier 			up->fpstate = FPinactive;
272*a81c3ea0SDavid du Colombier 			savefpregs(&up->fpsave);
273*a81c3ea0SDavid du Colombier 		}
274*a81c3ea0SDavid du Colombier 	}
275*a81c3ea0SDavid du Colombier 
276*a81c3ea0SDavid du Colombier 	if (up && (char *)(ur) - up->kstack < 1024 && dumps++ == 0) {
277*a81c3ea0SDavid du Colombier 		iprint("trap: proc %ld kernel stack getting full\n", up->pid);
278*a81c3ea0SDavid du Colombier 		dumpregs(ur);
279*a81c3ea0SDavid du Colombier 		dumpstack();
280*a81c3ea0SDavid du Colombier 	}
281*a81c3ea0SDavid du Colombier 	if (up == nil &&
282*a81c3ea0SDavid du Colombier 	    (char *)(ur) - (char *)m->stack < 1024 && dumps++ == 0) {
283*a81c3ea0SDavid du Colombier 		iprint("trap: cpu%d kernel stack getting full\n", m->machno);
284*a81c3ea0SDavid du Colombier 		dumpregs(ur);
285*a81c3ea0SDavid du Colombier 		dumpstack();
286*a81c3ea0SDavid du Colombier 	}
287*a81c3ea0SDavid du Colombier 
288*a81c3ea0SDavid du Colombier //	splhi();		/* for the experiment: make it explicit */
289*a81c3ea0SDavid du Colombier 	/* clear EXL in status */
290*a81c3ea0SDavid du Colombier 	setstatus(getstatus() & ~EXL);
291*a81c3ea0SDavid du Colombier 
292*a81c3ea0SDavid du Colombier 	clockintr = 0;
293*a81c3ea0SDavid du Colombier 	switch(ecode){
294*a81c3ea0SDavid du Colombier 	case CINT:
295*a81c3ea0SDavid du Colombier 		clockintr = intr(ur);
296*a81c3ea0SDavid du Colombier 		break;
297*a81c3ea0SDavid du Colombier 
298*a81c3ea0SDavid du Colombier 	case CFPE:
299*a81c3ea0SDavid du Colombier 		fptrap(ur);
300*a81c3ea0SDavid du Colombier 		clrfpintr();
301*a81c3ea0SDavid du Colombier 		fpchk = 1;
302*a81c3ea0SDavid du Colombier 		break;
303*a81c3ea0SDavid du Colombier 
304*a81c3ea0SDavid du Colombier 	case CTLBM:
305*a81c3ea0SDavid du Colombier 	case CTLBL:
306*a81c3ea0SDavid du Colombier 	case CTLBS:
307*a81c3ea0SDavid du Colombier 		/* user tlb entries assumed not overwritten during startup */
308*a81c3ea0SDavid du Colombier 		if(up == 0)
309*a81c3ea0SDavid du Colombier 			kernfault(ur, ecode);
310*a81c3ea0SDavid du Colombier 
311*a81c3ea0SDavid du Colombier 		if(!user && (ur->badvaddr & KSEGM) == KSEG3) {
312*a81c3ea0SDavid du Colombier 			kfault(ur);
313*a81c3ea0SDavid du Colombier 			break;
314*a81c3ea0SDavid du Colombier 		}
315*a81c3ea0SDavid du Colombier 		x = up->insyscall;
316*a81c3ea0SDavid du Colombier 		up->insyscall = 1;
317*a81c3ea0SDavid du Colombier 		spllo();
318*a81c3ea0SDavid du Colombier 		faultmips(ur, user, ecode);
319*a81c3ea0SDavid du Colombier 		up->insyscall = x;
320*a81c3ea0SDavid du Colombier 		break;
321*a81c3ea0SDavid du Colombier 
322*a81c3ea0SDavid du Colombier 	case CVCEI:
323*a81c3ea0SDavid du Colombier 	case CVCED:
324*a81c3ea0SDavid du Colombier 		kvce(ur, ecode);
325*a81c3ea0SDavid du Colombier 		goto Default;
326*a81c3ea0SDavid du Colombier 
327*a81c3ea0SDavid du Colombier 	case CWATCH:
328*a81c3ea0SDavid du Colombier 		if(!user)
329*a81c3ea0SDavid du Colombier 			panic("watchpoint trap from kernel mode pc=%#p",
330*a81c3ea0SDavid du Colombier 				ur->pc);
331*a81c3ea0SDavid du Colombier 		//fpwatch(ur); XXX
332*a81c3ea0SDavid du Colombier 		break;
333*a81c3ea0SDavid du Colombier 
334*a81c3ea0SDavid du Colombier 	case CCPU:
335*a81c3ea0SDavid du Colombier 		cop = (ur->cause>>28)&3;
336*a81c3ea0SDavid du Colombier 		if(user && up && cop == 1) {
337*a81c3ea0SDavid du Colombier 			if(up->fpstate & FPillegal) {
338*a81c3ea0SDavid du Colombier 				/* someone used floating point in a note handler */
339*a81c3ea0SDavid du Colombier 				postnote(up, 1,
340*a81c3ea0SDavid du Colombier 					"sys: floating point in note handler",
341*a81c3ea0SDavid du Colombier 					NDebug);
342*a81c3ea0SDavid du Colombier 				break;
343*a81c3ea0SDavid du Colombier 			}
344*a81c3ea0SDavid du Colombier 			if(up->fpstate == FPinit) {
345*a81c3ea0SDavid du Colombier 				up->fpstate = FPinactive;
346*a81c3ea0SDavid du Colombier 				fpfcr31 = up->fpsave.fpstatus;
347*a81c3ea0SDavid du Colombier 				up->fpsave = initfp;
348*a81c3ea0SDavid du Colombier 				up->fpsave.fpstatus = fpfcr31;
349*a81c3ea0SDavid du Colombier 				break;
350*a81c3ea0SDavid du Colombier 			}
351*a81c3ea0SDavid du Colombier 			if(up->fpstate == FPinactive)
352*a81c3ea0SDavid du Colombier 				break;
353*a81c3ea0SDavid du Colombier 		}
354*a81c3ea0SDavid du Colombier 		/* Fallthrough */
355*a81c3ea0SDavid du Colombier 
356*a81c3ea0SDavid du Colombier 	Default:
357*a81c3ea0SDavid du Colombier 	default:
358*a81c3ea0SDavid du Colombier 		if(user) {
359*a81c3ea0SDavid du Colombier 			spllo();
360*a81c3ea0SDavid du Colombier 			snprint(buf, sizeof buf, "sys: %s", excname[ecode]);
361*a81c3ea0SDavid du Colombier 			postnote(up, 1, buf, NDebug);
362*a81c3ea0SDavid du Colombier 			break;
363*a81c3ea0SDavid du Colombier 		}
364*a81c3ea0SDavid du Colombier 		if (ecode == CADREL || ecode == CADRES)
365*a81c3ea0SDavid du Colombier 			iprint("kernel addr exception for va %#p pid %#ld %s\n",
366*a81c3ea0SDavid du Colombier 				ur->badvaddr, (up? up->pid: 0),
367*a81c3ea0SDavid du Colombier 				(up? up->text: ""));
368*a81c3ea0SDavid du Colombier 		print("cpu%d: kernel %s pc=%#lux\n",
369*a81c3ea0SDavid du Colombier 			m->machno, excname[ecode], ur->pc);
370*a81c3ea0SDavid du Colombier 		dumpregs(ur);
371*a81c3ea0SDavid du Colombier 		dumpstack();
372*a81c3ea0SDavid du Colombier 		if(m->machno == 0)
373*a81c3ea0SDavid du Colombier 			spllo();
374*a81c3ea0SDavid du Colombier 		exit(1);
375*a81c3ea0SDavid du Colombier 	}
376*a81c3ea0SDavid du Colombier 
377*a81c3ea0SDavid du Colombier 	if(fpchk) {
378*a81c3ea0SDavid du Colombier 		fpfcr31 = up->fpsave.fpstatus;
379*a81c3ea0SDavid du Colombier 		if((fpfcr31>>12) & ((fpfcr31>>7)|0x20) & 0x3f) {
380*a81c3ea0SDavid du Colombier 			spllo();
381*a81c3ea0SDavid du Colombier 			fpexcep	= fpexcname(ur, fpfcr31, buf1, sizeof buf1);
382*a81c3ea0SDavid du Colombier 			snprint(buf, sizeof buf, "sys: fp: %s", fpexcep);
383*a81c3ea0SDavid du Colombier 			postnote(up, 1, buf, NDebug);
384*a81c3ea0SDavid du Colombier 		}
385*a81c3ea0SDavid du Colombier 	}
386*a81c3ea0SDavid du Colombier 
387*a81c3ea0SDavid du Colombier 	splhi();
388*a81c3ea0SDavid du Colombier 
389*a81c3ea0SDavid du Colombier 	/* delaysched set because we held a lock or because our quantum ended */
390*a81c3ea0SDavid du Colombier 	if(up && up->delaysched && clockintr){
391*a81c3ea0SDavid du Colombier 		sched();
392*a81c3ea0SDavid du Colombier 		splhi();
393*a81c3ea0SDavid du Colombier 	}
394*a81c3ea0SDavid du Colombier 
395*a81c3ea0SDavid du Colombier 	if(user){
396*a81c3ea0SDavid du Colombier 		notify(ur);
397*a81c3ea0SDavid du Colombier 		if(up->fpstate == FPinactive) {
398*a81c3ea0SDavid du Colombier 			restfpregs(&up->fpsave, up->fpsave.fpstatus&~FPEXCMASK);
399*a81c3ea0SDavid du Colombier 			up->fpstate = FPactive;
400*a81c3ea0SDavid du Colombier 			ur->status |= CU1;
401*a81c3ea0SDavid du Colombier 		}
402*a81c3ea0SDavid du Colombier 		kexit(ur);
403*a81c3ea0SDavid du Colombier 	}
404*a81c3ea0SDavid du Colombier 
405*a81c3ea0SDavid du Colombier 	/* restore EXL in status */
406*a81c3ea0SDavid du Colombier 	setstatus(getstatus() | EXL);
407*a81c3ea0SDavid du Colombier }
408*a81c3ea0SDavid du Colombier 
409*a81c3ea0SDavid du Colombier /* periodically zero all the interrupt counts */
410*a81c3ea0SDavid du Colombier static void
resetcounts(void)411*a81c3ea0SDavid du Colombier resetcounts(void)
412*a81c3ea0SDavid du Colombier {
413*a81c3ea0SDavid du Colombier 	int i;
414*a81c3ea0SDavid du Colombier 	Handler *hp;
415*a81c3ea0SDavid du Colombier 
416*a81c3ea0SDavid du Colombier 	ilock(&intrlock);
417*a81c3ea0SDavid du Colombier 	for (i = 0; i < nelem(handlers); i++)
418*a81c3ea0SDavid du Colombier 		for (hp = &handlers[i]; hp != nil; hp = hp->next)
419*a81c3ea0SDavid du Colombier 			hp->intrs = 0;
420*a81c3ea0SDavid du Colombier 	iunlock(&intrlock);
421*a81c3ea0SDavid du Colombier }
422*a81c3ea0SDavid du Colombier 
423*a81c3ea0SDavid du Colombier /*
424*a81c3ea0SDavid du Colombier  *  set handlers
425*a81c3ea0SDavid du Colombier  */
426*a81c3ea0SDavid du Colombier void
intrenable(int irq,void (* h)(Ureg *,void *),void * arg,int subirq)427*a81c3ea0SDavid du Colombier intrenable(int irq, void (*h)(Ureg*, void*), void *arg, int subirq)
428*a81c3ea0SDavid du Colombier {
429*a81c3ea0SDavid du Colombier 	Handler *hp;
430*a81c3ea0SDavid du Colombier 	static int resetclock;
431*a81c3ea0SDavid du Colombier 
432*a81c3ea0SDavid du Colombier 	if (h == nil)
433*a81c3ea0SDavid du Colombier 		panic("intrenable: nil handler intr %d", irq);
434*a81c3ea0SDavid du Colombier 	if(irq < ILmin || irq >= nelem(handlers))
435*a81c3ea0SDavid du Colombier 		panic("intrenable: bad handler intr %d %#p", irq, h);
436*a81c3ea0SDavid du Colombier 
437*a81c3ea0SDavid du Colombier 	hp = &handlers[irq];
438*a81c3ea0SDavid du Colombier 	ilock(&intrlock);
439*a81c3ea0SDavid du Colombier 	if (hp->handler != nil) {		/* occupied? */
440*a81c3ea0SDavid du Colombier 		/* add a new one at the end of the chain */
441*a81c3ea0SDavid du Colombier 		for (; hp->next != nil; hp = hp->next)
442*a81c3ea0SDavid du Colombier 			;
443*a81c3ea0SDavid du Colombier 		hp->next = smalloc(sizeof *hp);
444*a81c3ea0SDavid du Colombier 		hp = hp->next;
445*a81c3ea0SDavid du Colombier 		hp->next = nil;
446*a81c3ea0SDavid du Colombier 	}
447*a81c3ea0SDavid du Colombier 	hp->handler = h;
448*a81c3ea0SDavid du Colombier 	hp->arg = arg;
449*a81c3ea0SDavid du Colombier 	iunlock(&intrlock);
450*a81c3ea0SDavid du Colombier 
451*a81c3ea0SDavid du Colombier 	if (irq == ILpci) {		// enable pci sub-interrupt
452*a81c3ea0SDavid du Colombier 		*Pciintrsts = 0;
453*a81c3ea0SDavid du Colombier 		*Pciintrenset = 1 << subirq;
454*a81c3ea0SDavid du Colombier 		coherence();
455*a81c3ea0SDavid du Colombier 		pciintrmask |= 1 << subirq;
456*a81c3ea0SDavid du Colombier 	}
457*a81c3ea0SDavid du Colombier 
458*a81c3ea0SDavid du Colombier 	if (irq == IL8259)
459*a81c3ea0SDavid du Colombier 	{
460*a81c3ea0SDavid du Colombier 		i8259enable(subirq);
461*a81c3ea0SDavid du Colombier 		i8259intrmask |= 1 << subirq;
462*a81c3ea0SDavid du Colombier 	}
463*a81c3ea0SDavid du Colombier 
464*a81c3ea0SDavid du Colombier 	intron(1 << (ILshift + irq));
465*a81c3ea0SDavid du Colombier 	if (!resetclock) {
466*a81c3ea0SDavid du Colombier 		resetclock = 1;
467*a81c3ea0SDavid du Colombier 		addclock0link(resetcounts, 100);
468*a81c3ea0SDavid du Colombier 	}
469*a81c3ea0SDavid du Colombier }
470*a81c3ea0SDavid du Colombier 
471*a81c3ea0SDavid du Colombier void
intrshutdown(void)472*a81c3ea0SDavid du Colombier intrshutdown(void)
473*a81c3ea0SDavid du Colombier {
474*a81c3ea0SDavid du Colombier 	introff(INTMASK);
475*a81c3ea0SDavid du Colombier }
476*a81c3ea0SDavid du Colombier 
477*a81c3ea0SDavid du Colombier static void
jabberoff(Ureg * ur,int irq,ulong bit)478*a81c3ea0SDavid du Colombier jabberoff(Ureg *ur, int irq, ulong bit)
479*a81c3ea0SDavid du Colombier {
480*a81c3ea0SDavid du Colombier 	introff(bit);			/* interrupt off now ... */
481*a81c3ea0SDavid du Colombier 	if (ur)
482*a81c3ea0SDavid du Colombier 		ur->status &= ~bit;	/* ... and upon return */
483*a81c3ea0SDavid du Colombier 	offintrs |= bit;
484*a81c3ea0SDavid du Colombier 	iprint("irq %d jabbering; shutting it down\n", irq);
485*a81c3ea0SDavid du Colombier }
486*a81c3ea0SDavid du Colombier 
487*a81c3ea0SDavid du Colombier ulong
pollall(Ureg * ur,ulong cause)488*a81c3ea0SDavid du Colombier pollall(Ureg *ur, ulong cause)			/* must be called splhi */
489*a81c3ea0SDavid du Colombier {
490*a81c3ea0SDavid du Colombier 	int i, intrs, sts, subirq;
491*a81c3ea0SDavid du Colombier 	ulong bit;
492*a81c3ea0SDavid du Colombier 	Handler *hp;
493*a81c3ea0SDavid du Colombier 
494*a81c3ea0SDavid du Colombier 	/* exclude clock and sw intrs */
495*a81c3ea0SDavid du Colombier 	intrs = cause & (INTR6|INTR5|INTR4|INTR3|INTR2) & getstatus();
496*a81c3ea0SDavid du Colombier 	if(intrs == 0)
497*a81c3ea0SDavid du Colombier 		return cause;
498*a81c3ea0SDavid du Colombier 
499*a81c3ea0SDavid du Colombier 	ilock(&intrlock);
500*a81c3ea0SDavid du Colombier 	for (i = ILmax; i >= ILmin; i--) {
501*a81c3ea0SDavid du Colombier 		bit = 1 << (ILshift + i);
502*a81c3ea0SDavid du Colombier 		if (!(intrs & bit))
503*a81c3ea0SDavid du Colombier 			continue;
504*a81c3ea0SDavid du Colombier 		intrcauses[i]++;
505*a81c3ea0SDavid du Colombier 		for (hp = &handlers[i]; hp != nil; hp = hp->next)
506*a81c3ea0SDavid du Colombier 			if (hp->handler) {
507*a81c3ea0SDavid du Colombier 				if (i == ILpci) {
508*a81c3ea0SDavid du Colombier 					sts = *Pciintrsts & *Pciintren;
509*a81c3ea0SDavid du Colombier 					if((sts & pciintrmask) == 0)
510*a81c3ea0SDavid du Colombier 						continue;
511*a81c3ea0SDavid du Colombier 					// XXX need to clear sub-intr bits ?
512*a81c3ea0SDavid du Colombier 					//*Pciintrsts &= ~(1 << Pciintrether);
513*a81c3ea0SDavid du Colombier 					*Pciintrsts = 0;
514*a81c3ea0SDavid du Colombier 				}
515*a81c3ea0SDavid du Colombier 
516*a81c3ea0SDavid du Colombier 				if (i == IL8259) {
517*a81c3ea0SDavid du Colombier 					subirq = i8259intack();
518*a81c3ea0SDavid du Colombier 					if((1 << subirq) & i8259intrmask == 0)
519*a81c3ea0SDavid du Colombier 						continue;
520*a81c3ea0SDavid du Colombier 					i8259isr(subirq);
521*a81c3ea0SDavid du Colombier 				}
522*a81c3ea0SDavid du Colombier 
523*a81c3ea0SDavid du Colombier 				(*hp->handler)(ur, hp->arg);
524*a81c3ea0SDavid du Colombier 				splhi();
525*a81c3ea0SDavid du Colombier 				if (++hp->intrs > 25000) {
526*a81c3ea0SDavid du Colombier 					jabberoff(ur, i, bit);
527*a81c3ea0SDavid du Colombier 					intrs &= ~bit;
528*a81c3ea0SDavid du Colombier 					hp->intrs = 0;
529*a81c3ea0SDavid du Colombier 				}
530*a81c3ea0SDavid du Colombier 			} else if (ur)
531*a81c3ea0SDavid du Colombier 				iprint("no handler for interrupt %d\n", i);
532*a81c3ea0SDavid du Colombier 		cause &= ~bit;
533*a81c3ea0SDavid du Colombier 	}
534*a81c3ea0SDavid du Colombier 	iunlock(&intrlock);
535*a81c3ea0SDavid du Colombier 	return cause;
536*a81c3ea0SDavid du Colombier }
537*a81c3ea0SDavid du Colombier 
538*a81c3ea0SDavid du Colombier int
intr(Ureg * ur)539*a81c3ea0SDavid du Colombier intr(Ureg *ur)
540*a81c3ea0SDavid du Colombier {
541*a81c3ea0SDavid du Colombier 	int clockintr;
542*a81c3ea0SDavid du Colombier 	ulong cause;
543*a81c3ea0SDavid du Colombier 
544*a81c3ea0SDavid du Colombier 	m->intr++;
545*a81c3ea0SDavid du Colombier 	clockintr = 0;
546*a81c3ea0SDavid du Colombier 	/*
547*a81c3ea0SDavid du Colombier 	 * ignore interrupts that we have disabled, even if their cause bits
548*a81c3ea0SDavid du Colombier 	 * are set.
549*a81c3ea0SDavid du Colombier 	 */
550*a81c3ea0SDavid du Colombier 	cause = ur->cause & ur->status & INTMASK;
551*a81c3ea0SDavid du Colombier 	cause &= ~(INTR1|INTR0);		/* ignore sw interrupts */
552*a81c3ea0SDavid du Colombier 	if (cause == 0)
553*a81c3ea0SDavid du Colombier 		print("spurious interrupt\n");
554*a81c3ea0SDavid du Colombier 	if(cause & INTR7){
555*a81c3ea0SDavid du Colombier 		clock(ur);
556*a81c3ea0SDavid du Colombier 		intrcauses[ILclock]++;
557*a81c3ea0SDavid du Colombier 		cause &= ~(1 << (ILclock + ILshift));
558*a81c3ea0SDavid du Colombier 		clockintr = 1;
559*a81c3ea0SDavid du Colombier 	}
560*a81c3ea0SDavid du Colombier 	cause = pollall(ur, cause);
561*a81c3ea0SDavid du Colombier 	if(cause){
562*a81c3ea0SDavid du Colombier 		print("intr: cause %#lux not handled\n", cause);
563*a81c3ea0SDavid du Colombier 		exit(1);
564*a81c3ea0SDavid du Colombier 	}
565*a81c3ea0SDavid du Colombier 
566*a81c3ea0SDavid du Colombier 	/* preemptive scheduling */
567*a81c3ea0SDavid du Colombier 	if(up && !clockintr)
568*a81c3ea0SDavid du Colombier 		preempted();
569*a81c3ea0SDavid du Colombier 	/* if it was a clockintr, sched will be called at end of trap() */
570*a81c3ea0SDavid du Colombier 	return clockintr;
571*a81c3ea0SDavid du Colombier }
572*a81c3ea0SDavid du Colombier 
573*a81c3ea0SDavid du Colombier void
kernfault(Ureg * ur,int code)574*a81c3ea0SDavid du Colombier kernfault(Ureg *ur, int code)
575*a81c3ea0SDavid du Colombier {
576*a81c3ea0SDavid du Colombier 	print("panic: kfault %s badvaddr=%#lux", excname[code], ur->badvaddr);
577*a81c3ea0SDavid du Colombier 	kpteprint(ur);
578*a81c3ea0SDavid du Colombier 	print("u=%#p status=%#lux pc=%#lux sp=%#lux\n",
579*a81c3ea0SDavid du Colombier 		up, ur->status, ur->pc, ur->sp);
580*a81c3ea0SDavid du Colombier 	delay(500);
581*a81c3ea0SDavid du Colombier 	panic("kfault");
582*a81c3ea0SDavid du Colombier }
583*a81c3ea0SDavid du Colombier 
584*a81c3ea0SDavid du Colombier static void
getpcsp(ulong * pc,ulong * sp)585*a81c3ea0SDavid du Colombier getpcsp(ulong *pc, ulong *sp)
586*a81c3ea0SDavid du Colombier {
587*a81c3ea0SDavid du Colombier 	*pc = getcallerpc(&pc);
588*a81c3ea0SDavid du Colombier 	*sp = (ulong)&pc-4;
589*a81c3ea0SDavid du Colombier }
590*a81c3ea0SDavid du Colombier 
591*a81c3ea0SDavid du Colombier void
callwithureg(void (* fn)(Ureg *))592*a81c3ea0SDavid du Colombier callwithureg(void (*fn)(Ureg*))
593*a81c3ea0SDavid du Colombier {
594*a81c3ea0SDavid du Colombier 	Ureg ureg;
595*a81c3ea0SDavid du Colombier 
596*a81c3ea0SDavid du Colombier 	memset(&ureg, 0, sizeof ureg);
597*a81c3ea0SDavid du Colombier 	getpcsp((ulong*)&ureg.pc, (ulong*)&ureg.sp);
598*a81c3ea0SDavid du Colombier 	ureg.r31 = getcallerpc(&fn);
599*a81c3ea0SDavid du Colombier 	fn(&ureg);
600*a81c3ea0SDavid du Colombier }
601*a81c3ea0SDavid du Colombier 
602*a81c3ea0SDavid du Colombier static void
_dumpstack(Ureg * ureg)603*a81c3ea0SDavid du Colombier _dumpstack(Ureg *ureg)
604*a81c3ea0SDavid du Colombier {
605*a81c3ea0SDavid du Colombier 	ulong l, v, top, i;
606*a81c3ea0SDavid du Colombier 	extern ulong etext;
607*a81c3ea0SDavid du Colombier 
608*a81c3ea0SDavid du Colombier 	if(up == 0)
609*a81c3ea0SDavid du Colombier 		return;
610*a81c3ea0SDavid du Colombier 
611*a81c3ea0SDavid du Colombier 	print("ktrace /kernel/path %.8lux %.8lux %.8lux\n",
612*a81c3ea0SDavid du Colombier 		ureg->pc, ureg->sp, ureg->r31);
613*a81c3ea0SDavid du Colombier 	top = (ulong)up->kstack + KSTACK;
614*a81c3ea0SDavid du Colombier 	i = 0;
615*a81c3ea0SDavid du Colombier 	for(l=ureg->sp; l < top; l += BY2WD) {
616*a81c3ea0SDavid du Colombier 		v = *(ulong*)l;
617*a81c3ea0SDavid du Colombier 		if(KTZERO < v && v < (ulong)&etext) {
618*a81c3ea0SDavid du Colombier 			print("%.8lux=%.8lux ", l, v);
619*a81c3ea0SDavid du Colombier 			if((++i%4) == 0){
620*a81c3ea0SDavid du Colombier 				print("\n");
621*a81c3ea0SDavid du Colombier 				delay(200);
622*a81c3ea0SDavid du Colombier 			}
623*a81c3ea0SDavid du Colombier 		}
624*a81c3ea0SDavid du Colombier 	}
625*a81c3ea0SDavid du Colombier 	print("\n");
626*a81c3ea0SDavid du Colombier }
627*a81c3ea0SDavid du Colombier 
628*a81c3ea0SDavid du Colombier void
dumpstack(void)629*a81c3ea0SDavid du Colombier dumpstack(void)
630*a81c3ea0SDavid du Colombier {
631*a81c3ea0SDavid du Colombier 	callwithureg(_dumpstack);
632*a81c3ea0SDavid du Colombier }
633*a81c3ea0SDavid du Colombier 
634*a81c3ea0SDavid du Colombier static ulong
R(Ureg * ur,int i)635*a81c3ea0SDavid du Colombier R(Ureg *ur, int i)
636*a81c3ea0SDavid du Colombier {
637*a81c3ea0SDavid du Colombier 	uchar *s;
638*a81c3ea0SDavid du Colombier 
639*a81c3ea0SDavid du Colombier 	s = (uchar*)ur;
640*a81c3ea0SDavid du Colombier 	return *(ulong*)(s + regname[i].off - Uoffset);
641*a81c3ea0SDavid du Colombier }
642*a81c3ea0SDavid du Colombier 
643*a81c3ea0SDavid du Colombier void
dumpregs(Ureg * ur)644*a81c3ea0SDavid du Colombier dumpregs(Ureg *ur)
645*a81c3ea0SDavid du Colombier {
646*a81c3ea0SDavid du Colombier 	int i;
647*a81c3ea0SDavid du Colombier 
648*a81c3ea0SDavid du Colombier 	if(up)
649*a81c3ea0SDavid du Colombier 		print("registers for %s %lud\n", up->text, up->pid);
650*a81c3ea0SDavid du Colombier 	else
651*a81c3ea0SDavid du Colombier 		print("registers for kernel\n");
652*a81c3ea0SDavid du Colombier 
653*a81c3ea0SDavid du Colombier 	for(i = 0; i < nelem(regname); i += 2)
654*a81c3ea0SDavid du Colombier 		print("%s\t%#.8lux\t%s\t%#.8lux\n",
655*a81c3ea0SDavid du Colombier 			regname[i].name,   R(ur, i),
656*a81c3ea0SDavid du Colombier 			regname[i+1].name, R(ur, i+1));
657*a81c3ea0SDavid du Colombier }
658*a81c3ea0SDavid du Colombier 
659*a81c3ea0SDavid du Colombier int
notify(Ureg * ur)660*a81c3ea0SDavid du Colombier notify(Ureg *ur)
661*a81c3ea0SDavid du Colombier {
662*a81c3ea0SDavid du Colombier 	int l, s;
663*a81c3ea0SDavid du Colombier 	ulong sp;
664*a81c3ea0SDavid du Colombier 	Note *n;
665*a81c3ea0SDavid du Colombier 
666*a81c3ea0SDavid du Colombier 	if(up->procctl)
667*a81c3ea0SDavid du Colombier 		procctl(up);
668*a81c3ea0SDavid du Colombier 	if(up->nnote == 0)
669*a81c3ea0SDavid du Colombier 		return 0;
670*a81c3ea0SDavid du Colombier 
671*a81c3ea0SDavid du Colombier 	s = spllo();
672*a81c3ea0SDavid du Colombier 	qlock(&up->debug);
673*a81c3ea0SDavid du Colombier 	up->fpstate |= FPillegal;
674*a81c3ea0SDavid du Colombier 	up->notepending = 0;
675*a81c3ea0SDavid du Colombier 	n = &up->note[0];
676*a81c3ea0SDavid du Colombier 	if(strncmp(n->msg, "sys:", 4) == 0) {
677*a81c3ea0SDavid du Colombier 		l = strlen(n->msg);
678*a81c3ea0SDavid du Colombier 		if(l > ERRMAX-15)	/* " pc=0x12345678\0" */
679*a81c3ea0SDavid du Colombier 			l = ERRMAX-15;
680*a81c3ea0SDavid du Colombier 
681*a81c3ea0SDavid du Colombier 		seprint(n->msg+l, &n->msg[sizeof n->msg], " pc=%#lux", ur->pc);
682*a81c3ea0SDavid du Colombier 	}
683*a81c3ea0SDavid du Colombier 
684*a81c3ea0SDavid du Colombier 	if(n->flag != NUser && (up->notified || up->notify==0)) {
685*a81c3ea0SDavid du Colombier 		if(n->flag == NDebug)
686*a81c3ea0SDavid du Colombier 			pprint("suicide: %s\n", n->msg);
687*a81c3ea0SDavid du Colombier 
688*a81c3ea0SDavid du Colombier 		qunlock(&up->debug);
689*a81c3ea0SDavid du Colombier 		pexit(n->msg, n->flag!=NDebug);
690*a81c3ea0SDavid du Colombier 	}
691*a81c3ea0SDavid du Colombier 
692*a81c3ea0SDavid du Colombier 	if(up->notified) {
693*a81c3ea0SDavid du Colombier 		qunlock(&up->debug);
694*a81c3ea0SDavid du Colombier 		splx(s);
695*a81c3ea0SDavid du Colombier 		return 0;
696*a81c3ea0SDavid du Colombier 	}
697*a81c3ea0SDavid du Colombier 
698*a81c3ea0SDavid du Colombier 	if(!up->notify) {
699*a81c3ea0SDavid du Colombier 		qunlock(&up->debug);
700*a81c3ea0SDavid du Colombier 		pexit(n->msg, n->flag!=NDebug);
701*a81c3ea0SDavid du Colombier 	}
702*a81c3ea0SDavid du Colombier 	sp = ur->usp - sizeof(Ureg) - BY2WD;	/* libc adds 4 to usp */
703*a81c3ea0SDavid du Colombier 
704*a81c3ea0SDavid du Colombier 	if(!okaddr((ulong)up->notify, BY2WD, 0) ||
705*a81c3ea0SDavid du Colombier 	   !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)) {
706*a81c3ea0SDavid du Colombier 		pprint("suicide: bad address or sp in notify\n");
707*a81c3ea0SDavid du Colombier 		qunlock(&up->debug);
708*a81c3ea0SDavid du Colombier 		pexit("Suicide", 0);
709*a81c3ea0SDavid du Colombier 	}
710*a81c3ea0SDavid du Colombier 
711*a81c3ea0SDavid du Colombier 	memmove((Ureg*)sp, ur, sizeof(Ureg));	/* push user regs */
712*a81c3ea0SDavid du Colombier 	*(Ureg**)(sp-BY2WD) = up->ureg;	/* word under Ureg is old up->ureg */
713*a81c3ea0SDavid du Colombier 	up->ureg = (void*)sp;
714*a81c3ea0SDavid du Colombier 
715*a81c3ea0SDavid du Colombier 	sp -= BY2WD+ERRMAX;
716*a81c3ea0SDavid du Colombier 	memmove((char*)sp, up->note[0].msg, ERRMAX);	/* push err string */
717*a81c3ea0SDavid du Colombier 
718*a81c3ea0SDavid du Colombier 	sp -= 3*BY2WD;
719*a81c3ea0SDavid du Colombier 	*(ulong*)(sp+2*BY2WD) = sp+3*BY2WD;	/* arg 2 is string */
720*a81c3ea0SDavid du Colombier 	ur->r1 = (long)up->ureg;		/* arg 1 is ureg* */
721*a81c3ea0SDavid du Colombier 	((ulong*)sp)[1] = (ulong)up->ureg;	/* arg 1 0(FP) is ureg* */
722*a81c3ea0SDavid du Colombier 	((ulong*)sp)[0] = 0;			/* arg 0 is pc */
723*a81c3ea0SDavid du Colombier 	ur->usp = sp;
724*a81c3ea0SDavid du Colombier 	/*
725*a81c3ea0SDavid du Colombier 	 * arrange to resume at user's handler as if handler(ureg, errstr)
726*a81c3ea0SDavid du Colombier 	 * were being called.
727*a81c3ea0SDavid du Colombier 	 */
728*a81c3ea0SDavid du Colombier 	ur->pc = (ulong)up->notify;
729*a81c3ea0SDavid du Colombier 
730*a81c3ea0SDavid du Colombier 	up->notified = 1;
731*a81c3ea0SDavid du Colombier 	up->nnote--;
732*a81c3ea0SDavid du Colombier 	memmove(&up->lastnote, &up->note[0], sizeof(Note));
733*a81c3ea0SDavid du Colombier 	memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note));
734*a81c3ea0SDavid du Colombier 
735*a81c3ea0SDavid du Colombier 	qunlock(&up->debug);
736*a81c3ea0SDavid du Colombier 	splx(s);
737*a81c3ea0SDavid du Colombier 	return 1;
738*a81c3ea0SDavid du Colombier }
739*a81c3ea0SDavid du Colombier 
740*a81c3ea0SDavid du Colombier /*
741*a81c3ea0SDavid du Colombier  * Check that status is OK to return from note.
742*a81c3ea0SDavid du Colombier  */
743*a81c3ea0SDavid du Colombier int
validstatus(ulong kstatus,ulong ustatus)744*a81c3ea0SDavid du Colombier validstatus(ulong kstatus, ulong ustatus)
745*a81c3ea0SDavid du Colombier {
746*a81c3ea0SDavid du Colombier //	if((kstatus & (INTMASK|KX|SX|UX)) != (ustatus & (INTMASK|KX|SX|UX)))
747*a81c3ea0SDavid du Colombier 	if((kstatus & INTMASK) != (ustatus & INTMASK))
748*a81c3ea0SDavid du Colombier 		return 0;
749*a81c3ea0SDavid du Colombier 	if((ustatus&(KSU|ERL|EXL|IE)) != (KUSER|EXL|IE))
750*a81c3ea0SDavid du Colombier 		return 0;
751*a81c3ea0SDavid du Colombier 	if(ustatus & (0xFFFF0000&~CU1))	/* no CU3, CU2, CU0, RP, FR, RE, DS */
752*a81c3ea0SDavid du Colombier 		return 0;
753*a81c3ea0SDavid du Colombier 	return 1;
754*a81c3ea0SDavid du Colombier }
755*a81c3ea0SDavid du Colombier 
756*a81c3ea0SDavid du Colombier /*
757*a81c3ea0SDavid du Colombier  * Return user to state before notify(); called from user's handler.
758*a81c3ea0SDavid du Colombier  */
759*a81c3ea0SDavid du Colombier void
noted(Ureg * kur,Ureg ** urp,ulong arg0)760*a81c3ea0SDavid du Colombier noted(Ureg *kur, Ureg **urp, ulong arg0)
761*a81c3ea0SDavid du Colombier {
762*a81c3ea0SDavid du Colombier 	Ureg *nur;
763*a81c3ea0SDavid du Colombier 	ulong oureg, sp;
764*a81c3ea0SDavid du Colombier 
765*a81c3ea0SDavid du Colombier 	qlock(&up->debug);
766*a81c3ea0SDavid du Colombier 	if(arg0!=NRSTR && !up->notified) {
767*a81c3ea0SDavid du Colombier 		qunlock(&up->debug);
768*a81c3ea0SDavid du Colombier 		pprint("call to noted() when not notified\n");
769*a81c3ea0SDavid du Colombier 		pexit("Suicide", 0);
770*a81c3ea0SDavid du Colombier 	}
771*a81c3ea0SDavid du Colombier 	up->notified = 0;
772*a81c3ea0SDavid du Colombier 
773*a81c3ea0SDavid du Colombier 	up->fpstate &= ~FPillegal;
774*a81c3ea0SDavid du Colombier 
775*a81c3ea0SDavid du Colombier 	nur = up->ureg;
776*a81c3ea0SDavid du Colombier 
777*a81c3ea0SDavid du Colombier 	oureg = (ulong)nur;
778*a81c3ea0SDavid du Colombier 	if((oureg & (BY2WD-1))
779*a81c3ea0SDavid du Colombier 	|| !okaddr((ulong)oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){
780*a81c3ea0SDavid du Colombier 		pprint("bad up->ureg in noted or call to noted() when not notified\n");
781*a81c3ea0SDavid du Colombier 		qunlock(&up->debug);
782*a81c3ea0SDavid du Colombier 		pexit("Suicide", 0);
783*a81c3ea0SDavid du Colombier 	}
784*a81c3ea0SDavid du Colombier 
785*a81c3ea0SDavid du Colombier 	if(!validstatus(kur->status, nur->status)) {
786*a81c3ea0SDavid du Colombier 		qunlock(&up->debug);
787*a81c3ea0SDavid du Colombier 		pprint("bad noted ureg status %#lux\n", nur->status);
788*a81c3ea0SDavid du Colombier 		pexit("Suicide", 0);
789*a81c3ea0SDavid du Colombier 	}
790*a81c3ea0SDavid du Colombier 
791*a81c3ea0SDavid du Colombier 	memmove(*urp, up->ureg, sizeof(Ureg));
792*a81c3ea0SDavid du Colombier 	switch(arg0) {
793*a81c3ea0SDavid du Colombier 	case NCONT:
794*a81c3ea0SDavid du Colombier 	case NRSTR:				/* only used by APE */
795*a81c3ea0SDavid du Colombier 		if(!okaddr(nur->pc, BY2WD, 0) || !okaddr(nur->usp, BY2WD, 0)){
796*a81c3ea0SDavid du Colombier 			pprint("suicide: trap in noted\n");
797*a81c3ea0SDavid du Colombier 			qunlock(&up->debug);
798*a81c3ea0SDavid du Colombier 			pexit("Suicide", 0);
799*a81c3ea0SDavid du Colombier 		}
800*a81c3ea0SDavid du Colombier 		up->ureg = (Ureg*)(*(ulong*)(oureg-BY2WD));
801*a81c3ea0SDavid du Colombier 		qunlock(&up->debug);
802*a81c3ea0SDavid du Colombier 		splhi();
803*a81c3ea0SDavid du Colombier 		/*
804*a81c3ea0SDavid du Colombier 		 * the old challenge and carrera ports called rfnote here,
805*a81c3ea0SDavid du Colombier 		 * but newer ports do not, and notes seem to work only
806*a81c3ea0SDavid du Colombier 		 * without this call.
807*a81c3ea0SDavid du Colombier 		 */
808*a81c3ea0SDavid du Colombier 		// rfnote(urp);		/* return from note with SP=urp */
809*a81c3ea0SDavid du Colombier 		break;
810*a81c3ea0SDavid du Colombier 
811*a81c3ea0SDavid du Colombier 	case NSAVE:				/* only used by APE */
812*a81c3ea0SDavid du Colombier 		if(!okaddr(nur->pc, BY2WD, 0) || !okaddr(nur->usp, BY2WD, 0)){
813*a81c3ea0SDavid du Colombier 			pprint("suicide: trap in noted\n");
814*a81c3ea0SDavid du Colombier 			qunlock(&up->debug);
815*a81c3ea0SDavid du Colombier 			pexit("Suicide", 0);
816*a81c3ea0SDavid du Colombier 		}
817*a81c3ea0SDavid du Colombier 		qunlock(&up->debug);
818*a81c3ea0SDavid du Colombier 		sp = oureg-4*BY2WD-ERRMAX;
819*a81c3ea0SDavid du Colombier 
820*a81c3ea0SDavid du Colombier 		splhi();
821*a81c3ea0SDavid du Colombier 		(*urp)->sp = sp;
822*a81c3ea0SDavid du Colombier 		((ulong*)sp)[1] = oureg;	/* arg 1 0(FP) is ureg* */
823*a81c3ea0SDavid du Colombier 		((ulong*)sp)[0] = 0;		/* arg 0 is pc */
824*a81c3ea0SDavid du Colombier 		(*urp)->r1 = oureg;		/* arg 1 is ureg* */
825*a81c3ea0SDavid du Colombier 
826*a81c3ea0SDavid du Colombier 		// rfnote(urp);		/* return from note with SP=urp */
827*a81c3ea0SDavid du Colombier 		break;
828*a81c3ea0SDavid du Colombier 
829*a81c3ea0SDavid du Colombier 	default:
830*a81c3ea0SDavid du Colombier 		pprint("unknown noted arg %#lux\n", arg0);
831*a81c3ea0SDavid du Colombier 		up->lastnote.flag = NDebug;
832*a81c3ea0SDavid du Colombier 		/* fall through */
833*a81c3ea0SDavid du Colombier 
834*a81c3ea0SDavid du Colombier 	case NDFLT:
835*a81c3ea0SDavid du Colombier 		if(up->lastnote.flag == NDebug)
836*a81c3ea0SDavid du Colombier 			pprint("suicide: %s\n", up->lastnote.msg);
837*a81c3ea0SDavid du Colombier 		qunlock(&up->debug);
838*a81c3ea0SDavid du Colombier 		pexit(up->lastnote.msg, up->lastnote.flag!=NDebug);
839*a81c3ea0SDavid du Colombier 	}
840*a81c3ea0SDavid du Colombier }
841*a81c3ea0SDavid du Colombier 
842*a81c3ea0SDavid du Colombier #include "../port/systab.h"
843*a81c3ea0SDavid du Colombier 
844*a81c3ea0SDavid du Colombier static Ref goodsyscall;
845*a81c3ea0SDavid du Colombier static Ref totalsyscall;
846*a81c3ea0SDavid du Colombier 
847*a81c3ea0SDavid du Colombier static void
sctracesetup(ulong scallnr,ulong sp,uintptr pc,vlong * startnsp)848*a81c3ea0SDavid du Colombier sctracesetup(ulong scallnr, ulong sp, uintptr pc, vlong *startnsp)
849*a81c3ea0SDavid du Colombier {
850*a81c3ea0SDavid du Colombier 	if(up->procctl == Proc_tracesyscall){
851*a81c3ea0SDavid du Colombier 		/*
852*a81c3ea0SDavid du Colombier 		 * Redundant validaddr.  Do we care?
853*a81c3ea0SDavid du Colombier 		 * Tracing syscalls is not exactly a fast path...
854*a81c3ea0SDavid du Colombier 		 * Beware, validaddr currently does a pexit rather
855*a81c3ea0SDavid du Colombier 		 * than an error if there's a problem; that might
856*a81c3ea0SDavid du Colombier 		 * change in the future.
857*a81c3ea0SDavid du Colombier 		 */
858*a81c3ea0SDavid du Colombier 		if(sp < (USTKTOP-BY2PG) || sp > (USTKTOP-sizeof(Sargs)))
859*a81c3ea0SDavid du Colombier 			validaddr(sp, sizeof(Sargs), 0);
860*a81c3ea0SDavid du Colombier 
861*a81c3ea0SDavid du Colombier 		syscallfmt(scallnr, pc, (va_list)sp);
862*a81c3ea0SDavid du Colombier 		up->procctl = Proc_stopme;
863*a81c3ea0SDavid du Colombier 		procctl(up);
864*a81c3ea0SDavid du Colombier 		if(up->syscalltrace)
865*a81c3ea0SDavid du Colombier 			free(up->syscalltrace);
866*a81c3ea0SDavid du Colombier 		up->syscalltrace = nil;
867*a81c3ea0SDavid du Colombier 		*startnsp = todget(nil);
868*a81c3ea0SDavid du Colombier 	}
869*a81c3ea0SDavid du Colombier }
870*a81c3ea0SDavid du Colombier 
871*a81c3ea0SDavid du Colombier static void
sctracefinish(ulong scallnr,ulong sp,int ret,vlong startns)872*a81c3ea0SDavid du Colombier sctracefinish(ulong scallnr, ulong sp, int ret, vlong startns)
873*a81c3ea0SDavid du Colombier {
874*a81c3ea0SDavid du Colombier 	int s;
875*a81c3ea0SDavid du Colombier 
876*a81c3ea0SDavid du Colombier 	if(up->procctl == Proc_tracesyscall){
877*a81c3ea0SDavid du Colombier 		up->procctl = Proc_stopme;
878*a81c3ea0SDavid du Colombier 		sysretfmt(scallnr, (va_list)sp, ret,
879*a81c3ea0SDavid du Colombier 			startns, todget(nil));
880*a81c3ea0SDavid du Colombier 		s = splhi();
881*a81c3ea0SDavid du Colombier 		procctl(up);
882*a81c3ea0SDavid du Colombier 		splx(s);
883*a81c3ea0SDavid du Colombier 		if(up->syscalltrace)
884*a81c3ea0SDavid du Colombier 			free(up->syscalltrace);
885*a81c3ea0SDavid du Colombier 		up->syscalltrace = nil;
886*a81c3ea0SDavid du Colombier 	}
887*a81c3ea0SDavid du Colombier }
888*a81c3ea0SDavid du Colombier 
889*a81c3ea0SDavid du Colombier /*
890*a81c3ea0SDavid du Colombier  * called directly from assembler, not via trap()
891*a81c3ea0SDavid du Colombier  */
892*a81c3ea0SDavid du Colombier long
syscall(Ureg * aur)893*a81c3ea0SDavid du Colombier syscall(Ureg *aur)
894*a81c3ea0SDavid du Colombier {
895*a81c3ea0SDavid du Colombier 	int i;
896*a81c3ea0SDavid du Colombier 	volatile long ret;
897*a81c3ea0SDavid du Colombier 	ulong sp, scallnr;
898*a81c3ea0SDavid du Colombier 	vlong startns;
899*a81c3ea0SDavid du Colombier 	char *e;
900*a81c3ea0SDavid du Colombier 	Ureg *ur;
901*a81c3ea0SDavid du Colombier 
902*a81c3ea0SDavid du Colombier 	cycles(&up->kentry);
903*a81c3ea0SDavid du Colombier 
904*a81c3ea0SDavid du Colombier 	incref(&totalsyscall);
905*a81c3ea0SDavid du Colombier 	m->syscall++;
906*a81c3ea0SDavid du Colombier 	up->insyscall = 1;
907*a81c3ea0SDavid du Colombier 	ur = aur;
908*a81c3ea0SDavid du Colombier 	up->pc = ur->pc;
909*a81c3ea0SDavid du Colombier 	up->dbgreg = aur;
910*a81c3ea0SDavid du Colombier 	ur->cause = 16<<2;	/* for debugging: system call is undef 16 */
911*a81c3ea0SDavid du Colombier 
912*a81c3ea0SDavid du Colombier 	scallnr = ur->r1;
913*a81c3ea0SDavid du Colombier 	up->scallnr = ur->r1;
914*a81c3ea0SDavid du Colombier 	sp = ur->sp;
915*a81c3ea0SDavid du Colombier 	sctracesetup(scallnr, sp, ur->pc, &startns);
916*a81c3ea0SDavid du Colombier 
917*a81c3ea0SDavid du Colombier 	/* clear EXL in status */
918*a81c3ea0SDavid du Colombier 	setstatus(getstatus() & ~EXL);
919*a81c3ea0SDavid du Colombier 
920*a81c3ea0SDavid du Colombier 	if(up->fpstate == FPactive) {
921*a81c3ea0SDavid du Colombier 		if((ur->status & CU1) == 0)
922*a81c3ea0SDavid du Colombier 			panic("syscall: FPactive but no CU1");
923*a81c3ea0SDavid du Colombier 		up->fpsave.fpstatus = fcr31();
924*a81c3ea0SDavid du Colombier 		up->fpstate = FPinit;
925*a81c3ea0SDavid du Colombier 		ur->status &= ~CU1;
926*a81c3ea0SDavid du Colombier 	}
927*a81c3ea0SDavid du Colombier 	spllo();
928*a81c3ea0SDavid du Colombier 
929*a81c3ea0SDavid du Colombier 	up->nerrlab = 0;
930*a81c3ea0SDavid du Colombier 	ret = -1;
931*a81c3ea0SDavid du Colombier 	if(!waserror()) {
932*a81c3ea0SDavid du Colombier 		if(scallnr >= nsyscall || systab[scallnr] == 0){
933*a81c3ea0SDavid du Colombier 			pprint("bad sys call number %ld pc %#lux\n",
934*a81c3ea0SDavid du Colombier 				scallnr, ur->pc);
935*a81c3ea0SDavid du Colombier 			postnote(up, 1, "sys: bad sys call", NDebug);
936*a81c3ea0SDavid du Colombier 			error(Ebadarg);
937*a81c3ea0SDavid du Colombier 		}
938*a81c3ea0SDavid du Colombier 
939*a81c3ea0SDavid du Colombier 		if(sp & (BY2WD-1)){
940*a81c3ea0SDavid du Colombier 			pprint("odd sp in sys call pc %#lux sp %#lux\n",
941*a81c3ea0SDavid du Colombier 				ur->pc, ur->sp);
942*a81c3ea0SDavid du Colombier 			postnote(up, 1, "sys: odd stack", NDebug);
943*a81c3ea0SDavid du Colombier 			error(Ebadarg);
944*a81c3ea0SDavid du Colombier 		}
945*a81c3ea0SDavid du Colombier 
946*a81c3ea0SDavid du Colombier 		if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)))
947*a81c3ea0SDavid du Colombier 			validaddr(sp, sizeof(Sargs), 0);
948*a81c3ea0SDavid du Colombier 
949*a81c3ea0SDavid du Colombier 		up->s = *(Sargs*)sp;		/* spim's libc is different to mips ... */
950*a81c3ea0SDavid du Colombier 		up->psstate = sysctab[scallnr];
951*a81c3ea0SDavid du Colombier 
952*a81c3ea0SDavid du Colombier 		ret = systab[scallnr](up->s.args);
953*a81c3ea0SDavid du Colombier 		poperror();
954*a81c3ea0SDavid du Colombier 	}else{
955*a81c3ea0SDavid du Colombier 		/* failure: save the error buffer for errstr */
956*a81c3ea0SDavid du Colombier 		e = up->syserrstr;
957*a81c3ea0SDavid du Colombier 		up->syserrstr = up->errstr;
958*a81c3ea0SDavid du Colombier 		up->errstr = e;
959*a81c3ea0SDavid du Colombier 	}
960*a81c3ea0SDavid du Colombier 	if(up->nerrlab){
961*a81c3ea0SDavid du Colombier 		print("bad errstack [%lud]: %d extra\n", scallnr, up->nerrlab);
962*a81c3ea0SDavid du Colombier 		for(i = 0; i < NERR; i++)
963*a81c3ea0SDavid du Colombier 			print("sp=%#lux pc=%#lux\n",
964*a81c3ea0SDavid du Colombier 				up->errlab[i].sp, up->errlab[i].pc);
965*a81c3ea0SDavid du Colombier 		panic("error stack");
966*a81c3ea0SDavid du Colombier 	}
967*a81c3ea0SDavid du Colombier 	sctracefinish(scallnr, sp, ret, startns);
968*a81c3ea0SDavid du Colombier 
969*a81c3ea0SDavid du Colombier 	ur->pc += 4;
970*a81c3ea0SDavid du Colombier 	ur->r1 = ret;
971*a81c3ea0SDavid du Colombier 
972*a81c3ea0SDavid du Colombier 	up->psstate = 0;
973*a81c3ea0SDavid du Colombier 	up->insyscall = 0;
974*a81c3ea0SDavid du Colombier 
975*a81c3ea0SDavid du Colombier 	if(scallnr == NOTED) {				/* ugly hack */
976*a81c3ea0SDavid du Colombier 		noted(ur, &aur, *(ulong*)sp);	/* may return */
977*a81c3ea0SDavid du Colombier 		ret = ur->r1;
978*a81c3ea0SDavid du Colombier 	}
979*a81c3ea0SDavid du Colombier 	incref(&goodsyscall);
980*a81c3ea0SDavid du Colombier 	splhi();
981*a81c3ea0SDavid du Colombier 	if(scallnr!=RFORK && (up->procctl || up->nnote)){
982*a81c3ea0SDavid du Colombier 		ur->r1 = ret;			/* load up for noted() above */
983*a81c3ea0SDavid du Colombier 		notify(ur);
984*a81c3ea0SDavid du Colombier 	}
985*a81c3ea0SDavid du Colombier 	/* if we delayed sched because we held a lock, sched now */
986*a81c3ea0SDavid du Colombier 	if(up->delaysched)
987*a81c3ea0SDavid du Colombier 		sched();
988*a81c3ea0SDavid du Colombier 	kexit(ur);
989*a81c3ea0SDavid du Colombier 
990*a81c3ea0SDavid du Colombier 	/* restore EXL in status */
991*a81c3ea0SDavid du Colombier 	setstatus(getstatus() | EXL);
992*a81c3ea0SDavid du Colombier 
993*a81c3ea0SDavid du Colombier 	return ret;
994*a81c3ea0SDavid du Colombier }
995*a81c3ea0SDavid du Colombier 
996*a81c3ea0SDavid du Colombier void
forkchild(Proc * p,Ureg * ur)997*a81c3ea0SDavid du Colombier forkchild(Proc *p, Ureg *ur)
998*a81c3ea0SDavid du Colombier {
999*a81c3ea0SDavid du Colombier 	Ureg *cur;
1000*a81c3ea0SDavid du Colombier 
1001*a81c3ea0SDavid du Colombier 	p->sched.sp = (ulong)p->kstack+KSTACK-UREGSIZE;
1002*a81c3ea0SDavid du Colombier 	p->sched.pc = (ulong)forkret;
1003*a81c3ea0SDavid du Colombier 
1004*a81c3ea0SDavid du Colombier 	cur = (Ureg*)(p->sched.sp+2*BY2WD);
1005*a81c3ea0SDavid du Colombier 	memmove(cur, ur, sizeof(Ureg));
1006*a81c3ea0SDavid du Colombier 
1007*a81c3ea0SDavid du Colombier 	cur->pc += 4;
1008*a81c3ea0SDavid du Colombier 
1009*a81c3ea0SDavid du Colombier 	/* Things from bottom of syscall we never got to execute */
1010*a81c3ea0SDavid du Colombier 	p->psstate = 0;
1011*a81c3ea0SDavid du Colombier 	p->insyscall = 0;
1012*a81c3ea0SDavid du Colombier }
1013*a81c3ea0SDavid du Colombier 
1014*a81c3ea0SDavid du Colombier static void
linkproc(void)1015*a81c3ea0SDavid du Colombier linkproc(void)
1016*a81c3ea0SDavid du Colombier {
1017*a81c3ea0SDavid du Colombier 	spllo();
1018*a81c3ea0SDavid du Colombier 	up->kpfun(up->kparg);
1019*a81c3ea0SDavid du Colombier 	pexit("kproc exiting", 0);
1020*a81c3ea0SDavid du Colombier }
1021*a81c3ea0SDavid du Colombier 
1022*a81c3ea0SDavid du Colombier void
kprocchild(Proc * p,void (* func)(void *),void * arg)1023*a81c3ea0SDavid du Colombier kprocchild(Proc *p, void (*func)(void*), void *arg)
1024*a81c3ea0SDavid du Colombier {
1025*a81c3ea0SDavid du Colombier 	p->sched.pc = (ulong)linkproc;
1026*a81c3ea0SDavid du Colombier 	p->sched.sp = (ulong)p->kstack+KSTACK;
1027*a81c3ea0SDavid du Colombier 
1028*a81c3ea0SDavid du Colombier 	p->kpfun = func;
1029*a81c3ea0SDavid du Colombier 	p->kparg = arg;
1030*a81c3ea0SDavid du Colombier }
1031*a81c3ea0SDavid du Colombier 
1032*a81c3ea0SDavid du Colombier /* set up user registers before return from exec() */
1033*a81c3ea0SDavid du Colombier long
execregs(ulong entry,ulong ssize,ulong nargs)1034*a81c3ea0SDavid du Colombier execregs(ulong entry, ulong ssize, ulong nargs)
1035*a81c3ea0SDavid du Colombier {
1036*a81c3ea0SDavid du Colombier 	Ureg *ur;
1037*a81c3ea0SDavid du Colombier 	ulong *sp;
1038*a81c3ea0SDavid du Colombier 
1039*a81c3ea0SDavid du Colombier 	sp = (ulong*)(USTKTOP - ssize);
1040*a81c3ea0SDavid du Colombier 	*--sp = nargs;
1041*a81c3ea0SDavid du Colombier 
1042*a81c3ea0SDavid du Colombier 	ur = (Ureg*)up->dbgreg;
1043*a81c3ea0SDavid du Colombier 	ur->usp = (ulong)sp;
1044*a81c3ea0SDavid du Colombier 	ur->pc = entry - 4;		/* syscall advances it */
1045*a81c3ea0SDavid du Colombier 	up->fpsave.fpstatus = initfp.fpstatus;
1046*a81c3ea0SDavid du Colombier 	return USTKTOP-sizeof(Tos);	/* address of kernel/user shared data */
1047*a81c3ea0SDavid du Colombier }
1048*a81c3ea0SDavid du Colombier 
1049*a81c3ea0SDavid du Colombier ulong
userpc(void)1050*a81c3ea0SDavid du Colombier userpc(void)
1051*a81c3ea0SDavid du Colombier {
1052*a81c3ea0SDavid du Colombier 	Ureg *ur;
1053*a81c3ea0SDavid du Colombier 
1054*a81c3ea0SDavid du Colombier 	ur = (Ureg*)up->dbgreg;
1055*a81c3ea0SDavid du Colombier 	return ur->pc;
1056*a81c3ea0SDavid du Colombier }
1057*a81c3ea0SDavid du Colombier 
1058*a81c3ea0SDavid du Colombier /*
1059*a81c3ea0SDavid du Colombier  * This routine must save the values of registers the user is not
1060*a81c3ea0SDavid du Colombier  * permitted to write from devproc and then restore the saved values
1061*a81c3ea0SDavid du Colombier  * before returning
1062*a81c3ea0SDavid du Colombier  */
1063*a81c3ea0SDavid du Colombier void
setregisters(Ureg * xp,char * pureg,char * uva,int n)1064*a81c3ea0SDavid du Colombier setregisters(Ureg *xp, char *pureg, char *uva, int n)
1065*a81c3ea0SDavid du Colombier {
1066*a81c3ea0SDavid du Colombier 	ulong status;
1067*a81c3ea0SDavid du Colombier 
1068*a81c3ea0SDavid du Colombier 	status = xp->status;
1069*a81c3ea0SDavid du Colombier 	memmove(pureg, uva, n);
1070*a81c3ea0SDavid du Colombier 	xp->status = status;
1071*a81c3ea0SDavid du Colombier }
1072*a81c3ea0SDavid du Colombier 
1073*a81c3ea0SDavid du Colombier /*
1074*a81c3ea0SDavid du Colombier  * Give enough context in the ureg to produce a kernel stack for
1075*a81c3ea0SDavid du Colombier  * a sleeping process
1076*a81c3ea0SDavid du Colombier  */
1077*a81c3ea0SDavid du Colombier void
setkernur(Ureg * xp,Proc * p)1078*a81c3ea0SDavid du Colombier setkernur(Ureg *xp, Proc *p)
1079*a81c3ea0SDavid du Colombier {
1080*a81c3ea0SDavid du Colombier 	xp->pc = p->sched.pc;
1081*a81c3ea0SDavid du Colombier 	xp->sp = p->sched.sp;
1082*a81c3ea0SDavid du Colombier 	xp->r24 = (ulong)p;		/* up */
1083*a81c3ea0SDavid du Colombier 	xp->r31 = (ulong)sched;
1084*a81c3ea0SDavid du Colombier }
1085*a81c3ea0SDavid du Colombier 
1086*a81c3ea0SDavid du Colombier ulong
dbgpc(Proc * p)1087*a81c3ea0SDavid du Colombier dbgpc(Proc *p)
1088*a81c3ea0SDavid du Colombier {
1089*a81c3ea0SDavid du Colombier 	Ureg *ur;
1090*a81c3ea0SDavid du Colombier 
1091*a81c3ea0SDavid du Colombier 	ur = p->dbgreg;
1092*a81c3ea0SDavid du Colombier 	if(ur == 0)
1093*a81c3ea0SDavid du Colombier 		return 0;
1094*a81c3ea0SDavid du Colombier 
1095*a81c3ea0SDavid du Colombier 	return ur->pc;
1096*a81c3ea0SDavid du Colombier }
1097