xref: /plan9/sys/src/9/mtx/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	"io.h"
8 #include	"tos.h"
9 #include	"../port/error.h"
10 
11 static Lock vctllock;
12 static Vctl *vctl[256];
13 
14 void
hwintrinit(void)15 hwintrinit(void)
16 {
17 	i8259init();
18 	mpicenable(0, nil);	/* 8259 interrupts are routed through MPIC intr 0 */
19 }
20 
21 static int
hwintrenable(Vctl * v)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
hwintrdisable(Vctl * v)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
hwvecno(int irq,int tbdf)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
intrenable(int irq,void (* f)(Ureg *,void *),void * a,int tbdf,char * name)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
intrdisable(int irq,void (* f)(Ureg *,void *),void * a,int tbdf,char * name)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
trap(Ureg * ureg)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
faultpower(Ureg * ureg,ulong addr,int read)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
sethvec(int v,void (* r)(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
trapinit(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
intr(Ureg * ureg)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*
fpexcname(Ureg * ur,ulong fpscr,char * buf)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
getpcsp(ulong * pc,ulong * sp)428 getpcsp(ulong *pc, ulong *sp)
429 {
430 	*pc = getcallerpc(&pc);
431 	*sp = (ulong)&pc-4;
432 }
433 
434 void
callwithureg(void (* fn)(Ureg *))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
_dumpstack(Ureg * ureg)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
dumpstack(void)480 dumpstack(void)
481 {
482 	callwithureg(_dumpstack);
483 }
484 
485 void
dumpregs(Ureg * ur)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
linkproc(void)507 linkproc(void)
508 {
509 	spllo();
510 	(*up->kpfun)(up->kparg);
511 	pexit("", 0);
512 }
513 
514 void
kprocchild(Proc * p,void (* func)(void *),void * arg)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 syscallfmt.c, sysfile.c, sysproc.c
526  */
527 void
validalign(uintptr addr,unsigned align)528 validalign(uintptr addr, unsigned align)
529 {
530 	/*
531 	 * Plan 9 is a 32-bit O/S, and the hardware it runs on
532 	 * does not usually have instructions which move 64-bit
533 	 * quantities directly, synthesizing the operations
534 	 * with 32-bit move instructions. Therefore, the compiler
535 	 * (and hardware) usually only enforce 32-bit alignment,
536 	 * if at all.
537 	 *
538 	 * Take this out if the architecture warrants it.
539 	 */
540 	if(align == sizeof(vlong))
541 		align = sizeof(long);
542 
543 	/*
544 	 * Check align is a power of 2, then addr alignment.
545 	 */
546 	if((align != 0 && !(align & (align-1))) && !(addr & (align-1)))
547 		return;
548 	postnote(up, 1, "sys: odd address", NDebug);
549 	error(Ebadarg);
550 	/*NOTREACHED*/
551 }
552 
553 long
execregs(ulong entry,ulong ssize,ulong nargs)554 execregs(ulong entry, ulong ssize, ulong nargs)
555 {
556 	ulong *sp;
557 	Ureg *ureg;
558 
559 	sp = (ulong*)(USTKTOP - ssize);
560 	*--sp = nargs;
561 
562 	ureg = up->dbgreg;
563 	ureg->usp = (ulong)sp;
564 	ureg->pc = entry;
565 	ureg->srr1 &= ~MSR_FP;
566 	return USTKTOP-sizeof(Tos);		/* address of kernel/user shared data */
567 }
568 
569 void
forkchild(Proc * p,Ureg * ur)570 forkchild(Proc *p, Ureg *ur)
571 {
572 	Ureg *cur;
573 
574 	p->sched.sp = (ulong)p->kstack+KSTACK-UREGSIZE;
575 	p->sched.pc = (ulong)forkret;
576 
577 	cur = (Ureg*)(p->sched.sp+2*BY2WD);
578 	memmove(cur, ur, sizeof(Ureg));
579 	cur->r3 = 0;
580 
581 	/* Things from bottom of syscall we never got to execute */
582 	p->psstate = 0;
583 	p->insyscall = 0;
584 }
585 
586 ulong
userpc(void)587 userpc(void)
588 {
589 	Ureg *ureg;
590 
591 	ureg = (Ureg*)up->dbgreg;
592 	return ureg->pc;
593 }
594 
595 
596 /* This routine must save the values of registers the user is not
597  * permitted to write from devproc and then restore the saved values
598  * before returning
599  */
600 void
setregisters(Ureg * xp,char * pureg,char * uva,int n)601 setregisters(Ureg *xp, char *pureg, char *uva, int n)
602 {
603 	ulong status;
604 
605 	status = xp->status;
606 	memmove(pureg, uva, n);
607 	xp->status = status;
608 }
609 
610 /* Give enough context in the ureg to produce a kernel stack for
611  * a sleeping process
612  */
613 void
setkernur(Ureg * ureg,Proc * p)614 setkernur(Ureg* ureg, Proc* p)
615 {
616 	ureg->pc = p->sched.pc;
617 	ureg->sp = p->sched.sp+4;
618 }
619 
620 ulong
dbgpc(Proc * p)621 dbgpc(Proc *p)
622 {
623 	Ureg *ureg;
624 
625 	ureg = p->dbgreg;
626 	if(ureg == 0)
627 		return 0;
628 
629 	return ureg->pc;
630 }
631 
632 /*
633  *  system calls
634  */
635 #include "../port/systab.h"
636 
637 /* TODO: make this trap a separate asm entry point, like on other RISC architectures */
638 void
syscall(Ureg * ureg)639 syscall(Ureg* ureg)
640 {
641 	int i;
642 	char *e;
643 	long	ret;
644 	ulong sp, scallnr;
645 
646 	m->syscall++;
647 	up->insyscall = 1;
648 	up->pc = ureg->pc;
649 	up->dbgreg = ureg;
650 
651 	scallnr = ureg->r3;
652 	up->scallnr = ureg->r3;
653 	spllo();
654 
655 	sp = ureg->usp;
656 	up->nerrlab = 0;
657 	ret = -1;
658 	if(!waserror()){
659 		if(scallnr >= nsyscall || systab[scallnr] == nil){
660 			pprint("bad sys call number %lud pc %lux\n",
661 				scallnr, ureg->pc);
662 			postnote(up, 1, "sys: bad sys call", NDebug);
663 			error(Ebadarg);
664 		}
665 
666 		if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)-BY2WD))
667 			validaddr(sp, sizeof(Sargs)+BY2WD, 0);
668 
669 		up->s = *((Sargs*)(sp+BY2WD));
670 		up->psstate = sysctab[scallnr];
671 
672 		ret = systab[scallnr](up->s.args);
673 		poperror();
674 	}else{
675 		/* failure: save the error buffer for errstr */
676 		e = up->syserrstr;
677 		up->syserrstr = up->errstr;
678 		up->errstr = e;
679 	}
680 	if(up->nerrlab){
681 		print("bad errstack [%uld]: %d extra\n", scallnr, up->nerrlab);
682 		print("scall %s lr =%lux\n", sysctab[scallnr], ureg->lr);
683 		for(i = 0; i < NERR; i++)
684 			print("sp=%lux pc=%lux\n", up->errlab[i].sp, up->errlab[i].pc);
685 		panic("error stack");
686 	}
687 
688 	up->insyscall = 0;
689 	up->psstate = 0;
690 
691 	/*
692 	 *  Put return value in frame.  On the x86 the syscall is
693 	 *  just another trap and the return value from syscall is
694 	 *  ignored.  On other machines the return value is put into
695 	 *  the results register by caller of syscall.
696 	 */
697 	ureg->r3 = ret;
698 
699 	if(scallnr == NOTED)
700 		noted(ureg, *(ulong*)(sp+BY2WD));
701 
702 	/* restoreureg must execute at high IPL */
703 	splhi();
704 	if(scallnr!=RFORK)
705 		notify(ureg);
706 	if(up->fpstate == FPinactive)
707 		ureg->srr1 &= ~MSR_FP;
708 }
709 
710 /*
711  *  Call user, if necessary, with note.
712  *  Pass user the Ureg struct and the note on his stack.
713  */
714 int
notify(Ureg * ur)715 notify(Ureg* ur)
716 {
717 	int l;
718 	ulong s, sp;
719 	Note *n;
720 
721 	if(up->procctl)
722 		procctl(up);
723 	if(up->nnote == 0)
724 		return 0;
725 
726 	s = spllo();
727 	qlock(&up->debug);
728 	up->notepending = 0;
729 	n = &up->note[0];
730 	if(strncmp(n->msg, "sys:", 4) == 0){
731 		l = strlen(n->msg);
732 		if(l > ERRMAX-15)	/* " pc=0x12345678\0" */
733 			l = ERRMAX-15;
734 		sprint(n->msg+l, " pc=0x%.8lux", ur->pc);
735 	}
736 
737 	if(n->flag!=NUser && (up->notified || up->notify==0)){
738 		if(n->flag == NDebug)
739 			pprint("suicide: %s\n", n->msg);
740 		qunlock(&up->debug);
741 		pexit(n->msg, n->flag!=NDebug);
742 	}
743 
744 	if(up->notified) {
745 		qunlock(&up->debug);
746 		splhi();
747 		return 0;
748 	}
749 
750 	if(!up->notify) {
751 		qunlock(&up->debug);
752 		pexit(n->msg, n->flag!=NDebug);
753 	}
754 	sp = ur->usp & ~(BY2V-1);
755 	sp -= sizeof(Ureg);
756 
757 	if(!okaddr((ulong)up->notify, BY2WD, 0) ||
758 	   !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)) {
759 		pprint("suicide: bad address or sp in notify\n");
760 		qunlock(&up->debug);
761 		pexit("Suicide", 0);
762 	}
763 
764 	memmove((Ureg*)sp, ur, sizeof(Ureg));
765 	*(Ureg**)(sp-BY2WD) = up->ureg;	/* word under Ureg is old up->ureg */
766 	up->ureg = (void*)sp;
767 	sp -= BY2WD+ERRMAX;
768 	memmove((char*)sp, up->note[0].msg, ERRMAX);
769 	sp -= 3*BY2WD;
770 	*(ulong*)(sp+2*BY2WD) = sp+3*BY2WD;	/* arg 2 is string */
771 	ur->r1 = (long)up->ureg;		/* arg 1 is ureg* */
772 	((ulong*)sp)[1] = (ulong)up->ureg;	/* arg 1 0(FP) is ureg* */
773 	((ulong*)sp)[0] = 0;			/* arg 0 is pc */
774 	ur->usp = sp;
775 	ur->pc = (ulong)up->notify;
776 	up->notified = 1;
777 	up->nnote--;
778 	memmove(&up->lastnote, &up->note[0], sizeof(Note));
779 	memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note));
780 
781 	qunlock(&up->debug);
782 	splx(s);
783 	return 1;
784 }
785 
786 
787 /*
788  *   Return user to state before notify()
789  */
790 void
noted(Ureg * ureg,ulong arg0)791 noted(Ureg* ureg, ulong arg0)
792 {
793 	Ureg *nureg;
794 	ulong oureg, sp;
795 
796 	qlock(&up->debug);
797 	if(arg0!=NRSTR && !up->notified) {
798 		qunlock(&up->debug);
799 		pprint("call to noted() when not notified\n");
800 		pexit("Suicide", 0);
801 	}
802 	up->notified = 0;
803 
804 	nureg = up->ureg;	/* pointer to user returned Ureg struct */
805 
806 	/* sanity clause */
807 	oureg = (ulong)nureg;
808 	if(!okaddr((ulong)oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){
809 		pprint("bad ureg in noted or call to noted when not notified\n");
810 		qunlock(&up->debug);
811 		pexit("Suicide", 0);
812 	}
813 
814 	memmove(ureg, nureg, sizeof(Ureg));
815 
816 	switch(arg0){
817 	case NCONT:
818 	case NRSTR:
819 		if(!okaddr(nureg->pc, 1, 0) || !okaddr(nureg->usp, BY2WD, 0)){
820 			pprint("suicide: trap in noted\n");
821 			qunlock(&up->debug);
822 			pexit("Suicide", 0);
823 		}
824 		up->ureg = (Ureg*)(*(ulong*)(oureg-BY2WD));
825 		qunlock(&up->debug);
826 		break;
827 
828 	case NSAVE:
829 		if(!okaddr(nureg->pc, BY2WD, 0)
830 		|| !okaddr(nureg->usp, BY2WD, 0)){
831 			pprint("suicide: trap in noted\n");
832 			qunlock(&up->debug);
833 			pexit("Suicide", 0);
834 		}
835 		qunlock(&up->debug);
836 		sp = oureg-4*BY2WD-ERRMAX;
837 		splhi();
838 		ureg->sp = sp;
839 		((ulong*)sp)[1] = oureg;	/* arg 1 0(FP) is ureg* */
840 		((ulong*)sp)[0] = 0;		/* arg 0 is pc */
841 		break;
842 
843 	default:
844 		pprint("unknown noted arg 0x%lux\n", arg0);
845 		up->lastnote.flag = NDebug;
846 		/* fall through */
847 
848 	case NDFLT:
849 		if(up->lastnote.flag == NDebug)
850 			pprint("suicide: %s\n", up->lastnote.msg);
851 		qunlock(&up->debug);
852 		pexit(up->lastnote.msg, up->lastnote.flag!=NDebug);
853 	}
854 }
855