]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/alphapc/trap.c
merge
[plan9front.git] / sys / src / 9 / alphapc / 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        "../port/error.h"
9
10 void    noted(Ureg*, Ureg**, ulong);
11 void    rfnote(Ureg**);
12 void    kernfault(Ureg*, int);
13 void    illegal(Ureg *);
14 void    fen(Ureg *);
15
16 char *regname[]={
17         "type", "a0",           "a1",
18         "a2",           "R0",           "R1",
19         "R2",           "R3",           "R4",
20         "R5",           "R6",           "R7",
21         "R8",           "R9",           "R10",
22         "R11",  "R12",  "R13",
23         "R14",  "R15",  "R19",
24         "R20",  "R21",  "R22",
25         "R23",  "R24",  "R25",
26         "R26",  "R27",  "R28",
27         "R30",  "status",       "PC",
28         "R29",  "R16",  "R17",
29         "R18",
30 };
31
32 static Lock vctllock;
33 static Vctl *vctl[256];
34
35 void
36 intrenable(int irq, void (*f)(Ureg*, void*), void* a, int tbdf, char *name)
37 {
38         int vno;
39         Vctl *v;
40
41         if(f == nil){
42                 print("intrenable: nil handler for %d, tbdf 0x%uX for %s\n",
43                         irq, tbdf, name);
44                 return;
45         }
46
47         v = xalloc(sizeof(Vctl));
48         v->isintr = 1;
49         v->irq = irq;
50         v->tbdf = tbdf;
51         v->f = f;
52         v->a = a;
53         strncpy(v->name, name, KNAMELEN-1);
54         v->name[KNAMELEN-1] = 0;
55
56         ilock(&vctllock);
57         vno = arch->intrenable(v);
58         if(vno == -1){
59                 iunlock(&vctllock);
60                 print("intrenable: couldn't enable irq %d, tbdf 0x%uX for %s\n",
61                         irq, tbdf, v->name);
62                 xfree(v);
63                 return;
64         }
65         if(vctl[vno]){
66                 if(vctl[vno]->isr != v->isr || vctl[vno]->eoi != v->eoi)
67                         panic("intrenable: handler: %s %s %#p %#p %#p %#p",
68                                 vctl[vno]->name, v->name,
69                                 vctl[vno]->isr, v->isr, vctl[vno]->eoi, v->eoi);
70                 v->next = vctl[vno];
71         }
72         vctl[vno] = v;
73         iunlock(&vctllock);
74 }
75
76 int
77 intrdisable(int irq, void (*f)(Ureg *, void *), void *a, int tbdf, char *name)
78 {
79         Vctl **pv, *v;
80         int vno;
81
82         /*
83          * For now, none of this will work with the APIC code,
84          * there is no mapping between irq and vector as the IRQ
85          * is pretty meaningless.
86          */
87         if(arch->intrvecno == nil)
88                 return -1;
89         vno = arch->intrvecno(irq);
90         ilock(&vctllock);
91         for(pv = &vctl[vno]; *pv != nil; pv = &((*pv)->next)){
92                 if((*pv)->irq != irq)
93                         continue;
94                 if((*pv)->tbdf != tbdf)
95                         continue;
96                 if((*pv)->f != f)
97                         continue;
98                 if((*pv)->a != a)
99                         continue;
100                 if(strcmp((*pv)->name, name) != 0)
101                         continue;
102                 break;
103         }
104         assert(*pv != nil);
105
106         v = *pv;
107         *pv = (*pv)->next;      /* Link out the entry */
108         
109         if (vctl[vno] == nil && arch->intrdisable != nil)
110                 arch->intrdisable(irq);
111         iunlock(&vctllock);
112         xfree(v);
113         return 0;
114 }
115
116 int
117 irqallocread(char *buf, long n, vlong offset)
118 {
119         int vno;
120         Vctl *v;
121         long oldn;
122         char str[11+1+KNAMELEN+1], *p;
123         int m;
124
125         if(n < 0 || offset < 0)
126                 error(Ebadarg);
127
128         oldn = n;
129         for(vno=0; vno<nelem(vctl); vno++){
130                 for(v=vctl[vno]; v; v=v->next){
131                         m = snprint(str, sizeof str, "%11d %11d %.*s\n", vno, v->irq, KNAMELEN, v->name);
132                         if(m <= offset) /* if do not want this, skip entry */
133                                 offset -= m;
134                         else{
135                                 /* skip offset bytes */
136                                 m -= offset;
137                                 p = str+offset;
138                                 offset = 0;
139
140                                 /* write at most max(n,m) bytes */
141                                 if(m > n)
142                                         m = n;
143                                 memmove(buf, p, m);
144                                 n -= m;
145                                 buf += m;
146
147                                 if(n == 0)
148                                         return oldn;
149                         }       
150                 }
151         }
152         return oldn - n;
153 }
154
155 typedef struct Mcheck Mcheck;
156 struct Mcheck
157 {
158         ulong   len;
159         ulong   inprogress;
160         ulong   procoff;
161         ulong   sysoff;
162         ulong   code;
163 };
164
165 static char *
166 smcheck(ulong code)
167 {
168         switch (code) {
169         case 0x80: return "tag parity error";
170         case 0x82: return "tag control parity error";
171         case 0x84: return "generic hard error";
172         case 0x86: return "correctable ECC error";
173         case 0x88: return "uncorrectable ECC error";
174         case 0x8a: return "OS-specific PAL bugcheck";
175         case 0x90: return "callsys in kernel mode";
176         case 0x96: return "i-cache read retryable error";
177         case 0x98: return "processor detected hard error";
178
179         case 0x203: return "system detected uncorrectable ECC error";
180         case 0x205: return "parity error detected by CIA";
181         case 0x207: return "non-existent memory error";
182         case 0x209: return "PCI SERR detected";
183         case 0x20b: return "PCI data parity error detected";
184         case 0x20d: return "PCI address parity error detected";
185         case 0x20f: return "PCI master abort error";
186         case 0x211: return "PCI target abort error";
187         case 0x213: return "scatter/gather PTE invalid error";
188         case 0x215: return "flash ROM write error";
189         case 0x217: return "IOA timeout detected";
190         case 0x219: return "IOCHK#, EISA add-in board parity or other catastrophic error";
191         case 0x21b: return "EISA fail-safe timer timeout";
192         case 0x21d: return "EISA bus time-out";
193         case 0x21f: return "EISA software generated NMI";
194         case 0x221: return "unexpected ev5 IRQ[3] interrupt";
195         default: return "unknown mcheck";
196         }
197 }
198
199 void
200 mcheck(Ureg *ur, void *x)
201 {
202         Mcheck *m;
203         uvlong *data;
204         int i, col;
205
206         m = x;
207         data = x;
208         iprint("panic: Machine Check @%#p: %s (%lux) len %lud\n",
209                         m, smcheck(m->code), m->code, m->len);
210         iprint("proc offset %lux sys offset %lux\n", m->procoff, m->sysoff);
211         for (i = 0, col = 0; i < m->len/8; i++) {
212                 iprint("%.3x: %.16llux%s", 8*i, data[i], (col == 2) ? "\n" : "    ");
213                 if (col++ == 2)
214                         col = 0;
215         }
216         if(col != 2)
217                 print("\n");
218         print("\n");
219         dumpregs(ur);
220         prflush();
221         firmware();
222 }
223
224 void
225 intr(Ureg *ur)
226 {
227         int i, vno;
228         Vctl *ctl, *v;
229         Mach *mach;
230
231         vno = (ulong)ur->a1>>4;
232         vno -= 0x80;
233         if(vno < nelem(vctl) && (ctl = vctl[vno])){
234                 if(ctl->isintr){
235                         m->intr++;
236                         if(vno >= VectorPIC && vno <= MaxVectorPIC)
237                                 m->lastintr = vno-VectorPIC;
238                 }
239
240                 if(ctl->isr)
241                         ctl->isr(vno);
242                 for(v = ctl; v != nil; v = v->next) {
243                         if(v->f)
244                                 v->f(ur, v->a);
245                 }
246
247                 if(ctl->eoi)
248                         ctl->eoi(vno);
249
250                 if(ctl->isintr && up)
251                         preempted();
252         }
253         else if(vno >= VectorPIC && vno <= MaxVectorPIC){
254                 /*
255                  * An unknown interrupt.
256                  * Check for a default IRQ7. This can happen when
257                  * the IRQ input goes away before the acknowledge.
258                  * In this case, a 'default IRQ7' is generated, but
259                  * the corresponding bit in the ISR isn't set.
260                  * In fact, just ignore all such interrupts.
261                  */
262                 iprint("cpu%d: spurious interrupt %d, last %d",
263                         m->machno, vno-VectorPIC, m->lastintr);
264                 for(i = 0; i < 32; i++){
265                         if(!(active.machs & (1<<i)))
266                                 continue;
267                         mach = MACHP(i);
268                         if(m->machno == mach->machno)
269                                 continue;
270                         iprint(": cpu%d: last %d", mach->machno, mach->lastintr);
271                 }
272                 iprint("\n");
273                 m->spuriousintr++;
274                 return;
275         }
276         else{
277                 dumpregs(ur);
278                 print("unknown intr: %d\n", vno); /* */
279         }
280 }
281
282 void
283 trap(Ureg *ur)
284 {
285         char buf[ERRMAX];
286         int clockintr, user, x;
287
288         user = ur->status&UMODE;
289
290         if(user){
291                 up = m->proc;
292                 up->dbgreg = ur;
293         }
294         clockintr = 0;
295         switch ((int)ur->type) {
296         case 1: /* arith */
297                 fptrap(ur);
298                 break;
299         case 2: /* bad instr or FEN */
300                 illegal(ur);
301                 break;
302
303         case 3: /* intr */
304                 m->intr++;
305                 switch ((int)ur->a0) {
306                 case 0: /* interprocessor */
307                         panic("interprocessor intr");
308                         break;
309                 case 1: /* clock */
310                         clockintr = 1;
311                         clock(ur);
312                         break;
313                 case 2: /* machine check */
314                         mcheck(ur, (void*)(KZERO|(ulong)ur->a2));
315                         break;
316                 case 3: /* device */
317                         intr(ur);
318                         break;
319                 case 4: /* perf counter */
320                         panic("perf count");
321                         break;
322                 default:
323                         panic("bad intr");
324                         break;
325                 }
326                 break;
327
328         case 4: /* memory fault */
329                 if(up == 0)
330                         kernfault(ur, (ulong)ur->a1);
331
332                 x = up->insyscall;
333                 up->insyscall = 1;
334                 spllo();
335                 faultalpha(ur);
336                 up->insyscall = x;
337                 break;
338         case 6: /* alignment fault */
339                 ur->pc -= 4;
340                 sprint(buf, "trap: unaligned addr 0x%lux", (ulong)ur->a0);
341                 fataltrap(ur, buf);
342                 break;
343         default:        /* cannot happen */
344                 panic("bad trap type %d", (int)ur->type);
345                 break;
346         }
347
348         splhi();
349
350         /* delaysched set because we held a lock or because our quantum ended */
351         if(up && up->delaysched && clockintr){
352                 sched();
353                 splhi();
354         }
355
356         if(user){
357                 if(up->procctl || up->nnote)
358                         notify(ur);
359                 kexit(ur);
360         }
361 }
362
363 void
364 trapinit(void)
365 {
366         splhi();
367         wrent(0, intr0);
368         wrent(1, arith);
369         wrent(2, fault0);
370         wrent(3, illegal0);
371         wrent(4, unaligned);
372         wrent(5, syscall0);
373 }
374
375 void
376 fataltrap(Ureg *ur, char *reason)
377 {
378         char buf[ERRMAX];
379
380         if(ur->status&UMODE) {
381                 spllo();
382                 sprint(buf, "sys: %s", reason);
383                 postnote(up, 1, buf, NDebug);
384                 return;
385         }
386         print("kernel %s pc=%lux\n", reason, (ulong)ur->pc);
387         dumpregs(ur);
388         dumpstack();
389         if(m->machno == 0)
390                 spllo();
391         exit(1);
392 }
393
394 void
395 kernfault(Ureg *ur, int code)
396 {
397         Label l;
398         char *s;
399
400         splhi();
401         if (code == 0)
402                 s = "read";
403         else if (code == 1)
404                 s = "write";
405         else
406                 s = "ifetch";
407         print("panic: kfault %s VA=0x%lux\n", s, (ulong)ur->a0);
408         print("u=%#p status=0x%lux pc=0x%lux sp=0x%lux\n",
409                         up, (ulong)ur->status, (ulong)ur->pc, (ulong)ur->sp);
410         dumpregs(ur);
411         l.sp = ur->sp;
412         l.pc = ur->pc;
413         dumpstack();
414         exit(1);
415 }
416
417 void
418 dumpregs(Ureg *ur)
419 {
420         int i, col;
421         uvlong *l;
422
423         if(up)
424                 print("registers for %s %ld\n", up->text, up->pid);
425         else
426                 print("registers for kernel\n");
427
428         l = &ur->type;
429         col = 0;
430         for (i = 0; i < sizeof regname/sizeof(char*); i++, l++) {
431                 print("%-7s%.16llux%s", regname[i], *l, col == 2 ? "\n" : "     ");
432                 if (col++ == 2)
433                         col = 0;
434         }
435         print("\n");
436 }
437
438
439 /*
440  * Fill in enough of Ureg to get a stack trace, and call a function.
441  * Used by debugging interface rdb.
442  */
443 static void
444 getpcsp(ulong *pc, ulong *sp)
445 {
446         *pc = getcallerpc(&pc);
447         *sp = (ulong)&pc-8;
448 }
449
450 void
451 callwithureg(void (*fn)(Ureg*))
452 {
453         Ureg ureg;
454
455         getpcsp((ulong*)&ureg.pc, (ulong*)&ureg.sp);
456         ureg.r26 = getcallerpc(&fn);
457         fn(&ureg);
458 }
459
460 void
461 _dumpstack(Ureg *ureg)
462 {
463         ulong l, sl, el, v, i, instr, op;
464         extern ulong etext;
465
466         l=(ulong)&l;
467         if(l&4)
468                 l += 4;
469         if(up == 0){
470                 el = (ulong)m+BY2PG;
471                 sl = el-KSTACK;
472         }
473         else{
474                 sl = (ulong)up->kstack;
475                 el = sl + KSTACK;
476         }
477         if(l > el || l < sl){
478                 el = (ulong)m+BY2PG;
479                 sl = el-KSTACK;
480         }
481         if(l > el || l < sl)
482                 return;
483         print("ktrace /kernel/path %.8lux %.8lux %.8lux\n", (ulong)ureg->pc, (ulong)ureg->sp, (ulong)ureg->r26);
484
485         i = 0;
486         for(; l<el; l+=8){
487                 v = *(ulong*)l - 4;
488                 if(KTZERO < v && v < (ulong)&etext && (v&3) == 0){
489                         /*
490                          * Check for JSR/BSR
491                          */
492                         instr = *(ulong*)v;
493                         op = (instr>>26);
494                         if(op == 26 || op == 52){
495                                 print("%lux=%lux ", l, v);
496                                 i++;
497                         }
498                 }
499                 if(i == 4){
500                         i = 0;
501                         print("\n");
502                 }
503         }
504         if(i)
505                 print("\n");
506 }
507
508 void
509 dumpstack(void)
510 {
511         callwithureg(_dumpstack);
512 }
513
514 int
515 notify(Ureg *ur)
516 {
517         int l;
518         ulong sp;
519         Note *n;
520
521         if(up->procctl)
522                 procctl(up);
523         if(up->nnote == 0)
524                 return 0;
525
526         spllo();
527         qlock(&up->debug);
528         up->notepending = 0;
529
530         if(up->fpstate == FPactive){
531                 savefpregs(&up->fpsave);
532                 up->fpstate = FPinactive;
533         }
534         up->fpstate |= FPillegal;
535
536         n = &up->note[0];
537         if(strncmp(n->msg, "sys:", 4) == 0) {
538                 l = strlen(n->msg);
539                 if(l > ERRMAX-15)       /* " pc=0x12345678\0" */
540                         l = ERRMAX-15;
541
542                 sprint(n->msg+l, " pc=0x%lux", (ulong)ur->pc);
543         }
544
545         if(n->flag != NUser && (up->notified || up->notify==0)) {
546                 if(n->flag == NDebug)
547                         pprint("suicide: %s\n", n->msg);
548                 qunlock(&up->debug);
549                 pexit(n->msg, n->flag!=NDebug);
550         }
551
552         if(up->notified) {
553                 qunlock(&up->debug);
554                 splhi();
555                 return 0;
556         }
557                 
558         if(!up->notify) {
559                 qunlock(&up->debug);
560                 pexit(n->msg, n->flag!=NDebug);
561         }
562         sp = ur->usp & ~(BY2V-1);
563         sp -= sizeof(Ureg);
564
565         if(!okaddr((ulong)up->notify, BY2WD, 0)
566         || !okaddr(sp-ERRMAX-6*BY2WD, sizeof(Ureg)+ERRMAX-6*BY2WD, 1)) {
567                 pprint("suicide: bad address or sp in notify\n");
568 print("suicide: bad address or sp in notify\n");
569                 qunlock(&up->debug);
570                 pexit("Suicide", 0);
571         }
572
573         memmove((Ureg*)sp, ur, sizeof(Ureg));
574         *(Ureg**)(sp-BY2WD) = up->ureg; /* word under Ureg is old up->ureg */
575         up->ureg = (void*)sp;
576         sp -= 2*BY2WD+ERRMAX;
577         memmove((char*)sp, up->note[0].msg, ERRMAX);
578         sp -= 4*BY2WD;
579         *(ulong*)(sp+3*BY2WD) = sp+4*BY2WD;     /* arg 2 is string */
580         ur->r0 = (ulong)up->ureg;               /* arg 1 (R0) is ureg* */
581         *(ulong*)(sp+2*BY2WD) = (ulong)up->ureg;        /* arg 1 0(FP) is ureg* */
582         *(ulong*)(sp+0*BY2WD) = 0;              /* arg 0 is pc */
583         ur->usp = sp;
584         ur->pc = (ulong)up->notify;
585         up->notified = 1;
586         up->nnote--;
587         memmove(&up->lastnote, &up->note[0], sizeof(Note));
588         memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note));
589
590         qunlock(&up->debug);
591         splhi();
592         return 1;
593 }
594
595 /*
596  * Check that status is OK to return from note.
597  */
598 int
599 validstatus(ulong kstatus, ulong ustatus)
600 {
601         if((kstatus & 7) != (ustatus & 7))
602                 return 0;
603         if((ustatus&UMODE) != UMODE)
604                 return 0;
605         return 1;
606 }
607
608 /*
609  * Return user to state before notify()
610  */
611 void
612 noted(Ureg *kur, Ureg **urp, ulong arg0)
613 {
614         Ureg *nur;
615         ulong oureg, sp;
616
617         qlock(&up->debug);
618         if(arg0!=NRSTR && !up->notified) {
619                 qunlock(&up->debug);
620                 pprint("call to noted() when not notified\n");
621 print("call to noted() when not notified\n");
622                 pexit("Suicide", 0);
623         }
624         up->notified = 0;
625
626         up->fpstate &= ~FPillegal;
627
628         nur = up->ureg;
629
630         oureg = (ulong)nur;
631         if((oureg & (BY2V-1))
632         || !okaddr((ulong)oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){
633                 pprint("bad ureg in noted or call to noted() when not notified\n");
634 print("bad ureg in noted or call to noted() when not notified\n");
635                 qunlock(&up->debug);
636                 pexit("Suicide", 0);
637         }
638
639         if(!validstatus(kur->status, nur->status)) {
640                 qunlock(&up->debug);
641                 pprint("bad noted ureg status %lux\n", (ulong)nur->status);
642 print("bad noted ureg status %lux\n", (ulong)nur->status);
643                 pexit("Suicide", 0);
644         }
645
646         memmove(*urp, up->ureg, sizeof(Ureg));
647         switch(arg0) {
648         case NCONT:
649         case NRSTR:
650                 if(!okaddr(nur->pc, BY2WD, 0) || !okaddr(nur->usp, BY2WD, 0)){
651                         pprint("suicide: trap in noted\n");
652 print("suicide: trap in noted\n");
653                         qunlock(&up->debug);
654                         pexit("Suicide", 0);
655                 }
656                 up->ureg = (Ureg*)(*(ulong*)(oureg-BY2WD));
657                 qunlock(&up->debug);
658                 splhi();
659                 rfnote(urp);
660                 break;
661
662         case NSAVE:
663                 if(!okaddr(nur->pc, BY2WD, 0) || !okaddr(nur->usp, BY2WD, 0)){
664                         pprint("suicide: trap in noted\n");
665 print("suicide: trap in noted\n");
666                         qunlock(&up->debug);
667                         pexit("Suicide", 0);
668                 }
669                 qunlock(&up->debug);
670                 sp = oureg-4*BY2WD-ERRMAX;
671                 splhi();
672                 (*urp)->sp = sp;
673                 ((ulong*)sp)[1] = oureg;        /* arg 1 0(FP) is ureg* */
674                 ((ulong*)sp)[0] = 0;                    /* arg 0 is pc */
675                 (*urp)->r0 = oureg;             /* arg 1 is ureg* */
676                 rfnote(urp);
677                 break;
678
679         default:
680                 pprint("unknown noted arg 0x%lux\n", arg0);
681 print("unknown noted arg 0x%lux\n", arg0);
682                 up->lastnote.flag = NDebug;
683                 /* fall through */
684                 
685         case NDFLT:
686                 if(up->lastnote.flag == NDebug)
687                         pprint("suicide: %s\n", up->lastnote.msg);
688                 qunlock(&up->debug);
689                 pexit(up->lastnote.msg, up->lastnote.flag!=NDebug);
690         }
691 }
692
693 #include "../port/systab.h"
694
695 long
696 syscall(Ureg *aur)
697 {
698         int i;
699         char *e;
700         long ret;
701         ulong sp;
702         Ureg *ur;
703         ulong scallnr;
704
705         m->syscall++;
706         up = m->proc;
707         up->insyscall = 1;
708         ur = aur;
709         up->pc = ur->pc;
710         up->dbgreg = aur;
711         ur->type = 5;           /* for debugging */
712
713         scallnr = ur->r0;
714         up->scallnr = ur->r0;
715
716         if(scallnr == RFORK && up->fpstate == FPactive){
717                 savefpregs(&up->fpsave);
718                 up->fpstate = FPinactive;
719 //print("SR=%lux+", up->fpsave.fpstatus);
720         }
721         spllo();
722
723         sp = ur->sp;
724         up->nerrlab = 0;
725         ret = -1;
726         if(!waserror()) {
727                 if(scallnr >= nsyscall || systab[scallnr] == nil){
728                         pprint("bad sys call %d pc %lux\n", up->scallnr, (ulong)ur->pc);
729                         postnote(up, 1, "sys: bad sys call", NDebug);
730                         error(Ebadarg);
731                 }
732
733                 if(sp & (BY2WD-1)){     /* XXX too weak? */
734                         pprint("odd sp in sys call pc %lux sp %lux\n",
735                                 (ulong)ur->pc, (ulong)ur->sp);
736                         postnote(up, 1, "sys: odd stack", NDebug);
737                         error(Ebadarg);
738                 }
739
740                 if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)))
741                         validaddr(sp, sizeof(Sargs), 0);
742
743                 up->s = *((Sargs*)(sp+2*BY2WD));
744                 up->psstate = sysctab[scallnr];
745                 ret = systab[scallnr](up->s.args);
746                 poperror();
747         }else{
748                 /* failure: save the error buffer for errstr */
749                 e = up->syserrstr;
750                 up->syserrstr = up->errstr;
751                 up->errstr = e;
752         }
753         if(up->nerrlab){
754                 print("bad errstack [%uld]: %d extra\n", scallnr, up->nerrlab);
755                 for(i = 0; i < NERR; i++)
756                         print("sp=%lux pc=%lux\n",
757                                 up->errlab[i].sp, up->errlab[i].pc);
758                 panic("error stack");
759         }
760
761         up->nerrlab = 0;
762         up->psstate = 0;
763         up->insyscall = 0;
764         if(scallnr == NOTED)                    /* ugly hack */
765                 noted(ur, &aur, *(ulong*)(sp+2*BY2WD)); /* doesn't return */
766
767         if(scallnr!=RFORK && (up->procctl || up->nnote)){
768                 ur->r0 = ret;                           /* load up for noted() */
769                 if(notify(ur))
770                         return ur->r0;
771         }
772
773         return ret;
774 }
775
776 void
777 forkchild(Proc *p, Ureg *ur)
778 {
779         Ureg *cur;
780
781         p->sched.sp = (ulong)p->kstack+KSTACK-(4*BY2WD+sizeof(Ureg));
782         p->sched.pc = (ulong)forkret;
783
784         cur = (Ureg*)(p->sched.sp+4*BY2WD);
785         memmove(cur, ur, sizeof(Ureg));
786
787         /* Things from bottom of syscall we never got to execute */
788         p->psstate = 0;
789         p->insyscall = 0;
790 }
791
792 static
793 void
794 linkproc(void)
795 {
796         spllo();
797         up->kpfun(up->kparg);
798         pexit("kproc exiting", 0);
799 }
800
801 void
802 kprocchild(Proc *p, void (*func)(void*), void *arg)
803 {
804         p->sched.pc = (ulong)linkproc;
805         p->sched.sp = (ulong)p->kstack+KSTACK;
806
807         p->kpfun = func;
808         p->kparg = arg;
809 }
810
811 long
812 execregs(ulong entry, ulong ssize, ulong nargs)
813 {
814         Ureg *ur;
815         ulong *sp;
816
817         sp = (ulong*)(USTKTOP - ssize);
818         *--sp = nargs;
819
820         ur = (Ureg*)up->dbgreg;
821         ur->usp = (ulong)sp;
822         ur->pc = entry;
823         return USTKTOP-BY2WD;                   /* address of user-level clock */
824 }
825
826 ulong
827 userpc(void)
828 {
829         Ureg *ur;
830
831         ur = (Ureg*)up->dbgreg;
832         return ur->pc;
833 }
834
835 /* This routine must save the values of registers the user is not permitted to write
836  * from devproc and then restore the saved values before returning
837  */
838 void
839 setregisters(Ureg *xp, char *pureg, char *uva, int n)
840 {
841         ulong status;
842
843         status = xp->status;
844         memmove(pureg, uva, n);
845         xp->status = status;
846 }
847
848 /* Give enough context in the ureg to produce a kernel stack for
849  * a sleeping process
850  */
851 void
852 setkernur(Ureg *xp, Proc *p)
853 {
854         xp->pc = p->sched.pc;
855         xp->sp = p->sched.sp;
856         xp->r26 = (ulong)sched;
857 }
858
859 ulong
860 dbgpc(Proc *p)
861 {
862         Ureg *ur;
863
864         ur = p->dbgreg;
865         if(ur == 0)
866                 return 0;
867
868         return ur->pc;
869 }
870
871 void
872 illegal(Ureg *ur)
873 {
874         switch ((int)ur->a0) {
875         case 0: /* breakpoint */
876                 ur->pc -= 4;
877                 fataltrap(ur, "breakpoint");
878                 break;
879         case 1: /* bugchk */
880                 fataltrap(ur, "trap: bugchk");
881                 break;
882         case 2: /* gentrap */
883                 fataltrap(ur, "trap: gentrap");
884                 break;
885         case 3: /* FEN */
886                 fen(ur);
887                 break;
888         case 4: /* opDEC */
889                 fataltrap(ur, "trap: illegal instruction");
890                 break;
891         default:
892                 panic("illegal illegal %d", (int)ur->a0);
893                 break;
894         }
895 }
896
897 void
898 fen(Ureg *ur)
899 {
900         if(up){
901                 switch(up->fpstate){
902                 case FPinit:
903                         restfpregs(&initfp);
904                         up->fpstate = FPactive;
905 //print("EI=%lux+", initfp.fpstatus);
906                         return;
907
908                 case FPinactive:
909                         restfpregs(&up->fpsave);
910                         up->fpstate = FPactive;
911 //print("EIA=%lux+", up->fpsave.fpstatus);
912                         return;
913                 }
914         }
915         fataltrap(ur, "trap: floating enable"); /* should never happen */
916 }