]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/sgi/trap.c
etheriwl: don't break controller on command flush timeout
[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 /* prepare to go to user space */
156 void
157 kexit(Ureg *ur)
158 {
159         Tos *tos;
160
161         /* replicate fpstate to ureg status */
162         if(up->fpstate != FPactive)
163                 ur->status &= ~CU1;
164
165         /* precise time accounting, kernel exit */
166         tos = (Tos*)(USTKTOP-sizeof(Tos));
167         tos->kcycles += fastticks(&tos->cyclefreq) - up->kentry;
168         tos->pcycles = up->pcycles;
169         tos->pid = up->pid;
170 }
171
172 void
173 trap(Ureg *ur)
174 {
175         int ecode, clockintr, user, cop, x, fpchk;
176         ulong fpfcr31;
177         char buf[2*ERRMAX], buf1[ERRMAX], *fpexcep;
178         static int dumps;
179
180         if (up && (char *)(ur) - up->kstack < 1024 && dumps++ == 0) {
181                 iprint("trap: proc %ld kernel stack getting full\n", up->pid);
182                 dumpregs(ur);
183                 dumpstack();
184                 for(;;);
185         }
186         if (up == nil &&
187             (char *)(ur) - (char *)m->stack < 1024 && dumps++ == 0) {
188                 iprint("trap: cpu%d kernel stack getting full\n", m->machno);
189                 dumpregs(ur);
190                 dumpstack();
191                 for(;;);
192         }
193
194         ecode = (ur->cause>>2)&EXCMASK;
195         user = userureg(ur);
196         if (ur->cause & TS)
197                 panic("trap: tlb shutdown");
198
199         fpchk = 0;
200         if(user){
201                 up->dbgreg = ur;
202                 cycles(&up->kentry);
203         }
204
205         clockintr = 0;
206         switch(ecode){
207         case CINT:
208                 clockintr = intr(ur);
209                 break;
210
211         case CFPE:
212                 if(!user)
213                         goto Default;
214                 if(up->fpstate == FPactive){
215                         savefpregs(up->fpsave);
216                         up->fpstate = FPinactive;
217                 }
218                 clrfpintr();
219                 fptrap(ur);
220                 fpchk = 1;
221                 break;
222
223         case CTLBM:
224         case CTLBL:
225         case CTLBS:
226                 if(up == nil || !user && (ur->badvaddr & KSEGM) == KSEG3) {
227                         kfault(ur);
228                         break;
229                 }
230                 x = up->insyscall;
231                 up->insyscall = 1;
232                 spllo();
233                 faultmips(ur, user, ecode);
234                 up->insyscall = x;
235                 break;
236
237         case CVCEI:
238         case CVCED:
239                 kvce(ur, ecode);
240                 goto Default;
241
242         case CWATCH:
243                 if(!user)
244                         panic("watchpoint trap from kernel mode pc=%#p",
245                                 ur->pc);
246                 // fpwatch(ur);
247                 break;
248
249         case CCPU:
250                 cop = (ur->cause>>28)&3;
251                 if(user && up && cop == 1) {
252                         if(up->fpstate & FPillegal) {
253                                 /* someone used floating point in a note handler */
254                                 postnote(up, 1,
255                                         "sys: floating point in note handler",
256                                         NDebug);
257                                 break;
258                         }
259                         if(up->fpstate == FPinit || up->fpstate == FPinactive){
260                                 restfpregs(up->fpsave, up->fpsave->fpstatus&~FPEXPMASK);
261                                 up->fpstate = FPactive;
262                                 ur->status |= CU1;
263                                 break;
264                         }
265                         fpchk = 1;
266                         break;
267                 }
268                 /* Fallthrough */
269
270         Default:
271         default:
272                 if(user) {
273                         spllo();
274                         snprint(buf, sizeof buf, "sys: %s", excname[ecode]);
275                         postnote(up, 1, buf, NDebug);
276                         break;
277                 }
278                 if (ecode == CADREL || ecode == CADRES)
279                         iprint("kernel addr exception for va %#p pid %#ld %s\n",
280                                 ur->badvaddr, (up? up->pid: 0),
281                                 (up? up->text: ""));
282                 print("cpu%d: kernel %s pc=%#lux\n",
283                         m->machno, excname[ecode], ur->pc);
284                 dumpregs(ur);
285                 dumpstack();
286                 if(m->machno == 0)
287                         spllo();
288                 exit(1);
289         }
290
291         if(fpchk) {
292                 fpfcr31 = up->fpsave->fpstatus;
293                 if((fpfcr31>>12) & ((fpfcr31>>7)|0x20) & 0x3f) {
294                         spllo();
295                         fpexcep = fpexcname(ur, fpfcr31, buf1, sizeof buf1);
296                         snprint(buf, sizeof buf, "sys: fp: %s", fpexcep);
297                         postnote(up, 1, buf, NDebug);
298                 }
299         }
300
301         splhi();
302
303         /* delaysched set because we held a lock or because our quantum ended */
304         if(up && up->delaysched && clockintr){
305                 sched();
306                 splhi();
307         }
308
309         if(user){
310                 notify(ur);
311                 kexit(ur);
312         }
313 }
314
315 /* map HPC3 irq to INTR2 */
316 int
317 hpc3irqlevel(int irq)
318 {
319         *IO(uchar, LIO_0_MASK) |= 1 << (irq & 7);
320         return 2 + irq/8;
321 }
322
323 /*
324  *  set handlers
325  */
326 void
327 intrenable(int level, void (*h)(Ureg*, void *), void *arg)
328 {
329         Handler *hp;
330
331         hp = &handlers[level];
332         if (hp->handler != nil) {               /* occupied? */
333                 /* add a new one at the end of the chain */
334                 for (; hp->next != nil; hp = hp->next)
335                         ;
336                 if((hp->next = xalloc(sizeof *hp)) == nil)
337                         panic("intrenable: out of memory");
338                 hp = hp->next;
339         }
340         hp->arg = arg;
341         hp->handler = h;
342
343         intron(INTR0 << level);
344 }
345
346 int
347 intr(Ureg *ur)
348 {
349         ulong cause, mask;
350         int clockintr;
351         Handler *hh, *hp;
352
353         m->intr++;
354         clockintr = 0;
355         /*
356          * ignore interrupts that we have disabled, even if their cause bits
357          * are set.
358          */
359         cause = ur->cause & ur->status & INTMASK;
360         cause &= ~(INTR1|INTR0);                /* ignore sw interrupts */
361         if(cause & INTR7){
362                 clock(ur);
363                 cause &= ~INTR7;
364                 clockintr = 1;
365         }
366         hh = &handlers[2];
367         for(mask = INTR2; cause != 0 && mask < INTR7; mask <<= 1){
368                 if(cause & mask){
369                         for(hp = hh; hp != nil; hp = hp->next){
370                                 if(hp->handler != nil){
371                                         (*hp->handler)(ur, hp->arg);
372                                         cause &= ~mask;
373                                 }
374                         }
375                 }
376                 hh++;
377         }
378         if(cause != 0)
379                 iprint("unhandled interrupts %lux\n", cause);
380
381         /* preemptive scheduling */
382         if(up != nil && !clockintr)
383                 preempted();
384         /* if it was a clockintr, sched will be called at end of trap() */
385         return clockintr;
386 }
387
388 char*
389 fpexcname(Ureg *ur, ulong fcr31, char *buf, uint size)
390 {
391         int i;
392         char *s;
393         ulong fppc;
394
395         fppc = ur->pc;
396         if(ur->cause & BD)      /* branch delay */
397                 fppc += 4;
398         s = 0;
399         if(fcr31 & (1<<17))
400                 s = "unimplemented operation";
401         else{
402                 fcr31 >>= 7;            /* trap enable bits */
403                 fcr31 &= (fcr31>>5);    /* anded with exceptions */
404                 for(i=0; i<5; i++)
405                         if(fcr31 & (1<<i))
406                                 s = fpcause[i];
407         }
408
409         if(s == 0)
410                 return "no floating point exception";
411
412         snprint(buf, size, "%s fppc=%#lux", s, fppc);
413         return buf;
414 }
415
416 static void
417 getpcsp(ulong *pc, ulong *sp)
418 {
419         *pc = getcallerpc(&pc);
420         *sp = (ulong)&pc-4;
421 }
422
423 void
424 callwithureg(void (*fn)(Ureg*))
425 {
426         Ureg ureg;
427
428         memset(&ureg, 0, sizeof ureg);
429         getpcsp((ulong*)&ureg.pc, (ulong*)&ureg.sp);
430         ureg.r31 = getcallerpc(&fn);
431         fn(&ureg);
432 }
433
434 static void
435 _dumpstack(Ureg *ureg)
436 {
437         ulong l, v, top, i;
438         extern ulong etext;
439
440         print("ktrace /kernel/path %.8lux %.8lux %.8lux\n",
441                 ureg->pc, ureg->sp, ureg->r31);
442         if(up == nil)
443                 top = (ulong)MACHADDR + MACHSIZE;
444         else
445                 top = (ulong)up->kstack + KSTACK;
446         i = 0;
447         for(l=ureg->sp; l < top; l += BY2WD) {
448                 v = *(ulong*)l;
449                 if(KTZERO < v && v < (ulong)&etext) {
450                         print("%.8lux=%.8lux ", l, v);
451                         if((++i%4) == 0){
452                                 print("\n");
453                                 delay(200);
454                         }
455                 }
456         }
457         print("\n");
458 }
459
460 void
461 dumpstack(void)
462 {
463         callwithureg(_dumpstack);
464 }
465
466 static ulong
467 R(Ureg *ur, int i)
468 {
469         uchar *s;
470
471         s = (uchar*)ur;
472         return *(ulong*)(s + regname[i].off);
473 }
474
475 void
476 dumpregs(Ureg *ur)
477 {
478         int i;
479
480         if(up)
481                 print("registers for %s %lud\n", up->text, up->pid);
482         else
483                 print("registers for kernel\n");
484
485         for(i = 0; i < nelem(regname); i += 2)
486                 print("%s\t%#.8lux\t%s\t%#.8lux\n",
487                         regname[i].name,   R(ur, i),
488                         regname[i+1].name, R(ur, i+1));
489 }
490
491 int
492 notify(Ureg *ur)
493 {
494         int l, s;
495         ulong sp;
496         Note *n;
497
498         if(up->procctl)
499                 procctl();
500         if(up->nnote == 0)
501                 return 0;
502
503         if(up->fpstate == FPactive){
504                 savefpregs(up->fpsave);
505                 up->fpstate = FPinactive;
506         }
507         up->fpstate |= FPillegal;
508
509         s = spllo();
510         qlock(&up->debug);
511         up->notepending = 0;
512         n = &up->note[0];
513         if(strncmp(n->msg, "sys:", 4) == 0) {
514                 l = strlen(n->msg);
515                 if(l > ERRMAX-15)       /* " pc=0x12345678\0" */
516                         l = ERRMAX-15;
517
518                 seprint(n->msg+l, &n->msg[sizeof n->msg], " pc=%#lux", ur->pc);
519         }
520
521         if(n->flag != NUser && (up->notified || up->notify==0)) {
522                 if(n->flag == NDebug)
523                         pprint("suicide: %s\n", n->msg);
524
525                 qunlock(&up->debug);
526                 pexit(n->msg, n->flag!=NDebug);
527         }
528
529         if(up->notified) {
530                 qunlock(&up->debug);
531                 splx(s);
532                 return 0;
533         }
534
535         if(!up->notify) {
536                 qunlock(&up->debug);
537                 pexit(n->msg, n->flag!=NDebug);
538         }
539         sp = ur->usp & ~(BY2V-1);
540         sp -= sizeof(Ureg);
541
542         if(!okaddr((ulong)up->notify, BY2WD, 0) ||
543            !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)) {
544                 pprint("suicide: bad address or sp in notify\n");
545                 qunlock(&up->debug);
546                 pexit("Suicide", 0);
547         }
548
549         memmove((Ureg*)sp, ur, sizeof(Ureg));   /* push user regs */
550         *(Ureg**)(sp-BY2WD) = up->ureg; /* word under Ureg is old up->ureg */
551         up->ureg = (void*)sp;
552
553         sp -= BY2WD+ERRMAX;
554         memmove((char*)sp, up->note[0].msg, ERRMAX);    /* push err string */
555
556         sp -= 3*BY2WD;
557         *(ulong*)(sp+2*BY2WD) = sp+3*BY2WD;     /* arg 2 is string */
558         ur->r1 = (long)up->ureg;                /* arg 1 is ureg* */
559         ((ulong*)sp)[1] = (ulong)up->ureg;      /* arg 1 0(FP) is ureg* */
560         ((ulong*)sp)[0] = 0;                    /* arg 0 is pc */
561         ur->usp = sp;
562         /*
563          * arrange to resume at user's handler as if handler(ureg, errstr)
564          * were being called.
565          */
566         ur->pc = (ulong)up->notify;
567
568         up->notified = 1;
569         up->nnote--;
570         memmove(&up->lastnote, &up->note[0], sizeof(Note));
571         memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note));
572
573         qunlock(&up->debug);
574         splx(s);
575         return 1;
576 }
577
578 /*
579  * Return user to state before notify(); called from user's handler.
580  */
581 void
582 noted(Ureg *kur, ulong arg0)
583 {
584         Ureg *nur;
585         ulong oureg, sp;
586
587         qlock(&up->debug);
588         if(arg0!=NRSTR && !up->notified) {
589                 qunlock(&up->debug);
590                 pprint("call to noted() when not notified\n");
591                 pexit("Suicide", 0);
592         }
593         up->notified = 0;
594
595         up->fpstate &= ~FPillegal;
596
597         nur = up->ureg;
598
599         oureg = (ulong)nur;
600         if((oureg & (BY2WD-1)) || !okaddr((ulong)oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){
601                 pprint("bad up->ureg in noted or call to noted() when not notified\n");
602                 qunlock(&up->debug);
603                 pexit("Suicide", 0);
604         }
605
606         setregisters(kur, (char*)kur, (char*)up->ureg, sizeof(Ureg));
607         switch(arg0) {
608         case NCONT:
609         case NRSTR:                             /* only used by APE */
610                 if(!okaddr(nur->pc, BY2WD, 0) || !okaddr(nur->usp, BY2WD, 0)){
611                         pprint("suicide: trap in noted\n");
612                         qunlock(&up->debug);
613                         pexit("Suicide", 0);
614                 }
615                 up->ureg = (Ureg*)(*(ulong*)(oureg-BY2WD));
616                 qunlock(&up->debug);
617                 splhi();
618                 break;
619
620         case NSAVE:                             /* only used by APE */
621                 if(!okaddr(nur->pc, BY2WD, 0) || !okaddr(nur->usp, BY2WD, 0)){
622                         pprint("suicide: trap in noted\n");
623                         qunlock(&up->debug);
624                         pexit("Suicide", 0);
625                 }
626                 qunlock(&up->debug);
627                 sp = oureg-4*BY2WD-ERRMAX;
628                 splhi();
629                 kur->sp = sp;
630                 kur->r1 = oureg;                /* arg 1 is ureg* */
631                 ((ulong*)sp)[1] = oureg;        /* arg 1 0(FP) is ureg* */
632                 ((ulong*)sp)[0] = 0;            /* arg 0 is pc */
633                 break;
634
635         default:
636                 pprint("unknown noted arg %#lux\n", arg0);
637                 up->lastnote.flag = NDebug;
638                 /* fall through */
639
640         case NDFLT:
641                 if(up->lastnote.flag == NDebug)
642                         pprint("suicide: %s\n", up->lastnote.msg);
643                 qunlock(&up->debug);
644                 pexit(up->lastnote.msg, up->lastnote.flag!=NDebug);
645         }
646 }
647
648 #include "../port/systab.h"
649
650 static void
651 sctracesetup(ulong scallnr, ulong sp, uintptr pc, vlong *startnsp)
652 {
653         if(up->procctl == Proc_tracesyscall){
654                 /*
655                  * Redundant validaddr.  Do we care?
656                  * Tracing syscalls is not exactly a fast path...
657                  * Beware, validaddr currently does a pexit rather
658                  * than an error if there's a problem; that might
659                  * change in the future.
660                  */
661                 if(sp < (USTKTOP-BY2PG) || sp > (USTKTOP-sizeof(Sargs)-BY2WD))
662                         validaddr(sp, sizeof(Sargs)+BY2WD, 0);
663
664                 syscallfmt(scallnr, pc, (va_list)(sp+BY2WD));
665                 up->procctl = Proc_stopme;
666                 procctl();
667                 if(up->syscalltrace)
668                         free(up->syscalltrace);
669                 up->syscalltrace = nil;
670                 *startnsp = todget(nil);
671         }
672 }
673
674 static void
675 sctracefinish(ulong scallnr, ulong sp, int ret, vlong startns)
676 {
677         int s;
678
679         if(up->procctl == Proc_tracesyscall){
680                 up->procctl = Proc_stopme;
681                 sysretfmt(scallnr, (va_list)(sp+BY2WD), ret,
682                         startns, todget(nil));
683                 s = splhi();
684                 procctl();
685                 splx(s);
686                 if(up->syscalltrace)
687                         free(up->syscalltrace);
688                 up->syscalltrace = nil;
689         }
690 }
691
692 /*
693  * called directly from assembler, not via trap()
694  */
695 void
696 syscall(Ureg *ur)
697 {
698         int i;
699         volatile long ret;
700         ulong sp, scallnr;
701         vlong startns;
702         char *e;
703
704         cycles(&up->kentry);
705
706         m->syscall++;
707         up->insyscall = 1;
708         up->pc = ur->pc;
709         up->dbgreg = ur;
710         ur->cause = 16<<2;      /* for debugging: system call is undef 16 */
711
712         scallnr = ur->r1;
713         up->scallnr = ur->r1;
714         sp = ur->sp;
715         sctracesetup(scallnr, sp, ur->pc, &startns);
716
717         /* no fpu, so no fp state to save */
718         spllo();
719
720         up->nerrlab = 0;
721         ret = -1;
722         if(!waserror()) {
723                 if(scallnr >= nsyscall || systab[scallnr] == 0){
724                         pprint("bad sys call number %ld pc %#lux\n",
725                                 scallnr, ur->pc);
726                         postnote(up, 1, "sys: bad sys call", NDebug);
727                         error(Ebadarg);
728                 }
729
730                 if(sp & (BY2WD-1)){
731                         pprint("odd sp in sys call pc %#lux sp %#lux\n",
732                                 ur->pc, ur->sp);
733                         postnote(up, 1, "sys: odd stack", NDebug);
734                         error(Ebadarg);
735                 }
736
737                 if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)-BY2WD))
738                         validaddr(sp, sizeof(Sargs)+BY2WD, 0);
739
740                 up->s = *((Sargs*)(sp+BY2WD));
741                 up->psstate = sysctab[scallnr];
742
743                 ret = systab[scallnr]((va_list)up->s.args);
744                 poperror();
745         }else{
746                 /* failure: save the error buffer for errstr */
747                 e = up->syserrstr;
748                 up->syserrstr = up->errstr;
749                 up->errstr = e;
750                 if(0 && up->pid == 1)
751                         print("[%lud %s] syscall %lud: %s\n",
752                                 up->pid, up->text, scallnr, up->errstr);
753         }
754         if(up->nerrlab){
755                 print("bad errstack [%lud]: %d extra\n", scallnr, up->nerrlab);
756                 for(i = 0; i < NERR; i++)
757                         print("sp=%#lux pc=%#lux\n",
758                                 up->errlab[i].sp, up->errlab[i].pc);
759                 panic("error stack");
760         }
761         sctracefinish(scallnr, sp, ret, startns);
762
763         ur->pc += 4;
764         ur->r1 = ret;
765
766         up->psstate = 0;
767         up->insyscall = 0;
768
769         if(scallnr == NOTED)                            /* ugly hack */
770                 noted(ur, *(ulong*)(sp+BY2WD)); /* may return */
771         splhi();
772         if(scallnr!=RFORK && (up->procctl || up->nnote))
773                 notify(ur);
774         /* if we delayed sched because we held a lock, sched now */
775         if(up->delaysched)
776                 sched();
777         kexit(ur);
778 }
779
780 void
781 forkchild(Proc *p, Ureg *ur)
782 {
783         Ureg *cur;
784
785         p->sched.sp = (ulong)p->kstack+KSTACK-UREGSIZE;
786         p->sched.pc = (ulong)forkret;
787
788         cur = (Ureg*)(p->sched.sp+2*BY2WD);
789         memmove(cur, ur, sizeof(Ureg));
790
791         cur->status &= ~CU1;    /* FPU off when returning */
792
793         cur->r1 = 0;
794         cur->pc += 4;
795 }
796
797 static
798 void
799 linkproc(void)
800 {
801         spllo();
802         up->kpfun(up->kparg);
803         pexit("kproc exiting", 0);
804 }
805
806 void
807 kprocchild(Proc *p, void (*func)(void*), void *arg)
808 {
809         p->sched.pc = (ulong)linkproc;
810         p->sched.sp = (ulong)p->kstack+KSTACK;
811
812         p->kpfun = func;
813         p->kparg = arg;
814 }
815
816 /* set up user registers before return from exec() */
817 uintptr
818 execregs(ulong entry, ulong ssize, ulong nargs)
819 {
820         Ureg *ur;
821         ulong *sp;
822
823         sp = (ulong*)(USTKTOP - ssize);
824         *--sp = nargs;
825
826         ur = (Ureg*)up->dbgreg;
827         ur->usp = (ulong)sp;
828         ur->pc = entry - 4;             /* syscall advances it */
829         return USTKTOP-sizeof(Tos);     /* address of kernel/user shared data */
830 }
831
832 ulong
833 userpc(void)
834 {
835         Ureg *ur;
836
837         ur = (Ureg*)up->dbgreg;
838         return ur->pc;
839 }
840
841 /*
842  * This routine must save the values of registers the user is not
843  * permitted to write from devproc and then restore the saved values
844  * before returning
845  */
846 void
847 setregisters(Ureg *xp, char *pureg, char *uva, int n)
848 {
849         ulong status, r27;
850
851         r27 = xp->r27;                  /* return PC for GEVector() */
852         status = xp->status;
853         memmove(pureg, uva, n);
854         xp->r27 = r27;
855         xp->status = status;
856 }
857
858 /*
859  * Give enough context in the ureg to produce a kernel stack for
860  * a sleeping process
861  */
862 void
863 setkernur(Ureg *xp, Proc *p)
864 {
865         xp->pc = p->sched.pc;
866         xp->sp = p->sched.sp;
867         xp->r24 = (ulong)p;             /* up */
868         xp->r31 = (ulong)sched;
869 }
870
871 ulong
872 dbgpc(Proc *p)
873 {
874         Ureg *ur;
875
876         ur = p->dbgreg;
877         if(ur == 0)
878                 return 0;
879
880         return ur->pc;
881 }