]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/sgi/trap.c
devvmx: remove unncessary locking in gotcmd() sleep test function
[plan9front.git] / sys / src / 9 / sgi / trap.c
1 /*
2  * traps, exceptions, faults and interrupts on ar7161
3  */
4 #include        "u.h"
5 #include        "tos.h"
6 #include        "../port/lib.h"
7 #include        "mem.h"
8 #include        "dat.h"
9 #include        "fns.h"
10 #include        "ureg.h"
11 #include        "io.h"
12 #include        "../port/error.h"
13
14 typedef struct Handler Handler;
15
16 struct Handler {
17         void    (*handler)(Ureg*, void *);
18         void    *arg;
19         Handler *next;                  /* at this interrupt level */
20 };
21
22 int     intr(Ureg*);
23 void    kernfault(Ureg*, int);
24 void    noted(Ureg*, ulong);
25 void    rfnote(Ureg**);
26
27 char *excname[] =
28 {
29         "trap: external interrupt",
30         "trap: TLB modification (store to unwritable)",
31         "trap: TLB miss (load or fetch)",
32         "trap: TLB miss (store)",
33         "trap: address error (load or fetch)",
34         "trap: address error (store)",
35         "trap: bus error (fetch)",
36         "trap: bus error (data load or store)",
37         "trap: system call",
38         "breakpoint",
39         "trap: reserved instruction",
40         "trap: coprocessor unusable",
41         "trap: arithmetic overflow",
42         "trap: TRAP exception",
43         "trap: VCE (instruction)",
44         "trap: floating-point exception",
45         "trap: coprocessor 2 implementation-specific", /* used as sys call for debugger */
46         "trap: corextend unusable",
47         "trap: precise coprocessor 2 exception",
48         "trap: TLB read-inhibit",
49         "trap: TLB execute-inhibit",
50         "trap: undefined 21",
51         "trap: undefined 22",
52         "trap: WATCH exception",
53         "trap: machine checkcore",
54         "trap: undefined 25",
55         "trap: undefined 26",
56         "trap: undefined 27",
57         "trap: undefined 28",
58         "trap: undefined 29",
59         "trap: cache error",
60         "trap: VCE (data)",
61 };
62
63 char *fpcause[] =
64 {
65         "inexact operation",
66         "underflow",
67         "overflow",
68         "division by zero",
69         "invalid operation",
70 };
71 char    *fpexcname(Ureg*, ulong, char*, uint);
72 #define FPEXPMASK       (0x3f<<12)      /* Floating exception bits in fcr31 */
73
74 struct {
75         char    *name;
76         uint    off;
77 } regname[] = {
78         "STATUS", offsetof(Ureg, status),
79         "PC",   offsetof(Ureg, pc),
80         "SP",   offsetof(Ureg, sp),
81         "CAUSE",offsetof(Ureg, cause),
82         "BADADDR", offsetof(Ureg, badvaddr),
83         "TLBVIRT", offsetof(Ureg, tlbvirt),
84         "HI",   offsetof(Ureg, hi),
85         "LO",   offsetof(Ureg, lo),
86         "R31",  offsetof(Ureg, r31),
87         "R30",  offsetof(Ureg, r30),
88         "R28",  offsetof(Ureg, r28),
89         "R27",  offsetof(Ureg, r27),
90         "R26",  offsetof(Ureg, r26),
91         "R25",  offsetof(Ureg, r25),
92         "R24",  offsetof(Ureg, r24),
93         "R23",  offsetof(Ureg, r23),
94         "R22",  offsetof(Ureg, r22),
95         "R21",  offsetof(Ureg, r21),
96         "R20",  offsetof(Ureg, r20),
97         "R19",  offsetof(Ureg, r19),
98         "R18",  offsetof(Ureg, r18),
99         "R17",  offsetof(Ureg, r17),
100         "R16",  offsetof(Ureg, r16),
101         "R15",  offsetof(Ureg, r15),
102         "R14",  offsetof(Ureg, r14),
103         "R13",  offsetof(Ureg, r13),
104         "R12",  offsetof(Ureg, r12),
105         "R11",  offsetof(Ureg, r11),
106         "R10",  offsetof(Ureg, r10),
107         "R9",   offsetof(Ureg, r9),
108         "R8",   offsetof(Ureg, r8),
109         "R7",   offsetof(Ureg, r7),
110         "R6",   offsetof(Ureg, r6),
111         "R5",   offsetof(Ureg, r5),
112         "R4",   offsetof(Ureg, r4),
113         "R3",   offsetof(Ureg, r3),
114         "R2",   offsetof(Ureg, r2),
115         "R1",   offsetof(Ureg, r1),
116 };
117
118 static Handler handlers[8];
119
120 void
121 kvce(Ureg *ur, int ecode)
122 {
123         char c;
124         Pte **p;
125         Page **pg;
126         Segment *s;
127         ulong addr, soff;
128
129         c = 'D';
130         if(ecode == CVCEI)
131                 c = 'I';
132         print("Trap: VCE%c: addr=%#lux\n", c, ur->badvaddr);
133         if(up && !(ur->badvaddr & KSEGM)) {
134                 addr = ur->badvaddr;
135                 s = seg(up, addr, 0);
136                 if(s == nil){
137                         print("kvce: no seg for %#lux\n", addr);
138                         for(;;);
139                 }
140                 addr &= ~(BY2PG-1);
141                 soff = addr - s->base;
142                 p = &s->map[soff/PTEMAPMEM];
143                 if(*p){
144                         pg = &(*p)->pages[(soff&(PTEMAPMEM-1))/BY2PG];
145                         if(*pg)
146                                 print("kvce: pa=%#lux, va=%#lux\n",
147                                         (*pg)->pa, (*pg)->va);
148                         else
149                                 print("kvce: no *pg\n");
150                 }else
151                         print("kvce: no *p\n");
152         }
153 }
154
155 void
156 trap(Ureg *ur)
157 {
158         int ecode, clockintr, user, cop, x, fpchk;
159         ulong fpfcr31;
160         char buf[2*ERRMAX], buf1[ERRMAX], *fpexcep;
161         static int dumps;
162
163         if (up && (char *)(ur) - up->kstack < 1024 && dumps++ == 0) {
164                 iprint("trap: proc %ld kernel stack getting full\n", up->pid);
165                 dumpregs(ur);
166                 dumpstack();
167                 for(;;);
168         }
169         if (up == nil &&
170             (char *)(ur) - (char *)m->stack < 1024 && dumps++ == 0) {
171                 iprint("trap: cpu%d kernel stack getting full\n", m->machno);
172                 dumpregs(ur);
173                 dumpstack();
174                 for(;;);
175         }
176         user = kenter(ur);
177         if (ur->cause & TS)
178                 panic("trap: tlb shutdown");
179         ecode = (ur->cause>>2)&EXCMASK;
180         fpchk = 0;
181         clockintr = 0;
182         switch(ecode){
183         case CINT:
184                 clockintr = intr(ur);
185                 break;
186
187         case CFPE:
188                 if(!user)
189                         goto Default;
190                 if(up->fpstate == FPactive){
191                         savefpregs(up->fpsave);
192                         up->fpstate = FPinactive;
193                 }
194                 clrfpintr();
195                 fptrap(ur);
196                 fpchk = 1;
197                 break;
198
199         case CTLBM:
200         case CTLBL:
201         case CTLBS:
202                 if(up == nil || !user && (ur->badvaddr & KSEGM) == KSEG3) {
203                         kfault(ur);
204                         break;
205                 }
206                 x = up->insyscall;
207                 up->insyscall = 1;
208                 spllo();
209                 faultmips(ur, user, ecode);
210                 up->insyscall = x;
211                 break;
212
213         case CVCEI:
214         case CVCED:
215                 kvce(ur, ecode);
216                 goto Default;
217
218         case CWATCH:
219                 if(!user)
220                         panic("watchpoint trap from kernel mode pc=%#p",
221                                 ur->pc);
222                 // fpwatch(ur);
223                 break;
224
225         case CCPU:
226                 cop = (ur->cause>>28)&3;
227                 if(user && up && cop == 1) {
228                         if(up->fpstate & FPillegal) {
229                                 /* someone used floating point in a note handler */
230                                 postnote(up, 1,
231                                         "sys: floating point in note handler",
232                                         NDebug);
233                                 break;
234                         }
235                         if(up->fpstate == FPinit || up->fpstate == FPinactive){
236                                 restfpregs(up->fpsave, up->fpsave->fpstatus&~FPEXPMASK);
237                                 up->fpstate = FPactive;
238                                 ur->status |= CU1;
239                                 break;
240                         }
241                         fpchk = 1;
242                         break;
243                 }
244                 /* Fallthrough */
245
246         Default:
247         default:
248                 if(user) {
249                         spllo();
250                         snprint(buf, sizeof buf, "sys: %s", excname[ecode]);
251                         postnote(up, 1, buf, NDebug);
252                         break;
253                 }
254                 if (ecode == CADREL || ecode == CADRES)
255                         iprint("kernel addr exception for va %#p pid %#ld %s\n",
256                                 ur->badvaddr, (up? up->pid: 0),
257                                 (up? up->text: ""));
258                 print("cpu%d: kernel %s pc=%#lux\n",
259                         m->machno, excname[ecode], ur->pc);
260                 dumpregs(ur);
261                 dumpstack();
262                 if(m->machno == 0)
263                         spllo();
264                 exit(1);
265         }
266
267         if(fpchk) {
268                 fpfcr31 = up->fpsave->fpstatus;
269                 if((fpfcr31>>12) & ((fpfcr31>>7)|0x20) & 0x3f) {
270                         spllo();
271                         fpexcep = fpexcname(ur, fpfcr31, buf1, sizeof buf1);
272                         snprint(buf, sizeof buf, "sys: fp: %s", fpexcep);
273                         postnote(up, 1, buf, NDebug);
274                 }
275         }
276
277         splhi();
278
279         /* delaysched set because we held a lock or because our quantum ended */
280         if(up && up->delaysched && clockintr){
281                 sched();
282                 splhi();
283         }
284
285         if(user){
286                 notify(ur);
287                 /* replicate fpstate to ureg status */
288                 if(up->fpstate != FPactive)
289                         ur->status &= ~CU1;
290                 kexit(ur);
291         }
292 }
293
294 /* map HPC3 irq to INTR2 */
295 int
296 hpc3irqlevel(int irq)
297 {
298         *IO(uchar, LIO_0_MASK) |= 1 << (irq & 7);
299         return 2 + irq/8;
300 }
301
302 /*
303  *  set handlers
304  */
305 void
306 intrenable(int level, void (*h)(Ureg*, void *), void *arg)
307 {
308         Handler *hp;
309
310         hp = &handlers[level];
311         if (hp->handler != nil) {               /* occupied? */
312                 /* add a new one at the end of the chain */
313                 for (; hp->next != nil; hp = hp->next)
314                         ;
315                 if((hp->next = xalloc(sizeof *hp)) == nil)
316                         panic("intrenable: out of memory");
317                 hp = hp->next;
318         }
319         hp->arg = arg;
320         hp->handler = h;
321
322         intron(INTR0 << level);
323 }
324
325 int
326 intr(Ureg *ur)
327 {
328         ulong cause, mask;
329         int clockintr;
330         Handler *hh, *hp;
331
332         m->intr++;
333         clockintr = 0;
334         /*
335          * ignore interrupts that we have disabled, even if their cause bits
336          * are set.
337          */
338         cause = ur->cause & ur->status & INTMASK;
339         cause &= ~(INTR1|INTR0);                /* ignore sw interrupts */
340         if(cause & INTR7){
341                 clock(ur);
342                 cause &= ~INTR7;
343                 clockintr = 1;
344         }
345         hh = &handlers[2];
346         for(mask = INTR2; cause != 0 && mask < INTR7; mask <<= 1){
347                 if(cause & mask){
348                         for(hp = hh; hp != nil; hp = hp->next){
349                                 if(hp->handler != nil){
350                                         (*hp->handler)(ur, hp->arg);
351                                         cause &= ~mask;
352                                 }
353                         }
354                 }
355                 hh++;
356         }
357         if(cause != 0)
358                 iprint("unhandled interrupts %lux\n", cause);
359
360         /* preemptive scheduling */
361         if(up != nil && !clockintr)
362                 preempted();
363         /* if it was a clockintr, sched will be called at end of trap() */
364         return clockintr;
365 }
366
367 char*
368 fpexcname(Ureg *ur, ulong fcr31, char *buf, uint size)
369 {
370         int i;
371         char *s;
372         ulong fppc;
373
374         fppc = ur->pc;
375         if(ur->cause & BD)      /* branch delay */
376                 fppc += 4;
377         s = 0;
378         if(fcr31 & (1<<17))
379                 s = "unimplemented operation";
380         else{
381                 fcr31 >>= 7;            /* trap enable bits */
382                 fcr31 &= (fcr31>>5);    /* anded with exceptions */
383                 for(i=0; i<5; i++)
384                         if(fcr31 & (1<<i))
385                                 s = fpcause[i];
386         }
387
388         if(s == 0)
389                 return "no floating point exception";
390
391         snprint(buf, size, "%s fppc=%#lux", s, fppc);
392         return buf;
393 }
394
395 static void
396 getpcsp(ulong *pc, ulong *sp)
397 {
398         *pc = getcallerpc(&pc);
399         *sp = (ulong)&pc-4;
400 }
401
402 void
403 callwithureg(void (*fn)(Ureg*))
404 {
405         Ureg ureg;
406
407         memset(&ureg, 0, sizeof ureg);
408         getpcsp((ulong*)&ureg.pc, (ulong*)&ureg.sp);
409         ureg.r31 = getcallerpc(&fn);
410         fn(&ureg);
411 }
412
413 static void
414 _dumpstack(Ureg *ureg)
415 {
416         ulong l, v, top, i;
417         extern ulong etext;
418
419         print("ktrace /kernel/path %.8lux %.8lux %.8lux\n",
420                 ureg->pc, ureg->sp, ureg->r31);
421         if(up == nil)
422                 top = (ulong)MACHADDR + MACHSIZE;
423         else
424                 top = (ulong)up->kstack + KSTACK;
425         i = 0;
426         for(l=ureg->sp; l < top; l += BY2WD) {
427                 v = *(ulong*)l;
428                 if(KTZERO < v && v < (ulong)&etext) {
429                         print("%.8lux=%.8lux ", l, v);
430                         if((++i%4) == 0){
431                                 print("\n");
432                                 delay(200);
433                         }
434                 }
435         }
436         print("\n");
437 }
438
439 void
440 dumpstack(void)
441 {
442         callwithureg(_dumpstack);
443 }
444
445 static ulong
446 R(Ureg *ur, int i)
447 {
448         uchar *s;
449
450         s = (uchar*)ur;
451         return *(ulong*)(s + regname[i].off);
452 }
453
454 void
455 dumpregs(Ureg *ur)
456 {
457         int i;
458
459         if(up)
460                 print("registers for %s %lud\n", up->text, up->pid);
461         else
462                 print("registers for kernel\n");
463
464         for(i = 0; i < nelem(regname); i += 2)
465                 print("%s\t%#.8lux\t%s\t%#.8lux\n",
466                         regname[i].name,   R(ur, i),
467                         regname[i+1].name, R(ur, i+1));
468 }
469
470 int
471 notify(Ureg *ur)
472 {
473         int l, s;
474         ulong sp;
475         Note *n;
476
477         if(up->procctl)
478                 procctl();
479         if(up->nnote == 0)
480                 return 0;
481
482         if(up->fpstate == FPactive){
483                 savefpregs(up->fpsave);
484                 up->fpstate = FPinactive;
485         }
486         up->fpstate |= FPillegal;
487
488         s = spllo();
489         qlock(&up->debug);
490         up->notepending = 0;
491         n = &up->note[0];
492         if(strncmp(n->msg, "sys:", 4) == 0) {
493                 l = strlen(n->msg);
494                 if(l > ERRMAX-15)       /* " pc=0x12345678\0" */
495                         l = ERRMAX-15;
496
497                 seprint(n->msg+l, &n->msg[sizeof n->msg], " pc=%#lux", ur->pc);
498         }
499
500         if(n->flag != NUser && (up->notified || up->notify==0)) {
501                 if(n->flag == NDebug)
502                         pprint("suicide: %s\n", n->msg);
503
504                 qunlock(&up->debug);
505                 pexit(n->msg, n->flag!=NDebug);
506         }
507
508         if(up->notified) {
509                 qunlock(&up->debug);
510                 splx(s);
511                 return 0;
512         }
513
514         if(!up->notify) {
515                 qunlock(&up->debug);
516                 pexit(n->msg, n->flag!=NDebug);
517         }
518         sp = ur->usp & ~(BY2V-1);
519         sp -= sizeof(Ureg);
520
521         if(!okaddr((ulong)up->notify, BY2WD, 0) ||
522            !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)) {
523                 pprint("suicide: bad address or sp in notify\n");
524                 qunlock(&up->debug);
525                 pexit("Suicide", 0);
526         }
527
528         memmove((Ureg*)sp, ur, sizeof(Ureg));   /* push user regs */
529         *(Ureg**)(sp-BY2WD) = up->ureg; /* word under Ureg is old up->ureg */
530         up->ureg = (void*)sp;
531
532         sp -= BY2WD+ERRMAX;
533         memmove((char*)sp, up->note[0].msg, ERRMAX);    /* push err string */
534
535         sp -= 3*BY2WD;
536         *(ulong*)(sp+2*BY2WD) = sp+3*BY2WD;     /* arg 2 is string */
537         ur->r1 = (long)up->ureg;                /* arg 1 is ureg* */
538         ((ulong*)sp)[1] = (ulong)up->ureg;      /* arg 1 0(FP) is ureg* */
539         ((ulong*)sp)[0] = 0;                    /* arg 0 is pc */
540         ur->usp = sp;
541         /*
542          * arrange to resume at user's handler as if handler(ureg, errstr)
543          * were being called.
544          */
545         ur->pc = (ulong)up->notify;
546
547         up->notified = 1;
548         up->nnote--;
549         memmove(&up->lastnote, &up->note[0], sizeof(Note));
550         memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note));
551
552         qunlock(&up->debug);
553         splx(s);
554         return 1;
555 }
556
557 /*
558  * Return user to state before notify(); called from user's handler.
559  */
560 void
561 noted(Ureg *kur, ulong arg0)
562 {
563         Ureg *nur;
564         ulong oureg, sp;
565
566         qlock(&up->debug);
567         if(arg0!=NRSTR && !up->notified) {
568                 qunlock(&up->debug);
569                 pprint("call to noted() when not notified\n");
570                 pexit("Suicide", 0);
571         }
572         up->notified = 0;
573
574         up->fpstate &= ~FPillegal;
575
576         nur = up->ureg;
577
578         oureg = (ulong)nur;
579         if((oureg & (BY2WD-1)) || !okaddr((ulong)oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){
580                 pprint("bad up->ureg in noted or call to noted() when not notified\n");
581                 qunlock(&up->debug);
582                 pexit("Suicide", 0);
583         }
584
585         setregisters(kur, (char*)kur, (char*)up->ureg, sizeof(Ureg));
586         switch(arg0) {
587         case NCONT:
588         case NRSTR:                             /* only used by APE */
589                 if(!okaddr(nur->pc, BY2WD, 0) || !okaddr(nur->usp, BY2WD, 0)){
590                         pprint("suicide: trap in noted\n");
591                         qunlock(&up->debug);
592                         pexit("Suicide", 0);
593                 }
594                 up->ureg = (Ureg*)(*(ulong*)(oureg-BY2WD));
595                 qunlock(&up->debug);
596                 splhi();
597                 break;
598
599         case NSAVE:                             /* only used by APE */
600                 if(!okaddr(nur->pc, BY2WD, 0) || !okaddr(nur->usp, BY2WD, 0)){
601                         pprint("suicide: trap in noted\n");
602                         qunlock(&up->debug);
603                         pexit("Suicide", 0);
604                 }
605                 qunlock(&up->debug);
606                 sp = oureg-4*BY2WD-ERRMAX;
607                 splhi();
608                 kur->sp = sp;
609                 kur->r1 = oureg;                /* arg 1 is ureg* */
610                 ((ulong*)sp)[1] = oureg;        /* arg 1 0(FP) is ureg* */
611                 ((ulong*)sp)[0] = 0;            /* arg 0 is pc */
612                 break;
613
614         default:
615                 pprint("unknown noted arg %#lux\n", arg0);
616                 up->lastnote.flag = NDebug;
617                 /* fall through */
618
619         case NDFLT:
620                 if(up->lastnote.flag == NDebug)
621                         pprint("suicide: %s\n", up->lastnote.msg);
622                 qunlock(&up->debug);
623                 pexit(up->lastnote.msg, up->lastnote.flag!=NDebug);
624         }
625 }
626
627 #include "../port/systab.h"
628
629 static void
630 sctracesetup(ulong scallnr, ulong sp, uintptr pc, vlong *startnsp)
631 {
632         if(up->procctl == Proc_tracesyscall){
633                 /*
634                  * Redundant validaddr.  Do we care?
635                  * Tracing syscalls is not exactly a fast path...
636                  * Beware, validaddr currently does a pexit rather
637                  * than an error if there's a problem; that might
638                  * change in the future.
639                  */
640                 if(sp < (USTKTOP-BY2PG) || sp > (USTKTOP-sizeof(Sargs)-BY2WD))
641                         validaddr(sp, sizeof(Sargs)+BY2WD, 0);
642
643                 syscallfmt(scallnr, pc, (va_list)(sp+BY2WD));
644                 up->procctl = Proc_stopme;
645                 procctl();
646                 if(up->syscalltrace)
647                         free(up->syscalltrace);
648                 up->syscalltrace = nil;
649                 *startnsp = todget(nil);
650         }
651 }
652
653 static void
654 sctracefinish(ulong scallnr, ulong sp, int ret, vlong startns)
655 {
656         int s;
657
658         if(up->procctl == Proc_tracesyscall){
659                 up->procctl = Proc_stopme;
660                 sysretfmt(scallnr, (va_list)(sp+BY2WD), ret,
661                         startns, todget(nil));
662                 s = splhi();
663                 procctl();
664                 splx(s);
665                 if(up->syscalltrace)
666                         free(up->syscalltrace);
667                 up->syscalltrace = nil;
668         }
669 }
670
671 /*
672  * called directly from assembler, not via trap()
673  */
674 void
675 syscall(Ureg *ur)
676 {
677         int i;
678         volatile long ret;
679         ulong sp, scallnr;
680         vlong startns;
681         char *e;
682
683         if(!kenter(ur))
684                 panic("syscall from kernel");
685
686         m->syscall++;
687         up->insyscall = 1;
688         up->pc = ur->pc;
689         ur->cause = 16<<2;      /* for debugging: system call is undef 16 */
690
691         scallnr = ur->r1;
692         up->scallnr = ur->r1;
693         sp = ur->sp;
694         sctracesetup(scallnr, sp, ur->pc, &startns);
695
696         /* no fpu, so no fp state to save */
697         spllo();
698
699         up->nerrlab = 0;
700         ret = -1;
701         if(!waserror()) {
702                 if(scallnr >= nsyscall || systab[scallnr] == 0){
703                         pprint("bad sys call number %ld pc %#lux\n",
704                                 scallnr, ur->pc);
705                         postnote(up, 1, "sys: bad sys call", NDebug);
706                         error(Ebadarg);
707                 }
708
709                 if(sp & (BY2WD-1)){
710                         pprint("odd sp in sys call pc %#lux sp %#lux\n",
711                                 ur->pc, ur->sp);
712                         postnote(up, 1, "sys: odd stack", NDebug);
713                         error(Ebadarg);
714                 }
715
716                 if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)-BY2WD))
717                         validaddr(sp, sizeof(Sargs)+BY2WD, 0);
718
719                 up->s = *((Sargs*)(sp+BY2WD));
720                 up->psstate = sysctab[scallnr];
721
722                 ret = systab[scallnr]((va_list)up->s.args);
723                 poperror();
724         }else{
725                 /* failure: save the error buffer for errstr */
726                 e = up->syserrstr;
727                 up->syserrstr = up->errstr;
728                 up->errstr = e;
729                 if(0 && up->pid == 1)
730                         print("[%lud %s] syscall %lud: %s\n",
731                                 up->pid, up->text, scallnr, up->errstr);
732         }
733         if(up->nerrlab){
734                 print("bad errstack [%lud]: %d extra\n", scallnr, up->nerrlab);
735                 for(i = 0; i < NERR; i++)
736                         print("sp=%#lux pc=%#lux\n",
737                                 up->errlab[i].sp, up->errlab[i].pc);
738                 panic("error stack");
739         }
740         sctracefinish(scallnr, sp, ret, startns);
741
742         ur->pc += 4;
743         ur->r1 = ret;
744
745         up->psstate = 0;
746         up->insyscall = 0;
747
748         if(scallnr == NOTED)                            /* ugly hack */
749                 noted(ur, *(ulong*)(sp+BY2WD)); /* may return */
750         splhi();
751         if(scallnr!=RFORK && (up->procctl || up->nnote))
752                 notify(ur);
753         /* if we delayed sched because we held a lock, sched now */
754         if(up->delaysched)
755                 sched();
756         /* replicate fpstate to ureg status */
757         if(up->fpstate != FPactive)
758                 ur->status &= ~CU1;
759         kexit(ur);
760 }
761
762 void
763 forkchild(Proc *p, Ureg *ur)
764 {
765         Ureg *cur;
766
767         p->sched.sp = (ulong)p->kstack+KSTACK-UREGSIZE;
768         p->sched.pc = (ulong)forkret;
769
770         cur = (Ureg*)(p->sched.sp+2*BY2WD);
771         memmove(cur, ur, sizeof(Ureg));
772
773         cur->status &= ~CU1;    /* FPU off when returning */
774
775         cur->r1 = 0;
776         cur->pc += 4;
777 }
778
779 void
780 kprocchild(Proc *p, void (*entry)(void))
781 {
782         p->sched.pc = (ulong)entry;
783         p->sched.sp = (ulong)p->kstack+KSTACK;
784 }
785
786 /* set up user registers before return from exec() */
787 uintptr
788 execregs(ulong entry, ulong ssize, ulong nargs)
789 {
790         Ureg *ur;
791         ulong *sp;
792
793         sp = (ulong*)(USTKTOP - ssize);
794         *--sp = nargs;
795
796         ur = (Ureg*)up->dbgreg;
797         ur->usp = (ulong)sp;
798         ur->pc = entry - 4;             /* syscall advances it */
799         return USTKTOP-sizeof(Tos);     /* address of kernel/user shared data */
800 }
801
802 ulong
803 userpc(void)
804 {
805         Ureg *ur;
806
807         ur = (Ureg*)up->dbgreg;
808         return ur->pc;
809 }
810
811 /*
812  * This routine must save the values of registers the user is not
813  * permitted to write from devproc and then restore the saved values
814  * before returning
815  */
816 void
817 setregisters(Ureg *xp, char *pureg, char *uva, int n)
818 {
819         ulong status, r27;
820
821         r27 = xp->r27;                  /* return PC for GEVector() */
822         status = xp->status;
823         memmove(pureg, uva, n);
824         xp->r27 = r27;
825         xp->status = status;
826 }
827
828 /*
829  * Give enough context in the ureg to produce a kernel stack for
830  * a sleeping process
831  */
832 void
833 setkernur(Ureg *xp, Proc *p)
834 {
835         xp->pc = p->sched.pc;
836         xp->sp = p->sched.sp;
837         xp->r24 = (ulong)p;             /* up */
838         xp->r31 = (ulong)sched;
839 }
840
841 ulong
842 dbgpc(Proc *p)
843 {
844         Ureg *ur;
845
846         ur = p->dbgreg;
847         if(ur == 0)
848                 return 0;
849
850         return ur->pc;
851 }