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