xref: /plan9/sys/src/9/ppc/trap.c (revision fac6300f1f1b25611e114fc0bdda9cf428c13da4)
1 #include	"u.h"
2 #include	"../port/lib.h"
3 #include	"mem.h"
4 #include	"dat.h"
5 #include	"fns.h"
6 #include	"ureg.h"
7 #include	"../port/error.h"
8 #include	"tos.h"
9 #include	<trace.h>
10 
11 static Lock vctllock;
12 Vctl *vctl[256];
13 
14 int intrstack[5];
15 uvlong intrtime[5];
16 vlong lastoffset;
17 int inintr;
18 int nintr[10];
19 int nintro;
20 int dblintr[64];
21 ulong thisto[32];
22 ulong thistoo;
23 vlong vnot[64];
24 ulong vnon[64];
25 
26 void
intrenable(int irq,void (* f)(Ureg *,void *),void * a,char * name)27 intrenable(int irq, void (*f)(Ureg*, void*), void* a, char *name)
28 {
29 	int vno;
30 	Vctl *v;
31 
32 	if(f == nil){
33 		print("intrenable: nil handler for %d for %s\n",
34 			irq, name);
35 		return;
36 	}
37 
38 	v = xalloc(sizeof(Vctl));
39 	v->isintr = 1;
40 	v->irq = irq;
41 	v->f = f;
42 	v->a = a;
43 	strncpy(v->name, name, KNAMELEN-1);
44 	v->name[KNAMELEN-1] = 0;
45 
46 	ilock(&vctllock);
47 	vno = vectorenable(v);
48 	if(vno == -1){
49 		iunlock(&vctllock);
50 		print("intrenable: couldn't enable irq %d for %s\n",
51 			irq, v->name);
52 		xfree(v);
53 		return;
54 	}
55 	v->next = vctl[vno];
56 	vctl[vno] = v;
57 	iunlock(&vctllock);
58 }
59 
60 void
intrdisable(int irq,void (* f)(Ureg *,void *),void * a,char * name)61 intrdisable(int irq, void (*f)(Ureg *, void *), void *a, char *name)
62 {
63 	Vctl **pv, *v;
64 
65 	ilock(&vctllock);
66 	pv = &vctl[irq];
67 	while (*pv &&
68 		  ((*pv)->irq != irq || (*pv)->f != f || (*pv)->a != a ||
69 		   strcmp((*pv)->name, name)))
70 		pv = &((*pv)->next);
71 
72 	if(*pv == nil){
73 		print("intrdisable: irq %d not found\n", irq);
74 		iunlock(&vctllock);
75 		return;
76 	}
77 
78 	v = *pv;
79 	*pv = (*pv)->next;	/* Link out the entry */
80 
81 	if(vctl[irq] == nil)
82 		vectordisable(v);
83 	iunlock(&vctllock);
84 	xfree(v);
85 }
86 
87 void	syscall(Ureg*);
88 void	noted(Ureg*, ulong);
89 static void _dumpstack(Ureg*);
90 
91 char *excname[] =
92 {
93 	"reserved 0",
94 	"system reset",
95 	"machine check",
96 	"data access",
97 	"instruction access",
98 	"external interrupt",
99 	"alignment",
100 	"program exception",
101 	"floating-point unavailable",
102 	"decrementer",
103 	"reserved A",
104 	"reserved B",
105 	"system call",
106 	"trace trap",
107 	"floating point assist",
108 	"reserved F",
109 	"reserved 10",
110 	"data load translation miss",
111 	"data store translation miss",
112 	"instruction address breakpoint",
113 	"system management interrupt",
114 };
115 
116 char *fpcause[] =
117 {
118 	"inexact operation",
119 	"division by zero",
120 	"underflow",
121 	"overflow",
122 	"invalid operation",
123 };
124 char	*fpexcname(Ureg*, ulong, char*);
125 #define FPEXPMASK	0xfff80300		/* Floating exception bits in fpscr */
126 
127 
128 char *regname[]={
129 	"CAUSE",	"SRR1",
130 	"PC",		"GOK",
131 	"LR",		"CR",
132 	"XER",		"CTR",
133 	"R0",		"R1",
134 	"R2",		"R3",
135 	"R4",		"R5",
136 	"R6",		"R7",
137 	"R8",		"R9",
138 	"R10",		"R11",
139 	"R12",		"R13",
140 	"R14",		"R15",
141 	"R16",		"R17",
142 	"R18",		"R19",
143 	"R20",		"R21",
144 	"R22",		"R23",
145 	"R24",		"R25",
146 	"R26",		"R27",
147 	"R28",		"R29",
148 	"R30",		"R31",
149 	"DCMP",		"ICMP",
150 	"DMISS",	"IMISS",
151 	"HASH1",	"HASH2",
152 	"DAR",		"DSISR",
153 };
154 
155 void
kexit(Ureg *)156 kexit(Ureg*)
157 {
158 	uvlong t;
159 	Tos *tos;
160 
161 	/* precise time accounting, kernel exit */
162 	tos = (Tos*)(USTKTOP-sizeof(Tos));
163 	cycles(&t);
164 	tos->kcycles += t - up->kentry;
165 	tos->pcycles = up->pcycles;
166 	tos->pid = up->pid;
167 }
168 
169 void
trap(Ureg * ureg)170 trap(Ureg *ureg)
171 {
172 	int ecode, user;
173 	char buf[ERRMAX], *s;
174 	extern FPsave initfp;
175 
176 	ecode = (ureg->cause >> 8) & 0xff;
177 	user = (ureg->srr1 & MSR_PR) != 0;
178 	if(user){
179 		cycles(&up->kentry);
180 		up->dbgreg = ureg;
181 	}
182 	if(ureg->status & MSR_RI == 0)
183 		print("double fault?: ecode = %d\n", ecode);
184 
185 	switch(ecode) {
186 	case CEI:
187 		m->intr++;
188 		intr(ureg);
189 		break;
190 	case CDEC:
191 		clockintr(ureg);
192 		break;
193 	case CDSI:
194 		m->pfault++;
195 		if (up == nil){
196 			dumpregs(ureg);
197 			panic("kernel fault");
198 		}
199 		up->mmureg = ureg;
200 		faultpower(ureg, ureg->dar, (ureg->dsisr & BIT(6)) == 0);
201 		break;
202 	case CISI:
203 		m->pfault++;
204 		if (up == nil){
205 			dumpregs(ureg);
206 			panic("kernel fault");
207 		}
208 		up->mmureg = ureg;
209 		faultpower(ureg, ureg->pc, 1);
210 		break;
211 	case CIMISS:	/* instruction miss */
212 		if (up == nil){
213 			dumpregs(ureg);
214 			panic("kernel fault");
215 		}
216 		up->mmureg = ureg;
217 		faultpower(ureg, ureg->imiss, 1);
218 		break;
219 	case CLMISS:	/* data load miss */
220 		if (up == nil){
221 			dumpregs(ureg);
222 			panic("kernel fault");
223 		}
224 		up->mmureg = ureg;
225 		faultpower(ureg, ureg->dmiss, 1);
226 		break;
227 	case CSMISS:	/* data store miss */
228 		if (up == nil){
229 			dumpregs(ureg);
230 			panic("kernel fault");
231 		}
232 		up->mmureg = ureg;
233 		faultpower(ureg, ureg->dmiss, 0);
234 		break;
235 
236 	case CSYSCALL:
237 		if(!user)
238 			panic("syscall in kernel: srr1 0x%4.4luX\n", ureg->srr1);
239 		syscall(ureg);
240 		if (up->delaysched){
241 			sched();
242 			splhi();
243 		}
244 		kexit(ureg);
245 		return;		/* syscall() calls notify itself, don't do it again */
246 
247 	case CFPU:
248 		if(!user || up == nil) {
249 			dumpregs(ureg);
250 			panic("floating point in kernel");
251 		}
252 		switch(up->fpstate){
253 		case FPinit:
254 			fprestore(&initfp);
255 			up->fpstate = FPactive;
256 			break;
257 		case FPinactive:
258 			fprestore(&up->fpsave);
259 			up->fpstate = FPactive;
260 			break;
261 		case FPactive:
262 			print("up->fpstate %d\n", up->fpstate);
263 			delay(100);
264 			dumpregs(ureg);
265 			delay(200);
266 			panic("fpstate");
267 			break;
268 		default:
269 			if(user){
270 				spllo();
271 				sprint(buf, "sys: floating point in note handler:");
272 				postnote(up, 1, buf, NDebug);
273 				break;
274 			}
275 			panic("kernel fpstate illegal");
276 		}
277 		ureg->srr1 |= MSR_FP;
278 		break;
279 	case CPROG:
280 		if(ureg->status & (1<<19))
281 			s = "floating point exception";
282 		else if(ureg->status & (1<<18))
283 			s = "illegal instruction";
284 		else if(ureg->status & (1<<17))
285 			s = "privileged instruction";
286 		else
287 			s = "undefined program exception";
288 		if(user){
289 			spllo();
290 			sprint(buf, "sys: trap: %s", s);
291 			postnote(up, 1, buf, NDebug);
292 			break;
293 		}
294 		dumpregs(ureg);
295 		panic(s);
296 		break;
297 	default:
298 		if(ecode < nelem(excname) && user){
299 			spllo();
300 			sprint(buf, "sys: trap: %s", excname[ecode]);
301 			postnote(up, 1, buf, NDebug);
302 			break;
303 		}
304 		dumpregs(ureg);
305 		if(ecode < nelem(excname))
306 			panic("%s", excname[ecode]);
307 		panic("unknown trap/intr: %d\n", ecode);
308 	}
309 
310 	/* restoreureg must execute at high IPL */
311 	splhi();
312 
313 	/* delaysched set because we held a lock or because our quantum ended */
314 	if(up && up->delaysched && ecode == CDEC){
315 		sched();
316 		splhi();
317 	}
318 
319 	if(user) {
320 		if (up->fpstate == FPactive && (ureg->srr1 & MSR_FP) == 0){
321 			postnote(up, 1, buf, NDebug);
322 		}
323 		notify(ureg);
324 		if(up->fpstate != FPactive)
325 			ureg->srr1 &= ~MSR_FP;
326 		kexit(ureg);
327 	}
328 }
329 
330 void
faultpower(Ureg * ureg,ulong addr,int read)331 faultpower(Ureg *ureg, ulong addr, int read)
332 {
333 	int user, insyscall, n;
334 	char buf[ERRMAX];
335 
336 	user = (ureg->srr1 & MSR_PR) != 0;
337 	insyscall = up->insyscall;
338 	up->insyscall = 1;
339 	n = fault(addr, read);
340 	if(n < 0){
341 		if(!user){
342 			dumpregs(ureg);
343 			panic("fault: 0x%lux", addr);
344 		}
345 		sprint(buf, "sys: trap: fault %s addr=0x%lux", read? "read" : "write", addr);
346 		postnote(up, 1, buf, NDebug);
347 	}
348 	up->insyscall = insyscall;
349 }
350 
351 void
sethvec(int v,void (* r)(void))352 sethvec(int v, void (*r)(void))
353 {
354 	ulong *vp, pa, o;
355 
356 	vp = KADDR(v);
357 	vp[0] = 0x7c1043a6;			/* MOVW R0, SPR(SPRG0) */
358 	vp[1] = 0x7c0802a6;			/* MOVW LR, R0 */
359 	vp[2] = 0x7c1243a6;			/* MOVW R0, SPR(SPRG2) */
360 	pa = PADDR(r);
361 	o = pa >> 25;
362 	if(o != 0 && o != 0x7F){
363 		/* a branch too far */
364 		vp[3] = (15<<26)|(pa>>16);	/* MOVW $r&~0xFFFF, R0 */
365 		vp[4] = (24<<26)|(pa&0xFFFF);	/* OR $r&0xFFFF, R0 */
366 		vp[5] = 0x7c0803a6;		/* MOVW	R0, LR */
367 		vp[6] = 0x4e800021;		/* BL (LR) */
368 	}else
369 		vp[3] = (18<<26)|(pa&0x3FFFFFC)|3;	/* bla */
370 }
371 
372 void
setmvec(int v,void (* r)(void),void (* t)(void))373 setmvec(int v, void (*r)(void), void (*t)(void))
374 {
375 	ulong *vp, pa, o, n;
376 
377 	vp = KADDR(v);
378 	n = 0;
379 	vp[n++] = 0x7c1043a6;			/* MOVW R0, SPR(SPRG0) */
380 	vp[n++] = 0x7c0802a6;			/* MOVW LR, R0 */
381 	vp[n++] = 0x7c1243a6;			/* MOVW R0, SPR(SPRG2) */
382 	pa = PADDR(r);
383 	o = pa >> 25;
384 	if(o != 0 && o != 0x7F){
385 		/* a branch too far */
386 		vp[n++] = (15<<26)|(pa>>16);	/* MOVW $r&~0xFFFF, R0 */
387 		vp[n++] = (24<<26)|(pa&0xFFFF);	/* OR $r&0xFFFF, R0 */
388 		vp[n++] = 0x7c0803a6;		/* MOVW	R0, LR */
389 		vp[n++] = 0x4e800021;		/* BL (LR) */
390 	}else
391 		vp[n++] = (18<<26)|(pa&0x3FFFFFC)|3;	/* bla */
392 	pa = PADDR(t);
393 	o = pa >> 25;
394 	if(o != 0 && o != 0x7F){
395 		/* a branch too far */
396 		vp[n++] = (15<<26)|(pa>>16);	/* MOVW $r&~0xFFFF, R0 */
397 		vp[n++] = (24<<26)|(pa&0xFFFF);	/* OR $r&0xFFFF, R0 */
398 		vp[n++] = 0x7c0803a6;		/* MOVW	R0, LR */
399 		vp[n] = 0x4e800021;		/* BL (LR) */
400 	}else
401 		vp[n] = (18<<26)|(pa&0x3FFFFFC)|3;	/* bla */
402 }
403 
404 
405 void
intr(Ureg * ureg)406 intr(Ureg *ureg)
407 {
408 	int vno, pvno, i;
409 	Vctl *ctl, *v;
410 	void (*pt)(Proc*, int, vlong);
411 	uvlong tt, x;
412 
413 	cycles(&tt);
414 	pt = proctrace;
415 	pvno = -1;
416 	for(i = 0; i < 64; i++){
417 		vno = intvec();
418 		if(vno == 0)
419 			break;
420 		cycles(&x);
421 		vnot[vno] -= x;
422 		if(vno == pvno)
423 			dblintr[vno]++;
424 		pvno = vno;
425 		if(pt && up && up->trace)
426 			pt(up, (vno << 16) | SInts, 0);
427 
428 		if(vno > nelem(vctl) || (ctl = vctl[vno]) == 0) {
429 			iprint("spurious intr %d\n", vno);
430 			return;
431 		}
432 
433 		for(v = ctl; v != nil; v = v->next)
434 			if(v->f)
435 				v->f(ureg, v->a);
436 
437 		intend(vno);	/* reenable the interrupt */
438 
439 		if(pt && up && up->trace)
440 			pt(up, (vno << 16) | SInte, 0);
441 		cycles(&x);
442 		vnot[vno] += x;
443 		vnon[vno]++;
444 	}
445 	if(i < nelem(nintr))
446 		nintr[i]++;
447 	else
448 		nintro++;
449 	cycles(&x);
450 	tt = x - tt;
451 	i = tt / 3600;	 /* 100 microseconds units */
452 	if(i < nelem(thisto))
453 		thisto[i]++;
454 	else
455 		thistoo++;
456 
457 	if(up)
458 		preempted();
459 }
460 
461 char*
fpexcname(Ureg * ur,ulong fpscr,char * buf)462 fpexcname(Ureg *ur, ulong fpscr, char *buf)
463 {
464 	int i;
465 	char *s;
466 	ulong fppc;
467 
468 	fppc = ur->pc;
469 	s = 0;
470 	fpscr >>= 3;		/* trap enable bits */
471 	fpscr &= (fpscr>>22);	/* anded with exceptions */
472 	for(i=0; i<5; i++)
473 		if(fpscr & (1<<i))
474 			s = fpcause[i];
475 	if(s == 0)
476 		return "no floating point exception";
477 	sprint(buf, "%s fppc=0x%lux", s, fppc);
478 	return buf;
479 }
480 
481 /*
482  * Fill in enough of Ureg to get a stack trace, and call a function.
483  * Used by debugging interface rdb.
484  */
485 
486 static void
getpcsp(ulong * pc,ulong * sp)487 getpcsp(ulong *pc, ulong *sp)
488 {
489 	*pc = getcallerpc(&pc);
490 	*sp = (ulong)&pc-4;
491 }
492 
493 void
callwithureg(void (* fn)(Ureg *))494 callwithureg(void (*fn)(Ureg*))
495 {
496 	Ureg ureg;
497 
498 	getpcsp((ulong*)&ureg.pc, (ulong*)&ureg.sp);
499 	ureg.lr = getcallerpc(&fn);
500 	fn(&ureg);
501 }
502 
503 static void
_dumpstack(Ureg * ureg)504 _dumpstack(Ureg *ureg)
505 {
506 	ulong l, sl, el, v;
507 	int i;
508 
509 	l = (ulong)&l;
510 	if(up == 0){
511 		el = (ulong)m+BY2PG;
512 		sl = el-KSTACK;
513 	}
514 	else{
515 		sl = (ulong)up->kstack;
516 		el = sl + KSTACK;
517 	}
518 	if(l > el || l < sl){
519 		el = (ulong)m+BY2PG;
520 		sl = el-KSTACK;
521 	}
522 	if(l > el || l < sl)
523 		return;
524 	print("ktrace /kernel/path %.8lux %.8lux %.8lux\n", ureg->pc, ureg->sp, ureg->lr);
525 	i = 0;
526 	for(; l < el; l += 4){
527 		v = *(ulong*)l;
528 		if(KTZERO < v && v < (ulong)etext){
529 			print("%.8lux=%.8lux ", l, v);
530 			if(i++ == 4){
531 				print("\n");
532 				i = 0;
533 			}
534 		}
535 	}
536 }
537 
538 void
dumpstack(void)539 dumpstack(void)
540 {
541 	callwithureg(_dumpstack);
542 }
543 
544 void
dumpregs(Ureg * ur)545 dumpregs(Ureg *ur)
546 {
547 	int i;
548 	ulong *l;
549 
550 	if(up) {
551 		print("registers for %s %ld\n", up->text, up->pid);
552 		if(ur->srr1 & MSR_PR == 0)
553 		if(ur->usp < (ulong)up->kstack || ur->usp > (ulong)up->kstack+KSTACK)
554 			print("invalid stack ptr\n");
555 	}
556 	else
557 		print("registers for kernel\n");
558 
559 	for(i=0; i<16; i+=2)
560 		print("sr[%x]\t0x%.8lux\tsr[%x]\t0x%.8lux\n", i, getsr(i<<28), i+1, getsr((i+1)<<28));
561 	l = &ur->cause;
562 	for(i=0; i<sizeof regname/sizeof(char*); i+=2, l+=2)
563 		print("%s\t0x%.8lux\t%s\t0x%.8lux\n", regname[i], l[0], regname[i+1], l[1]);
564 	delay(500);
565 }
566 
567 static void
linkproc(void)568 linkproc(void)
569 {
570 	spllo();
571 	(*up->kpfun)(up->kparg);
572 	pexit("", 0);
573 }
574 
575 void
kprocchild(Proc * p,void (* func)(void *),void * arg)576 kprocchild(Proc *p, void (*func)(void*), void *arg)
577 {
578 	p->sched.pc = (ulong)linkproc;
579 	p->sched.sp = (ulong)p->kstack+KSTACK;
580 
581 	p->kpfun = func;
582 	p->kparg = arg;
583 }
584 
585 /*
586  * called in syscallfmt.c, sysfile.c, sysproc.c
587  */
588 void
validalign(uintptr addr,unsigned align)589 validalign(uintptr addr, unsigned align)
590 {
591 	/*
592 	 * Plan 9 is a 32-bit O/S, and the hardware it runs on
593 	 * does not usually have instructions which move 64-bit
594 	 * quantities directly, synthesizing the operations
595 	 * with 32-bit move instructions. Therefore, the compiler
596 	 * (and hardware) usually only enforce 32-bit alignment,
597 	 * if at all.
598 	 *
599 	 * Take this out if the architecture warrants it.
600 	 */
601 	if(align == sizeof(vlong))
602 		align = sizeof(long);
603 
604 	/*
605 	 * Check align is a power of 2, then addr alignment.
606 	 */
607 	if((align != 0 && !(align & (align-1))) && !(addr & (align-1)))
608 		return;
609 	postnote(up, 1, "sys: odd address", NDebug);
610 	error(Ebadarg);
611 	/*NOTREACHED*/
612 }
613 
614 long
execregs(ulong entry,ulong ssize,ulong nargs)615 execregs(ulong entry, ulong ssize, ulong nargs)
616 {
617 	ulong *sp;
618 	Ureg *ureg;
619 
620 	sp = (ulong*)(USTKTOP - ssize);
621 	*--sp = nargs;
622 
623 	ureg = up->dbgreg;
624 	ureg->usp = (ulong)sp;
625 	ureg->pc = entry;
626 	ureg->srr1 &= ~MSR_FP;		/* disable floating point */
627 	up->fpstate = FPinit;
628 	return USTKTOP-sizeof(Tos);		/* address of kernel/user shared data */
629 }
630 
631 void
forkchild(Proc * p,Ureg * ur)632 forkchild(Proc *p, Ureg *ur)
633 {
634 	Ureg *cur;
635 
636 	p->sched.sp = (ulong)p->kstack+KSTACK-UREGSIZE;
637 	p->sched.pc = (ulong)forkret;
638 
639 	cur = (Ureg*)(p->sched.sp+2*BY2WD);
640 	memmove(cur, ur, sizeof(Ureg));
641 	cur->r3 = 0;
642 
643 	/* Things from bottom of syscall we never got to execute */
644 	p->psstate = 0;
645 	p->insyscall = 0;
646 }
647 
648 ulong
userpc(void)649 userpc(void)
650 {
651 	Ureg *ureg;
652 
653 	ureg = (Ureg*)up->dbgreg;
654 	return ureg->pc;
655 }
656 
657 
658 /* This routine must save the values of registers the user is not
659  * permitted to write from devproc and then restore the saved values
660  * before returning
661  */
662 void
setregisters(Ureg * xp,char * pureg,char * uva,int n)663 setregisters(Ureg *xp, char *pureg, char *uva, int n)
664 {
665 	ulong status;
666 
667 	status = xp->status;
668 	memmove(pureg, uva, n);
669 	xp->status = status;
670 }
671 
672 /* Give enough context in the ureg to produce a kernel stack for
673  * a sleeping process
674  */
675 void
setkernur(Ureg * ureg,Proc * p)676 setkernur(Ureg* ureg, Proc* p)
677 {
678 	ureg->pc = p->sched.pc;
679 	ureg->sp = p->sched.sp+4;
680 }
681 
682 ulong
dbgpc(Proc * p)683 dbgpc(Proc *p)
684 {
685 	Ureg *ureg;
686 
687 	ureg = p->dbgreg;
688 	if(ureg == 0)
689 		return 0;
690 
691 	return ureg->pc;
692 }
693 
694 /*
695  *  system calls
696  */
697 #include "../port/systab.h"
698 
699 /* TODO: make this trap a separate asm entry point, like on other RISC architectures */
700 void
syscall(Ureg * ureg)701 syscall(Ureg* ureg)
702 {
703 	int i;
704 	char *e;
705 	long	ret;
706 	ulong sp, scallnr;
707 
708 	m->syscall++;
709 	up->insyscall = 1;
710 	up->pc = ureg->pc;
711 	up->dbgreg = ureg;
712 
713 	if (up->fpstate == FPactive && (ureg->srr1 & MSR_FP) == 0){
714 		print("fpstate check, entry syscall\n");
715 		delay(200);
716 		dumpregs(ureg);
717 		print("fpstate check, entry syscall\n");
718 	}
719 
720 	scallnr = ureg->r3;
721 	up->scallnr = ureg->r3;
722 	if(scallnr == RFORK && up->fpstate == FPactive){
723 		fpsave(&up->fpsave);
724 		up->fpstate = FPinactive;
725 	}
726 	spllo();
727 
728 	sp = ureg->usp;
729 	up->nerrlab = 0;
730 	ret = -1;
731 	if(!waserror()){
732 		if(scallnr >= nsyscall || systab[scallnr] == nil){
733 			pprint("bad sys call number %ld pc %lux\n", scallnr, ureg->pc);
734 			postnote(up, 1, "sys: bad sys call", NDebug);
735 			error(Ebadarg);
736 		}
737 
738 		if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)-BY2WD))
739 			validaddr(sp, sizeof(Sargs)+BY2WD, 0);
740 
741 		up->s = *((Sargs*)(sp+BY2WD));
742 		up->psstate = sysctab[scallnr];
743 
744 		ret = systab[scallnr](up->s.args);
745 		poperror();
746 	}else{
747 		/* failure: save the error buffer for errstr */
748 		e = up->syserrstr;
749 		up->syserrstr = up->errstr;
750 		up->errstr = e;
751 	}
752 	if(up->nerrlab){
753 		print("bad errstack [%uld]: %d extra\n", scallnr, up->nerrlab);
754 		print("scall %s lr =%lux\n", sysctab[scallnr], ureg->lr);
755 		for(i = 0; i < NERR; i++)
756 			print("sp=%lux pc=%lux\n", up->errlab[i].sp, up->errlab[i].pc);
757 		panic("error stack");
758 	}
759 
760 	up->insyscall = 0;
761 	up->psstate = 0;
762 
763 	/*
764 	 *  Put return value in frame.  On the x86 the syscall is
765 	 *  just another trap and the return value from syscall is
766 	 *  ignored.  On other machines the return value is put into
767 	 *  the results register by caller of syscall.
768 	 */
769 	ureg->r3 = ret;
770 
771 	if(scallnr == NOTED)
772 		noted(ureg, *(ulong*)(sp+BY2WD));
773 
774 	/* restoreureg must execute at high IPL */
775 	splhi();
776 	if(scallnr!=RFORK)
777 		notify(ureg);
778 
779 	if (up->fpstate == FPactive && (ureg->srr1 & MSR_FP) == 0){
780 		print("fpstate check, exit syscall nr %lud, pid %lud\n", scallnr, up->pid);
781 		dumpregs(ureg);
782 	}
783 	if(up->fpstate != FPactive)
784 		ureg->srr1 &= ~MSR_FP;
785 }
786 
787 /*
788  *  Call user, if necessary, with note.
789  *  Pass user the Ureg struct and the note on his stack.
790  */
791 int
notify(Ureg * ur)792 notify(Ureg* ur)
793 {
794 	int l;
795 	ulong s, sp;
796 	Note *n;
797 
798 	if(up->procctl)
799 		procctl(up);
800 	if(up->nnote == 0)
801 		return 0;
802 
803 	s = spllo();
804 	qlock(&up->debug);
805 	up->notepending = 0;
806 	n = &up->note[0];
807 	if(strncmp(n->msg, "sys:", 4) == 0){
808 		l = strlen(n->msg);
809 		if(l > ERRMAX-15)	/* " pc=0x12345678\0" */
810 			l = ERRMAX-15;
811 		sprint(n->msg+l, " pc=0x%.8lux", ur->pc);
812 	}
813 
814 	if(n->flag!=NUser && (up->notified || up->notify==0)){
815 		if(n->flag == NDebug)
816 			pprint("suicide: %s\n", n->msg);
817 		qunlock(&up->debug);
818 		pexit(n->msg, n->flag!=NDebug);
819 	}
820 
821 	if(up->notified) {
822 		qunlock(&up->debug);
823 		splhi();
824 		return 0;
825 	}
826 
827 	if(!up->notify) {
828 		qunlock(&up->debug);
829 		pexit(n->msg, n->flag!=NDebug);
830 	}
831 
832 	if(up->fpstate == FPactive){
833 		fpsave(&up->fpsave);
834 		up->fpstate = FPinactive;
835 	}
836 	up->fpstate |= FPillegal;
837 
838 	sp = ur->usp & ~(BY2V-1);
839 	sp -= sizeof(Ureg);
840 
841 	if(!okaddr((ulong)up->notify, BY2WD, 0) ||
842 	   !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)) {
843 		pprint("suicide: bad address or sp in notify\n");
844 		qunlock(&up->debug);
845 		pexit("Suicide", 0);
846 	}
847 
848 	memmove((Ureg*)sp, ur, sizeof(Ureg));
849 	*(Ureg**)(sp-BY2WD) = up->ureg;	/* word under Ureg is old up->ureg */
850 	up->ureg = (void*)sp;
851 	sp -= BY2WD+ERRMAX;
852 	memmove((char*)sp, up->note[0].msg, ERRMAX);
853 	sp -= 3*BY2WD;
854 	*(ulong*)(sp+2*BY2WD) = sp+3*BY2WD;	/* arg 2 is string */
855 	ur->r1 = (long)up->ureg;		/* arg 1 is ureg* */
856 	((ulong*)sp)[1] = (ulong)up->ureg;	/* arg 1 0(FP) is ureg* */
857 	((ulong*)sp)[0] = 0;			/* arg 0 is pc */
858 	ur->usp = sp;
859 	ur->pc = (ulong)up->notify;
860 	up->notified = 1;
861 	up->nnote--;
862 	memmove(&up->lastnote, &up->note[0], sizeof(Note));
863 	memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note));
864 
865 	qunlock(&up->debug);
866 	splx(s);
867 	return 1;
868 }
869 
870 
871 /*
872  *   Return user to state before notify()
873  */
874 void
noted(Ureg * ureg,ulong arg0)875 noted(Ureg* ureg, ulong arg0)
876 {
877 	Ureg *nureg;
878 	ulong oureg, sp;
879 
880 	qlock(&up->debug);
881 	if(arg0!=NRSTR && !up->notified) {
882 		qunlock(&up->debug);
883 		pprint("call to noted() when not notified\n");
884 		pexit("Suicide", 0);
885 	}
886 	up->notified = 0;
887 
888 	nureg = up->ureg;	/* pointer to user returned Ureg struct */
889 
890 	/* sanity clause */
891 	oureg = (ulong)nureg;
892 	if(!okaddr((ulong)oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){
893 		pprint("bad ureg in noted or call to noted when not notified\n");
894 		qunlock(&up->debug);
895 		pexit("Suicide", 0);
896 	}
897 
898 	memmove(ureg, nureg, sizeof(Ureg));
899 
900 	switch(arg0){
901 	case NCONT:
902 	case NRSTR:
903 		if(!okaddr(nureg->pc, 1, 0) || !okaddr(nureg->usp, BY2WD, 0)){
904 			pprint("suicide: trap in noted\n");
905 			qunlock(&up->debug);
906 			pexit("Suicide", 0);
907 		}
908 		up->ureg = (Ureg*)(*(ulong*)(oureg-BY2WD));
909 		qunlock(&up->debug);
910 		break;
911 
912 	case NSAVE:
913 		if(!okaddr(nureg->pc, BY2WD, 0)
914 		|| !okaddr(nureg->usp, BY2WD, 0)){
915 			pprint("suicide: trap in noted\n");
916 			qunlock(&up->debug);
917 			pexit("Suicide", 0);
918 		}
919 		qunlock(&up->debug);
920 		sp = oureg-4*BY2WD-ERRMAX;
921 		splhi();
922 		ureg->sp = sp;
923 		((ulong*)sp)[1] = oureg;	/* arg 1 0(FP) is ureg* */
924 		((ulong*)sp)[0] = 0;		/* arg 0 is pc */
925 		break;
926 
927 	default:
928 		pprint("unknown noted arg 0x%lux\n", arg0);
929 		up->lastnote.flag = NDebug;
930 		/* fall through */
931 
932 	case NDFLT:
933 		if(up->lastnote.flag == NDebug)
934 			pprint("suicide: %s\n", up->lastnote.msg);
935 		qunlock(&up->debug);
936 		pexit(up->lastnote.msg, up->lastnote.flag!=NDebug);
937 	}
938 	up->fpstate &= ~FPillegal;
939 	if (up->fpstate == FPactive)
940 		ureg->srr1 |= MSR_FP;
941 	else
942 		ureg->srr1 &= ~MSR_FP;
943 }
944