]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/ppc/trap.c
pc/vga*: use 64-bit physical addresses and check pci membar types and sizes
[plan9front.git] / sys / src / 9 / ppc / 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        "../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 = t + 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, ureg->pc, 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 uintptr
529 execregs(uintptr 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
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
558 uintptr
559 userpc(void)
560 {
561         Ureg *ureg;
562
563         ureg = (Ureg*)up->dbgreg;
564         return ureg->pc;
565 }
566
567
568 /* This routine must save the values of registers the user is not 
569  * permitted to write from devproc and then restore the saved values 
570  * before returning
571  */
572 void
573 setregisters(Ureg *xp, char *pureg, char *uva, int n)
574 {
575         ulong status;
576
577         status = xp->status;
578         memmove(pureg, uva, n);
579         xp->status = status;
580 }
581
582 /* Give enough context in the ureg to produce a kernel stack for
583  * a sleeping process
584  */
585 void
586 setkernur(Ureg* ureg, Proc* p)
587 {
588         ureg->pc = p->sched.pc;
589         ureg->sp = p->sched.sp+4;
590 }
591
592 uintptr
593 dbgpc(Proc *p)
594 {
595         Ureg *ureg;
596
597         ureg = p->dbgreg;
598         if(ureg == 0)
599                 return 0;
600
601         return ureg->pc;
602 }
603
604 /*
605  *  system calls
606  */
607 #include "../port/systab.h"
608
609 /* TODO: make this trap a separate asm entry point, like on other RISC architectures */
610 void
611 syscall(Ureg* ureg)
612 {
613         int i;
614         char *e;
615         long    ret;
616         ulong sp, scallnr;
617
618         m->syscall++;
619         up->insyscall = 1;
620         up->pc = ureg->pc;
621         up->dbgreg = ureg;
622
623         if (up->fpstate == FPactive && (ureg->srr1 & MSR_FP) == 0){
624                 print("fpstate check, entry syscall\n");
625                 delay(200);
626                 dumpregs(ureg);
627                 print("fpstate check, entry syscall\n");
628         }
629
630         scallnr = ureg->r3;
631         up->scallnr = ureg->r3;
632         spllo();
633
634         sp = ureg->usp;
635         up->nerrlab = 0;
636         ret = -1;
637         if(!waserror()){
638                 if(scallnr >= nsyscall || systab[scallnr] == nil){
639                         pprint("bad sys call number %d pc %lux\n", scallnr, ureg->pc);
640                         postnote(up, 1, "sys: bad sys call", NDebug);
641                         error(Ebadarg);
642                 }
643
644                 if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)-BY2WD))
645                         validaddr(sp, sizeof(Sargs)+BY2WD, 0);
646
647                 up->s = *((Sargs*)(sp+BY2WD));
648                 up->psstate = sysctab[scallnr];
649
650                 ret = systab[scallnr]((va_list)up->s.args);
651                 poperror();
652         }else{
653                 /* failure: save the error buffer for errstr */
654                 e = up->syserrstr;
655                 up->syserrstr = up->errstr;
656                 up->errstr = e;
657         }
658         if(up->nerrlab){
659                 print("bad errstack [%uld]: %d extra\n", scallnr, up->nerrlab);
660                 print("scall %s lr =%lux\n", sysctab[scallnr], ureg->lr);
661                 for(i = 0; i < NERR; i++)
662                         print("sp=%lux pc=%lux\n", up->errlab[i].sp, up->errlab[i].pc);
663                 panic("error stack");
664         }
665
666         up->insyscall = 0;
667         up->psstate = 0;
668
669         /*
670          *  Put return value in frame.  On the x86 the syscall is
671          *  just another trap and the return value from syscall is
672          *  ignored.  On other machines the return value is put into
673          *  the results register by caller of syscall.
674          */
675         ureg->r3 = ret;
676
677         if(scallnr == NOTED)
678                 noted(ureg, *(ulong*)(sp+BY2WD));
679
680         /* restoreureg must execute at high IPL */
681         splhi();
682         if(scallnr!=RFORK)
683                 notify(ureg);
684
685         if (up->fpstate == FPactive && (ureg->srr1 & MSR_FP) == 0){
686                 print("fpstate check, exit syscall nr %lud, pid %lud\n", scallnr, up->pid);
687                 dumpregs(ureg);
688         }
689         if(up->fpstate != FPactive)
690                 ureg->srr1 &= ~MSR_FP;
691 }
692
693 /*
694  *  Call user, if necessary, with note.
695  *  Pass user the Ureg struct and the note on his stack.
696  */
697 int
698 notify(Ureg* ur)
699 {
700         int l;
701         ulong s, sp;
702         Note *n;
703
704         if(up->procctl)
705                 procctl();
706         if(up->nnote == 0)
707                 return 0;
708
709         if(up->fpstate == FPactive){
710                 fpsave(up->fpsave);
711                 up->fpstate = FPinactive;
712         }
713         up->fpstate |= FPillegal;
714
715         s = spllo();
716         qlock(&up->debug);
717         up->notepending = 0;
718         n = &up->note[0];
719         if(strncmp(n->msg, "sys:", 4) == 0){
720                 l = strlen(n->msg);
721                 if(l > ERRMAX-15)       /* " pc=0x12345678\0" */
722                         l = ERRMAX-15;
723                 sprint(n->msg+l, " pc=0x%.8lux", ur->pc);
724         }
725
726         if(n->flag!=NUser && (up->notified || up->notify==0)){
727                 qunlock(&up->debug);
728                 if(n->flag == NDebug)
729                         pprint("suicide: %s\n", n->msg);
730                 pexit(n->msg, n->flag!=NDebug);
731         }
732
733         if(up->notified) {
734                 qunlock(&up->debug);
735                 splhi();
736                 return 0;
737         }
738
739         if(!up->notify) {
740                 qunlock(&up->debug);
741                 pexit(n->msg, n->flag!=NDebug);
742         }
743
744         sp = ur->usp & ~(BY2V-1);
745         sp -= sizeof(Ureg);
746
747         if(!okaddr((uintptr)up->notify, BY2WD, 0) ||
748            !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)) {
749                 qunlock(&up->debug);
750                 pprint("suicide: bad address or sp in notify\n");
751                 pexit("Suicide", 0);
752         }
753
754         memmove((Ureg*)sp, ur, sizeof(Ureg));
755         *(Ureg**)(sp-BY2WD) = up->ureg; /* word under Ureg is old up->ureg */
756         up->ureg = (void*)sp;
757         sp -= BY2WD+ERRMAX;
758         memmove((char*)sp, up->note[0].msg, ERRMAX);
759         sp -= 3*BY2WD;
760         *(ulong*)(sp+2*BY2WD) = sp+3*BY2WD;     /* arg 2 is string */
761         ur->r1 = (long)up->ureg;                /* arg 1 is ureg* */
762         ((ulong*)sp)[1] = (ulong)up->ureg;      /* arg 1 0(FP) is ureg* */
763         ((ulong*)sp)[0] = 0;                    /* arg 0 is pc */
764         ur->usp = sp;
765         ur->pc = (ulong)up->notify;
766         up->notified = 1;
767         up->nnote--;
768         memmove(&up->lastnote, &up->note[0], sizeof(Note));
769         memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note));
770
771         qunlock(&up->debug);
772         splx(s);
773         return 1;
774 }
775
776
777 /*
778  *   Return user to state before notify()
779  */
780 void
781 noted(Ureg* ureg, ulong arg0)
782 {
783         Ureg *nureg;
784         ulong oureg, sp;
785
786         qlock(&up->debug);
787         if(arg0!=NRSTR && !up->notified) {
788                 qunlock(&up->debug);
789                 pprint("call to noted() when not notified\n");
790                 pexit("Suicide", 0);
791         }
792         up->notified = 0;
793
794         nureg = up->ureg;       /* pointer to user returned Ureg struct */
795
796         /* sanity clause */
797         oureg = (ulong)nureg;
798         if(!okaddr(oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){
799                 qunlock(&up->debug);
800                 pprint("bad ureg in noted or call to noted when not notified\n");
801                 pexit("Suicide", 0);
802         }
803
804         memmove(ureg, nureg, sizeof(Ureg));
805
806         switch(arg0){
807         case NCONT:
808         case NRSTR:
809                 if(!okaddr(nureg->pc, 1, 0) || !okaddr(nureg->usp, BY2WD, 0)){
810                         qunlock(&up->debug);
811                         pprint("suicide: trap in noted\n");
812                         pexit("Suicide", 0);
813                 }
814                 up->ureg = (Ureg*)(*(ulong*)(oureg-BY2WD));
815                 qunlock(&up->debug);
816                 break;
817
818         case NSAVE:
819                 if(!okaddr(nureg->pc, BY2WD, 0)
820                 || !okaddr(nureg->usp, BY2WD, 0)){
821                         qunlock(&up->debug);
822                         pprint("suicide: trap in noted\n");
823                         pexit("Suicide", 0);
824                 }
825                 qunlock(&up->debug);
826                 sp = oureg-4*BY2WD-ERRMAX;
827                 splhi();
828                 ureg->sp = sp;
829                 ((ulong*)sp)[1] = oureg;        /* arg 1 0(FP) is ureg* */
830                 ((ulong*)sp)[0] = 0;            /* arg 0 is pc */
831                 break;
832
833         default:
834                 up->lastnote.flag = NDebug;
835                 /* fall through */
836                 
837         case NDFLT:
838                 qunlock(&up->debug);
839                 if(up->lastnote.flag == NDebug)
840                         pprint("suicide: %s\n", up->lastnote.msg);
841                 pexit(up->lastnote.msg, up->lastnote.flag!=NDebug);
842         }
843         up->fpstate &= ~FPillegal;
844         if (up->fpstate == FPactive)
845                 ureg->srr1 |= MSR_FP;
846         else
847                 ureg->srr1 &= ~MSR_FP;
848 }