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