1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "ureg.h"
7 #include "io.h"
8 #include <tos.h>
9 #include "../port/error.h"
10
11 #define setstatus(v) /* experiment: delete this to enable recursive traps */
12
13 typedef struct Handler Handler;
14
15 struct Handler {
16 void (*handler)(Ureg*, void*);
17 void *arg;
18 Handler *next; /* at this interrupt level */
19 ulong intrs;
20 };
21
22 ulong offintrs;
23 ulong intrcauses[ILmax+1];
24
25 int intr(Ureg*);
26 void kernfault(Ureg*, int);
27 void noted(Ureg*, Ureg**, ulong);
28 void rfnote(Ureg**);
29
30 char *excname[] =
31 {
32 "trap: external interrupt",
33 "trap: TLB modification (store to unwritable)",
34 "trap: TLB miss (load or fetch)",
35 "trap: TLB miss (store)",
36 "trap: address error (load or fetch)",
37 "trap: address error (store)",
38 "trap: bus error (fetch)",
39 "trap: bus error (data load or store)",
40 "trap: system call",
41 "breakpoint",
42 "trap: reserved instruction",
43 "trap: coprocessor unusable",
44 "trap: arithmetic overflow",
45 "trap: TRAP exception",
46 "trap: VCE (instruction)",
47 "trap: floating-point exception",
48 "trap: coprocessor 2 implementation-specific", /* used as sys call for debugger */
49 "trap: corextend unusable",
50 "trap: precise coprocessor 2 exception",
51 "trap: TLB read-inhibit",
52 "trap: TLB execute-inhibit",
53 "trap: undefined 21",
54 "trap: undefined 22",
55 "trap: WATCH exception",
56 "trap: machine checkcore",
57 "trap: undefined 25",
58 "trap: undefined 26",
59 "trap: undefined 27",
60 "trap: undefined 28",
61 "trap: undefined 29",
62 "trap: cache error",
63 "trap: VCE (data)",
64 };
65
66 char *fpcause[] =
67 {
68 "inexact operation",
69 "underflow",
70 "overflow",
71 "division by zero",
72 "invalid operation",
73 };
74
75 struct {
76 char *name;
77 uint off;
78 } regname[] = {
79 "STATUS", Ureg_status,
80 "PC", Ureg_pc,
81 "SP", Ureg_sp,
82 "CAUSE",Ureg_cause,
83 "BADADDR", Ureg_badvaddr,
84 "TLBVIRT", Ureg_tlbvirt,
85 "HI", Ureg_hi,
86 "LO", Ureg_lo,
87 "R31", Ureg_r31,
88 "R30", Ureg_r30,
89 "R28", Ureg_r28,
90 "R27", Ureg_r27,
91 "R26", Ureg_r26,
92 "R25", Ureg_r25,
93 "R24", Ureg_r24,
94 "R23", Ureg_r23,
95 "R22", Ureg_r22,
96 "R21", Ureg_r21,
97 "R20", Ureg_r20,
98 "R19", Ureg_r19,
99 "R18", Ureg_r18,
100 "R17", Ureg_r17,
101 "R16", Ureg_r16,
102 "R15", Ureg_r15,
103 "R14", Ureg_r14,
104 "R13", Ureg_r13,
105 "R12", Ureg_r12,
106 "R11", Ureg_r11,
107 "R10", Ureg_r10,
108 "R9", Ureg_r9,
109 "R8", Ureg_r8,
110 "R7", Ureg_r7,
111 "R6", Ureg_r6,
112 "R5", Ureg_r5,
113 "R4", Ureg_r4,
114 "R3", Ureg_r3,
115 "R2", Ureg_r2,
116 "R1", Ureg_r1,
117 };
118
119 static Lock intrlock;
120 static Handler handlers[ILmax+1];
121 static ulong pciintrmask;
122 static ulong i8259intrmask;
123
124 static char *
ptlb(ulong phys)125 ptlb(ulong phys)
126 {
127 static char buf[4][32];
128 static int k;
129 char *p;
130
131 k = (k+1)&3;
132 p = buf[k];
133 p += snprint(p, sizeof buf[k] - (p - buf[k]), "(%#lux %lud ",
134 (phys<<6) & ~(BY2PG-1), (phys>>3)&7);
135 if(phys & 4)
136 *p++ = 'd';
137 if(phys & 2)
138 *p++ = 'v';
139 if(phys & 1)
140 *p++ = 'g';
141 *p++ = ')';
142 *p = 0;
143 return buf[k];
144 }
145
146 static void
kpteprint(Ureg * ur)147 kpteprint(Ureg *ur)
148 {
149 ulong i, tlbstuff[3];
150 KMap *k;
151
152 i = (ur->badvaddr & ~(2*BY2PG-1)) | TLBPID(tlbvirt());
153 print("tlbvirt=%#lux\n", i);
154 i = gettlbp(i, tlbstuff);
155 print("i=%lud v=%#lux p0=%s p1=%s\n",
156 i, tlbstuff[0], ptlb(tlbstuff[1]), ptlb(tlbstuff[2]));
157
158 i = (ur->badvaddr & ~KMAPADDR)>>15;
159 if(i > KPTESIZE){
160 print("kpte index = %lud ?\n", i);
161 return;
162 }
163 k = &kpte[i];
164 print("i=%lud, &k=%#p, k={v=%#lux, p0=%s, p1=%s, pg=%#p}\n",
165 i, k, k->virt, ptlb(k->phys0), ptlb(k->phys1), k->pg);
166 print("pg={pa=%#lux, va=%#lux}\n", k->pg->pa, k->pg->va);
167 }
168
169 void
kvce(Ureg * ur,int ecode)170 kvce(Ureg *ur, int ecode)
171 {
172 char c;
173 Pte **p;
174 Page **pg;
175 Segment *s;
176 ulong addr, soff;
177
178 c = 'D';
179 if(ecode == CVCEI)
180 c = 'I';
181 print("Trap: VCE%c: addr=%#lux\n", c, ur->badvaddr);
182 if((ur->badvaddr & KSEGM) == KSEG3) {
183 kpteprint(ur);
184 return;
185 }
186 if(up && !(ur->badvaddr & KSEGM)) {
187 addr = ur->badvaddr;
188 s = seg(up, addr, 0);
189 if(s == 0){
190 print("kvce: no seg for %#lux\n", addr);
191 for(;;)
192 ;
193 }
194 addr &= ~(BY2PG-1);
195 soff = addr - s->base;
196 p = &s->map[soff/PTEMAPMEM];
197 if(*p){
198 pg = &(*p)->pages[(soff&(PTEMAPMEM-1))/BY2PG];
199 if(*pg)
200 print("kvce: pa=%#lux, va=%#lux\n",
201 (*pg)->pa, (*pg)->va);
202 else
203 print("kvce: no *pg\n");
204 }else
205 print("kvce: no *p\n");
206 }
207 }
208
209 /* prepare to go to user space */
210 void
kexit(Ureg *)211 kexit(Ureg*)
212 {
213 Tos *tos;
214
215 /* precise time accounting, kernel exit */
216 tos = (Tos*)(USTKTOP-sizeof(Tos));
217 tos->kcycles += fastticks(&tos->cyclefreq) - up->kentry;
218 tos->pcycles = up->pcycles;
219 tos->pid = up->pid;
220 }
221
222 char*
fpexcname(Ureg * ur,ulong fcr31,char * buf,uint size)223 fpexcname(Ureg *ur, ulong fcr31, char *buf, uint size)
224 {
225 int i;
226 char *s;
227 ulong fppc;
228
229 fppc = ur->pc;
230 if(ur->cause & BD) /* branch delay */
231 fppc += 4;
232 s = 0;
233 if(fcr31 & FPUNIMP)
234 s = "unimplemented operation";
235 else {
236 fcr31 >>= 7; /* trap enable bits */
237 fcr31 &= (fcr31>>5); /* anded with exceptions */
238 for(i=0; i<5; i++)
239 if(fcr31 & (1<<i))
240 s = fpcause[i];
241 }
242
243 if(s == 0)
244 return "no floating point exception";
245
246 snprint(buf, size, "%s fppc=%#lux", s, fppc);
247 return buf;
248 }
249
250 void
trap(Ureg * ur)251 trap(Ureg *ur)
252 {
253 int ecode, clockintr, user, cop, x, fpchk;
254 ulong fpfcr31;
255 char buf[2*ERRMAX], buf1[ERRMAX], *fpexcep;
256 static int dumps;
257
258 ecode = (ur->cause>>2)&EXCMASK;
259 user = ur->status&KUSER;
260 if (ur->cause & TS)
261 panic("trap: tlb shutdown");
262
263 fpchk = 0;
264 if(user){
265 up->dbgreg = ur;
266 cycles(&up->kentry);
267 if(up && up->fpstate == FPactive) {
268 if((ur->status & CU1) == 0)
269 panic("FPactive but no CU1");
270 ur->status &= ~CU1;
271 up->fpstate = FPinactive;
272 savefpregs(&up->fpsave);
273 }
274 }
275
276 if (up && (char *)(ur) - up->kstack < 1024 && dumps++ == 0) {
277 iprint("trap: proc %ld kernel stack getting full\n", up->pid);
278 dumpregs(ur);
279 dumpstack();
280 }
281 if (up == nil &&
282 (char *)(ur) - (char *)m->stack < 1024 && dumps++ == 0) {
283 iprint("trap: cpu%d kernel stack getting full\n", m->machno);
284 dumpregs(ur);
285 dumpstack();
286 }
287
288 // splhi(); /* for the experiment: make it explicit */
289 /* clear EXL in status */
290 setstatus(getstatus() & ~EXL);
291
292 clockintr = 0;
293 switch(ecode){
294 case CINT:
295 clockintr = intr(ur);
296 break;
297
298 case CFPE:
299 fptrap(ur);
300 clrfpintr();
301 fpchk = 1;
302 break;
303
304 case CTLBM:
305 case CTLBL:
306 case CTLBS:
307 /* user tlb entries assumed not overwritten during startup */
308 if(up == 0)
309 kernfault(ur, ecode);
310
311 if(!user && (ur->badvaddr & KSEGM) == KSEG3) {
312 kfault(ur);
313 break;
314 }
315 x = up->insyscall;
316 up->insyscall = 1;
317 spllo();
318 faultmips(ur, user, ecode);
319 up->insyscall = x;
320 break;
321
322 case CVCEI:
323 case CVCED:
324 kvce(ur, ecode);
325 goto Default;
326
327 case CWATCH:
328 if(!user)
329 panic("watchpoint trap from kernel mode pc=%#p",
330 ur->pc);
331 //fpwatch(ur); XXX
332 break;
333
334 case CCPU:
335 cop = (ur->cause>>28)&3;
336 if(user && up && cop == 1) {
337 if(up->fpstate & FPillegal) {
338 /* someone used floating point in a note handler */
339 postnote(up, 1,
340 "sys: floating point in note handler",
341 NDebug);
342 break;
343 }
344 if(up->fpstate == FPinit) {
345 up->fpstate = FPinactive;
346 fpfcr31 = up->fpsave.fpstatus;
347 up->fpsave = initfp;
348 up->fpsave.fpstatus = fpfcr31;
349 break;
350 }
351 if(up->fpstate == FPinactive)
352 break;
353 }
354 /* Fallthrough */
355
356 Default:
357 default:
358 if(user) {
359 spllo();
360 snprint(buf, sizeof buf, "sys: %s", excname[ecode]);
361 postnote(up, 1, buf, NDebug);
362 break;
363 }
364 if (ecode == CADREL || ecode == CADRES)
365 iprint("kernel addr exception for va %#p pid %#ld %s\n",
366 ur->badvaddr, (up? up->pid: 0),
367 (up? up->text: ""));
368 print("cpu%d: kernel %s pc=%#lux\n",
369 m->machno, excname[ecode], ur->pc);
370 dumpregs(ur);
371 dumpstack();
372 if(m->machno == 0)
373 spllo();
374 exit(1);
375 }
376
377 if(fpchk) {
378 fpfcr31 = up->fpsave.fpstatus;
379 if((fpfcr31>>12) & ((fpfcr31>>7)|0x20) & 0x3f) {
380 spllo();
381 fpexcep = fpexcname(ur, fpfcr31, buf1, sizeof buf1);
382 snprint(buf, sizeof buf, "sys: fp: %s", fpexcep);
383 postnote(up, 1, buf, NDebug);
384 }
385 }
386
387 splhi();
388
389 /* delaysched set because we held a lock or because our quantum ended */
390 if(up && up->delaysched && clockintr){
391 sched();
392 splhi();
393 }
394
395 if(user){
396 notify(ur);
397 if(up->fpstate == FPinactive) {
398 restfpregs(&up->fpsave, up->fpsave.fpstatus&~FPEXCMASK);
399 up->fpstate = FPactive;
400 ur->status |= CU1;
401 }
402 kexit(ur);
403 }
404
405 /* restore EXL in status */
406 setstatus(getstatus() | EXL);
407 }
408
409 /* periodically zero all the interrupt counts */
410 static void
resetcounts(void)411 resetcounts(void)
412 {
413 int i;
414 Handler *hp;
415
416 ilock(&intrlock);
417 for (i = 0; i < nelem(handlers); i++)
418 for (hp = &handlers[i]; hp != nil; hp = hp->next)
419 hp->intrs = 0;
420 iunlock(&intrlock);
421 }
422
423 /*
424 * set handlers
425 */
426 void
intrenable(int irq,void (* h)(Ureg *,void *),void * arg,int subirq)427 intrenable(int irq, void (*h)(Ureg*, void*), void *arg, int subirq)
428 {
429 Handler *hp;
430 static int resetclock;
431
432 if (h == nil)
433 panic("intrenable: nil handler intr %d", irq);
434 if(irq < ILmin || irq >= nelem(handlers))
435 panic("intrenable: bad handler intr %d %#p", irq, h);
436
437 hp = &handlers[irq];
438 ilock(&intrlock);
439 if (hp->handler != nil) { /* occupied? */
440 /* add a new one at the end of the chain */
441 for (; hp->next != nil; hp = hp->next)
442 ;
443 hp->next = smalloc(sizeof *hp);
444 hp = hp->next;
445 hp->next = nil;
446 }
447 hp->handler = h;
448 hp->arg = arg;
449 iunlock(&intrlock);
450
451 if (irq == ILpci) { // enable pci sub-interrupt
452 *Pciintrsts = 0;
453 *Pciintrenset = 1 << subirq;
454 coherence();
455 pciintrmask |= 1 << subirq;
456 }
457
458 if (irq == IL8259)
459 {
460 i8259enable(subirq);
461 i8259intrmask |= 1 << subirq;
462 }
463
464 intron(1 << (ILshift + irq));
465 if (!resetclock) {
466 resetclock = 1;
467 addclock0link(resetcounts, 100);
468 }
469 }
470
471 void
intrshutdown(void)472 intrshutdown(void)
473 {
474 introff(INTMASK);
475 }
476
477 static void
jabberoff(Ureg * ur,int irq,ulong bit)478 jabberoff(Ureg *ur, int irq, ulong bit)
479 {
480 introff(bit); /* interrupt off now ... */
481 if (ur)
482 ur->status &= ~bit; /* ... and upon return */
483 offintrs |= bit;
484 iprint("irq %d jabbering; shutting it down\n", irq);
485 }
486
487 ulong
pollall(Ureg * ur,ulong cause)488 pollall(Ureg *ur, ulong cause) /* must be called splhi */
489 {
490 int i, intrs, sts, subirq;
491 ulong bit;
492 Handler *hp;
493
494 /* exclude clock and sw intrs */
495 intrs = cause & (INTR6|INTR5|INTR4|INTR3|INTR2) & getstatus();
496 if(intrs == 0)
497 return cause;
498
499 ilock(&intrlock);
500 for (i = ILmax; i >= ILmin; i--) {
501 bit = 1 << (ILshift + i);
502 if (!(intrs & bit))
503 continue;
504 intrcauses[i]++;
505 for (hp = &handlers[i]; hp != nil; hp = hp->next)
506 if (hp->handler) {
507 if (i == ILpci) {
508 sts = *Pciintrsts & *Pciintren;
509 if((sts & pciintrmask) == 0)
510 continue;
511 // XXX need to clear sub-intr bits ?
512 //*Pciintrsts &= ~(1 << Pciintrether);
513 *Pciintrsts = 0;
514 }
515
516 if (i == IL8259) {
517 subirq = i8259intack();
518 if((1 << subirq) & i8259intrmask == 0)
519 continue;
520 i8259isr(subirq);
521 }
522
523 (*hp->handler)(ur, hp->arg);
524 splhi();
525 if (++hp->intrs > 25000) {
526 jabberoff(ur, i, bit);
527 intrs &= ~bit;
528 hp->intrs = 0;
529 }
530 } else if (ur)
531 iprint("no handler for interrupt %d\n", i);
532 cause &= ~bit;
533 }
534 iunlock(&intrlock);
535 return cause;
536 }
537
538 int
intr(Ureg * ur)539 intr(Ureg *ur)
540 {
541 int clockintr;
542 ulong cause;
543
544 m->intr++;
545 clockintr = 0;
546 /*
547 * ignore interrupts that we have disabled, even if their cause bits
548 * are set.
549 */
550 cause = ur->cause & ur->status & INTMASK;
551 cause &= ~(INTR1|INTR0); /* ignore sw interrupts */
552 if (cause == 0)
553 print("spurious interrupt\n");
554 if(cause & INTR7){
555 clock(ur);
556 intrcauses[ILclock]++;
557 cause &= ~(1 << (ILclock + ILshift));
558 clockintr = 1;
559 }
560 cause = pollall(ur, cause);
561 if(cause){
562 print("intr: cause %#lux not handled\n", cause);
563 exit(1);
564 }
565
566 /* preemptive scheduling */
567 if(up && !clockintr)
568 preempted();
569 /* if it was a clockintr, sched will be called at end of trap() */
570 return clockintr;
571 }
572
573 void
kernfault(Ureg * ur,int code)574 kernfault(Ureg *ur, int code)
575 {
576 print("panic: kfault %s badvaddr=%#lux", excname[code], ur->badvaddr);
577 kpteprint(ur);
578 print("u=%#p status=%#lux pc=%#lux sp=%#lux\n",
579 up, ur->status, ur->pc, ur->sp);
580 delay(500);
581 panic("kfault");
582 }
583
584 static void
getpcsp(ulong * pc,ulong * sp)585 getpcsp(ulong *pc, ulong *sp)
586 {
587 *pc = getcallerpc(&pc);
588 *sp = (ulong)&pc-4;
589 }
590
591 void
callwithureg(void (* fn)(Ureg *))592 callwithureg(void (*fn)(Ureg*))
593 {
594 Ureg ureg;
595
596 memset(&ureg, 0, sizeof ureg);
597 getpcsp((ulong*)&ureg.pc, (ulong*)&ureg.sp);
598 ureg.r31 = getcallerpc(&fn);
599 fn(&ureg);
600 }
601
602 static void
_dumpstack(Ureg * ureg)603 _dumpstack(Ureg *ureg)
604 {
605 ulong l, v, top, i;
606 extern ulong etext;
607
608 if(up == 0)
609 return;
610
611 print("ktrace /kernel/path %.8lux %.8lux %.8lux\n",
612 ureg->pc, ureg->sp, ureg->r31);
613 top = (ulong)up->kstack + KSTACK;
614 i = 0;
615 for(l=ureg->sp; l < top; l += BY2WD) {
616 v = *(ulong*)l;
617 if(KTZERO < v && v < (ulong)&etext) {
618 print("%.8lux=%.8lux ", l, v);
619 if((++i%4) == 0){
620 print("\n");
621 delay(200);
622 }
623 }
624 }
625 print("\n");
626 }
627
628 void
dumpstack(void)629 dumpstack(void)
630 {
631 callwithureg(_dumpstack);
632 }
633
634 static ulong
R(Ureg * ur,int i)635 R(Ureg *ur, int i)
636 {
637 uchar *s;
638
639 s = (uchar*)ur;
640 return *(ulong*)(s + regname[i].off - Uoffset);
641 }
642
643 void
dumpregs(Ureg * ur)644 dumpregs(Ureg *ur)
645 {
646 int i;
647
648 if(up)
649 print("registers for %s %lud\n", up->text, up->pid);
650 else
651 print("registers for kernel\n");
652
653 for(i = 0; i < nelem(regname); i += 2)
654 print("%s\t%#.8lux\t%s\t%#.8lux\n",
655 regname[i].name, R(ur, i),
656 regname[i+1].name, R(ur, i+1));
657 }
658
659 int
notify(Ureg * ur)660 notify(Ureg *ur)
661 {
662 int l, s;
663 ulong sp;
664 Note *n;
665
666 if(up->procctl)
667 procctl(up);
668 if(up->nnote == 0)
669 return 0;
670
671 s = spllo();
672 qlock(&up->debug);
673 up->fpstate |= FPillegal;
674 up->notepending = 0;
675 n = &up->note[0];
676 if(strncmp(n->msg, "sys:", 4) == 0) {
677 l = strlen(n->msg);
678 if(l > ERRMAX-15) /* " pc=0x12345678\0" */
679 l = ERRMAX-15;
680
681 seprint(n->msg+l, &n->msg[sizeof n->msg], " pc=%#lux", ur->pc);
682 }
683
684 if(n->flag != NUser && (up->notified || up->notify==0)) {
685 if(n->flag == NDebug)
686 pprint("suicide: %s\n", n->msg);
687
688 qunlock(&up->debug);
689 pexit(n->msg, n->flag!=NDebug);
690 }
691
692 if(up->notified) {
693 qunlock(&up->debug);
694 splx(s);
695 return 0;
696 }
697
698 if(!up->notify) {
699 qunlock(&up->debug);
700 pexit(n->msg, n->flag!=NDebug);
701 }
702 sp = ur->usp - sizeof(Ureg) - BY2WD; /* libc adds 4 to usp */
703
704 if(!okaddr((ulong)up->notify, BY2WD, 0) ||
705 !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)) {
706 pprint("suicide: bad address or sp in notify\n");
707 qunlock(&up->debug);
708 pexit("Suicide", 0);
709 }
710
711 memmove((Ureg*)sp, ur, sizeof(Ureg)); /* push user regs */
712 *(Ureg**)(sp-BY2WD) = up->ureg; /* word under Ureg is old up->ureg */
713 up->ureg = (void*)sp;
714
715 sp -= BY2WD+ERRMAX;
716 memmove((char*)sp, up->note[0].msg, ERRMAX); /* push err string */
717
718 sp -= 3*BY2WD;
719 *(ulong*)(sp+2*BY2WD) = sp+3*BY2WD; /* arg 2 is string */
720 ur->r1 = (long)up->ureg; /* arg 1 is ureg* */
721 ((ulong*)sp)[1] = (ulong)up->ureg; /* arg 1 0(FP) is ureg* */
722 ((ulong*)sp)[0] = 0; /* arg 0 is pc */
723 ur->usp = sp;
724 /*
725 * arrange to resume at user's handler as if handler(ureg, errstr)
726 * were being called.
727 */
728 ur->pc = (ulong)up->notify;
729
730 up->notified = 1;
731 up->nnote--;
732 memmove(&up->lastnote, &up->note[0], sizeof(Note));
733 memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note));
734
735 qunlock(&up->debug);
736 splx(s);
737 return 1;
738 }
739
740 /*
741 * Check that status is OK to return from note.
742 */
743 int
validstatus(ulong kstatus,ulong ustatus)744 validstatus(ulong kstatus, ulong ustatus)
745 {
746 // if((kstatus & (INTMASK|KX|SX|UX)) != (ustatus & (INTMASK|KX|SX|UX)))
747 if((kstatus & INTMASK) != (ustatus & INTMASK))
748 return 0;
749 if((ustatus&(KSU|ERL|EXL|IE)) != (KUSER|EXL|IE))
750 return 0;
751 if(ustatus & (0xFFFF0000&~CU1)) /* no CU3, CU2, CU0, RP, FR, RE, DS */
752 return 0;
753 return 1;
754 }
755
756 /*
757 * Return user to state before notify(); called from user's handler.
758 */
759 void
noted(Ureg * kur,Ureg ** urp,ulong arg0)760 noted(Ureg *kur, Ureg **urp, ulong arg0)
761 {
762 Ureg *nur;
763 ulong oureg, sp;
764
765 qlock(&up->debug);
766 if(arg0!=NRSTR && !up->notified) {
767 qunlock(&up->debug);
768 pprint("call to noted() when not notified\n");
769 pexit("Suicide", 0);
770 }
771 up->notified = 0;
772
773 up->fpstate &= ~FPillegal;
774
775 nur = up->ureg;
776
777 oureg = (ulong)nur;
778 if((oureg & (BY2WD-1))
779 || !okaddr((ulong)oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){
780 pprint("bad up->ureg in noted or call to noted() when not notified\n");
781 qunlock(&up->debug);
782 pexit("Suicide", 0);
783 }
784
785 if(!validstatus(kur->status, nur->status)) {
786 qunlock(&up->debug);
787 pprint("bad noted ureg status %#lux\n", nur->status);
788 pexit("Suicide", 0);
789 }
790
791 memmove(*urp, up->ureg, sizeof(Ureg));
792 switch(arg0) {
793 case NCONT:
794 case NRSTR: /* only used by APE */
795 if(!okaddr(nur->pc, BY2WD, 0) || !okaddr(nur->usp, BY2WD, 0)){
796 pprint("suicide: trap in noted\n");
797 qunlock(&up->debug);
798 pexit("Suicide", 0);
799 }
800 up->ureg = (Ureg*)(*(ulong*)(oureg-BY2WD));
801 qunlock(&up->debug);
802 splhi();
803 /*
804 * the old challenge and carrera ports called rfnote here,
805 * but newer ports do not, and notes seem to work only
806 * without this call.
807 */
808 // rfnote(urp); /* return from note with SP=urp */
809 break;
810
811 case NSAVE: /* only used by APE */
812 if(!okaddr(nur->pc, BY2WD, 0) || !okaddr(nur->usp, BY2WD, 0)){
813 pprint("suicide: trap in noted\n");
814 qunlock(&up->debug);
815 pexit("Suicide", 0);
816 }
817 qunlock(&up->debug);
818 sp = oureg-4*BY2WD-ERRMAX;
819
820 splhi();
821 (*urp)->sp = sp;
822 ((ulong*)sp)[1] = oureg; /* arg 1 0(FP) is ureg* */
823 ((ulong*)sp)[0] = 0; /* arg 0 is pc */
824 (*urp)->r1 = oureg; /* arg 1 is ureg* */
825
826 // rfnote(urp); /* return from note with SP=urp */
827 break;
828
829 default:
830 pprint("unknown noted arg %#lux\n", arg0);
831 up->lastnote.flag = NDebug;
832 /* fall through */
833
834 case NDFLT:
835 if(up->lastnote.flag == NDebug)
836 pprint("suicide: %s\n", up->lastnote.msg);
837 qunlock(&up->debug);
838 pexit(up->lastnote.msg, up->lastnote.flag!=NDebug);
839 }
840 }
841
842 #include "../port/systab.h"
843
844 static Ref goodsyscall;
845 static Ref totalsyscall;
846
847 static void
sctracesetup(ulong scallnr,ulong sp,uintptr pc,vlong * startnsp)848 sctracesetup(ulong scallnr, ulong sp, uintptr pc, vlong *startnsp)
849 {
850 if(up->procctl == Proc_tracesyscall){
851 /*
852 * Redundant validaddr. Do we care?
853 * Tracing syscalls is not exactly a fast path...
854 * Beware, validaddr currently does a pexit rather
855 * than an error if there's a problem; that might
856 * change in the future.
857 */
858 if(sp < (USTKTOP-BY2PG) || sp > (USTKTOP-sizeof(Sargs)))
859 validaddr(sp, sizeof(Sargs), 0);
860
861 syscallfmt(scallnr, pc, (va_list)sp);
862 up->procctl = Proc_stopme;
863 procctl(up);
864 if(up->syscalltrace)
865 free(up->syscalltrace);
866 up->syscalltrace = nil;
867 *startnsp = todget(nil);
868 }
869 }
870
871 static void
sctracefinish(ulong scallnr,ulong sp,int ret,vlong startns)872 sctracefinish(ulong scallnr, ulong sp, int ret, vlong startns)
873 {
874 int s;
875
876 if(up->procctl == Proc_tracesyscall){
877 up->procctl = Proc_stopme;
878 sysretfmt(scallnr, (va_list)sp, ret,
879 startns, todget(nil));
880 s = splhi();
881 procctl(up);
882 splx(s);
883 if(up->syscalltrace)
884 free(up->syscalltrace);
885 up->syscalltrace = nil;
886 }
887 }
888
889 /*
890 * called directly from assembler, not via trap()
891 */
892 long
syscall(Ureg * aur)893 syscall(Ureg *aur)
894 {
895 int i;
896 volatile long ret;
897 ulong sp, scallnr;
898 vlong startns;
899 char *e;
900 Ureg *ur;
901
902 cycles(&up->kentry);
903
904 incref(&totalsyscall);
905 m->syscall++;
906 up->insyscall = 1;
907 ur = aur;
908 up->pc = ur->pc;
909 up->dbgreg = aur;
910 ur->cause = 16<<2; /* for debugging: system call is undef 16 */
911
912 scallnr = ur->r1;
913 up->scallnr = ur->r1;
914 sp = ur->sp;
915 sctracesetup(scallnr, sp, ur->pc, &startns);
916
917 /* clear EXL in status */
918 setstatus(getstatus() & ~EXL);
919
920 if(up->fpstate == FPactive) {
921 if((ur->status & CU1) == 0)
922 panic("syscall: FPactive but no CU1");
923 up->fpsave.fpstatus = fcr31();
924 up->fpstate = FPinit;
925 ur->status &= ~CU1;
926 }
927 spllo();
928
929 up->nerrlab = 0;
930 ret = -1;
931 if(!waserror()) {
932 if(scallnr >= nsyscall || systab[scallnr] == 0){
933 pprint("bad sys call number %ld pc %#lux\n",
934 scallnr, ur->pc);
935 postnote(up, 1, "sys: bad sys call", NDebug);
936 error(Ebadarg);
937 }
938
939 if(sp & (BY2WD-1)){
940 pprint("odd sp in sys call pc %#lux sp %#lux\n",
941 ur->pc, ur->sp);
942 postnote(up, 1, "sys: odd stack", NDebug);
943 error(Ebadarg);
944 }
945
946 if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)))
947 validaddr(sp, sizeof(Sargs), 0);
948
949 up->s = *(Sargs*)sp; /* spim's libc is different to mips ... */
950 up->psstate = sysctab[scallnr];
951
952 ret = systab[scallnr](up->s.args);
953 poperror();
954 }else{
955 /* failure: save the error buffer for errstr */
956 e = up->syserrstr;
957 up->syserrstr = up->errstr;
958 up->errstr = e;
959 }
960 if(up->nerrlab){
961 print("bad errstack [%lud]: %d extra\n", scallnr, up->nerrlab);
962 for(i = 0; i < NERR; i++)
963 print("sp=%#lux pc=%#lux\n",
964 up->errlab[i].sp, up->errlab[i].pc);
965 panic("error stack");
966 }
967 sctracefinish(scallnr, sp, ret, startns);
968
969 ur->pc += 4;
970 ur->r1 = ret;
971
972 up->psstate = 0;
973 up->insyscall = 0;
974
975 if(scallnr == NOTED) { /* ugly hack */
976 noted(ur, &aur, *(ulong*)sp); /* may return */
977 ret = ur->r1;
978 }
979 incref(&goodsyscall);
980 splhi();
981 if(scallnr!=RFORK && (up->procctl || up->nnote)){
982 ur->r1 = ret; /* load up for noted() above */
983 notify(ur);
984 }
985 /* if we delayed sched because we held a lock, sched now */
986 if(up->delaysched)
987 sched();
988 kexit(ur);
989
990 /* restore EXL in status */
991 setstatus(getstatus() | EXL);
992
993 return ret;
994 }
995
996 void
forkchild(Proc * p,Ureg * ur)997 forkchild(Proc *p, Ureg *ur)
998 {
999 Ureg *cur;
1000
1001 p->sched.sp = (ulong)p->kstack+KSTACK-UREGSIZE;
1002 p->sched.pc = (ulong)forkret;
1003
1004 cur = (Ureg*)(p->sched.sp+2*BY2WD);
1005 memmove(cur, ur, sizeof(Ureg));
1006
1007 cur->pc += 4;
1008
1009 /* Things from bottom of syscall we never got to execute */
1010 p->psstate = 0;
1011 p->insyscall = 0;
1012 }
1013
1014 static void
linkproc(void)1015 linkproc(void)
1016 {
1017 spllo();
1018 up->kpfun(up->kparg);
1019 pexit("kproc exiting", 0);
1020 }
1021
1022 void
kprocchild(Proc * p,void (* func)(void *),void * arg)1023 kprocchild(Proc *p, void (*func)(void*), void *arg)
1024 {
1025 p->sched.pc = (ulong)linkproc;
1026 p->sched.sp = (ulong)p->kstack+KSTACK;
1027
1028 p->kpfun = func;
1029 p->kparg = arg;
1030 }
1031
1032 /* set up user registers before return from exec() */
1033 long
execregs(ulong entry,ulong ssize,ulong nargs)1034 execregs(ulong entry, ulong ssize, ulong nargs)
1035 {
1036 Ureg *ur;
1037 ulong *sp;
1038
1039 sp = (ulong*)(USTKTOP - ssize);
1040 *--sp = nargs;
1041
1042 ur = (Ureg*)up->dbgreg;
1043 ur->usp = (ulong)sp;
1044 ur->pc = entry - 4; /* syscall advances it */
1045 up->fpsave.fpstatus = initfp.fpstatus;
1046 return USTKTOP-sizeof(Tos); /* address of kernel/user shared data */
1047 }
1048
1049 ulong
userpc(void)1050 userpc(void)
1051 {
1052 Ureg *ur;
1053
1054 ur = (Ureg*)up->dbgreg;
1055 return ur->pc;
1056 }
1057
1058 /*
1059 * This routine must save the values of registers the user is not
1060 * permitted to write from devproc and then restore the saved values
1061 * before returning
1062 */
1063 void
setregisters(Ureg * xp,char * pureg,char * uva,int n)1064 setregisters(Ureg *xp, char *pureg, char *uva, int n)
1065 {
1066 ulong status;
1067
1068 status = xp->status;
1069 memmove(pureg, uva, n);
1070 xp->status = status;
1071 }
1072
1073 /*
1074 * Give enough context in the ureg to produce a kernel stack for
1075 * a sleeping process
1076 */
1077 void
setkernur(Ureg * xp,Proc * p)1078 setkernur(Ureg *xp, Proc *p)
1079 {
1080 xp->pc = p->sched.pc;
1081 xp->sp = p->sched.sp;
1082 xp->r24 = (ulong)p; /* up */
1083 xp->r31 = (ulong)sched;
1084 }
1085
1086 ulong
dbgpc(Proc * p)1087 dbgpc(Proc *p)
1088 {
1089 Ureg *ur;
1090
1091 ur = p->dbgreg;
1092 if(ur == 0)
1093 return 0;
1094
1095 return ur->pc;
1096 }
1097