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