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