]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/mtx/trap.c
bcm64: set XN bits for kernel device mappings
[plan9front.git] / sys / src / 9 / mtx / trap.c
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 uintptr
537 execregs(uintptr 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 uintptr
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 uintptr
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();
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                 qunlock(&up->debug);
721                 if(n->flag == NDebug)
722                         pprint("suicide: %s\n", n->msg);
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((uintptr)up->notify, BY2WD, 0) ||
740            !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)) {
741                 qunlock(&up->debug);
742                 pprint("suicide: bad address or sp in notify\n");
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(oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){
791                 qunlock(&up->debug);
792                 pprint("bad ureg in noted or call to noted when not notified\n");
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                         qunlock(&up->debug);
803                         pprint("suicide: trap in noted\n");
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                         qunlock(&up->debug);
814                         pprint("suicide: trap in noted\n");
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                 up->lastnote.flag = NDebug;
827                 /* fall through */
828                 
829         case NDFLT:
830                 qunlock(&up->debug);
831                 if(up->lastnote.flag == NDebug)
832                         pprint("suicide: %s\n", up->lastnote.msg);
833                 pexit(up->lastnote.msg, up->lastnote.flag!=NDebug);
834         }
835 }