xref: /plan9-contrib/sys/src/9/vt4/trap.c (revision d6dfd9ef91cf0fa8514a249d5f2a550978c19369)
1*d6dfd9efSDavid du Colombier #include	"u.h"
2*d6dfd9efSDavid du Colombier #include	"../port/lib.h"
3*d6dfd9efSDavid du Colombier #include	"mem.h"
4*d6dfd9efSDavid du Colombier #include	"dat.h"
5*d6dfd9efSDavid du Colombier #include	"fns.h"
6*d6dfd9efSDavid du Colombier 
7*d6dfd9efSDavid du Colombier #include	<tos.h>
8*d6dfd9efSDavid du Colombier #include	"ureg.h"
9*d6dfd9efSDavid du Colombier 
10*d6dfd9efSDavid du Colombier #include	"io.h"
11*d6dfd9efSDavid du Colombier 
12*d6dfd9efSDavid du Colombier enum {
13*d6dfd9efSDavid du Colombier 	VECSIZE = 0x100,
14*d6dfd9efSDavid du Colombier 	VECBASE = PHYSSRAM,
15*d6dfd9efSDavid du Colombier };
16*d6dfd9efSDavid du Colombier 
17*d6dfd9efSDavid du Colombier static struct {
18*d6dfd9efSDavid du Colombier 	ulong off;
19*d6dfd9efSDavid du Colombier 	char *name;
20*d6dfd9efSDavid du Colombier } intcause[] = {
21*d6dfd9efSDavid du Colombier 	{ INT_RESET,	"system reset" },
22*d6dfd9efSDavid du Colombier 	{ INT_MCHECK,	"machine check" },
23*d6dfd9efSDavid du Colombier 	{ INT_DSI,	"data access" },
24*d6dfd9efSDavid du Colombier 	{ INT_ISI,	"instruction access" },
25*d6dfd9efSDavid du Colombier 	{ INT_EI,	"external interrupt" },
26*d6dfd9efSDavid du Colombier 	{ INT_ALIGN,	"alignment" },
27*d6dfd9efSDavid du Colombier 	{ INT_PROG,	"program exception" },
28*d6dfd9efSDavid du Colombier 	{ INT_FPU,	"floating-point unavailable" },
29*d6dfd9efSDavid du Colombier 	{ INT_DEC,	"decrementer" },
30*d6dfd9efSDavid du Colombier 	{ INT_SYSCALL,	"system call" },
31*d6dfd9efSDavid du Colombier 	{ INT_TRACE,	"trace trap" },
32*d6dfd9efSDavid du Colombier 	{ INT_FPA,	"floating point unavailable" },
33*d6dfd9efSDavid du Colombier 	{ INT_APU,	"auxiliary processor unavailable" },
34*d6dfd9efSDavid du Colombier 	{ INT_PIT,	"programmable interval timer interrrupt" },
35*d6dfd9efSDavid du Colombier 	{ INT_FIT,	"fixed interval timer interrupt" },
36*d6dfd9efSDavid du Colombier 	{ INT_WDT,	"watch dog timer interrupt" },
37*d6dfd9efSDavid du Colombier 	{ INT_DMISS,	"data TLB miss" },
38*d6dfd9efSDavid du Colombier 	{ INT_IMISS,	"instruction TLB miss" },
39*d6dfd9efSDavid du Colombier 	{ INT_DEBUG,	"debug interrupt" },
40*d6dfd9efSDavid du Colombier 	{ INT_DEBUG+VECSIZE, "system reset" },
41*d6dfd9efSDavid du Colombier 	{ 0,		"unknown interrupt" }
42*d6dfd9efSDavid du Colombier };
43*d6dfd9efSDavid du Colombier 
44*d6dfd9efSDavid du Colombier static char *excname(ulong, u32int);
45*d6dfd9efSDavid du Colombier 
46*d6dfd9efSDavid du Colombier char *regname[]={
47*d6dfd9efSDavid du Colombier 	"CAUSE",	"SRR1",
48*d6dfd9efSDavid du Colombier 	"PC",		"GOK",
49*d6dfd9efSDavid du Colombier 	"LR",		"CR",
50*d6dfd9efSDavid du Colombier 	"XER",	"CTR",
51*d6dfd9efSDavid du Colombier 	"R0",		"R1",
52*d6dfd9efSDavid du Colombier 	"R2",		"R3",
53*d6dfd9efSDavid du Colombier 	"R4",		"R5",
54*d6dfd9efSDavid du Colombier 	"R6",		"R7",
55*d6dfd9efSDavid du Colombier 	"R8",		"R9",
56*d6dfd9efSDavid du Colombier 	"R10",	"R11",
57*d6dfd9efSDavid du Colombier 	"R12",	"R13",
58*d6dfd9efSDavid du Colombier 	"R14",	"R15",
59*d6dfd9efSDavid du Colombier 	"R16",	"R17",
60*d6dfd9efSDavid du Colombier 	"R18",	"R19",
61*d6dfd9efSDavid du Colombier 	"R20",	"R21",
62*d6dfd9efSDavid du Colombier 	"R22",	"R23",
63*d6dfd9efSDavid du Colombier 	"R24",	"R25",
64*d6dfd9efSDavid du Colombier 	"R26",	"R27",
65*d6dfd9efSDavid du Colombier 	"R28",	"R29",
66*d6dfd9efSDavid du Colombier 	"R30",	"R31",
67*d6dfd9efSDavid du Colombier };
68*d6dfd9efSDavid du Colombier 
69*d6dfd9efSDavid du Colombier static int probing, trapped;
70*d6dfd9efSDavid du Colombier 
71*d6dfd9efSDavid du Colombier /* populate a normal vector */
72*d6dfd9efSDavid du Colombier static void
sethvec(int v,void (* r)(void))73*d6dfd9efSDavid du Colombier sethvec(int v, void (*r)(void))
74*d6dfd9efSDavid du Colombier {
75*d6dfd9efSDavid du Colombier 	ulong *vp, pa, o;
76*d6dfd9efSDavid du Colombier 
77*d6dfd9efSDavid du Colombier 	vp = (ulong*)KADDR(v);
78*d6dfd9efSDavid du Colombier 	vp[0] = 0x7c1043a6;			/* MOVW R0, SPR(SPRG0) */
79*d6dfd9efSDavid du Colombier 	vp[1] = 0x7c0802a6;			/* MOVW LR, R0 */
80*d6dfd9efSDavid du Colombier 	vp[2] = 0x7c1243a6;			/* MOVW R0, SPR(SPRG2) */
81*d6dfd9efSDavid du Colombier 	pa = PADDR(r);
82*d6dfd9efSDavid du Colombier 	o = pa >> 25;
83*d6dfd9efSDavid du Colombier 	if(o != 0 && o != 0x7F){
84*d6dfd9efSDavid du Colombier 		/* a branch too far: running from ROM */
85*d6dfd9efSDavid du Colombier 		vp[3] = (15<<26)|(pa>>16);	/* MOVW $r&~0xFFFF, R0 */
86*d6dfd9efSDavid du Colombier 		vp[4] = (24<<26)|(pa&0xFFFF);	/* OR $r&0xFFFF, R0 */
87*d6dfd9efSDavid du Colombier 		vp[5] = 0x7c0803a6;		/* MOVW	R0, LR */
88*d6dfd9efSDavid du Colombier 		vp[6] = 0x4e800021;		/* BL (LR) */
89*d6dfd9efSDavid du Colombier 		if (v == VECBASE + INT_PIT || v == VECBASE + INT_FIT) {
90*d6dfd9efSDavid du Colombier 			uartlputc('?');
91*d6dfd9efSDavid du Colombier 			uartlputc('v');
92*d6dfd9efSDavid du Colombier 			print("branch too far for vector %#x!\n", v);
93*d6dfd9efSDavid du Colombier 		}
94*d6dfd9efSDavid du Colombier 	}else
95*d6dfd9efSDavid du Colombier 		vp[3] = (18<<26)|(pa&0x3FFFFFC)|3;	/* bla */
96*d6dfd9efSDavid du Colombier 	dcflush(PTR2UINT(vp), 8*BY2WD);
97*d6dfd9efSDavid du Colombier }
98*d6dfd9efSDavid du Colombier 
99*d6dfd9efSDavid du Colombier /* populate a tlb-miss vector */
100*d6dfd9efSDavid du Colombier static void
sethvec2(int v,void (* r)(void))101*d6dfd9efSDavid du Colombier sethvec2(int v, void (*r)(void))
102*d6dfd9efSDavid du Colombier {
103*d6dfd9efSDavid du Colombier 	ulong *vp;
104*d6dfd9efSDavid du Colombier 	char msg[128];
105*d6dfd9efSDavid du Colombier 
106*d6dfd9efSDavid du Colombier 	if (((ulong)r & ~KSEGM) >= (1<<26)) {
107*d6dfd9efSDavid du Colombier 		uartlputc('?');
108*d6dfd9efSDavid du Colombier 		uartlputc('t');
109*d6dfd9efSDavid du Colombier 		snprint(msg, sizeof msg,
110*d6dfd9efSDavid du Colombier 			"tlb miss handler address %#p too high\n", r);
111*d6dfd9efSDavid du Colombier 		uartlputs(msg);
112*d6dfd9efSDavid du Colombier 	}
113*d6dfd9efSDavid du Colombier 	vp = (ulong*)KADDR(v);
114*d6dfd9efSDavid du Colombier 	vp[0] = (18<<26)|((ulong)r&~KSEGM)|2;	/* ba */
115*d6dfd9efSDavid du Colombier 	dcflush(PTR2UINT(vp), sizeof *vp);
116*d6dfd9efSDavid du Colombier }
117*d6dfd9efSDavid du Colombier 
118*d6dfd9efSDavid du Colombier static void
faultpower(Ureg * ureg,ulong addr,int read)119*d6dfd9efSDavid du Colombier faultpower(Ureg *ureg, ulong addr, int read)
120*d6dfd9efSDavid du Colombier {
121*d6dfd9efSDavid du Colombier 	int user, insyscall, n;
122*d6dfd9efSDavid du Colombier 	char buf[ERRMAX];
123*d6dfd9efSDavid du Colombier 
124*d6dfd9efSDavid du Colombier 	user = (ureg->srr1 & MSR_PR) != 0;
125*d6dfd9efSDavid du Colombier 	if(!user){
126*d6dfd9efSDavid du Colombier //		if(vmapsync(addr))
127*d6dfd9efSDavid du Colombier //			return;
128*d6dfd9efSDavid du Colombier //		if(addr >= USTKTOP)
129*d6dfd9efSDavid du Colombier //			panic("kernel fault: bad address pc=%.8#lux addr=%.8#lux",
130*d6dfd9efSDavid du Colombier //				ureg->pc, addr);
131*d6dfd9efSDavid du Colombier 		if(up == nil)
132*d6dfd9efSDavid du Colombier 			panic("kernel fault: no user process pc=%.8#lux addr=%.8#lux",
133*d6dfd9efSDavid du Colombier 				ureg->pc, addr);
134*d6dfd9efSDavid du Colombier 	}
135*d6dfd9efSDavid du Colombier 	if(up == nil)
136*d6dfd9efSDavid du Colombier 		panic("user fault: up=0 pc=%.8#lux addr=%.8#lux", ureg->pc, addr);
137*d6dfd9efSDavid du Colombier 	insyscall = 0;
138*d6dfd9efSDavid du Colombier 	if (up) {
139*d6dfd9efSDavid du Colombier 		insyscall = up->insyscall;
140*d6dfd9efSDavid du Colombier 		up->insyscall = 1;
141*d6dfd9efSDavid du Colombier 	}
142*d6dfd9efSDavid du Colombier 	n = fault(addr, read);		/* repair user-mode fault */
143*d6dfd9efSDavid du Colombier 	if(n < 0){
144*d6dfd9efSDavid du Colombier 		if(!user){
145*d6dfd9efSDavid du Colombier 			dumpregs(ureg);
146*d6dfd9efSDavid du Colombier 			panic("fault: addr %#lux", addr);
147*d6dfd9efSDavid du Colombier 		}else if(0)
148*d6dfd9efSDavid du Colombier 			dumpregs(ureg);
149*d6dfd9efSDavid du Colombier 		seprint(buf, buf + sizeof buf, "sys: trap: fault %s addr=%#lux",
150*d6dfd9efSDavid du Colombier 			read? "read" : "write", addr);
151*d6dfd9efSDavid du Colombier 		postnote(up, 1, buf, NDebug);
152*d6dfd9efSDavid du Colombier 	}
153*d6dfd9efSDavid du Colombier 	if (up)
154*d6dfd9efSDavid du Colombier 		up->insyscall = insyscall;
155*d6dfd9efSDavid du Colombier }
156*d6dfd9efSDavid du Colombier 
157*d6dfd9efSDavid du Colombier static void
setlights(int user)158*d6dfd9efSDavid du Colombier setlights(int user)
159*d6dfd9efSDavid du Colombier {
160*d6dfd9efSDavid du Colombier 	if (up == nil)
161*d6dfd9efSDavid du Colombier 		lightstate(Ledidle);
162*d6dfd9efSDavid du Colombier 	else
163*d6dfd9efSDavid du Colombier 		lightstate(user == 0? Ledkern: Leduser);
164*d6dfd9efSDavid du Colombier }
165*d6dfd9efSDavid du Colombier 
166*d6dfd9efSDavid du Colombier void
kexit(Ureg *)167*d6dfd9efSDavid du Colombier kexit(Ureg*)
168*d6dfd9efSDavid du Colombier {
169*d6dfd9efSDavid du Colombier 	uvlong t;
170*d6dfd9efSDavid du Colombier 	Tos *tos;
171*d6dfd9efSDavid du Colombier 
172*d6dfd9efSDavid du Colombier 	/* precise time accounting, kernel exit */
173*d6dfd9efSDavid du Colombier 	tos = (Tos*)(USTKTOP-sizeof(Tos));
174*d6dfd9efSDavid du Colombier 	cycles(&t);
175*d6dfd9efSDavid du Colombier 	tos->kcycles += t - up->kentry;
176*d6dfd9efSDavid du Colombier 	tos->pcycles = up->pcycles;
177*d6dfd9efSDavid du Colombier 	tos->pid = up->pid;
178*d6dfd9efSDavid du Colombier // surely only need to set tos->pid on rfork and exec?
179*d6dfd9efSDavid du Colombier }
180*d6dfd9efSDavid du Colombier 
181*d6dfd9efSDavid du Colombier void
trap(Ureg * ur)182*d6dfd9efSDavid du Colombier trap(Ureg *ur)
183*d6dfd9efSDavid du Colombier {
184*d6dfd9efSDavid du Colombier 	int ecode, user, v;
185*d6dfd9efSDavid du Colombier 	u32int esr;
186*d6dfd9efSDavid du Colombier 	char buf[ERRMAX];
187*d6dfd9efSDavid du Colombier 
188*d6dfd9efSDavid du Colombier 	if (ur == nil)
189*d6dfd9efSDavid du Colombier 		panic("trap: nil ur");
190*d6dfd9efSDavid du Colombier 	v = ur->cause;
191*d6dfd9efSDavid du Colombier 	lightstate(Ledtrap);
192*d6dfd9efSDavid du Colombier 	ur->cause &= 0xFFE0;
193*d6dfd9efSDavid du Colombier 	ecode = ur->cause;
194*d6dfd9efSDavid du Colombier 	esr = getesr();
195*d6dfd9efSDavid du Colombier 	clrmchk();
196*d6dfd9efSDavid du Colombier 
197*d6dfd9efSDavid du Colombier 	user = (ur->srr1 & MSR_PR) != 0;
198*d6dfd9efSDavid du Colombier 	if(user){
199*d6dfd9efSDavid du Colombier 		cycles(&up->kentry);
200*d6dfd9efSDavid du Colombier 		up->dbgreg = ur;
201*d6dfd9efSDavid du Colombier 	}
202*d6dfd9efSDavid du Colombier 	switch(ecode){
203*d6dfd9efSDavid du Colombier 	case INT_SYSCALL:
204*d6dfd9efSDavid du Colombier 		if(!user)
205*d6dfd9efSDavid du Colombier 			panic("syscall in kernel: srr1 %#4.4luX pc %#p",
206*d6dfd9efSDavid du Colombier 				ur->srr1, ur->pc);
207*d6dfd9efSDavid du Colombier 		syscall(ur);
208*d6dfd9efSDavid du Colombier 		setlights(user);
209*d6dfd9efSDavid du Colombier 		return;		/* syscall() calls notify itself */
210*d6dfd9efSDavid du Colombier 
211*d6dfd9efSDavid du Colombier 	case INT_PIT:
212*d6dfd9efSDavid du Colombier 		m->intr++;
213*d6dfd9efSDavid du Colombier 		clockintr(ur);
214*d6dfd9efSDavid du Colombier 		break;
215*d6dfd9efSDavid du Colombier 
216*d6dfd9efSDavid du Colombier 	case INT_WDT:
217*d6dfd9efSDavid du Colombier 		puttsr(~0);
218*d6dfd9efSDavid du Colombier 		panic("watchdog timer went off at pc %#lux", ur->pc);
219*d6dfd9efSDavid du Colombier 		break;
220*d6dfd9efSDavid du Colombier 
221*d6dfd9efSDavid du Colombier 	case INT_MCHECK:
222*d6dfd9efSDavid du Colombier 		if (probing && !user) {
223*d6dfd9efSDavid du Colombier 			if (trapped++ > 0)
224*d6dfd9efSDavid du Colombier 				panic("trap: recursive probe");
225*d6dfd9efSDavid du Colombier 			break;		/* continue at next instruction */
226*d6dfd9efSDavid du Colombier 		}
227*d6dfd9efSDavid du Colombier 		if(esr & ESR_MCI){
228*d6dfd9efSDavid du Colombier 			iprint("mcheck-mci %lux\n", ur->pc);
229*d6dfd9efSDavid du Colombier 			faultpower(ur, ur->pc, 1);
230*d6dfd9efSDavid du Colombier 			break;
231*d6dfd9efSDavid du Colombier 		}
232*d6dfd9efSDavid du Colombier 		iprint("mcheck %#lux esr=%#ux dear=%#ux\n", ur->pc, esr, getdear());
233*d6dfd9efSDavid du Colombier 		ur->pc -= 4;	/* back up to faulting instruction */
234*d6dfd9efSDavid du Colombier 		/* fall through */
235*d6dfd9efSDavid du Colombier 	case INT_DSI:
236*d6dfd9efSDavid du Colombier 	case INT_DMISS:
237*d6dfd9efSDavid du Colombier 		faultpower(ur, getdear(), !(esr&ESR_DST));
238*d6dfd9efSDavid du Colombier 		break;
239*d6dfd9efSDavid du Colombier 
240*d6dfd9efSDavid du Colombier 	case INT_ISI:
241*d6dfd9efSDavid du Colombier 	case INT_IMISS:
242*d6dfd9efSDavid du Colombier 		faultpower(ur, ur->pc, 1);
243*d6dfd9efSDavid du Colombier 		break;
244*d6dfd9efSDavid du Colombier 
245*d6dfd9efSDavid du Colombier 	case INT_EI:
246*d6dfd9efSDavid du Colombier 		m->intr++;
247*d6dfd9efSDavid du Colombier 		intr(ur);
248*d6dfd9efSDavid du Colombier 		break;
249*d6dfd9efSDavid du Colombier 
250*d6dfd9efSDavid du Colombier 	case 0:
251*d6dfd9efSDavid du Colombier 		puttsr(~0);
252*d6dfd9efSDavid du Colombier 		if (v == 0)
253*d6dfd9efSDavid du Colombier 			panic("watchdog reset? probable jump via "
254*d6dfd9efSDavid du Colombier 				"zeroed pointer; pc %#lux lr %#lux",
255*d6dfd9efSDavid du Colombier 				ur->pc, ur->lr);
256*d6dfd9efSDavid du Colombier 		else
257*d6dfd9efSDavid du Colombier 			panic("watchdog reset? interrupt at vector zero; "
258*d6dfd9efSDavid du Colombier 				"pc %#lux lr %#lux", ur->pc, ur->lr);
259*d6dfd9efSDavid du Colombier 		break;
260*d6dfd9efSDavid du Colombier 
261*d6dfd9efSDavid du Colombier 	case INT_DEBUG + VECSIZE:
262*d6dfd9efSDavid du Colombier 		panic("reset");
263*d6dfd9efSDavid du Colombier 		break;
264*d6dfd9efSDavid du Colombier 
265*d6dfd9efSDavid du Colombier 	case INT_PROG:
266*d6dfd9efSDavid du Colombier 		if(esr & ESR_PIL && user){
267*d6dfd9efSDavid du Colombier 			if(fpuemu(ur))
268*d6dfd9efSDavid du Colombier 				break;
269*d6dfd9efSDavid du Colombier 			/* otherwise it's an illegal instruction */
270*d6dfd9efSDavid du Colombier 		}
271*d6dfd9efSDavid du Colombier 		/* fall through */
272*d6dfd9efSDavid du Colombier 	default:
273*d6dfd9efSDavid du Colombier 		if(user){
274*d6dfd9efSDavid du Colombier 			spllo();
275*d6dfd9efSDavid du Colombier 			sprint(buf, "sys: trap: %s", excname(ecode, esr));
276*d6dfd9efSDavid du Colombier 			postnote(up, 1, buf, NDebug);
277*d6dfd9efSDavid du Colombier 			break;
278*d6dfd9efSDavid du Colombier 		}
279*d6dfd9efSDavid du Colombier 		splhi();
280*d6dfd9efSDavid du Colombier 		print("kernel %s; vector=%#ux pc=%#lux\n",
281*d6dfd9efSDavid du Colombier 			excname(ecode, esr), ecode, ur->pc);
282*d6dfd9efSDavid du Colombier 		if (ecode == 0)
283*d6dfd9efSDavid du Colombier 			print("probable jump via zeroed pointer; pc %#lux lr %#lux\n",
284*d6dfd9efSDavid du Colombier 				ur->pc, ur->lr);
285*d6dfd9efSDavid du Colombier 		dumpregs(ur);
286*d6dfd9efSDavid du Colombier 		dumpstack();
287*d6dfd9efSDavid du Colombier 		if(m->machno == 0)
288*d6dfd9efSDavid du Colombier 			spllo();
289*d6dfd9efSDavid du Colombier 		exit(1);
290*d6dfd9efSDavid du Colombier 	}
291*d6dfd9efSDavid du Colombier 	splhi();
292*d6dfd9efSDavid du Colombier 	setlights(user);
293*d6dfd9efSDavid du Colombier 
294*d6dfd9efSDavid du Colombier 	/* delaysched set because we held a lock or because our quantum ended */
295*d6dfd9efSDavid du Colombier 	if(up && up->delaysched && ecode == INT_PIT){
296*d6dfd9efSDavid du Colombier 		sched();
297*d6dfd9efSDavid du Colombier 		splhi();
298*d6dfd9efSDavid du Colombier 		setlights(user);
299*d6dfd9efSDavid du Colombier 	}
300*d6dfd9efSDavid du Colombier 
301*d6dfd9efSDavid du Colombier 	if(user){
302*d6dfd9efSDavid du Colombier 		if(up->procctl || up->nnote)
303*d6dfd9efSDavid du Colombier 			notify(ur);
304*d6dfd9efSDavid du Colombier 		kexit(ur);
305*d6dfd9efSDavid du Colombier 	}
306*d6dfd9efSDavid du Colombier }
307*d6dfd9efSDavid du Colombier 
308*d6dfd9efSDavid du Colombier void
trapinit(void)309*d6dfd9efSDavid du Colombier trapinit(void)
310*d6dfd9efSDavid du Colombier {
311*d6dfd9efSDavid du Colombier 	int i;
312*d6dfd9efSDavid du Colombier 
313*d6dfd9efSDavid du Colombier 	clrmchk();
314*d6dfd9efSDavid du Colombier 	intrinit();
315*d6dfd9efSDavid du Colombier 
316*d6dfd9efSDavid du Colombier 	/*
317*d6dfd9efSDavid du Colombier 	 * set all exceptions to trap by default
318*d6dfd9efSDavid du Colombier 	 */
319*d6dfd9efSDavid du Colombier 	for(i = 0; i < INT_DEBUG + VECSIZE; i += VECSIZE)
320*d6dfd9efSDavid du Colombier 		sethvec(VECBASE + i, trapvec);
321*d6dfd9efSDavid du Colombier 
322*d6dfd9efSDavid du Colombier 	/*
323*d6dfd9efSDavid du Colombier 	 * set exception handlers
324*d6dfd9efSDavid du Colombier 	 */
325*d6dfd9efSDavid du Colombier 	sethvec(VECBASE + INT_RESET, trapcritvec);
326*d6dfd9efSDavid du Colombier 	sethvec(VECBASE + INT_MCHECK, trapcritvec);
327*d6dfd9efSDavid du Colombier 	sethvec(VECBASE + INT_DSI, trapvec);
328*d6dfd9efSDavid du Colombier 	sethvec(VECBASE + INT_ISI, trapvec);
329*d6dfd9efSDavid du Colombier 	sethvec(VECBASE + INT_EI, trapvec);
330*d6dfd9efSDavid du Colombier 	sethvec(VECBASE + INT_ALIGN, trapvec);
331*d6dfd9efSDavid du Colombier 	sethvec(VECBASE + INT_PROG, trapvec);
332*d6dfd9efSDavid du Colombier 	sethvec(VECBASE + INT_FPU, trapvec);
333*d6dfd9efSDavid du Colombier 	sethvec(VECBASE + INT_SYSCALL, trapvec);
334*d6dfd9efSDavid du Colombier 	sethvec(VECBASE + INT_APU, trapvec);
335*d6dfd9efSDavid du Colombier 	sethvec(VECBASE + INT_PIT, trapvec);
336*d6dfd9efSDavid du Colombier 	sethvec(VECBASE + INT_FIT, trapvec);
337*d6dfd9efSDavid du Colombier 	sethvec(VECBASE + INT_WDT, trapcritvec);
338*d6dfd9efSDavid du Colombier 	sethvec2(VECBASE + INT_DMISS, dtlbmiss);
339*d6dfd9efSDavid du Colombier 	sethvec2(VECBASE + INT_IMISS, itlbmiss);
340*d6dfd9efSDavid du Colombier 	sethvec(VECBASE + INT_DEBUG, trapcritvec);
341*d6dfd9efSDavid du Colombier 	/*
342*d6dfd9efSDavid du Colombier 	 * the last word of sram (0xfffffffc) contains a branch
343*d6dfd9efSDavid du Colombier 	 * to the start of sram beyond the vectors (0xfffe2100),
344*d6dfd9efSDavid du Colombier 	 * which initially will be the start of our bootstrap loader.
345*d6dfd9efSDavid du Colombier 	 * overwrite it so that we can get control if the machine should
346*d6dfd9efSDavid du Colombier 	 * reset.
347*d6dfd9efSDavid du Colombier 	 */
348*d6dfd9efSDavid du Colombier 	sethvec(VECBASE + INT_DEBUG + VECSIZE, trapcritvec);
349*d6dfd9efSDavid du Colombier 	sethvec(0, trapcritvec);
350*d6dfd9efSDavid du Colombier 	sync();
351*d6dfd9efSDavid du Colombier 
352*d6dfd9efSDavid du Colombier 	putevpr(VECBASE);
353*d6dfd9efSDavid du Colombier 	sync();
354*d6dfd9efSDavid du Colombier 
355*d6dfd9efSDavid du Colombier 	putmsr(getmsr() | MSR_ME);
356*d6dfd9efSDavid du Colombier 	sync();
357*d6dfd9efSDavid du Colombier }
358*d6dfd9efSDavid du Colombier 
359*d6dfd9efSDavid du Colombier static char*
excname(ulong ivoff,u32int esr)360*d6dfd9efSDavid du Colombier excname(ulong ivoff, u32int esr)
361*d6dfd9efSDavid du Colombier {
362*d6dfd9efSDavid du Colombier 	int i;
363*d6dfd9efSDavid du Colombier 
364*d6dfd9efSDavid du Colombier 	if(ivoff == INT_PROG){
365*d6dfd9efSDavid du Colombier 		if(esr & ESR_PIL)
366*d6dfd9efSDavid du Colombier 			return "illegal instruction";
367*d6dfd9efSDavid du Colombier 		if(esr & ESR_PPR)
368*d6dfd9efSDavid du Colombier 			return "privileged";
369*d6dfd9efSDavid du Colombier 		if(esr & ESR_PTR)
370*d6dfd9efSDavid du Colombier 			return "trap with successful compare";
371*d6dfd9efSDavid du Colombier 		if(esr & ESR_PEU)
372*d6dfd9efSDavid du Colombier 			return "unimplemented APU/FPU";
373*d6dfd9efSDavid du Colombier 		if(esr & ESR_PAP)
374*d6dfd9efSDavid du Colombier 			return "APU exception";
375*d6dfd9efSDavid du Colombier 		if(esr & ESR_U0F)
376*d6dfd9efSDavid du Colombier 			return "data storage: u0 fault";
377*d6dfd9efSDavid du Colombier 	}
378*d6dfd9efSDavid du Colombier 	for(i=0; intcause[i].off != 0; i++)
379*d6dfd9efSDavid du Colombier 		if(intcause[i].off == ivoff)
380*d6dfd9efSDavid du Colombier 			break;
381*d6dfd9efSDavid du Colombier 	return intcause[i].name;
382*d6dfd9efSDavid du Colombier }
383*d6dfd9efSDavid du Colombier 
384*d6dfd9efSDavid du Colombier /*
385*d6dfd9efSDavid du Colombier  * Fill in enough of Ureg to get a stack trace, and call a function.
386*d6dfd9efSDavid du Colombier  * Used by debugging interface rdb.
387*d6dfd9efSDavid du Colombier  */
388*d6dfd9efSDavid du Colombier void
callwithureg(void (* fn)(Ureg *))389*d6dfd9efSDavid du Colombier callwithureg(void (*fn)(Ureg*))
390*d6dfd9efSDavid du Colombier {
391*d6dfd9efSDavid du Colombier 	Ureg ureg;
392*d6dfd9efSDavid du Colombier 
393*d6dfd9efSDavid du Colombier 	ureg.pc = getcallerpc(&fn);
394*d6dfd9efSDavid du Colombier 	ureg.sp = PTR2UINT(&fn);
395*d6dfd9efSDavid du Colombier 	fn(&ureg);
396*d6dfd9efSDavid du Colombier }
397*d6dfd9efSDavid du Colombier 
398*d6dfd9efSDavid du Colombier void
dumpstack(void)399*d6dfd9efSDavid du Colombier dumpstack(void)
400*d6dfd9efSDavid du Colombier {
401*d6dfd9efSDavid du Colombier 	ulong l, v;
402*d6dfd9efSDavid du Colombier 	int i;
403*d6dfd9efSDavid du Colombier 
404*d6dfd9efSDavid du Colombier 	if(up == 0)
405*d6dfd9efSDavid du Colombier 		return;
406*d6dfd9efSDavid du Colombier 	i = 0;
407*d6dfd9efSDavid du Colombier 	for(l=(ulong)&l; l<(ulong)(up->kstack+KSTACK); l+=4){
408*d6dfd9efSDavid du Colombier 		v = *(ulong*)l;
409*d6dfd9efSDavid du Colombier 		if(KTZERO < v && v < (ulong)etext){
410*d6dfd9efSDavid du Colombier 			iprint("%lux=%lux, ", l, v);
411*d6dfd9efSDavid du Colombier 			if(i++ == 4){
412*d6dfd9efSDavid du Colombier 				iprint("\n");
413*d6dfd9efSDavid du Colombier 				i = 0;
414*d6dfd9efSDavid du Colombier 			}
415*d6dfd9efSDavid du Colombier 		}
416*d6dfd9efSDavid du Colombier 	}
417*d6dfd9efSDavid du Colombier }
418*d6dfd9efSDavid du Colombier 
419*d6dfd9efSDavid du Colombier void
dumpregs(Ureg * ureg)420*d6dfd9efSDavid du Colombier dumpregs(Ureg *ureg)
421*d6dfd9efSDavid du Colombier {
422*d6dfd9efSDavid du Colombier 	int i;
423*d6dfd9efSDavid du Colombier 	uintptr *l;
424*d6dfd9efSDavid du Colombier 
425*d6dfd9efSDavid du Colombier 	splhi();		/* prevent recursive dumps */
426*d6dfd9efSDavid du Colombier 	if(up != nil)
427*d6dfd9efSDavid du Colombier 		iprint("cpu%d: registers for %s %ld\n",
428*d6dfd9efSDavid du Colombier 			m->machno, up->text, up->pid);
429*d6dfd9efSDavid du Colombier 	else
430*d6dfd9efSDavid du Colombier 		iprint("cpu%d: registers for kernel\n", m->machno);
431*d6dfd9efSDavid du Colombier 
432*d6dfd9efSDavid du Colombier 	if (ureg == nil) {
433*d6dfd9efSDavid du Colombier 		iprint("nil ureg, no dump\n");
434*d6dfd9efSDavid du Colombier 		return;
435*d6dfd9efSDavid du Colombier 	}
436*d6dfd9efSDavid du Colombier 	l = &ureg->cause;
437*d6dfd9efSDavid du Colombier 	for(i = 0; i < nelem(regname); i += 2, l += 2)
438*d6dfd9efSDavid du Colombier 		iprint("%s\t%.8p\t%s\t%.8p\n", regname[i], l[0], regname[i+1], l[1]);
439*d6dfd9efSDavid du Colombier }
440*d6dfd9efSDavid du Colombier 
441*d6dfd9efSDavid du Colombier static void
linkproc(void)442*d6dfd9efSDavid du Colombier linkproc(void)
443*d6dfd9efSDavid du Colombier {
444*d6dfd9efSDavid du Colombier 	spllo();
445*d6dfd9efSDavid du Colombier 	up->kpfun(up->kparg);
446*d6dfd9efSDavid du Colombier 	pexit("", 0);
447*d6dfd9efSDavid du Colombier }
448*d6dfd9efSDavid du Colombier 
449*d6dfd9efSDavid du Colombier void
kprocchild(Proc * p,void (* func)(void *),void * arg)450*d6dfd9efSDavid du Colombier kprocchild(Proc* p, void (*func)(void*), void* arg)
451*d6dfd9efSDavid du Colombier {
452*d6dfd9efSDavid du Colombier 	p->sched.pc = PTR2UINT(linkproc);
453*d6dfd9efSDavid du Colombier 	p->sched.sp = PTR2UINT(p->kstack+KSTACK);
454*d6dfd9efSDavid du Colombier 	p->sched.sp = STACKALIGN(p->sched.sp);
455*d6dfd9efSDavid du Colombier 
456*d6dfd9efSDavid du Colombier 	p->kpfun = func;
457*d6dfd9efSDavid du Colombier 	p->kparg = arg;
458*d6dfd9efSDavid du Colombier }
459*d6dfd9efSDavid du Colombier 
460*d6dfd9efSDavid du Colombier uintptr
userpc(void)461*d6dfd9efSDavid du Colombier userpc(void)
462*d6dfd9efSDavid du Colombier {
463*d6dfd9efSDavid du Colombier 	Ureg *ureg = up->dbgreg;
464*d6dfd9efSDavid du Colombier 	return ureg->pc;
465*d6dfd9efSDavid du Colombier }
466*d6dfd9efSDavid du Colombier 
467*d6dfd9efSDavid du Colombier /*
468*d6dfd9efSDavid du Colombier  * This routine must save the values of registers the user is not
469*d6dfd9efSDavid du Colombier  * permitted to write from devproc and then restore the saved values
470*d6dfd9efSDavid du Colombier  * before returning
471*d6dfd9efSDavid du Colombier  */
472*d6dfd9efSDavid du Colombier void
setregisters(Ureg * ureg,char * pureg,char * uva,int n)473*d6dfd9efSDavid du Colombier setregisters(Ureg *ureg, char *pureg, char *uva, int n)
474*d6dfd9efSDavid du Colombier {
475*d6dfd9efSDavid du Colombier 	u32int status;
476*d6dfd9efSDavid du Colombier 
477*d6dfd9efSDavid du Colombier 	status = ureg->status;
478*d6dfd9efSDavid du Colombier 	memmove(pureg, uva, n);
479*d6dfd9efSDavid du Colombier 	ureg->status = status;
480*d6dfd9efSDavid du Colombier }
481*d6dfd9efSDavid du Colombier 
482*d6dfd9efSDavid du Colombier /*
483*d6dfd9efSDavid du Colombier  * Give enough context in the ureg to produce a kernel stack for
484*d6dfd9efSDavid du Colombier  * a sleeping process
485*d6dfd9efSDavid du Colombier  */
486*d6dfd9efSDavid du Colombier void
setkernur(Ureg * ureg,Proc * p)487*d6dfd9efSDavid du Colombier setkernur(Ureg* ureg, Proc* p)
488*d6dfd9efSDavid du Colombier {
489*d6dfd9efSDavid du Colombier 	ureg->pc = p->sched.pc;
490*d6dfd9efSDavid du Colombier 	ureg->sp = p->sched.sp+BY2SE;
491*d6dfd9efSDavid du Colombier }
492*d6dfd9efSDavid du Colombier 
493*d6dfd9efSDavid du Colombier uintptr
dbgpc(Proc * p)494*d6dfd9efSDavid du Colombier dbgpc(Proc* p)
495*d6dfd9efSDavid du Colombier {
496*d6dfd9efSDavid du Colombier 	Ureg *ureg;
497*d6dfd9efSDavid du Colombier 
498*d6dfd9efSDavid du Colombier 	ureg = p->dbgreg;
499*d6dfd9efSDavid du Colombier 	if(ureg == 0)
500*d6dfd9efSDavid du Colombier 		return 0;
501*d6dfd9efSDavid du Colombier 	return ureg->pc;
502*d6dfd9efSDavid du Colombier }
503*d6dfd9efSDavid du Colombier 
504*d6dfd9efSDavid du Colombier vlong
probeaddr(uintptr addr)505*d6dfd9efSDavid du Colombier probeaddr(uintptr addr)
506*d6dfd9efSDavid du Colombier {
507*d6dfd9efSDavid du Colombier 	vlong v;
508*d6dfd9efSDavid du Colombier 	static Lock fltlck;
509*d6dfd9efSDavid du Colombier 
510*d6dfd9efSDavid du Colombier 	ilock(&fltlck);
511*d6dfd9efSDavid du Colombier 	trapped = 0;
512*d6dfd9efSDavid du Colombier 	probing = 1;
513*d6dfd9efSDavid du Colombier 	barriers();
514*d6dfd9efSDavid du Colombier 
515*d6dfd9efSDavid du Colombier 	v = *(ulong *)addr;	/* this may cause a fault */
516*d6dfd9efSDavid du Colombier 	USED(probing);
517*d6dfd9efSDavid du Colombier 	barriers();
518*d6dfd9efSDavid du Colombier 
519*d6dfd9efSDavid du Colombier 	probing = 0;
520*d6dfd9efSDavid du Colombier 	barriers();
521*d6dfd9efSDavid du Colombier 	if (trapped)
522*d6dfd9efSDavid du Colombier 		v = -1;
523*d6dfd9efSDavid du Colombier 	iunlock(&fltlck);
524*d6dfd9efSDavid du Colombier 	return v;
525*d6dfd9efSDavid du Colombier }
526