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