xref: /plan9/sys/src/9/rb/trap.c (revision f43f8ee646e2cb29aea7fd7bb5fc7318a3f4921f)
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