xref: /plan9-contrib/sys/src/9/ppc/trap.c (revision 1936bb650459bace06c38a45b60888b47e5cd459)
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
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
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
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
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
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
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
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
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*
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
487 getpcsp(ulong *pc, ulong *sp)
488 {
489 	*pc = getcallerpc(&pc);
490 	*sp = (ulong)&pc-4;
491 }
492 
493 void
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
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
539 dumpstack(void)
540 {
541 	callwithureg(_dumpstack);
542 }
543 
544 void
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
568 linkproc(void)
569 {
570 	spllo();
571 	(*up->kpfun)(up->kparg);
572 	pexit("", 0);
573 }
574 
575 void
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 sysfile.c
587  */
588 void
589 evenaddr(ulong addr)
590 {
591 	if(addr & 3){
592 		postnote(up, 1, "sys: odd address", NDebug);
593 		error(Ebadarg);
594 	}
595 }
596 
597 long
598 execregs(ulong entry, ulong ssize, ulong nargs)
599 {
600 	ulong *sp;
601 	Ureg *ureg;
602 
603 	sp = (ulong*)(USTKTOP - ssize);
604 	*--sp = nargs;
605 
606 	ureg = up->dbgreg;
607 	ureg->usp = (ulong)sp;
608 	ureg->pc = entry;
609 	ureg->srr1 &= ~MSR_FP;		/* disable floating point */
610 	up->fpstate = FPinit;
611 	return USTKTOP-sizeof(Tos);		/* address of kernel/user shared data */
612 }
613 
614 void
615 forkchild(Proc *p, Ureg *ur)
616 {
617 	Ureg *cur;
618 
619 	p->sched.sp = (ulong)p->kstack+KSTACK-UREGSIZE;
620 	p->sched.pc = (ulong)forkret;
621 
622 	cur = (Ureg*)(p->sched.sp+2*BY2WD);
623 	memmove(cur, ur, sizeof(Ureg));
624 	cur->r3 = 0;
625 
626 	/* Things from bottom of syscall we never got to execute */
627 	p->psstate = 0;
628 	p->insyscall = 0;
629 }
630 
631 ulong
632 userpc(void)
633 {
634 	Ureg *ureg;
635 
636 	ureg = (Ureg*)up->dbgreg;
637 	return ureg->pc;
638 }
639 
640 
641 /* This routine must save the values of registers the user is not
642  * permitted to write from devproc and then restore the saved values
643  * before returning
644  */
645 void
646 setregisters(Ureg *xp, char *pureg, char *uva, int n)
647 {
648 	ulong status;
649 
650 	status = xp->status;
651 	memmove(pureg, uva, n);
652 	xp->status = status;
653 }
654 
655 /* Give enough context in the ureg to produce a kernel stack for
656  * a sleeping process
657  */
658 void
659 setkernur(Ureg* ureg, Proc* p)
660 {
661 	ureg->pc = p->sched.pc;
662 	ureg->sp = p->sched.sp+4;
663 }
664 
665 ulong
666 dbgpc(Proc *p)
667 {
668 	Ureg *ureg;
669 
670 	ureg = p->dbgreg;
671 	if(ureg == 0)
672 		return 0;
673 
674 	return ureg->pc;
675 }
676 
677 /*
678  *  system calls
679  */
680 #include "../port/systab.h"
681 
682 /* TODO: make this trap a separate asm entry point, like on other RISC architectures */
683 void
684 syscall(Ureg* ureg)
685 {
686 	int i;
687 	char *e;
688 	long	ret;
689 	ulong sp, scallnr;
690 
691 	m->syscall++;
692 	up->insyscall = 1;
693 	up->pc = ureg->pc;
694 	up->dbgreg = ureg;
695 
696 	if (up->fpstate == FPactive && (ureg->srr1 & MSR_FP) == 0){
697 		print("fpstate check, entry syscall\n");
698 		delay(200);
699 		dumpregs(ureg);
700 		print("fpstate check, entry syscall\n");
701 	}
702 
703 	scallnr = ureg->r3;
704 	up->scallnr = ureg->r3;
705 	if(scallnr == RFORK && up->fpstate == FPactive){
706 		fpsave(&up->fpsave);
707 		up->fpstate = FPinactive;
708 	}
709 	spllo();
710 
711 	sp = ureg->usp;
712 	up->nerrlab = 0;
713 	ret = -1;
714 	if(!waserror()){
715 		if(scallnr >= nsyscall || systab[scallnr] == nil){
716 			pprint("bad sys call number %ld pc %lux\n", scallnr, ureg->pc);
717 			postnote(up, 1, "sys: bad sys call", NDebug);
718 			error(Ebadarg);
719 		}
720 
721 		if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)-BY2WD))
722 			validaddr(sp, sizeof(Sargs)+BY2WD, 0);
723 
724 		up->s = *((Sargs*)(sp+BY2WD));
725 		up->psstate = sysctab[scallnr];
726 
727 		ret = systab[scallnr](up->s.args);
728 		poperror();
729 	}else{
730 		/* failure: save the error buffer for errstr */
731 		e = up->syserrstr;
732 		up->syserrstr = up->errstr;
733 		up->errstr = e;
734 	}
735 	if(up->nerrlab){
736 		print("bad errstack [%uld]: %d extra\n", scallnr, up->nerrlab);
737 		print("scall %s lr =%lux\n", sysctab[scallnr], ureg->lr);
738 		for(i = 0; i < NERR; i++)
739 			print("sp=%lux pc=%lux\n", up->errlab[i].sp, up->errlab[i].pc);
740 		panic("error stack");
741 	}
742 
743 	up->insyscall = 0;
744 	up->psstate = 0;
745 
746 	/*
747 	 *  Put return value in frame.  On the x86 the syscall is
748 	 *  just another trap and the return value from syscall is
749 	 *  ignored.  On other machines the return value is put into
750 	 *  the results register by caller of syscall.
751 	 */
752 	ureg->r3 = ret;
753 
754 	if(scallnr == NOTED)
755 		noted(ureg, *(ulong*)(sp+BY2WD));
756 
757 	/* restoreureg must execute at high IPL */
758 	splhi();
759 	if(scallnr!=RFORK)
760 		notify(ureg);
761 
762 	if (up->fpstate == FPactive && (ureg->srr1 & MSR_FP) == 0){
763 		print("fpstate check, exit syscall nr %lud, pid %lud\n", scallnr, up->pid);
764 		dumpregs(ureg);
765 	}
766 	if(up->fpstate != FPactive)
767 		ureg->srr1 &= ~MSR_FP;
768 }
769 
770 /*
771  *  Call user, if necessary, with note.
772  *  Pass user the Ureg struct and the note on his stack.
773  */
774 int
775 notify(Ureg* ur)
776 {
777 	int l;
778 	ulong s, sp;
779 	Note *n;
780 
781 	if(up->procctl)
782 		procctl(up);
783 	if(up->nnote == 0)
784 		return 0;
785 
786 	s = spllo();
787 	qlock(&up->debug);
788 	up->notepending = 0;
789 	n = &up->note[0];
790 	if(strncmp(n->msg, "sys:", 4) == 0){
791 		l = strlen(n->msg);
792 		if(l > ERRMAX-15)	/* " pc=0x12345678\0" */
793 			l = ERRMAX-15;
794 		sprint(n->msg+l, " pc=0x%.8lux", ur->pc);
795 	}
796 
797 	if(n->flag!=NUser && (up->notified || up->notify==0)){
798 		if(n->flag == NDebug)
799 			pprint("suicide: %s\n", n->msg);
800 		qunlock(&up->debug);
801 		pexit(n->msg, n->flag!=NDebug);
802 	}
803 
804 	if(up->notified) {
805 		qunlock(&up->debug);
806 		splhi();
807 		return 0;
808 	}
809 
810 	if(!up->notify) {
811 		qunlock(&up->debug);
812 		pexit(n->msg, n->flag!=NDebug);
813 	}
814 
815 	if(up->fpstate == FPactive){
816 		fpsave(&up->fpsave);
817 		up->fpstate = FPinactive;
818 	}
819 	up->fpstate |= FPillegal;
820 
821 	sp = ur->usp & ~(BY2V-1);
822 	sp -= sizeof(Ureg);
823 
824 	if(!okaddr((ulong)up->notify, BY2WD, 0) ||
825 	   !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)) {
826 		pprint("suicide: bad address or sp in notify\n");
827 		qunlock(&up->debug);
828 		pexit("Suicide", 0);
829 	}
830 
831 	memmove((Ureg*)sp, ur, sizeof(Ureg));
832 	*(Ureg**)(sp-BY2WD) = up->ureg;	/* word under Ureg is old up->ureg */
833 	up->ureg = (void*)sp;
834 	sp -= BY2WD+ERRMAX;
835 	memmove((char*)sp, up->note[0].msg, ERRMAX);
836 	sp -= 3*BY2WD;
837 	*(ulong*)(sp+2*BY2WD) = sp+3*BY2WD;	/* arg 2 is string */
838 	ur->r1 = (long)up->ureg;		/* arg 1 is ureg* */
839 	((ulong*)sp)[1] = (ulong)up->ureg;	/* arg 1 0(FP) is ureg* */
840 	((ulong*)sp)[0] = 0;			/* arg 0 is pc */
841 	ur->usp = sp;
842 	ur->pc = (ulong)up->notify;
843 	up->notified = 1;
844 	up->nnote--;
845 	memmove(&up->lastnote, &up->note[0], sizeof(Note));
846 	memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note));
847 
848 	qunlock(&up->debug);
849 	splx(s);
850 	return 1;
851 }
852 
853 
854 /*
855  *   Return user to state before notify()
856  */
857 void
858 noted(Ureg* ureg, ulong arg0)
859 {
860 	Ureg *nureg;
861 	ulong oureg, sp;
862 
863 	qlock(&up->debug);
864 	if(arg0!=NRSTR && !up->notified) {
865 		qunlock(&up->debug);
866 		pprint("call to noted() when not notified\n");
867 		pexit("Suicide", 0);
868 	}
869 	up->notified = 0;
870 
871 	nureg = up->ureg;	/* pointer to user returned Ureg struct */
872 
873 	/* sanity clause */
874 	oureg = (ulong)nureg;
875 	if(!okaddr((ulong)oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){
876 		pprint("bad ureg in noted or call to noted when not notified\n");
877 		qunlock(&up->debug);
878 		pexit("Suicide", 0);
879 	}
880 
881 	memmove(ureg, nureg, sizeof(Ureg));
882 
883 	switch(arg0){
884 	case NCONT:
885 	case NRSTR:
886 		if(!okaddr(nureg->pc, 1, 0) || !okaddr(nureg->usp, BY2WD, 0)){
887 			pprint("suicide: trap in noted\n");
888 			qunlock(&up->debug);
889 			pexit("Suicide", 0);
890 		}
891 		up->ureg = (Ureg*)(*(ulong*)(oureg-BY2WD));
892 		qunlock(&up->debug);
893 		break;
894 
895 	case NSAVE:
896 		if(!okaddr(nureg->pc, BY2WD, 0)
897 		|| !okaddr(nureg->usp, BY2WD, 0)){
898 			pprint("suicide: trap in noted\n");
899 			qunlock(&up->debug);
900 			pexit("Suicide", 0);
901 		}
902 		qunlock(&up->debug);
903 		sp = oureg-4*BY2WD-ERRMAX;
904 		splhi();
905 		ureg->sp = sp;
906 		((ulong*)sp)[1] = oureg;	/* arg 1 0(FP) is ureg* */
907 		((ulong*)sp)[0] = 0;		/* arg 0 is pc */
908 		break;
909 
910 	default:
911 		pprint("unknown noted arg 0x%lux\n", arg0);
912 		up->lastnote.flag = NDebug;
913 		/* fall through */
914 
915 	case NDFLT:
916 		if(up->lastnote.flag == NDebug)
917 			pprint("suicide: %s\n", up->lastnote.msg);
918 		qunlock(&up->debug);
919 		pexit(up->lastnote.msg, up->lastnote.flag!=NDebug);
920 	}
921 	up->fpstate &= ~FPillegal;
922 	if (up->fpstate == FPactive)
923 		ureg->srr1 |= MSR_FP;
924 	else
925 		ureg->srr1 &= ~MSR_FP;
926 }
927