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