xref: /plan9-contrib/sys/src/boot/vt4/trap.c (revision da917039c7f233c1a27d212bf012c6afa758af39)
1*da917039SDavid du Colombier /*
2*da917039SDavid du Colombier  * power pc 405 traps
3*da917039SDavid du Colombier  */
4*da917039SDavid du Colombier #include "include.h"
5*da917039SDavid du Colombier 
6*da917039SDavid du Colombier static struct {
7*da917039SDavid du Colombier 	ulong off;
8*da917039SDavid du Colombier 	char *name;
9*da917039SDavid du Colombier } intcause[] = {
10*da917039SDavid du Colombier 	{ INT_RESET,	"system reset" },
11*da917039SDavid du Colombier 	{ INT_MCHECK,	"machine check" },
12*da917039SDavid du Colombier 	{ INT_DSI,	"data access" },
13*da917039SDavid du Colombier 	{ INT_ISI,	"instruction access" },
14*da917039SDavid du Colombier 	{ INT_EI,	"external interrupt" },
15*da917039SDavid du Colombier 	{ INT_ALIGN,	"alignment" },
16*da917039SDavid du Colombier 	{ INT_PROG,	"program exception" },
17*da917039SDavid du Colombier 	{ INT_FPU,	"floating-point unavailable" },
18*da917039SDavid du Colombier 	{ INT_DEC,	"decrementer" },
19*da917039SDavid du Colombier 	{ INT_SYSCALL,	"system call" },
20*da917039SDavid du Colombier 	{ INT_TRACE,	"trace trap" },
21*da917039SDavid du Colombier 	{ INT_FPA,	"floating point unavailable" },
22*da917039SDavid du Colombier 	{ INT_APU,	"auxiliary processor unavailable" },
23*da917039SDavid du Colombier 	{ INT_PIT,	"programmable interval timer interrrupt" },
24*da917039SDavid du Colombier 	{ INT_FIT,	"fixed interval timer interrupt" },
25*da917039SDavid du Colombier 	{ INT_WDT,	"watch dog timer interrupt" },
26*da917039SDavid du Colombier 	{ INT_DMISS,	"data TLB miss" },
27*da917039SDavid du Colombier 	{ INT_IMISS,	"instruction TLB miss" },
28*da917039SDavid du Colombier 	{ INT_DEBUG,	"debug interrupt" },
29*da917039SDavid du Colombier 	{ 0,		"unknown interrupt" }
30*da917039SDavid du Colombier };
31*da917039SDavid du Colombier 
32*da917039SDavid du Colombier static char *excname(ulong, u32int);
33*da917039SDavid du Colombier 
34*da917039SDavid du Colombier char *regname[]={
35*da917039SDavid du Colombier 	"CAUSE",	"SRR1",
36*da917039SDavid du Colombier 	"PC",		"GOK",
37*da917039SDavid du Colombier 	"LR",		"CR",
38*da917039SDavid du Colombier 	"XER",	"CTR",
39*da917039SDavid du Colombier 	"R0",		"R1",
40*da917039SDavid du Colombier 	"R2",		"R3",
41*da917039SDavid du Colombier 	"R4",		"R5",
42*da917039SDavid du Colombier 	"R6",		"R7",
43*da917039SDavid du Colombier 	"R8",		"R9",
44*da917039SDavid du Colombier 	"R10",	"R11",
45*da917039SDavid du Colombier 	"R12",	"R13",
46*da917039SDavid du Colombier 	"R14",	"R15",
47*da917039SDavid du Colombier 	"R16",	"R17",
48*da917039SDavid du Colombier 	"R18",	"R19",
49*da917039SDavid du Colombier 	"R20",	"R21",
50*da917039SDavid du Colombier 	"R22",	"R23",
51*da917039SDavid du Colombier 	"R24",	"R25",
52*da917039SDavid du Colombier 	"R26",	"R27",
53*da917039SDavid du Colombier 	"R28",	"R29",
54*da917039SDavid du Colombier 	"R30",	"R31",
55*da917039SDavid du Colombier };
56*da917039SDavid du Colombier 
57*da917039SDavid du Colombier static int probing, trapped;
58*da917039SDavid du Colombier static jmp_buf probenv;
59*da917039SDavid du Colombier 
60*da917039SDavid du Colombier static void
sethvec(uintptr v,void (* r)(void))61*da917039SDavid du Colombier sethvec(uintptr v, void (*r)(void))
62*da917039SDavid du Colombier {
63*da917039SDavid du Colombier 	u32int *vp;
64*da917039SDavid du Colombier 	ulong o, ra;
65*da917039SDavid du Colombier 	long d;
66*da917039SDavid du Colombier 
67*da917039SDavid du Colombier 	vp = UINT2PTR(v);
68*da917039SDavid du Colombier 	vp[0] = 0x7c1043a6;			/* MOVW R0, SPR(SPRG0) */
69*da917039SDavid du Colombier 	vp[1] = 0x7c0802a6;			/* MOVW LR, R0 */
70*da917039SDavid du Colombier 	vp[2] = 0x7c1243a6;			/* MOVW R0, SPR(SPRG2) */
71*da917039SDavid du Colombier 	d = (uchar*)r - (uchar*)&vp[3];
72*da917039SDavid du Colombier 	o = (ulong)d >> 25;
73*da917039SDavid du Colombier 	if(o != 0 && o != 0x7F){
74*da917039SDavid du Colombier 		/* a branch too far: running from ROM */
75*da917039SDavid du Colombier 		ra = (ulong)r;
76*da917039SDavid du Colombier 		vp[3] = (15<<26)|(ra>>16);	/* MOVW $r&~0xFFFF, R0 */
77*da917039SDavid du Colombier 		vp[4] = (24<<26)|(ra&0xFFFF);	/* OR $r&0xFFFF, R0 */
78*da917039SDavid du Colombier 		vp[5] = 0x7c0803a6;		/* MOVW	R0, LR */
79*da917039SDavid du Colombier 		vp[6] = 0x4e800021;		/* BL (LR) */
80*da917039SDavid du Colombier 	}
81*da917039SDavid du Colombier 	else
82*da917039SDavid du Colombier 		vp[3] = (18<<26)|(d&0x3FFFFFC)|1;	/* BL (relative) */
83*da917039SDavid du Colombier 	dcflush(PTR2UINT(vp), 8*sizeof(u32int));
84*da917039SDavid du Colombier }
85*da917039SDavid du Colombier 
86*da917039SDavid du Colombier static void
sethvec2(uintptr v,void (* r)(void))87*da917039SDavid du Colombier sethvec2(uintptr v, void (*r)(void))
88*da917039SDavid du Colombier {
89*da917039SDavid du Colombier 	u32int *vp;
90*da917039SDavid du Colombier 	long d;
91*da917039SDavid du Colombier 
92*da917039SDavid du Colombier 	vp = UINT2PTR(v);
93*da917039SDavid du Colombier 	d = (uchar*)r - (uchar*)&vp[0];
94*da917039SDavid du Colombier 	vp[0] = (18<<26)|(d & 0x3FFFFFC);	/* B (relative) */
95*da917039SDavid du Colombier 	dcflush(PTR2UINT(vp), sizeof(*vp));
96*da917039SDavid du Colombier }
97*da917039SDavid du Colombier 
98*da917039SDavid du Colombier extern uintptr vectorbase;
99*da917039SDavid du Colombier 
100*da917039SDavid du Colombier void
trapinit(void)101*da917039SDavid du Colombier trapinit(void)
102*da917039SDavid du Colombier {
103*da917039SDavid du Colombier 	uintptr e, s;
104*da917039SDavid du Colombier 
105*da917039SDavid du Colombier 	putesr(0);				/* clears machine check */
106*da917039SDavid du Colombier 	coherence();
107*da917039SDavid du Colombier 
108*da917039SDavid du Colombier 	/*
109*da917039SDavid du Colombier 	 * set all exceptions to trap
110*da917039SDavid du Colombier 	 */
111*da917039SDavid du Colombier 	s = vectorbase + 0x100;		/* Mach is at vectorbase */
112*da917039SDavid du Colombier 	/* 0x2000 is last documented 405 vector */
113*da917039SDavid du Colombier 	for(e = s+0x2100; s < e; s += 0x100)
114*da917039SDavid du Colombier 		sethvec(s, trapvec);
115*da917039SDavid du Colombier 	coherence();
116*da917039SDavid du Colombier 
117*da917039SDavid du Colombier 	/*
118*da917039SDavid du Colombier 	 * set exception handlers
119*da917039SDavid du Colombier 	 */
120*da917039SDavid du Colombier //	sethvec(vectorbase + INT_RESET, trapcritvec);
121*da917039SDavid du Colombier //	sethvec(vectorbase + INT_MCHECK, trapcritvec);
122*da917039SDavid du Colombier 	sethvec(vectorbase + INT_DSI, trapvec);
123*da917039SDavid du Colombier 	sethvec(vectorbase + INT_ISI, trapvec);
124*da917039SDavid du Colombier 	sethvec(vectorbase + INT_EI, trapvec); /* external non-critical intrs */
125*da917039SDavid du Colombier 	sethvec(vectorbase + INT_ALIGN, trapvec);
126*da917039SDavid du Colombier 	sethvec(vectorbase + INT_PROG, trapvec);
127*da917039SDavid du Colombier 	sethvec(vectorbase + INT_FPU, trapvec);
128*da917039SDavid du Colombier 	sethvec(vectorbase + INT_SYSCALL, trapvec);
129*da917039SDavid du Colombier 	sethvec(vectorbase + INT_APU, trapvec);
130*da917039SDavid du Colombier 	sethvec(vectorbase + INT_PIT, trapvec);
131*da917039SDavid du Colombier 	sethvec(vectorbase + INT_FIT, trapvec);
132*da917039SDavid du Colombier //	sethvec(vectorbase + INT_WDT, trapcritvec);
133*da917039SDavid du Colombier //	sethvec2(vectorbase + INT_DMISS, dtlbmiss);
134*da917039SDavid du Colombier //	sethvec2(vectorbase + INT_IMISS, itlbmiss);
135*da917039SDavid du Colombier //	sethvec(vectorbase + INT_DEBUG, trapcritvec);
136*da917039SDavid du Colombier 	syncall();
137*da917039SDavid du Colombier 
138*da917039SDavid du Colombier 	/* l.s already set EVPR */
139*da917039SDavid du Colombier 	putmsr(getmsr() | MSR_CE | MSR_ME);	/* no MSR_EE here */
140*da917039SDavid du Colombier 	coherence();
141*da917039SDavid du Colombier }
142*da917039SDavid du Colombier 
143*da917039SDavid du Colombier void
trapdisable(void)144*da917039SDavid du Colombier trapdisable(void)
145*da917039SDavid du Colombier {
146*da917039SDavid du Colombier 	putmsr(getmsr() & ~( MSR_EE | MSR_CE | MSR_ME)); /* MSR_DE as well? */
147*da917039SDavid du Colombier }
148*da917039SDavid du Colombier 
149*da917039SDavid du Colombier static char*
excname(ulong ivoff,u32int esr)150*da917039SDavid du Colombier excname(ulong ivoff, u32int esr)
151*da917039SDavid du Colombier {
152*da917039SDavid du Colombier 	int i;
153*da917039SDavid du Colombier 
154*da917039SDavid du Colombier 	if(ivoff == INT_PROG){
155*da917039SDavid du Colombier 		if(esr & ESR_PIL)
156*da917039SDavid du Colombier 			return "illegal instruction";
157*da917039SDavid du Colombier 		if(esr & ESR_PPR)
158*da917039SDavid du Colombier 			return "privileged";
159*da917039SDavid du Colombier 		if(esr & ESR_PTR)
160*da917039SDavid du Colombier 			return "trap with successful compare";
161*da917039SDavid du Colombier 		if(esr & ESR_PEU)
162*da917039SDavid du Colombier 			return "unimplemented APU/FPU";
163*da917039SDavid du Colombier 		if(esr & ESR_PAP)
164*da917039SDavid du Colombier 			return "APU exception";
165*da917039SDavid du Colombier 		if(esr & ESR_U0F)
166*da917039SDavid du Colombier 			return "data storage: u0 fault";
167*da917039SDavid du Colombier 	}
168*da917039SDavid du Colombier 	for(i=0; intcause[i].off != 0; i++)
169*da917039SDavid du Colombier 		if(intcause[i].off == ivoff)
170*da917039SDavid du Colombier 			break;
171*da917039SDavid du Colombier 	return intcause[i].name;
172*da917039SDavid du Colombier }
173*da917039SDavid du Colombier 
174*da917039SDavid du Colombier void
dumpstack(void)175*da917039SDavid du Colombier dumpstack(void)
176*da917039SDavid du Colombier {
177*da917039SDavid du Colombier 	/* sorry.  stack is in dram, not Mach now */
178*da917039SDavid du Colombier }
179*da917039SDavid du Colombier 
180*da917039SDavid du Colombier void
dumpregs(Ureg * ureg)181*da917039SDavid du Colombier dumpregs(Ureg *ureg)
182*da917039SDavid du Colombier {
183*da917039SDavid du Colombier 	int i;
184*da917039SDavid du Colombier 	uintptr *l;
185*da917039SDavid du Colombier 
186*da917039SDavid du Colombier 	iprint("cpu%d: registers for boot\n", m->machno);
187*da917039SDavid du Colombier 
188*da917039SDavid du Colombier 	l = &ureg->cause;
189*da917039SDavid du Colombier 	for(i = 0; i < nelem(regname); i += 2, l += 2)
190*da917039SDavid du Colombier 		iprint("%s\t%.8p\t%s\t%.8p\n", regname[i], l[0], regname[i+1], l[1]);
191*da917039SDavid du Colombier }
192*da917039SDavid du Colombier 
193*da917039SDavid du Colombier static void
faultpower(Ureg * ureg,ulong addr,int read)194*da917039SDavid du Colombier faultpower(Ureg *ureg, ulong addr, int read)
195*da917039SDavid du Colombier {
196*da917039SDavid du Colombier 	USED(read);
197*da917039SDavid du Colombier 	dumpregs(ureg);
198*da917039SDavid du Colombier 	panic("boot fault: 0x%lux", addr);
199*da917039SDavid du Colombier }
200*da917039SDavid du Colombier 
201*da917039SDavid du Colombier void
trap(Ureg * ur)202*da917039SDavid du Colombier trap(Ureg *ur)
203*da917039SDavid du Colombier {
204*da917039SDavid du Colombier 	int ecode;
205*da917039SDavid du Colombier 	u32int esr;
206*da917039SDavid du Colombier 
207*da917039SDavid du Colombier 	ur->cause &= 0xFFE0;
208*da917039SDavid du Colombier 	ecode = ur->cause;
209*da917039SDavid du Colombier 	if(ecode < 0 || ecode >= 0x2000)
210*da917039SDavid du Colombier 		ecode = 0x3000;
211*da917039SDavid du Colombier 	esr = getesr();
212*da917039SDavid du Colombier 	putesr(0);
213*da917039SDavid du Colombier 
214*da917039SDavid du Colombier 	switch(ecode){
215*da917039SDavid du Colombier 	case INT_SYSCALL:
216*da917039SDavid du Colombier 		panic("syscall in boot: srr1 %#4.4luX pc %#p\n",
217*da917039SDavid du Colombier 			ur->srr1, ur->pc);
218*da917039SDavid du Colombier 
219*da917039SDavid du Colombier 	case INT_PIT:
220*da917039SDavid du Colombier 		clockintr(ur);
221*da917039SDavid du Colombier 		break;
222*da917039SDavid du Colombier 
223*da917039SDavid du Colombier 	case INT_MCHECK:
224*da917039SDavid du Colombier 		if (probing) {
225*da917039SDavid du Colombier 			trapped++;
226*da917039SDavid du Colombier 			longjmp(probenv, 1);
227*da917039SDavid du Colombier 		}
228*da917039SDavid du Colombier 		if(esr & ESR_MCI){
229*da917039SDavid du Colombier 			//iprint("mcheck-mci %lux\n", ur->pc);
230*da917039SDavid du Colombier 			faultpower(ur, ur->pc, 1);
231*da917039SDavid du Colombier 			break;
232*da917039SDavid du Colombier 		}
233*da917039SDavid du Colombier 		//iprint("mcheck %#lux esr=%#ux dear=%#ux\n", ur->pc, esr, getdear());
234*da917039SDavid du Colombier 		ur->pc -= 4;	/* back up to faulting instruction */
235*da917039SDavid du Colombier 		/* fall through */
236*da917039SDavid du Colombier 	case INT_DSI:
237*da917039SDavid du Colombier 	case INT_DMISS:
238*da917039SDavid du Colombier 		faultpower(ur, getdear(), !(esr&ESR_DST));
239*da917039SDavid du Colombier 		break;
240*da917039SDavid du Colombier 
241*da917039SDavid du Colombier 	case INT_ISI:
242*da917039SDavid du Colombier 	case INT_IMISS:
243*da917039SDavid du Colombier 		faultpower(ur, ur->pc, 1);
244*da917039SDavid du Colombier 		break;
245*da917039SDavid du Colombier 
246*da917039SDavid du Colombier 	case INT_EI:
247*da917039SDavid du Colombier 		intr(ur);
248*da917039SDavid du Colombier 		break;
249*da917039SDavid du Colombier 
250*da917039SDavid du Colombier 	case INT_PROG:
251*da917039SDavid du Colombier 	default:
252*da917039SDavid du Colombier 		print("boot %s pc=%#lux\n", excname(ecode, esr), ur->pc);
253*da917039SDavid du Colombier 		dumpregs(ur);
254*da917039SDavid du Colombier 		dumpstack();
255*da917039SDavid du Colombier 		if(m->machno == 0)
256*da917039SDavid du Colombier 			spllo();
257*da917039SDavid du Colombier 		exit(1);
258*da917039SDavid du Colombier 	}
259*da917039SDavid du Colombier 	splhi();
260*da917039SDavid du Colombier }
261*da917039SDavid du Colombier 
262*da917039SDavid du Colombier static Lock fltlck;
263*da917039SDavid du Colombier 
264*da917039SDavid du Colombier vlong
probeaddr(uintptr addr)265*da917039SDavid du Colombier probeaddr(uintptr addr)
266*da917039SDavid du Colombier {
267*da917039SDavid du Colombier 	vlong v;
268*da917039SDavid du Colombier 
269*da917039SDavid du Colombier 	ilock(&fltlck);
270*da917039SDavid du Colombier 	probing = 1;
271*da917039SDavid du Colombier 	/*
272*da917039SDavid du Colombier 	 * using setjmp & longjmp is a sleazy hack; see ../../9k/vt4/trap.c
273*da917039SDavid du Colombier 	 * for a less sleazy hack.
274*da917039SDavid du Colombier 	 */
275*da917039SDavid du Colombier 	if (setjmp(probenv) == 0)
276*da917039SDavid du Colombier 		v = *(ulong *)addr;	/* this may cause a fault */
277*da917039SDavid du Colombier 	else
278*da917039SDavid du Colombier 		v = -1;
279*da917039SDavid du Colombier 	probing = 0;
280*da917039SDavid du Colombier 	iunlock(&fltlck);
281*da917039SDavid du Colombier 	return v;
282*da917039SDavid du Colombier }
283*da917039SDavid du Colombier 
284*da917039SDavid du Colombier vlong
qtmprobeaddr(uintptr addr)285*da917039SDavid du Colombier qtmprobeaddr(uintptr addr)
286*da917039SDavid du Colombier {
287*da917039SDavid du Colombier 	int i;
288*da917039SDavid du Colombier 	vlong v, junk;
289*da917039SDavid du Colombier 	vlong *ptr;
290*da917039SDavid du Colombier 
291*da917039SDavid du Colombier 	ilock(&fltlck);
292*da917039SDavid du Colombier 	probing = 1;
293*da917039SDavid du Colombier 	trapped = 0;
294*da917039SDavid du Colombier 	v = 0;
295*da917039SDavid du Colombier 	/*
296*da917039SDavid du Colombier 	 * using setjmp & longjmp is a sleazy hack; see ../../9k/vt4/trap.c
297*da917039SDavid du Colombier 	 * for a less sleazy hack.
298*da917039SDavid du Colombier 	 */
299*da917039SDavid du Colombier 	if (setjmp(probenv) == 0) {
300*da917039SDavid du Colombier 		syncall();
301*da917039SDavid du Colombier 		clrmchk();
302*da917039SDavid du Colombier 		syncall();
303*da917039SDavid du Colombier 
304*da917039SDavid du Colombier 		ptr = (vlong *)addr;
305*da917039SDavid du Colombier 		for (i = 0; !trapped && !(getesr() & ESR_MCI) &&
306*da917039SDavid du Colombier 		    i < DCACHELINESZ/sizeof *ptr; i++) {
307*da917039SDavid du Colombier 			ptr[i] = 0;
308*da917039SDavid du Colombier 			coherence();
309*da917039SDavid du Colombier 		}
310*da917039SDavid du Colombier 		junk = ptr[0];
311*da917039SDavid du Colombier 		USED(junk);
312*da917039SDavid du Colombier 	} else
313*da917039SDavid du Colombier 		v = -1;
314*da917039SDavid du Colombier 
315*da917039SDavid du Colombier 	syncall();
316*da917039SDavid du Colombier 	if(getesr() & ESR_MCI)
317*da917039SDavid du Colombier 		v = -1;
318*da917039SDavid du Colombier 	syncall();
319*da917039SDavid du Colombier 	clrmchk();
320*da917039SDavid du Colombier 	syncall();
321*da917039SDavid du Colombier 	probing = 0;
322*da917039SDavid du Colombier 	iunlock(&fltlck);
323*da917039SDavid du Colombier 	return v;
324*da917039SDavid du Colombier }
325