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