]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/mtx/trap.c
ether8169: support rtl8402 variant
[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         user = kenter(ureg);
219         ecode = (ureg->cause >> 8) & 0xff;
220         if((ureg->status & MSR_RI) == 0)
221                 print("double fault?: ecode = %d\n", ecode);
222
223         switch(ecode) {
224         case CEI:
225                 intr(ureg);
226                 break;
227         case CDEC:
228                 clockintr(ureg);
229                 break;
230         case CSYSCALL:
231                 if(!user)
232                         panic("syscall in kernel: srr1 0x%4.4luX", ureg->srr1);
233                 syscall(ureg);
234                 return;         /* syscall() calls notify itself, don't do it again */
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                 default:
250                         panic("fpstate");
251                 }
252                 ureg->srr1 |= MSR_FP;
253                 break;
254         case CISI:
255                 faultpower(ureg, ureg->pc, 1);
256                 break;
257         case CDSI:
258                 dsisr = getdsisr();
259                 if(dsisr & BIT(6))
260                         faultpower(ureg, getdar(), 0);
261                 else
262                         faultpower(ureg, getdar(), 1);
263                 break;
264         case CPROG:
265                 if(ureg->status & (1<<19))
266                         s = "floating point exception";
267                 else if(ureg->status & (1<<18))
268                         s = "illegal instruction";
269                 else if(ureg->status & (1<<17))
270                         s = "privileged instruction";
271                 else
272                         s = "undefined program exception";
273                 if(user){
274                         spllo();
275                         sprint(buf, "sys: trap: %s", s);
276                         postnote(up, 1, buf, NDebug);
277                         break;
278                 }
279                 dumpregs(ureg);
280                 panic(s);
281                 break;
282         default:
283                 if(ecode < nelem(excname) && user){
284                         spllo();
285                         sprint(buf, "sys: trap: %s", excname[ecode]);
286                         postnote(up, 1, buf, NDebug);
287                         break;
288                 }
289                 dumpregs(ureg);
290                 if(ecode < nelem(excname))
291                         panic("%s", excname[ecode]);
292                 panic("unknown trap/intr: %d", ecode);
293         }
294
295         /* restoreureg must execute at high IPL */
296         splhi();
297
298         /* delaysched set because we held a lock or because our quantum ended */
299         if(up && up->delaysched && ecode == CDEC){
300                 sched();
301                 splhi();
302         }
303
304         if(user) {
305                 notify(ureg);
306                 if(up->fpstate == FPinactive)
307                         ureg->srr1 &= ~MSR_FP;
308                 kexit(ureg);
309         }
310 }
311
312 void
313 faultpower(Ureg *ureg, ulong addr, int read)
314 {
315         int user, insyscall, n;
316         char buf[ERRMAX];
317
318         user = (ureg->srr1 & MSR_PR) != 0;
319         insyscall = up->insyscall;
320         up->insyscall = 1;
321         n = fault(addr, ureg->pc, read);
322         if(n < 0){
323                 if(!user){
324                         dumpregs(ureg);
325                         panic("fault: 0x%lux", addr);
326                 }
327                 sprint(buf, "sys: trap: fault %s addr=0x%lux", read? "read" : "write", addr);
328                 postnote(up, 1, buf, NDebug);
329         }
330         up->insyscall = insyscall;
331 }
332
333 void
334 sethvec(int v, void (*r)(void))
335 {
336         ulong *vp, pa, o;
337
338         vp = KADDR(v);
339         vp[0] = 0x7c1043a6;     /* MOVW R0, SPR(SPRG0) */
340         vp[1] = 0x7c0802a6;     /* MOVW LR, R0 */
341         vp[2] = 0x7c1243a6;     /* MOVW R0, SPR(SPRG2) */
342         pa = PADDR(r);
343         o = pa >> 25;
344         if(o != 0 && o != 0x7F){
345                 /* a branch too far */
346                 vp[3] = (15<<26)|(pa>>16);      /* MOVW $r&~0xFFFF, R0 */
347                 vp[4] = (24<<26)|(pa&0xFFFF);   /* OR $r&0xFFFF, R0 */
348                 vp[5] = 0x7c0803a6;     /* MOVW R0, LR */
349                 vp[6] = 0x4e800021;     /* BL (LR) */
350         }else
351                 vp[3] = (18<<26)|(pa&0x3FFFFFC)|3;      /* bla */
352         dcflush(vp, 8*sizeof(ulong));
353 }
354
355 void
356 trapinit(void)
357 {
358         int i;
359
360         /*
361          * set all exceptions to trap
362          */
363         for(i = 0; i < 0x2000; i += 0x100)
364                 sethvec(i, trapvec);
365
366         putmsr(getmsr() & ~MSR_IP);
367 }
368
369 void
370 intr(Ureg *ureg)
371 {
372         int vno;
373         Vctl *ctl, *v;
374
375         vno = mpicintack();
376         if(vno == 0) {                  /* 8259, wired through MPIC vec 0 */
377                 vno = i8259intack();
378                 mpiceoi(0);
379         }
380
381         if(vno > nelem(vctl) || (ctl = vctl[vno]) == 0) {
382                 panic("spurious intr %d", vno);
383                 return;
384         }
385
386         if(ctl->isr)
387                 ctl->isr(vno);
388         for(v = ctl; v != nil; v = v->next){
389                 if(v->f)
390                         v->f(ureg, v->a);
391         }
392         if(ctl->eoi)
393                 ctl->eoi(vno);
394
395         if(up)
396                 preempted();
397 }
398
399 char*
400 fpexcname(Ureg *ur, ulong fpscr, char *buf)
401 {
402         int i;
403         char *s;
404         ulong fppc;
405
406         fppc = ur->pc;
407         s = 0;
408         fpscr >>= 3;            /* trap enable bits */
409         fpscr &= (fpscr>>22);   /* anded with exceptions */
410         for(i=0; i<5; i++)
411                 if(fpscr & (1<<i))
412                         s = fpcause[i];
413         if(s == 0)
414                 return "no floating point exception";
415         sprint(buf, "%s fppc=0x%lux", s, fppc);
416         return buf;
417 }
418
419 /*
420  * Fill in enough of Ureg to get a stack trace, and call a function.
421  * Used by debugging interface rdb.
422  */
423
424 static void
425 getpcsp(ulong *pc, ulong *sp)
426 {
427         *pc = getcallerpc(&pc);
428         *sp = (ulong)&pc-4;
429 }
430
431 void
432 callwithureg(void (*fn)(Ureg*))
433 {
434         Ureg ureg;
435
436         getpcsp((ulong*)&ureg.pc, (ulong*)&ureg.sp);
437         ureg.lr = getcallerpc(&fn);
438         fn(&ureg);
439 }
440
441 static void
442 _dumpstack(Ureg *ureg)
443 {
444         ulong l, sl, el, v;
445         int i;
446
447         l = (ulong)&l;
448         if(up == 0){
449                 el = (ulong)m+BY2PG;
450                 sl = el-KSTACK;
451         }
452         else{
453                 sl = (ulong)up->kstack;
454                 el = sl + KSTACK;
455         }
456         if(l > el || l < sl){
457                 el = (ulong)m+BY2PG;
458                 sl = el-KSTACK;
459         }
460         if(l > el || l < sl)
461                 return;
462         print("ktrace /kernel/path %.8lux %.8lux %.8lux\n", ureg->pc, ureg->sp, ureg->lr);
463         i = 0;
464         for(; l < el; l += 4){
465                 v = *(ulong*)l;
466                 if(KTZERO < v && v < (ulong)etext){
467                         print("%.8lux=%.8lux ", l, v);
468                         if(i++ == 4){
469                                 print("\n");
470                                 i = 0;
471                         }
472                 }
473         }
474 }
475
476 void
477 dumpstack(void)
478 {
479         callwithureg(_dumpstack);
480 }
481
482 void
483 dumpregs(Ureg *ur)
484 {
485         int i;
486         ulong *l;
487
488         if(up) {
489                 print("registers for %s %ld\n", up->text, up->pid);
490                 if((ur->srr1 & MSR_PR) == 0)
491                 if(ur->usp < (ulong)up->kstack || ur->usp > (ulong)up->kstack+KSTACK)
492                         print("invalid stack ptr\n");
493         }
494         else
495                 print("registers for kernel\n");
496
497         print("dsisr\t%.8lux\tdar\t%.8lux\n", getdsisr(), getdar());
498         l = &ur->cause;
499         for(i=0; i<sizeof regname/sizeof(char*); i+=2, l+=2)
500                 print("%s\t%.8lux\t%s\t%.8lux\n", regname[i], l[0], regname[i+1], l[1]);
501 }
502
503 void
504 kprocchild(Proc *p, void (*entry)(void))
505 {
506         p->sched.pc = (ulong)entry;
507         p->sched.sp = (ulong)p->kstack+KSTACK;
508 }
509
510 /*
511  * called in sysfile.c
512  */
513 void
514 evenaddr(ulong addr)
515 {
516         if(addr & 3){
517                 postnote(up, 1, "sys: odd address", NDebug);
518                 error(Ebadarg);
519         }
520 }
521
522 uintptr
523 execregs(uintptr entry, ulong ssize, ulong nargs)
524 {
525         ulong *sp;
526         Ureg *ureg;
527
528         sp = (ulong*)(USTKTOP - ssize);
529         *--sp = nargs;
530
531         ureg = up->dbgreg;
532         ureg->usp = (ulong)sp;
533         ureg->pc = entry;
534         ureg->srr1 &= ~MSR_FP;
535         return USTKTOP-sizeof(Tos);             /* address of kernel/user shared data */
536 }
537
538 void
539 forkchild(Proc *p, Ureg *ur)
540 {
541         Ureg *cur;
542
543         p->sched.sp = (ulong)p->kstack+KSTACK-UREGSIZE;
544         p->sched.pc = (ulong)forkret;
545
546         cur = (Ureg*)(p->sched.sp+2*BY2WD);
547         memmove(cur, ur, sizeof(Ureg));
548         cur->r3 = 0;
549 }
550
551 uintptr
552 userpc(void)
553 {
554         Ureg *ureg;
555
556         ureg = (Ureg*)up->dbgreg;
557         return ureg->pc;
558 }
559
560
561 /* This routine must save the values of registers the user is not 
562  * permitted to write from devproc and then restore the saved values 
563  * before returning
564  */
565 void
566 setregisters(Ureg *xp, char *pureg, char *uva, int n)
567 {
568         ulong status;
569
570         status = xp->status;
571         memmove(pureg, uva, n);
572         xp->status = status;
573 }
574
575 /* Give enough context in the ureg to produce a kernel stack for
576  * a sleeping process
577  */
578 void
579 setkernur(Ureg* ureg, Proc* p)
580 {
581         ureg->pc = p->sched.pc;
582         ureg->sp = p->sched.sp+4;
583 }
584
585 uintptr
586 dbgpc(Proc *p)
587 {
588         Ureg *ureg;
589
590         ureg = p->dbgreg;
591         if(ureg == 0)
592                 return 0;
593
594         return ureg->pc;
595 }
596
597 /*
598  *  system calls
599  */
600 #include "../port/systab.h"
601
602 /* TODO: make this trap a separate asm entry point, like on other RISC architectures */
603 void
604 syscall(Ureg* ureg)
605 {
606         int i;
607         char *e;
608         long    ret;
609         ulong sp, scallnr;
610
611         m->syscall++;
612         up->insyscall = 1;
613         up->pc = ureg->pc;
614
615         scallnr = ureg->r3;
616         up->scallnr = ureg->r3;
617         spllo();
618
619         sp = ureg->usp;
620         up->nerrlab = 0;
621         ret = -1;
622         if(!waserror()){
623                 if(scallnr >= nsyscall || systab[scallnr] == nil){
624                         pprint("bad sys call number %d pc %lux\n", scallnr, ureg->pc);
625                         postnote(up, 1, "sys: bad sys call", NDebug);
626                         error(Ebadarg);
627                 }
628
629                 if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)-BY2WD))
630                         validaddr(sp, sizeof(Sargs)+BY2WD, 0);
631
632                 up->s = *((Sargs*)(sp+BY2WD));
633                 up->psstate = sysctab[scallnr];
634
635                 ret = systab[scallnr](up->s.args);
636                 poperror();
637         }else{
638                 /* failure: save the error buffer for errstr */
639                 e = up->syserrstr;
640                 up->syserrstr = up->errstr;
641                 up->errstr = e;
642         }
643         if(up->nerrlab){
644                 print("bad errstack [%uld]: %d extra\n", scallnr, up->nerrlab);
645                 print("scall %s lr =%lux\n", sysctab[scallnr], ureg->lr);
646                 for(i = 0; i < NERR; i++)
647                         print("sp=%lux pc=%lux\n", up->errlab[i].sp, up->errlab[i].pc);
648                 panic("error stack");
649         }
650
651         up->insyscall = 0;
652         up->psstate = 0;
653
654         /*
655          *  Put return value in frame.  On the x86 the syscall is
656          *  just another trap and the return value from syscall is
657          *  ignored.  On other machines the return value is put into
658          *  the results register by caller of syscall.
659          */
660         ureg->r3 = ret;
661
662         if(scallnr == NOTED)
663                 noted(ureg, *(ulong*)(sp+BY2WD));
664
665         /* restoreureg must execute at high IPL */
666         splhi();
667         if(scallnr!=RFORK)
668                 notify(ureg);
669         if(up->fpstate == FPinactive)
670                 ureg->srr1 &= ~MSR_FP;
671 }
672
673 /*
674  *  Call user, if necessary, with note.
675  *  Pass user the Ureg struct and the note on his stack.
676  */
677 int
678 notify(Ureg* ur)
679 {
680         int l;
681         ulong s, sp;
682         Note *n;
683
684         if(up->procctl)
685                 procctl();
686         if(up->nnote == 0)
687                 return 0;
688
689         s = spllo();
690         qlock(&up->debug);
691         up->notepending = 0;
692         n = &up->note[0];
693         if(strncmp(n->msg, "sys:", 4) == 0){
694                 l = strlen(n->msg);
695                 if(l > ERRMAX-15)       /* " pc=0x12345678\0" */
696                         l = ERRMAX-15;
697                 sprint(n->msg+l, " pc=0x%.8lux", ur->pc);
698         }
699
700         if(n->flag!=NUser && (up->notified || up->notify==0)){
701                 qunlock(&up->debug);
702                 if(n->flag == NDebug)
703                         pprint("suicide: %s\n", n->msg);
704                 pexit(n->msg, n->flag!=NDebug);
705         }
706
707         if(up->notified) {
708                 qunlock(&up->debug);
709                 splhi();
710                 return 0;
711         }
712
713         if(!up->notify) {
714                 qunlock(&up->debug);
715                 pexit(n->msg, n->flag!=NDebug);
716         }
717         sp = ur->usp & ~(BY2V-1);
718         sp -= sizeof(Ureg);
719
720         if(!okaddr((uintptr)up->notify, BY2WD, 0) ||
721            !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)) {
722                 qunlock(&up->debug);
723                 pprint("suicide: bad address or sp in notify\n");
724                 pexit("Suicide", 0);
725         }
726
727         memmove((Ureg*)sp, ur, sizeof(Ureg));
728         *(Ureg**)(sp-BY2WD) = up->ureg; /* word under Ureg is old up->ureg */
729         up->ureg = (void*)sp;
730         sp -= BY2WD+ERRMAX;
731         memmove((char*)sp, up->note[0].msg, ERRMAX);
732         sp -= 3*BY2WD;
733         *(ulong*)(sp+2*BY2WD) = sp+3*BY2WD;     /* arg 2 is string */
734         ur->r1 = (long)up->ureg;                /* arg 1 is ureg* */
735         ((ulong*)sp)[1] = (ulong)up->ureg;      /* arg 1 0(FP) is ureg* */
736         ((ulong*)sp)[0] = 0;                    /* arg 0 is pc */
737         ur->usp = sp;
738         ur->pc = (ulong)up->notify;
739         up->notified = 1;
740         up->nnote--;
741         memmove(&up->lastnote, &up->note[0], sizeof(Note));
742         memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note));
743
744         qunlock(&up->debug);
745         splx(s);
746         return 1;
747 }
748
749
750 /*
751  *   Return user to state before notify()
752  */
753 void
754 noted(Ureg* ureg, ulong arg0)
755 {
756         Ureg *nureg;
757         ulong oureg, sp;
758
759         qlock(&up->debug);
760         if(arg0!=NRSTR && !up->notified) {
761                 qunlock(&up->debug);
762                 pprint("call to noted() when not notified\n");
763                 pexit("Suicide", 0);
764         }
765         up->notified = 0;
766
767         nureg = up->ureg;       /* pointer to user returned Ureg struct */
768
769         /* sanity clause */
770         oureg = (ulong)nureg;
771         if(!okaddr(oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){
772                 qunlock(&up->debug);
773                 pprint("bad ureg in noted or call to noted when not notified\n");
774                 pexit("Suicide", 0);
775         }
776
777         memmove(ureg, nureg, sizeof(Ureg));
778
779         switch(arg0){
780         case NCONT:
781         case NRSTR:
782                 if(!okaddr(nureg->pc, 1, 0) || !okaddr(nureg->usp, BY2WD, 0)){
783                         qunlock(&up->debug);
784                         pprint("suicide: trap in noted\n");
785                         pexit("Suicide", 0);
786                 }
787                 up->ureg = (Ureg*)(*(ulong*)(oureg-BY2WD));
788                 qunlock(&up->debug);
789                 break;
790
791         case NSAVE:
792                 if(!okaddr(nureg->pc, BY2WD, 0)
793                 || !okaddr(nureg->usp, BY2WD, 0)){
794                         qunlock(&up->debug);
795                         pprint("suicide: trap in noted\n");
796                         pexit("Suicide", 0);
797                 }
798                 qunlock(&up->debug);
799                 sp = oureg-4*BY2WD-ERRMAX;
800                 splhi();
801                 ureg->sp = sp;
802                 ((ulong*)sp)[1] = oureg;        /* arg 1 0(FP) is ureg* */
803                 ((ulong*)sp)[0] = 0;            /* arg 0 is pc */
804                 break;
805
806         default:
807                 up->lastnote.flag = NDebug;
808                 /* fall through */
809                 
810         case NDFLT:
811                 qunlock(&up->debug);
812                 if(up->lastnote.flag == NDebug)
813                         pprint("suicide: %s\n", up->lastnote.msg);
814                 pexit(up->lastnote.msg, up->lastnote.flag!=NDebug);
815         }
816 }