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