xref: /plan9/sys/src/9/ppc/trap.c (revision fac6300f1f1b25611e114fc0bdda9cf428c13da4)
1458db832SDavid du Colombier #include	"u.h"
2458db832SDavid du Colombier #include	"../port/lib.h"
3458db832SDavid du Colombier #include	"mem.h"
4458db832SDavid du Colombier #include	"dat.h"
5458db832SDavid du Colombier #include	"fns.h"
6458db832SDavid du Colombier #include	"ureg.h"
7458db832SDavid du Colombier #include	"../port/error.h"
8fe853e23SDavid du Colombier #include	"tos.h"
94fec87e5SDavid du Colombier #include	<trace.h>
10458db832SDavid du Colombier 
11458db832SDavid du Colombier static Lock vctllock;
124de34a7eSDavid du Colombier Vctl *vctl[256];
13458db832SDavid du Colombier 
145d9de2d3SDavid du Colombier int intrstack[5];
155d9de2d3SDavid du Colombier uvlong intrtime[5];
165d9de2d3SDavid du Colombier vlong lastoffset;
175d9de2d3SDavid du Colombier int inintr;
185d9de2d3SDavid du Colombier int nintr[10];
195d9de2d3SDavid du Colombier int nintro;
205d9de2d3SDavid du Colombier int dblintr[64];
215d9de2d3SDavid du Colombier ulong thisto[32];
225d9de2d3SDavid du Colombier ulong thistoo;
235d9de2d3SDavid du Colombier vlong vnot[64];
245d9de2d3SDavid du Colombier ulong vnon[64];
255d9de2d3SDavid du Colombier 
26458db832SDavid du Colombier void
intrenable(int irq,void (* f)(Ureg *,void *),void * a,char * name)27458db832SDavid du Colombier intrenable(int irq, void (*f)(Ureg*, void*), void* a, char *name)
28458db832SDavid du Colombier {
29458db832SDavid du Colombier 	int vno;
30458db832SDavid du Colombier 	Vctl *v;
31458db832SDavid du Colombier 
32458db832SDavid du Colombier 	if(f == nil){
33458db832SDavid du Colombier 		print("intrenable: nil handler for %d for %s\n",
34458db832SDavid du Colombier 			irq, name);
35458db832SDavid du Colombier 		return;
36458db832SDavid du Colombier 	}
37458db832SDavid du Colombier 
38458db832SDavid du Colombier 	v = xalloc(sizeof(Vctl));
39458db832SDavid du Colombier 	v->isintr = 1;
40458db832SDavid du Colombier 	v->irq = irq;
41458db832SDavid du Colombier 	v->f = f;
42458db832SDavid du Colombier 	v->a = a;
43458db832SDavid du Colombier 	strncpy(v->name, name, KNAMELEN-1);
44458db832SDavid du Colombier 	v->name[KNAMELEN-1] = 0;
45458db832SDavid du Colombier 
46458db832SDavid du Colombier 	ilock(&vctllock);
47458db832SDavid du Colombier 	vno = vectorenable(v);
48458db832SDavid du Colombier 	if(vno == -1){
49458db832SDavid du Colombier 		iunlock(&vctllock);
50458db832SDavid du Colombier 		print("intrenable: couldn't enable irq %d for %s\n",
51458db832SDavid du Colombier 			irq, v->name);
52458db832SDavid du Colombier 		xfree(v);
53458db832SDavid du Colombier 		return;
54458db832SDavid du Colombier 	}
55458db832SDavid du Colombier 	v->next = vctl[vno];
56458db832SDavid du Colombier 	vctl[vno] = v;
57458db832SDavid du Colombier 	iunlock(&vctllock);
58458db832SDavid du Colombier }
59458db832SDavid du Colombier 
60458db832SDavid du Colombier void
intrdisable(int irq,void (* f)(Ureg *,void *),void * a,char * name)61458db832SDavid du Colombier intrdisable(int irq, void (*f)(Ureg *, void *), void *a, char *name)
62458db832SDavid du Colombier {
63458db832SDavid du Colombier 	Vctl **pv, *v;
64458db832SDavid du Colombier 
65458db832SDavid du Colombier 	ilock(&vctllock);
66458db832SDavid du Colombier 	pv = &vctl[irq];
67458db832SDavid du Colombier 	while (*pv &&
68458db832SDavid du Colombier 		  ((*pv)->irq != irq || (*pv)->f != f || (*pv)->a != a ||
69458db832SDavid du Colombier 		   strcmp((*pv)->name, name)))
70458db832SDavid du Colombier 		pv = &((*pv)->next);
714de34a7eSDavid du Colombier 
724de34a7eSDavid du Colombier 	if(*pv == nil){
734de34a7eSDavid du Colombier 		print("intrdisable: irq %d not found\n", irq);
744de34a7eSDavid du Colombier 		iunlock(&vctllock);
754de34a7eSDavid du Colombier 		return;
764de34a7eSDavid du Colombier 	}
77458db832SDavid du Colombier 
78458db832SDavid du Colombier 	v = *pv;
79458db832SDavid du Colombier 	*pv = (*pv)->next;	/* Link out the entry */
80458db832SDavid du Colombier 
81458db832SDavid du Colombier 	if(vctl[irq] == nil)
82458db832SDavid du Colombier 		vectordisable(v);
83458db832SDavid du Colombier 	iunlock(&vctllock);
84458db832SDavid du Colombier 	xfree(v);
85458db832SDavid du Colombier }
86458db832SDavid du Colombier 
87458db832SDavid du Colombier void	syscall(Ureg*);
88458db832SDavid du Colombier void	noted(Ureg*, ulong);
89458db832SDavid du Colombier static void _dumpstack(Ureg*);
90458db832SDavid du Colombier 
91458db832SDavid du Colombier char *excname[] =
92458db832SDavid du Colombier {
93458db832SDavid du Colombier 	"reserved 0",
94458db832SDavid du Colombier 	"system reset",
95458db832SDavid du Colombier 	"machine check",
96458db832SDavid du Colombier 	"data access",
97458db832SDavid du Colombier 	"instruction access",
98458db832SDavid du Colombier 	"external interrupt",
99458db832SDavid du Colombier 	"alignment",
100458db832SDavid du Colombier 	"program exception",
101458db832SDavid du Colombier 	"floating-point unavailable",
102458db832SDavid du Colombier 	"decrementer",
103458db832SDavid du Colombier 	"reserved A",
104458db832SDavid du Colombier 	"reserved B",
105458db832SDavid du Colombier 	"system call",
106458db832SDavid du Colombier 	"trace trap",
107458db832SDavid du Colombier 	"floating point assist",
108458db832SDavid du Colombier 	"reserved F",
109458db832SDavid du Colombier 	"reserved 10",
110458db832SDavid du Colombier 	"data load translation miss",
111458db832SDavid du Colombier 	"data store translation miss",
112458db832SDavid du Colombier 	"instruction address breakpoint",
113458db832SDavid du Colombier 	"system management interrupt",
114458db832SDavid du Colombier };
115458db832SDavid du Colombier 
116458db832SDavid du Colombier char *fpcause[] =
117458db832SDavid du Colombier {
118458db832SDavid du Colombier 	"inexact operation",
119458db832SDavid du Colombier 	"division by zero",
120458db832SDavid du Colombier 	"underflow",
121458db832SDavid du Colombier 	"overflow",
122458db832SDavid du Colombier 	"invalid operation",
123458db832SDavid du Colombier };
124458db832SDavid du Colombier char	*fpexcname(Ureg*, ulong, char*);
125458db832SDavid du Colombier #define FPEXPMASK	0xfff80300		/* Floating exception bits in fpscr */
126458db832SDavid du Colombier 
127458db832SDavid du Colombier 
128458db832SDavid du Colombier char *regname[]={
129458db832SDavid du Colombier 	"CAUSE",	"SRR1",
130458db832SDavid du Colombier 	"PC",		"GOK",
131458db832SDavid du Colombier 	"LR",		"CR",
132458db832SDavid du Colombier 	"XER",		"CTR",
133458db832SDavid du Colombier 	"R0",		"R1",
134458db832SDavid du Colombier 	"R2",		"R3",
135458db832SDavid du Colombier 	"R4",		"R5",
136458db832SDavid du Colombier 	"R6",		"R7",
137458db832SDavid du Colombier 	"R8",		"R9",
138458db832SDavid du Colombier 	"R10",		"R11",
139458db832SDavid du Colombier 	"R12",		"R13",
140458db832SDavid du Colombier 	"R14",		"R15",
141458db832SDavid du Colombier 	"R16",		"R17",
142458db832SDavid du Colombier 	"R18",		"R19",
143458db832SDavid du Colombier 	"R20",		"R21",
144458db832SDavid du Colombier 	"R22",		"R23",
145458db832SDavid du Colombier 	"R24",		"R25",
146458db832SDavid du Colombier 	"R26",		"R27",
147458db832SDavid du Colombier 	"R28",		"R29",
148458db832SDavid du Colombier 	"R30",		"R31",
149458db832SDavid du Colombier 	"DCMP",		"ICMP",
150458db832SDavid du Colombier 	"DMISS",	"IMISS",
151458db832SDavid du Colombier 	"HASH1",	"HASH2",
152458db832SDavid du Colombier 	"DAR",		"DSISR",
153458db832SDavid du Colombier };
154458db832SDavid du Colombier 
155458db832SDavid du Colombier void
kexit(Ureg *)156fe853e23SDavid du Colombier kexit(Ureg*)
157fe853e23SDavid du Colombier {
158fe853e23SDavid du Colombier 	uvlong t;
159fe853e23SDavid du Colombier 	Tos *tos;
160fe853e23SDavid du Colombier 
161fe853e23SDavid du Colombier 	/* precise time accounting, kernel exit */
162fe853e23SDavid du Colombier 	tos = (Tos*)(USTKTOP-sizeof(Tos));
163fe853e23SDavid du Colombier 	cycles(&t);
164fe853e23SDavid du Colombier 	tos->kcycles += t - up->kentry;
165fe853e23SDavid du Colombier 	tos->pcycles = up->pcycles;
166fe853e23SDavid du Colombier 	tos->pid = up->pid;
167fe853e23SDavid du Colombier }
168fe853e23SDavid du Colombier 
169fe853e23SDavid du Colombier void
trap(Ureg * ureg)170458db832SDavid du Colombier trap(Ureg *ureg)
171458db832SDavid du Colombier {
172458db832SDavid du Colombier 	int ecode, user;
173458db832SDavid du Colombier 	char buf[ERRMAX], *s;
1744de34a7eSDavid du Colombier 	extern FPsave initfp;
175458db832SDavid du Colombier 
176458db832SDavid du Colombier 	ecode = (ureg->cause >> 8) & 0xff;
177458db832SDavid du Colombier 	user = (ureg->srr1 & MSR_PR) != 0;
178fe853e23SDavid du Colombier 	if(user){
179fe853e23SDavid du Colombier 		cycles(&up->kentry);
180458db832SDavid du Colombier 		up->dbgreg = ureg;
181fe853e23SDavid du Colombier 	}
182458db832SDavid du Colombier 	if(ureg->status & MSR_RI == 0)
183458db832SDavid du Colombier 		print("double fault?: ecode = %d\n", ecode);
184458db832SDavid du Colombier 
185458db832SDavid du Colombier 	switch(ecode) {
186458db832SDavid du Colombier 	case CEI:
187458db832SDavid du Colombier 		m->intr++;
188458db832SDavid du Colombier 		intr(ureg);
189458db832SDavid du Colombier 		break;
190458db832SDavid du Colombier 	case CDEC:
191458db832SDavid du Colombier 		clockintr(ureg);
192458db832SDavid du Colombier 		break;
193458db832SDavid du Colombier 	case CDSI:
194458db832SDavid du Colombier 		m->pfault++;
195458db832SDavid du Colombier 		if (up == nil){
196458db832SDavid du Colombier 			dumpregs(ureg);
197458db832SDavid du Colombier 			panic("kernel fault");
198458db832SDavid du Colombier 		}
199458db832SDavid du Colombier 		up->mmureg = ureg;
200458db832SDavid du Colombier 		faultpower(ureg, ureg->dar, (ureg->dsisr & BIT(6)) == 0);
201458db832SDavid du Colombier 		break;
202458db832SDavid du Colombier 	case CISI:
203458db832SDavid du Colombier 		m->pfault++;
204458db832SDavid du Colombier 		if (up == nil){
205458db832SDavid du Colombier 			dumpregs(ureg);
206458db832SDavid du Colombier 			panic("kernel fault");
207458db832SDavid du Colombier 		}
208458db832SDavid du Colombier 		up->mmureg = ureg;
209458db832SDavid du Colombier 		faultpower(ureg, ureg->pc, 1);
210458db832SDavid du Colombier 		break;
211458db832SDavid du Colombier 	case CIMISS:	/* instruction miss */
212458db832SDavid du Colombier 		if (up == nil){
213458db832SDavid du Colombier 			dumpregs(ureg);
214458db832SDavid du Colombier 			panic("kernel fault");
215458db832SDavid du Colombier 		}
216458db832SDavid du Colombier 		up->mmureg = ureg;
217458db832SDavid du Colombier 		faultpower(ureg, ureg->imiss, 1);
218458db832SDavid du Colombier 		break;
219458db832SDavid du Colombier 	case CLMISS:	/* data load miss */
220458db832SDavid du Colombier 		if (up == nil){
221458db832SDavid du Colombier 			dumpregs(ureg);
222458db832SDavid du Colombier 			panic("kernel fault");
223458db832SDavid du Colombier 		}
224458db832SDavid du Colombier 		up->mmureg = ureg;
225458db832SDavid du Colombier 		faultpower(ureg, ureg->dmiss, 1);
226458db832SDavid du Colombier 		break;
227458db832SDavid du Colombier 	case CSMISS:	/* data store miss */
228458db832SDavid du Colombier 		if (up == nil){
229458db832SDavid du Colombier 			dumpregs(ureg);
230458db832SDavid du Colombier 			panic("kernel fault");
231458db832SDavid du Colombier 		}
232458db832SDavid du Colombier 		up->mmureg = ureg;
233458db832SDavid du Colombier 		faultpower(ureg, ureg->dmiss, 0);
234458db832SDavid du Colombier 		break;
235458db832SDavid du Colombier 
236458db832SDavid du Colombier 	case CSYSCALL:
237458db832SDavid du Colombier 		if(!user)
238458db832SDavid du Colombier 			panic("syscall in kernel: srr1 0x%4.4luX\n", ureg->srr1);
239458db832SDavid du Colombier 		syscall(ureg);
2402cca75a1SDavid du Colombier 		if (up->delaysched){
241fe853e23SDavid du Colombier 			sched();
2422cca75a1SDavid du Colombier 			splhi();
2432cca75a1SDavid du Colombier 		}
244fe853e23SDavid du Colombier 		kexit(ureg);
245458db832SDavid du Colombier 		return;		/* syscall() calls notify itself, don't do it again */
246458db832SDavid du Colombier 
247458db832SDavid du Colombier 	case CFPU:
248458db832SDavid du Colombier 		if(!user || up == nil) {
249458db832SDavid du Colombier 			dumpregs(ureg);
250458db832SDavid du Colombier 			panic("floating point in kernel");
251458db832SDavid du Colombier 		}
252458db832SDavid du Colombier 		switch(up->fpstate){
253458db832SDavid du Colombier 		case FPinit:
254458db832SDavid du Colombier 			fprestore(&initfp);
255458db832SDavid du Colombier 			up->fpstate = FPactive;
256458db832SDavid du Colombier 			break;
257458db832SDavid du Colombier 		case FPinactive:
258458db832SDavid du Colombier 			fprestore(&up->fpsave);
259458db832SDavid du Colombier 			up->fpstate = FPactive;
260458db832SDavid du Colombier 			break;
261458db832SDavid du Colombier 		case FPactive:
262458db832SDavid du Colombier 			print("up->fpstate %d\n", up->fpstate);
263458db832SDavid du Colombier 			delay(100);
264458db832SDavid du Colombier 			dumpregs(ureg);
265458db832SDavid du Colombier 			delay(200);
266458db832SDavid du Colombier 			panic("fpstate");
267458db832SDavid du Colombier 			break;
268458db832SDavid du Colombier 		default:
269458db832SDavid du Colombier 			if(user){
270458db832SDavid du Colombier 				spllo();
271458db832SDavid du Colombier 				sprint(buf, "sys: floating point in note handler:");
272458db832SDavid du Colombier 				postnote(up, 1, buf, NDebug);
273458db832SDavid du Colombier 				break;
274458db832SDavid du Colombier 			}
275458db832SDavid du Colombier 			panic("kernel fpstate illegal");
276458db832SDavid du Colombier 		}
277458db832SDavid du Colombier 		ureg->srr1 |= MSR_FP;
278458db832SDavid du Colombier 		break;
279458db832SDavid du Colombier 	case CPROG:
280458db832SDavid du Colombier 		if(ureg->status & (1<<19))
281458db832SDavid du Colombier 			s = "floating point exception";
282458db832SDavid du Colombier 		else if(ureg->status & (1<<18))
283458db832SDavid du Colombier 			s = "illegal instruction";
284458db832SDavid du Colombier 		else if(ureg->status & (1<<17))
285458db832SDavid du Colombier 			s = "privileged instruction";
286458db832SDavid du Colombier 		else
287458db832SDavid du Colombier 			s = "undefined program exception";
288458db832SDavid du Colombier 		if(user){
289458db832SDavid du Colombier 			spllo();
290458db832SDavid du Colombier 			sprint(buf, "sys: trap: %s", s);
291458db832SDavid du Colombier 			postnote(up, 1, buf, NDebug);
292458db832SDavid du Colombier 			break;
293458db832SDavid du Colombier 		}
294458db832SDavid du Colombier 		dumpregs(ureg);
295458db832SDavid du Colombier 		panic(s);
296458db832SDavid du Colombier 		break;
297458db832SDavid du Colombier 	default:
2982615514eSDavid du Colombier 		if(ecode < nelem(excname) && user){
299458db832SDavid du Colombier 			spllo();
300458db832SDavid du Colombier 			sprint(buf, "sys: trap: %s", excname[ecode]);
301458db832SDavid du Colombier 			postnote(up, 1, buf, NDebug);
302458db832SDavid du Colombier 			break;
303458db832SDavid du Colombier 		}
304458db832SDavid du Colombier 		dumpregs(ureg);
305458db832SDavid du Colombier 		if(ecode < nelem(excname))
306458db832SDavid du Colombier 			panic("%s", excname[ecode]);
307458db832SDavid du Colombier 		panic("unknown trap/intr: %d\n", ecode);
308458db832SDavid du Colombier 	}
309458db832SDavid du Colombier 
310458db832SDavid du Colombier 	/* restoreureg must execute at high IPL */
311458db832SDavid du Colombier 	splhi();
312da51d93aSDavid du Colombier 
313da51d93aSDavid du Colombier 	/* delaysched set because we held a lock or because our quantum ended */
3142009dc88SDavid du Colombier 	if(up && up->delaysched && ecode == CDEC){
315da51d93aSDavid du Colombier 		sched();
316da51d93aSDavid du Colombier 		splhi();
317da51d93aSDavid du Colombier 	}
318da51d93aSDavid du Colombier 
319458db832SDavid du Colombier 	if(user) {
320458db832SDavid du Colombier 		if (up->fpstate == FPactive && (ureg->srr1 & MSR_FP) == 0){
321458db832SDavid du Colombier 			postnote(up, 1, buf, NDebug);
322458db832SDavid du Colombier 		}
323458db832SDavid du Colombier 		notify(ureg);
324458db832SDavid du Colombier 		if(up->fpstate != FPactive)
325458db832SDavid du Colombier 			ureg->srr1 &= ~MSR_FP;
326fe853e23SDavid du Colombier 		kexit(ureg);
327458db832SDavid du Colombier 	}
328458db832SDavid du Colombier }
329458db832SDavid du Colombier 
330458db832SDavid du Colombier void
faultpower(Ureg * ureg,ulong addr,int read)331458db832SDavid du Colombier faultpower(Ureg *ureg, ulong addr, int read)
332458db832SDavid du Colombier {
333458db832SDavid du Colombier 	int user, insyscall, n;
334458db832SDavid du Colombier 	char buf[ERRMAX];
335458db832SDavid du Colombier 
336458db832SDavid du Colombier 	user = (ureg->srr1 & MSR_PR) != 0;
337458db832SDavid du Colombier 	insyscall = up->insyscall;
338458db832SDavid du Colombier 	up->insyscall = 1;
339458db832SDavid du Colombier 	n = fault(addr, read);
340458db832SDavid du Colombier 	if(n < 0){
341458db832SDavid du Colombier 		if(!user){
342458db832SDavid du Colombier 			dumpregs(ureg);
343458db832SDavid du Colombier 			panic("fault: 0x%lux", addr);
344458db832SDavid du Colombier 		}
345458db832SDavid du Colombier 		sprint(buf, "sys: trap: fault %s addr=0x%lux", read? "read" : "write", addr);
346458db832SDavid du Colombier 		postnote(up, 1, buf, NDebug);
347458db832SDavid du Colombier 	}
348458db832SDavid du Colombier 	up->insyscall = insyscall;
349458db832SDavid du Colombier }
350458db832SDavid du Colombier 
351458db832SDavid du Colombier void
sethvec(int v,void (* r)(void))352458db832SDavid du Colombier sethvec(int v, void (*r)(void))
353458db832SDavid du Colombier {
354458db832SDavid du Colombier 	ulong *vp, pa, o;
355458db832SDavid du Colombier 
356458db832SDavid du Colombier 	vp = KADDR(v);
357458db832SDavid du Colombier 	vp[0] = 0x7c1043a6;			/* MOVW R0, SPR(SPRG0) */
358458db832SDavid du Colombier 	vp[1] = 0x7c0802a6;			/* MOVW LR, R0 */
359458db832SDavid du Colombier 	vp[2] = 0x7c1243a6;			/* MOVW R0, SPR(SPRG2) */
360458db832SDavid du Colombier 	pa = PADDR(r);
361458db832SDavid du Colombier 	o = pa >> 25;
362458db832SDavid du Colombier 	if(o != 0 && o != 0x7F){
363458db832SDavid du Colombier 		/* a branch too far */
364458db832SDavid du Colombier 		vp[3] = (15<<26)|(pa>>16);	/* MOVW $r&~0xFFFF, R0 */
365458db832SDavid du Colombier 		vp[4] = (24<<26)|(pa&0xFFFF);	/* OR $r&0xFFFF, R0 */
366458db832SDavid du Colombier 		vp[5] = 0x7c0803a6;		/* MOVW	R0, LR */
367458db832SDavid du Colombier 		vp[6] = 0x4e800021;		/* BL (LR) */
368458db832SDavid du Colombier 	}else
369458db832SDavid du Colombier 		vp[3] = (18<<26)|(pa&0x3FFFFFC)|3;	/* bla */
370458db832SDavid du Colombier }
371458db832SDavid du Colombier 
372458db832SDavid du Colombier void
setmvec(int v,void (* r)(void),void (* t)(void))373458db832SDavid du Colombier setmvec(int v, void (*r)(void), void (*t)(void))
374458db832SDavid du Colombier {
375458db832SDavid du Colombier 	ulong *vp, pa, o, n;
376458db832SDavid du Colombier 
377458db832SDavid du Colombier 	vp = KADDR(v);
378458db832SDavid du Colombier 	n = 0;
379458db832SDavid du Colombier 	vp[n++] = 0x7c1043a6;			/* MOVW R0, SPR(SPRG0) */
380458db832SDavid du Colombier 	vp[n++] = 0x7c0802a6;			/* MOVW LR, R0 */
381458db832SDavid du Colombier 	vp[n++] = 0x7c1243a6;			/* MOVW R0, SPR(SPRG2) */
382458db832SDavid du Colombier 	pa = PADDR(r);
383458db832SDavid du Colombier 	o = pa >> 25;
384458db832SDavid du Colombier 	if(o != 0 && o != 0x7F){
385458db832SDavid du Colombier 		/* a branch too far */
386458db832SDavid du Colombier 		vp[n++] = (15<<26)|(pa>>16);	/* MOVW $r&~0xFFFF, R0 */
387458db832SDavid du Colombier 		vp[n++] = (24<<26)|(pa&0xFFFF);	/* OR $r&0xFFFF, R0 */
388458db832SDavid du Colombier 		vp[n++] = 0x7c0803a6;		/* MOVW	R0, LR */
389458db832SDavid du Colombier 		vp[n++] = 0x4e800021;		/* BL (LR) */
390458db832SDavid du Colombier 	}else
391458db832SDavid du Colombier 		vp[n++] = (18<<26)|(pa&0x3FFFFFC)|3;	/* bla */
392458db832SDavid du Colombier 	pa = PADDR(t);
393458db832SDavid du Colombier 	o = pa >> 25;
394458db832SDavid du Colombier 	if(o != 0 && o != 0x7F){
395458db832SDavid du Colombier 		/* a branch too far */
396458db832SDavid du Colombier 		vp[n++] = (15<<26)|(pa>>16);	/* MOVW $r&~0xFFFF, R0 */
397458db832SDavid du Colombier 		vp[n++] = (24<<26)|(pa&0xFFFF);	/* OR $r&0xFFFF, R0 */
398458db832SDavid du Colombier 		vp[n++] = 0x7c0803a6;		/* MOVW	R0, LR */
399458db832SDavid du Colombier 		vp[n] = 0x4e800021;		/* BL (LR) */
400458db832SDavid du Colombier 	}else
401458db832SDavid du Colombier 		vp[n] = (18<<26)|(pa&0x3FFFFFC)|3;	/* bla */
402458db832SDavid du Colombier }
403458db832SDavid du Colombier 
4045d9de2d3SDavid du Colombier 
4055d9de2d3SDavid du Colombier void
intr(Ureg * ureg)4065d9de2d3SDavid du Colombier intr(Ureg *ureg)
4075d9de2d3SDavid du Colombier {
4085d9de2d3SDavid du Colombier 	int vno, pvno, i;
4095d9de2d3SDavid du Colombier 	Vctl *ctl, *v;
4105d9de2d3SDavid du Colombier 	void (*pt)(Proc*, int, vlong);
4115d9de2d3SDavid du Colombier 	uvlong tt, x;
4125d9de2d3SDavid du Colombier 
4135d9de2d3SDavid du Colombier 	cycles(&tt);
4145d9de2d3SDavid du Colombier 	pt = proctrace;
4155d9de2d3SDavid du Colombier 	pvno = -1;
4165d9de2d3SDavid du Colombier 	for(i = 0; i < 64; i++){
4175d9de2d3SDavid du Colombier 		vno = intvec();
4185d9de2d3SDavid du Colombier 		if(vno == 0)
4195d9de2d3SDavid du Colombier 			break;
4205d9de2d3SDavid du Colombier 		cycles(&x);
4215d9de2d3SDavid du Colombier 		vnot[vno] -= x;
4225d9de2d3SDavid du Colombier 		if(vno == pvno)
4235d9de2d3SDavid du Colombier 			dblintr[vno]++;
4245d9de2d3SDavid du Colombier 		pvno = vno;
4255d9de2d3SDavid du Colombier 		if(pt && up && up->trace)
4265d9de2d3SDavid du Colombier 			pt(up, (vno << 16) | SInts, 0);
4275d9de2d3SDavid du Colombier 
4285d9de2d3SDavid du Colombier 		if(vno > nelem(vctl) || (ctl = vctl[vno]) == 0) {
4295d9de2d3SDavid du Colombier 			iprint("spurious intr %d\n", vno);
4305d9de2d3SDavid du Colombier 			return;
4315d9de2d3SDavid du Colombier 		}
4325d9de2d3SDavid du Colombier 
4335d9de2d3SDavid du Colombier 		for(v = ctl; v != nil; v = v->next)
4345d9de2d3SDavid du Colombier 			if(v->f)
4355d9de2d3SDavid du Colombier 				v->f(ureg, v->a);
4365d9de2d3SDavid du Colombier 
4375d9de2d3SDavid du Colombier 		intend(vno);	/* reenable the interrupt */
4385d9de2d3SDavid du Colombier 
4395d9de2d3SDavid du Colombier 		if(pt && up && up->trace)
4405d9de2d3SDavid du Colombier 			pt(up, (vno << 16) | SInte, 0);
4415d9de2d3SDavid du Colombier 		cycles(&x);
4425d9de2d3SDavid du Colombier 		vnot[vno] += x;
4435d9de2d3SDavid du Colombier 		vnon[vno]++;
4445d9de2d3SDavid du Colombier 	}
4455d9de2d3SDavid du Colombier 	if(i < nelem(nintr))
4465d9de2d3SDavid du Colombier 		nintr[i]++;
4475d9de2d3SDavid du Colombier 	else
4485d9de2d3SDavid du Colombier 		nintro++;
4495d9de2d3SDavid du Colombier 	cycles(&x);
4505d9de2d3SDavid du Colombier 	tt = x - tt;
4515d9de2d3SDavid du Colombier 	i = tt / 3600;	 /* 100 microseconds units */
4525d9de2d3SDavid du Colombier 	if(i < nelem(thisto))
4535d9de2d3SDavid du Colombier 		thisto[i]++;
4545d9de2d3SDavid du Colombier 	else
4555d9de2d3SDavid du Colombier 		thistoo++;
4565d9de2d3SDavid du Colombier 
4575d9de2d3SDavid du Colombier 	if(up)
4585d9de2d3SDavid du Colombier 		preempted();
4595d9de2d3SDavid du Colombier }
4605d9de2d3SDavid du Colombier 
461458db832SDavid du Colombier char*
fpexcname(Ureg * ur,ulong fpscr,char * buf)462458db832SDavid du Colombier fpexcname(Ureg *ur, ulong fpscr, char *buf)
463458db832SDavid du Colombier {
464458db832SDavid du Colombier 	int i;
465458db832SDavid du Colombier 	char *s;
466458db832SDavid du Colombier 	ulong fppc;
467458db832SDavid du Colombier 
468458db832SDavid du Colombier 	fppc = ur->pc;
469458db832SDavid du Colombier 	s = 0;
470458db832SDavid du Colombier 	fpscr >>= 3;		/* trap enable bits */
471458db832SDavid du Colombier 	fpscr &= (fpscr>>22);	/* anded with exceptions */
472458db832SDavid du Colombier 	for(i=0; i<5; i++)
473458db832SDavid du Colombier 		if(fpscr & (1<<i))
474458db832SDavid du Colombier 			s = fpcause[i];
475458db832SDavid du Colombier 	if(s == 0)
476458db832SDavid du Colombier 		return "no floating point exception";
477458db832SDavid du Colombier 	sprint(buf, "%s fppc=0x%lux", s, fppc);
478458db832SDavid du Colombier 	return buf;
479458db832SDavid du Colombier }
480458db832SDavid du Colombier 
481458db832SDavid du Colombier /*
482458db832SDavid du Colombier  * Fill in enough of Ureg to get a stack trace, and call a function.
483458db832SDavid du Colombier  * Used by debugging interface rdb.
484458db832SDavid du Colombier  */
485458db832SDavid du Colombier 
486458db832SDavid du Colombier static void
getpcsp(ulong * pc,ulong * sp)487458db832SDavid du Colombier getpcsp(ulong *pc, ulong *sp)
488458db832SDavid du Colombier {
489458db832SDavid du Colombier 	*pc = getcallerpc(&pc);
490458db832SDavid du Colombier 	*sp = (ulong)&pc-4;
491458db832SDavid du Colombier }
492458db832SDavid du Colombier 
493458db832SDavid du Colombier void
callwithureg(void (* fn)(Ureg *))494458db832SDavid du Colombier callwithureg(void (*fn)(Ureg*))
495458db832SDavid du Colombier {
496458db832SDavid du Colombier 	Ureg ureg;
497458db832SDavid du Colombier 
498458db832SDavid du Colombier 	getpcsp((ulong*)&ureg.pc, (ulong*)&ureg.sp);
499458db832SDavid du Colombier 	ureg.lr = getcallerpc(&fn);
500458db832SDavid du Colombier 	fn(&ureg);
501458db832SDavid du Colombier }
502458db832SDavid du Colombier 
503458db832SDavid du Colombier static void
_dumpstack(Ureg * ureg)504458db832SDavid du Colombier _dumpstack(Ureg *ureg)
505458db832SDavid du Colombier {
506458db832SDavid du Colombier 	ulong l, sl, el, v;
507458db832SDavid du Colombier 	int i;
508458db832SDavid du Colombier 
509458db832SDavid du Colombier 	l = (ulong)&l;
510458db832SDavid du Colombier 	if(up == 0){
511458db832SDavid du Colombier 		el = (ulong)m+BY2PG;
512458db832SDavid du Colombier 		sl = el-KSTACK;
513458db832SDavid du Colombier 	}
514458db832SDavid du Colombier 	else{
515458db832SDavid du Colombier 		sl = (ulong)up->kstack;
516458db832SDavid du Colombier 		el = sl + KSTACK;
517458db832SDavid du Colombier 	}
518458db832SDavid du Colombier 	if(l > el || l < sl){
519458db832SDavid du Colombier 		el = (ulong)m+BY2PG;
520458db832SDavid du Colombier 		sl = el-KSTACK;
521458db832SDavid du Colombier 	}
522458db832SDavid du Colombier 	if(l > el || l < sl)
523458db832SDavid du Colombier 		return;
524458db832SDavid du Colombier 	print("ktrace /kernel/path %.8lux %.8lux %.8lux\n", ureg->pc, ureg->sp, ureg->lr);
525458db832SDavid du Colombier 	i = 0;
526458db832SDavid du Colombier 	for(; l < el; l += 4){
527458db832SDavid du Colombier 		v = *(ulong*)l;
528458db832SDavid du Colombier 		if(KTZERO < v && v < (ulong)etext){
529458db832SDavid du Colombier 			print("%.8lux=%.8lux ", l, v);
530458db832SDavid du Colombier 			if(i++ == 4){
531458db832SDavid du Colombier 				print("\n");
532458db832SDavid du Colombier 				i = 0;
533458db832SDavid du Colombier 			}
534458db832SDavid du Colombier 		}
535458db832SDavid du Colombier 	}
536458db832SDavid du Colombier }
537458db832SDavid du Colombier 
538458db832SDavid du Colombier void
dumpstack(void)539458db832SDavid du Colombier dumpstack(void)
540458db832SDavid du Colombier {
541458db832SDavid du Colombier 	callwithureg(_dumpstack);
542458db832SDavid du Colombier }
543458db832SDavid du Colombier 
544458db832SDavid du Colombier void
dumpregs(Ureg * ur)545458db832SDavid du Colombier dumpregs(Ureg *ur)
546458db832SDavid du Colombier {
547458db832SDavid du Colombier 	int i;
548458db832SDavid du Colombier 	ulong *l;
549458db832SDavid du Colombier 
550458db832SDavid du Colombier 	if(up) {
551458db832SDavid du Colombier 		print("registers for %s %ld\n", up->text, up->pid);
552458db832SDavid du Colombier 		if(ur->srr1 & MSR_PR == 0)
553458db832SDavid du Colombier 		if(ur->usp < (ulong)up->kstack || ur->usp > (ulong)up->kstack+KSTACK)
554458db832SDavid du Colombier 			print("invalid stack ptr\n");
555458db832SDavid du Colombier 	}
556458db832SDavid du Colombier 	else
557458db832SDavid du Colombier 		print("registers for kernel\n");
558458db832SDavid du Colombier 
559458db832SDavid du Colombier 	for(i=0; i<16; i+=2)
560458db832SDavid du Colombier 		print("sr[%x]\t0x%.8lux\tsr[%x]\t0x%.8lux\n", i, getsr(i<<28), i+1, getsr((i+1)<<28));
561458db832SDavid du Colombier 	l = &ur->cause;
562458db832SDavid du Colombier 	for(i=0; i<sizeof regname/sizeof(char*); i+=2, l+=2)
563458db832SDavid du Colombier 		print("%s\t0x%.8lux\t%s\t0x%.8lux\n", regname[i], l[0], regname[i+1], l[1]);
564458db832SDavid du Colombier 	delay(500);
565458db832SDavid du Colombier }
566458db832SDavid du Colombier 
567458db832SDavid du Colombier static void
linkproc(void)568458db832SDavid du Colombier linkproc(void)
569458db832SDavid du Colombier {
570458db832SDavid du Colombier 	spllo();
571458db832SDavid du Colombier 	(*up->kpfun)(up->kparg);
572458db832SDavid du Colombier 	pexit("", 0);
573458db832SDavid du Colombier }
574458db832SDavid du Colombier 
575458db832SDavid du Colombier void
kprocchild(Proc * p,void (* func)(void *),void * arg)576458db832SDavid du Colombier kprocchild(Proc *p, void (*func)(void*), void *arg)
577458db832SDavid du Colombier {
578458db832SDavid du Colombier 	p->sched.pc = (ulong)linkproc;
579458db832SDavid du Colombier 	p->sched.sp = (ulong)p->kstack+KSTACK;
580458db832SDavid du Colombier 
581458db832SDavid du Colombier 	p->kpfun = func;
582458db832SDavid du Colombier 	p->kparg = arg;
583458db832SDavid du Colombier }
584458db832SDavid du Colombier 
585458db832SDavid du Colombier /*
586*fac6300fSDavid du Colombier  * called in syscallfmt.c, sysfile.c, sysproc.c
587458db832SDavid du Colombier  */
588458db832SDavid du Colombier void
validalign(uintptr addr,unsigned align)589*fac6300fSDavid du Colombier validalign(uintptr addr, unsigned align)
590458db832SDavid du Colombier {
591*fac6300fSDavid du Colombier 	/*
592*fac6300fSDavid du Colombier 	 * Plan 9 is a 32-bit O/S, and the hardware it runs on
593*fac6300fSDavid du Colombier 	 * does not usually have instructions which move 64-bit
594*fac6300fSDavid du Colombier 	 * quantities directly, synthesizing the operations
595*fac6300fSDavid du Colombier 	 * with 32-bit move instructions. Therefore, the compiler
596*fac6300fSDavid du Colombier 	 * (and hardware) usually only enforce 32-bit alignment,
597*fac6300fSDavid du Colombier 	 * if at all.
598*fac6300fSDavid du Colombier 	 *
599*fac6300fSDavid du Colombier 	 * Take this out if the architecture warrants it.
600*fac6300fSDavid du Colombier 	 */
601*fac6300fSDavid du Colombier 	if(align == sizeof(vlong))
602*fac6300fSDavid du Colombier 		align = sizeof(long);
603*fac6300fSDavid du Colombier 
604*fac6300fSDavid du Colombier 	/*
605*fac6300fSDavid du Colombier 	 * Check align is a power of 2, then addr alignment.
606*fac6300fSDavid du Colombier 	 */
607*fac6300fSDavid du Colombier 	if((align != 0 && !(align & (align-1))) && !(addr & (align-1)))
608*fac6300fSDavid du Colombier 		return;
609458db832SDavid du Colombier 	postnote(up, 1, "sys: odd address", NDebug);
610458db832SDavid du Colombier 	error(Ebadarg);
611*fac6300fSDavid du Colombier 	/*NOTREACHED*/
612458db832SDavid du Colombier }
613458db832SDavid du Colombier 
614458db832SDavid du Colombier long
execregs(ulong entry,ulong ssize,ulong nargs)615458db832SDavid du Colombier execregs(ulong entry, ulong ssize, ulong nargs)
616458db832SDavid du Colombier {
617458db832SDavid du Colombier 	ulong *sp;
618458db832SDavid du Colombier 	Ureg *ureg;
619458db832SDavid du Colombier 
620458db832SDavid du Colombier 	sp = (ulong*)(USTKTOP - ssize);
621458db832SDavid du Colombier 	*--sp = nargs;
622458db832SDavid du Colombier 
623458db832SDavid du Colombier 	ureg = up->dbgreg;
624458db832SDavid du Colombier 	ureg->usp = (ulong)sp;
625458db832SDavid du Colombier 	ureg->pc = entry;
626458db832SDavid du Colombier 	ureg->srr1 &= ~MSR_FP;		/* disable floating point */
627458db832SDavid du Colombier 	up->fpstate = FPinit;
628fe853e23SDavid du Colombier 	return USTKTOP-sizeof(Tos);		/* address of kernel/user shared data */
629458db832SDavid du Colombier }
630458db832SDavid du Colombier 
631458db832SDavid du Colombier void
forkchild(Proc * p,Ureg * ur)632458db832SDavid du Colombier forkchild(Proc *p, Ureg *ur)
633458db832SDavid du Colombier {
634458db832SDavid du Colombier 	Ureg *cur;
635458db832SDavid du Colombier 
636458db832SDavid du Colombier 	p->sched.sp = (ulong)p->kstack+KSTACK-UREGSIZE;
637458db832SDavid du Colombier 	p->sched.pc = (ulong)forkret;
638458db832SDavid du Colombier 
639458db832SDavid du Colombier 	cur = (Ureg*)(p->sched.sp+2*BY2WD);
640458db832SDavid du Colombier 	memmove(cur, ur, sizeof(Ureg));
641458db832SDavid du Colombier 	cur->r3 = 0;
642458db832SDavid du Colombier 
643458db832SDavid du Colombier 	/* Things from bottom of syscall we never got to execute */
644458db832SDavid du Colombier 	p->psstate = 0;
645458db832SDavid du Colombier 	p->insyscall = 0;
646458db832SDavid du Colombier }
647458db832SDavid du Colombier 
648458db832SDavid du Colombier ulong
userpc(void)649458db832SDavid du Colombier userpc(void)
650458db832SDavid du Colombier {
651458db832SDavid du Colombier 	Ureg *ureg;
652458db832SDavid du Colombier 
653458db832SDavid du Colombier 	ureg = (Ureg*)up->dbgreg;
654458db832SDavid du Colombier 	return ureg->pc;
655458db832SDavid du Colombier }
656458db832SDavid du Colombier 
657458db832SDavid du Colombier 
658458db832SDavid du Colombier /* This routine must save the values of registers the user is not
659458db832SDavid du Colombier  * permitted to write from devproc and then restore the saved values
660458db832SDavid du Colombier  * before returning
661458db832SDavid du Colombier  */
662458db832SDavid du Colombier void
setregisters(Ureg * xp,char * pureg,char * uva,int n)663458db832SDavid du Colombier setregisters(Ureg *xp, char *pureg, char *uva, int n)
664458db832SDavid du Colombier {
665458db832SDavid du Colombier 	ulong status;
666458db832SDavid du Colombier 
667458db832SDavid du Colombier 	status = xp->status;
668458db832SDavid du Colombier 	memmove(pureg, uva, n);
669458db832SDavid du Colombier 	xp->status = status;
670458db832SDavid du Colombier }
671458db832SDavid du Colombier 
672458db832SDavid du Colombier /* Give enough context in the ureg to produce a kernel stack for
673458db832SDavid du Colombier  * a sleeping process
674458db832SDavid du Colombier  */
675458db832SDavid du Colombier void
setkernur(Ureg * ureg,Proc * p)676458db832SDavid du Colombier setkernur(Ureg* ureg, Proc* p)
677458db832SDavid du Colombier {
678458db832SDavid du Colombier 	ureg->pc = p->sched.pc;
679458db832SDavid du Colombier 	ureg->sp = p->sched.sp+4;
680458db832SDavid du Colombier }
681458db832SDavid du Colombier 
682458db832SDavid du Colombier ulong
dbgpc(Proc * p)683458db832SDavid du Colombier dbgpc(Proc *p)
684458db832SDavid du Colombier {
685458db832SDavid du Colombier 	Ureg *ureg;
686458db832SDavid du Colombier 
687458db832SDavid du Colombier 	ureg = p->dbgreg;
688458db832SDavid du Colombier 	if(ureg == 0)
689458db832SDavid du Colombier 		return 0;
690458db832SDavid du Colombier 
691458db832SDavid du Colombier 	return ureg->pc;
692458db832SDavid du Colombier }
693458db832SDavid du Colombier 
694458db832SDavid du Colombier /*
695458db832SDavid du Colombier  *  system calls
696458db832SDavid du Colombier  */
697458db832SDavid du Colombier #include "../port/systab.h"
698458db832SDavid du Colombier 
699458db832SDavid du Colombier /* TODO: make this trap a separate asm entry point, like on other RISC architectures */
700458db832SDavid du Colombier void
syscall(Ureg * ureg)701458db832SDavid du Colombier syscall(Ureg* ureg)
702458db832SDavid du Colombier {
703458db832SDavid du Colombier 	int i;
704458db832SDavid du Colombier 	char *e;
705458db832SDavid du Colombier 	long	ret;
706458db832SDavid du Colombier 	ulong sp, scallnr;
707458db832SDavid du Colombier 
708458db832SDavid du Colombier 	m->syscall++;
709458db832SDavid du Colombier 	up->insyscall = 1;
710458db832SDavid du Colombier 	up->pc = ureg->pc;
711458db832SDavid du Colombier 	up->dbgreg = ureg;
712458db832SDavid du Colombier 
713458db832SDavid du Colombier 	if (up->fpstate == FPactive && (ureg->srr1 & MSR_FP) == 0){
714458db832SDavid du Colombier 		print("fpstate check, entry syscall\n");
715458db832SDavid du Colombier 		delay(200);
716458db832SDavid du Colombier 		dumpregs(ureg);
717458db832SDavid du Colombier 		print("fpstate check, entry syscall\n");
718458db832SDavid du Colombier 	}
719458db832SDavid du Colombier 
720458db832SDavid du Colombier 	scallnr = ureg->r3;
721458db832SDavid du Colombier 	up->scallnr = ureg->r3;
722458db832SDavid du Colombier 	if(scallnr == RFORK && up->fpstate == FPactive){
723458db832SDavid du Colombier 		fpsave(&up->fpsave);
724458db832SDavid du Colombier 		up->fpstate = FPinactive;
725458db832SDavid du Colombier 	}
726458db832SDavid du Colombier 	spllo();
727458db832SDavid du Colombier 
728458db832SDavid du Colombier 	sp = ureg->usp;
729458db832SDavid du Colombier 	up->nerrlab = 0;
730458db832SDavid du Colombier 	ret = -1;
731458db832SDavid du Colombier 	if(!waserror()){
732458db832SDavid du Colombier 		if(scallnr >= nsyscall || systab[scallnr] == nil){
733606e0002SDavid du Colombier 			pprint("bad sys call number %ld pc %lux\n", scallnr, ureg->pc);
734458db832SDavid du Colombier 			postnote(up, 1, "sys: bad sys call", NDebug);
735458db832SDavid du Colombier 			error(Ebadarg);
736458db832SDavid du Colombier 		}
737458db832SDavid du Colombier 
738458db832SDavid du Colombier 		if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)-BY2WD))
739458db832SDavid du Colombier 			validaddr(sp, sizeof(Sargs)+BY2WD, 0);
740458db832SDavid du Colombier 
741458db832SDavid du Colombier 		up->s = *((Sargs*)(sp+BY2WD));
742458db832SDavid du Colombier 		up->psstate = sysctab[scallnr];
743458db832SDavid du Colombier 
744458db832SDavid du Colombier 		ret = systab[scallnr](up->s.args);
745458db832SDavid du Colombier 		poperror();
746458db832SDavid du Colombier 	}else{
747458db832SDavid du Colombier 		/* failure: save the error buffer for errstr */
748458db832SDavid du Colombier 		e = up->syserrstr;
749458db832SDavid du Colombier 		up->syserrstr = up->errstr;
750458db832SDavid du Colombier 		up->errstr = e;
751458db832SDavid du Colombier 	}
752458db832SDavid du Colombier 	if(up->nerrlab){
753458db832SDavid du Colombier 		print("bad errstack [%uld]: %d extra\n", scallnr, up->nerrlab);
754458db832SDavid du Colombier 		print("scall %s lr =%lux\n", sysctab[scallnr], ureg->lr);
755458db832SDavid du Colombier 		for(i = 0; i < NERR; i++)
756458db832SDavid du Colombier 			print("sp=%lux pc=%lux\n", up->errlab[i].sp, up->errlab[i].pc);
757458db832SDavid du Colombier 		panic("error stack");
758458db832SDavid du Colombier 	}
759458db832SDavid du Colombier 
760458db832SDavid du Colombier 	up->insyscall = 0;
761458db832SDavid du Colombier 	up->psstate = 0;
762458db832SDavid du Colombier 
763458db832SDavid du Colombier 	/*
764458db832SDavid du Colombier 	 *  Put return value in frame.  On the x86 the syscall is
765458db832SDavid du Colombier 	 *  just another trap and the return value from syscall is
766458db832SDavid du Colombier 	 *  ignored.  On other machines the return value is put into
767458db832SDavid du Colombier 	 *  the results register by caller of syscall.
768458db832SDavid du Colombier 	 */
769458db832SDavid du Colombier 	ureg->r3 = ret;
770458db832SDavid du Colombier 
771458db832SDavid du Colombier 	if(scallnr == NOTED)
772458db832SDavid du Colombier 		noted(ureg, *(ulong*)(sp+BY2WD));
773458db832SDavid du Colombier 
774458db832SDavid du Colombier 	/* restoreureg must execute at high IPL */
775458db832SDavid du Colombier 	splhi();
776458db832SDavid du Colombier 	if(scallnr!=RFORK)
777458db832SDavid du Colombier 		notify(ureg);
778458db832SDavid du Colombier 
779458db832SDavid du Colombier 	if (up->fpstate == FPactive && (ureg->srr1 & MSR_FP) == 0){
780458db832SDavid du Colombier 		print("fpstate check, exit syscall nr %lud, pid %lud\n", scallnr, up->pid);
781458db832SDavid du Colombier 		dumpregs(ureg);
782458db832SDavid du Colombier 	}
783458db832SDavid du Colombier 	if(up->fpstate != FPactive)
784458db832SDavid du Colombier 		ureg->srr1 &= ~MSR_FP;
785458db832SDavid du Colombier }
786458db832SDavid du Colombier 
787458db832SDavid du Colombier /*
788458db832SDavid du Colombier  *  Call user, if necessary, with note.
789458db832SDavid du Colombier  *  Pass user the Ureg struct and the note on his stack.
790458db832SDavid du Colombier  */
791458db832SDavid du Colombier int
notify(Ureg * ur)792458db832SDavid du Colombier notify(Ureg* ur)
793458db832SDavid du Colombier {
794458db832SDavid du Colombier 	int l;
795458db832SDavid du Colombier 	ulong s, sp;
796458db832SDavid du Colombier 	Note *n;
797458db832SDavid du Colombier 
798458db832SDavid du Colombier 	if(up->procctl)
799458db832SDavid du Colombier 		procctl(up);
800458db832SDavid du Colombier 	if(up->nnote == 0)
801458db832SDavid du Colombier 		return 0;
802458db832SDavid du Colombier 
803458db832SDavid du Colombier 	s = spllo();
804458db832SDavid du Colombier 	qlock(&up->debug);
805458db832SDavid du Colombier 	up->notepending = 0;
806458db832SDavid du Colombier 	n = &up->note[0];
807458db832SDavid du Colombier 	if(strncmp(n->msg, "sys:", 4) == 0){
808458db832SDavid du Colombier 		l = strlen(n->msg);
809458db832SDavid du Colombier 		if(l > ERRMAX-15)	/* " pc=0x12345678\0" */
810458db832SDavid du Colombier 			l = ERRMAX-15;
811458db832SDavid du Colombier 		sprint(n->msg+l, " pc=0x%.8lux", ur->pc);
812458db832SDavid du Colombier 	}
813458db832SDavid du Colombier 
814458db832SDavid du Colombier 	if(n->flag!=NUser && (up->notified || up->notify==0)){
815458db832SDavid du Colombier 		if(n->flag == NDebug)
816458db832SDavid du Colombier 			pprint("suicide: %s\n", n->msg);
817458db832SDavid du Colombier 		qunlock(&up->debug);
818458db832SDavid du Colombier 		pexit(n->msg, n->flag!=NDebug);
819458db832SDavid du Colombier 	}
820458db832SDavid du Colombier 
821458db832SDavid du Colombier 	if(up->notified) {
822458db832SDavid du Colombier 		qunlock(&up->debug);
823458db832SDavid du Colombier 		splhi();
824458db832SDavid du Colombier 		return 0;
825458db832SDavid du Colombier 	}
826458db832SDavid du Colombier 
827458db832SDavid du Colombier 	if(!up->notify) {
828458db832SDavid du Colombier 		qunlock(&up->debug);
829458db832SDavid du Colombier 		pexit(n->msg, n->flag!=NDebug);
830458db832SDavid du Colombier 	}
831458db832SDavid du Colombier 
832458db832SDavid du Colombier 	if(up->fpstate == FPactive){
833458db832SDavid du Colombier 		fpsave(&up->fpsave);
834458db832SDavid du Colombier 		up->fpstate = FPinactive;
835458db832SDavid du Colombier 	}
836458db832SDavid du Colombier 	up->fpstate |= FPillegal;
837458db832SDavid du Colombier 
838458db832SDavid du Colombier 	sp = ur->usp & ~(BY2V-1);
839458db832SDavid du Colombier 	sp -= sizeof(Ureg);
840458db832SDavid du Colombier 
841458db832SDavid du Colombier 	if(!okaddr((ulong)up->notify, BY2WD, 0) ||
842458db832SDavid du Colombier 	   !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)) {
843458db832SDavid du Colombier 		pprint("suicide: bad address or sp in notify\n");
844458db832SDavid du Colombier 		qunlock(&up->debug);
845458db832SDavid du Colombier 		pexit("Suicide", 0);
846458db832SDavid du Colombier 	}
847458db832SDavid du Colombier 
848458db832SDavid du Colombier 	memmove((Ureg*)sp, ur, sizeof(Ureg));
849458db832SDavid du Colombier 	*(Ureg**)(sp-BY2WD) = up->ureg;	/* word under Ureg is old up->ureg */
850458db832SDavid du Colombier 	up->ureg = (void*)sp;
851458db832SDavid du Colombier 	sp -= BY2WD+ERRMAX;
852458db832SDavid du Colombier 	memmove((char*)sp, up->note[0].msg, ERRMAX);
853458db832SDavid du Colombier 	sp -= 3*BY2WD;
854458db832SDavid du Colombier 	*(ulong*)(sp+2*BY2WD) = sp+3*BY2WD;	/* arg 2 is string */
855458db832SDavid du Colombier 	ur->r1 = (long)up->ureg;		/* arg 1 is ureg* */
856458db832SDavid du Colombier 	((ulong*)sp)[1] = (ulong)up->ureg;	/* arg 1 0(FP) is ureg* */
857458db832SDavid du Colombier 	((ulong*)sp)[0] = 0;			/* arg 0 is pc */
858458db832SDavid du Colombier 	ur->usp = sp;
859458db832SDavid du Colombier 	ur->pc = (ulong)up->notify;
860458db832SDavid du Colombier 	up->notified = 1;
861458db832SDavid du Colombier 	up->nnote--;
862458db832SDavid du Colombier 	memmove(&up->lastnote, &up->note[0], sizeof(Note));
863458db832SDavid du Colombier 	memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note));
864458db832SDavid du Colombier 
865458db832SDavid du Colombier 	qunlock(&up->debug);
866458db832SDavid du Colombier 	splx(s);
867458db832SDavid du Colombier 	return 1;
868458db832SDavid du Colombier }
869458db832SDavid du Colombier 
870458db832SDavid du Colombier 
871458db832SDavid du Colombier /*
872458db832SDavid du Colombier  *   Return user to state before notify()
873458db832SDavid du Colombier  */
874458db832SDavid du Colombier void
noted(Ureg * ureg,ulong arg0)875458db832SDavid du Colombier noted(Ureg* ureg, ulong arg0)
876458db832SDavid du Colombier {
877458db832SDavid du Colombier 	Ureg *nureg;
878458db832SDavid du Colombier 	ulong oureg, sp;
879458db832SDavid du Colombier 
880458db832SDavid du Colombier 	qlock(&up->debug);
881458db832SDavid du Colombier 	if(arg0!=NRSTR && !up->notified) {
882458db832SDavid du Colombier 		qunlock(&up->debug);
883458db832SDavid du Colombier 		pprint("call to noted() when not notified\n");
884458db832SDavid du Colombier 		pexit("Suicide", 0);
885458db832SDavid du Colombier 	}
886458db832SDavid du Colombier 	up->notified = 0;
887458db832SDavid du Colombier 
888458db832SDavid du Colombier 	nureg = up->ureg;	/* pointer to user returned Ureg struct */
889458db832SDavid du Colombier 
890458db832SDavid du Colombier 	/* sanity clause */
891458db832SDavid du Colombier 	oureg = (ulong)nureg;
892458db832SDavid du Colombier 	if(!okaddr((ulong)oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){
893458db832SDavid du Colombier 		pprint("bad ureg in noted or call to noted when not notified\n");
894458db832SDavid du Colombier 		qunlock(&up->debug);
895458db832SDavid du Colombier 		pexit("Suicide", 0);
896458db832SDavid du Colombier 	}
897458db832SDavid du Colombier 
898458db832SDavid du Colombier 	memmove(ureg, nureg, sizeof(Ureg));
899458db832SDavid du Colombier 
900458db832SDavid du Colombier 	switch(arg0){
901458db832SDavid du Colombier 	case NCONT:
902458db832SDavid du Colombier 	case NRSTR:
903458db832SDavid du Colombier 		if(!okaddr(nureg->pc, 1, 0) || !okaddr(nureg->usp, BY2WD, 0)){
904458db832SDavid du Colombier 			pprint("suicide: trap in noted\n");
905458db832SDavid du Colombier 			qunlock(&up->debug);
906458db832SDavid du Colombier 			pexit("Suicide", 0);
907458db832SDavid du Colombier 		}
908458db832SDavid du Colombier 		up->ureg = (Ureg*)(*(ulong*)(oureg-BY2WD));
909458db832SDavid du Colombier 		qunlock(&up->debug);
910458db832SDavid du Colombier 		break;
911458db832SDavid du Colombier 
912458db832SDavid du Colombier 	case NSAVE:
913458db832SDavid du Colombier 		if(!okaddr(nureg->pc, BY2WD, 0)
914458db832SDavid du Colombier 		|| !okaddr(nureg->usp, BY2WD, 0)){
915458db832SDavid du Colombier 			pprint("suicide: trap in noted\n");
916458db832SDavid du Colombier 			qunlock(&up->debug);
917458db832SDavid du Colombier 			pexit("Suicide", 0);
918458db832SDavid du Colombier 		}
919458db832SDavid du Colombier 		qunlock(&up->debug);
920458db832SDavid du Colombier 		sp = oureg-4*BY2WD-ERRMAX;
921458db832SDavid du Colombier 		splhi();
922458db832SDavid du Colombier 		ureg->sp = sp;
923458db832SDavid du Colombier 		((ulong*)sp)[1] = oureg;	/* arg 1 0(FP) is ureg* */
924458db832SDavid du Colombier 		((ulong*)sp)[0] = 0;		/* arg 0 is pc */
925458db832SDavid du Colombier 		break;
926458db832SDavid du Colombier 
927458db832SDavid du Colombier 	default:
928458db832SDavid du Colombier 		pprint("unknown noted arg 0x%lux\n", arg0);
929458db832SDavid du Colombier 		up->lastnote.flag = NDebug;
930458db832SDavid du Colombier 		/* fall through */
931458db832SDavid du Colombier 
932458db832SDavid du Colombier 	case NDFLT:
933458db832SDavid du Colombier 		if(up->lastnote.flag == NDebug)
934458db832SDavid du Colombier 			pprint("suicide: %s\n", up->lastnote.msg);
935458db832SDavid du Colombier 		qunlock(&up->debug);
936458db832SDavid du Colombier 		pexit(up->lastnote.msg, up->lastnote.flag!=NDebug);
937458db832SDavid du Colombier 	}
938458db832SDavid du Colombier 	up->fpstate &= ~FPillegal;
939458db832SDavid du Colombier 	if (up->fpstate == FPactive)
940458db832SDavid du Colombier 		ureg->srr1 |= MSR_FP;
941458db832SDavid du Colombier 	else
942458db832SDavid du Colombier 		ureg->srr1 &= ~MSR_FP;
943458db832SDavid du Colombier }
944