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