1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6
7 #include <tos.h>
8 #include "ureg.h"
9
10 #include "io.h"
11
12 enum {
13 VECSIZE = 0x100,
14 VECBASE = PHYSSRAM,
15 };
16
17 static struct {
18 ulong off;
19 char *name;
20 } intcause[] = {
21 { INT_RESET, "system reset" },
22 { INT_MCHECK, "machine check" },
23 { INT_DSI, "data access" },
24 { INT_ISI, "instruction access" },
25 { INT_EI, "external interrupt" },
26 { INT_ALIGN, "alignment" },
27 { INT_PROG, "program exception" },
28 { INT_FPU, "floating-point unavailable" },
29 { INT_DEC, "decrementer" },
30 { INT_SYSCALL, "system call" },
31 { INT_TRACE, "trace trap" },
32 { INT_FPA, "floating point unavailable" },
33 { INT_APU, "auxiliary processor unavailable" },
34 { INT_PIT, "programmable interval timer interrrupt" },
35 { INT_FIT, "fixed interval timer interrupt" },
36 { INT_WDT, "watch dog timer interrupt" },
37 { INT_DMISS, "data TLB miss" },
38 { INT_IMISS, "instruction TLB miss" },
39 { INT_DEBUG, "debug interrupt" },
40 { INT_DEBUG+VECSIZE, "system reset" },
41 { 0, "unknown interrupt" }
42 };
43
44 static char *excname(ulong, u32int);
45
46 char *regname[]={
47 "CAUSE", "SRR1",
48 "PC", "GOK",
49 "LR", "CR",
50 "XER", "CTR",
51 "R0", "R1",
52 "R2", "R3",
53 "R4", "R5",
54 "R6", "R7",
55 "R8", "R9",
56 "R10", "R11",
57 "R12", "R13",
58 "R14", "R15",
59 "R16", "R17",
60 "R18", "R19",
61 "R20", "R21",
62 "R22", "R23",
63 "R24", "R25",
64 "R26", "R27",
65 "R28", "R29",
66 "R30", "R31",
67 };
68
69 static int probing, trapped;
70
71 /* populate a normal vector */
72 static void
sethvec(int v,void (* r)(void))73 sethvec(int v, void (*r)(void))
74 {
75 ulong *vp, pa, o;
76
77 vp = (ulong*)KADDR(v);
78 vp[0] = 0x7c1043a6; /* MOVW R0, SPR(SPRG0) */
79 vp[1] = 0x7c0802a6; /* MOVW LR, R0 */
80 vp[2] = 0x7c1243a6; /* MOVW R0, SPR(SPRG2) */
81 pa = PADDR(r);
82 o = pa >> 25;
83 if(o != 0 && o != 0x7F){
84 /* a branch too far: running from ROM */
85 vp[3] = (15<<26)|(pa>>16); /* MOVW $r&~0xFFFF, R0 */
86 vp[4] = (24<<26)|(pa&0xFFFF); /* OR $r&0xFFFF, R0 */
87 vp[5] = 0x7c0803a6; /* MOVW R0, LR */
88 vp[6] = 0x4e800021; /* BL (LR) */
89 if (v == VECBASE + INT_PIT || v == VECBASE + INT_FIT) {
90 uartlputc('?');
91 uartlputc('v');
92 print("branch too far for vector %#x!\n", v);
93 }
94 }else
95 vp[3] = (18<<26)|(pa&0x3FFFFFC)|3; /* bla */
96 dcflush(PTR2UINT(vp), 8*BY2WD);
97 }
98
99 /* populate a tlb-miss vector */
100 static void
sethvec2(int v,void (* r)(void))101 sethvec2(int v, void (*r)(void))
102 {
103 ulong *vp;
104 char msg[128];
105
106 if (((ulong)r & ~KSEGM) >= (1<<26)) {
107 uartlputc('?');
108 uartlputc('t');
109 snprint(msg, sizeof msg,
110 "tlb miss handler address %#p too high\n", r);
111 uartlputs(msg);
112 }
113 vp = (ulong*)KADDR(v);
114 vp[0] = (18<<26)|((ulong)r&~KSEGM)|2; /* ba */
115 dcflush(PTR2UINT(vp), sizeof *vp);
116 }
117
118 static void
faultpower(Ureg * ureg,ulong addr,int read)119 faultpower(Ureg *ureg, ulong addr, int read)
120 {
121 int user, insyscall, n;
122 char buf[ERRMAX];
123
124 user = (ureg->srr1 & MSR_PR) != 0;
125 if(!user){
126 // if(vmapsync(addr))
127 // return;
128 // if(addr >= USTKTOP)
129 // panic("kernel fault: bad address pc=%.8#lux addr=%.8#lux",
130 // ureg->pc, addr);
131 if(up == nil)
132 panic("kernel fault: no user process pc=%.8#lux addr=%.8#lux",
133 ureg->pc, addr);
134 }
135 if(up == nil)
136 panic("user fault: up=0 pc=%.8#lux addr=%.8#lux", ureg->pc, addr);
137 insyscall = 0;
138 if (up) {
139 insyscall = up->insyscall;
140 up->insyscall = 1;
141 }
142 n = fault(addr, read); /* repair user-mode fault */
143 if(n < 0){
144 if(!user){
145 dumpregs(ureg);
146 panic("fault: addr %#lux", addr);
147 }else if(0)
148 dumpregs(ureg);
149 seprint(buf, buf + sizeof buf, "sys: trap: fault %s addr=%#lux",
150 read? "read" : "write", addr);
151 postnote(up, 1, buf, NDebug);
152 }
153 if (up)
154 up->insyscall = insyscall;
155 }
156
157 static void
setlights(int user)158 setlights(int user)
159 {
160 if (up == nil)
161 lightstate(Ledidle);
162 else
163 lightstate(user == 0? Ledkern: Leduser);
164 }
165
166 void
kexit(Ureg *)167 kexit(Ureg*)
168 {
169 uvlong t;
170 Tos *tos;
171
172 /* precise time accounting, kernel exit */
173 tos = (Tos*)(USTKTOP-sizeof(Tos));
174 cycles(&t);
175 tos->kcycles += t - up->kentry;
176 tos->pcycles = up->pcycles;
177 tos->pid = up->pid;
178 // surely only need to set tos->pid on rfork and exec?
179 }
180
181 void
trap(Ureg * ur)182 trap(Ureg *ur)
183 {
184 int ecode, user, v;
185 u32int esr;
186 char buf[ERRMAX];
187
188 if (ur == nil)
189 panic("trap: nil ur");
190 v = ur->cause;
191 lightstate(Ledtrap);
192 ur->cause &= 0xFFE0;
193 ecode = ur->cause;
194 esr = getesr();
195 clrmchk();
196
197 user = (ur->srr1 & MSR_PR) != 0;
198 if(user){
199 cycles(&up->kentry);
200 up->dbgreg = ur;
201 }
202 switch(ecode){
203 case INT_SYSCALL:
204 if(!user)
205 panic("syscall in kernel: srr1 %#4.4luX pc %#p",
206 ur->srr1, ur->pc);
207 syscall(ur);
208 setlights(user);
209 return; /* syscall() calls notify itself */
210
211 case INT_PIT:
212 m->intr++;
213 clockintr(ur);
214 break;
215
216 case INT_WDT:
217 puttsr(~0);
218 panic("watchdog timer went off at pc %#lux", ur->pc);
219 break;
220
221 case INT_MCHECK:
222 if (probing && !user) {
223 if (trapped++ > 0)
224 panic("trap: recursive probe");
225 break; /* continue at next instruction */
226 }
227 if(esr & ESR_MCI){
228 iprint("mcheck-mci %lux\n", ur->pc);
229 faultpower(ur, ur->pc, 1);
230 break;
231 }
232 iprint("mcheck %#lux esr=%#ux dear=%#ux\n", ur->pc, esr, getdear());
233 ur->pc -= 4; /* back up to faulting instruction */
234 /* fall through */
235 case INT_DSI:
236 case INT_DMISS:
237 faultpower(ur, getdear(), !(esr&ESR_DST));
238 break;
239
240 case INT_ISI:
241 case INT_IMISS:
242 faultpower(ur, ur->pc, 1);
243 break;
244
245 case INT_EI:
246 m->intr++;
247 intr(ur);
248 break;
249
250 case 0:
251 puttsr(~0);
252 if (v == 0)
253 panic("watchdog reset? probable jump via "
254 "zeroed pointer; pc %#lux lr %#lux",
255 ur->pc, ur->lr);
256 else
257 panic("watchdog reset? interrupt at vector zero; "
258 "pc %#lux lr %#lux", ur->pc, ur->lr);
259 break;
260
261 case INT_DEBUG + VECSIZE:
262 panic("reset");
263 break;
264
265 case INT_PROG:
266 if(esr & ESR_PIL && user){
267 if(fpuemu(ur))
268 break;
269 /* otherwise it's an illegal instruction */
270 }
271 /* fall through */
272 default:
273 if(user){
274 spllo();
275 sprint(buf, "sys: trap: %s", excname(ecode, esr));
276 postnote(up, 1, buf, NDebug);
277 break;
278 }
279 splhi();
280 print("kernel %s; vector=%#ux pc=%#lux\n",
281 excname(ecode, esr), ecode, ur->pc);
282 if (ecode == 0)
283 print("probable jump via zeroed pointer; pc %#lux lr %#lux\n",
284 ur->pc, ur->lr);
285 dumpregs(ur);
286 dumpstack();
287 if(m->machno == 0)
288 spllo();
289 exit(1);
290 }
291 splhi();
292 setlights(user);
293
294 /* delaysched set because we held a lock or because our quantum ended */
295 if(up && up->delaysched && ecode == INT_PIT){
296 sched();
297 splhi();
298 setlights(user);
299 }
300
301 if(user){
302 if(up->procctl || up->nnote)
303 notify(ur);
304 kexit(ur);
305 }
306 }
307
308 void
trapinit(void)309 trapinit(void)
310 {
311 int i;
312
313 clrmchk();
314 intrinit();
315
316 /*
317 * set all exceptions to trap by default
318 */
319 for(i = 0; i < INT_DEBUG + VECSIZE; i += VECSIZE)
320 sethvec(VECBASE + i, trapvec);
321
322 /*
323 * set exception handlers
324 */
325 sethvec(VECBASE + INT_RESET, trapcritvec);
326 sethvec(VECBASE + INT_MCHECK, trapcritvec);
327 sethvec(VECBASE + INT_DSI, trapvec);
328 sethvec(VECBASE + INT_ISI, trapvec);
329 sethvec(VECBASE + INT_EI, trapvec);
330 sethvec(VECBASE + INT_ALIGN, trapvec);
331 sethvec(VECBASE + INT_PROG, trapvec);
332 sethvec(VECBASE + INT_FPU, trapvec);
333 sethvec(VECBASE + INT_SYSCALL, trapvec);
334 sethvec(VECBASE + INT_APU, trapvec);
335 sethvec(VECBASE + INT_PIT, trapvec);
336 sethvec(VECBASE + INT_FIT, trapvec);
337 sethvec(VECBASE + INT_WDT, trapcritvec);
338 sethvec2(VECBASE + INT_DMISS, dtlbmiss);
339 sethvec2(VECBASE + INT_IMISS, itlbmiss);
340 sethvec(VECBASE + INT_DEBUG, trapcritvec);
341 /*
342 * the last word of sram (0xfffffffc) contains a branch
343 * to the start of sram beyond the vectors (0xfffe2100),
344 * which initially will be the start of our bootstrap loader.
345 * overwrite it so that we can get control if the machine should
346 * reset.
347 */
348 sethvec(VECBASE + INT_DEBUG + VECSIZE, trapcritvec);
349 sethvec(0, trapcritvec);
350 sync();
351
352 putevpr(VECBASE);
353 sync();
354
355 putmsr(getmsr() | MSR_ME);
356 sync();
357 }
358
359 static char*
excname(ulong ivoff,u32int esr)360 excname(ulong ivoff, u32int esr)
361 {
362 int i;
363
364 if(ivoff == INT_PROG){
365 if(esr & ESR_PIL)
366 return "illegal instruction";
367 if(esr & ESR_PPR)
368 return "privileged";
369 if(esr & ESR_PTR)
370 return "trap with successful compare";
371 if(esr & ESR_PEU)
372 return "unimplemented APU/FPU";
373 if(esr & ESR_PAP)
374 return "APU exception";
375 if(esr & ESR_U0F)
376 return "data storage: u0 fault";
377 }
378 for(i=0; intcause[i].off != 0; i++)
379 if(intcause[i].off == ivoff)
380 break;
381 return intcause[i].name;
382 }
383
384 /*
385 * Fill in enough of Ureg to get a stack trace, and call a function.
386 * Used by debugging interface rdb.
387 */
388 void
callwithureg(void (* fn)(Ureg *))389 callwithureg(void (*fn)(Ureg*))
390 {
391 Ureg ureg;
392
393 ureg.pc = getcallerpc(&fn);
394 ureg.sp = PTR2UINT(&fn);
395 fn(&ureg);
396 }
397
398 void
dumpstack(void)399 dumpstack(void)
400 {
401 ulong l, v;
402 int i;
403
404 if(up == 0)
405 return;
406 i = 0;
407 for(l=(ulong)&l; l<(ulong)(up->kstack+KSTACK); l+=4){
408 v = *(ulong*)l;
409 if(KTZERO < v && v < (ulong)etext){
410 iprint("%lux=%lux, ", l, v);
411 if(i++ == 4){
412 iprint("\n");
413 i = 0;
414 }
415 }
416 }
417 }
418
419 void
dumpregs(Ureg * ureg)420 dumpregs(Ureg *ureg)
421 {
422 int i;
423 uintptr *l;
424
425 splhi(); /* prevent recursive dumps */
426 if(up != nil)
427 iprint("cpu%d: registers for %s %ld\n",
428 m->machno, up->text, up->pid);
429 else
430 iprint("cpu%d: registers for kernel\n", m->machno);
431
432 if (ureg == nil) {
433 iprint("nil ureg, no dump\n");
434 return;
435 }
436 l = &ureg->cause;
437 for(i = 0; i < nelem(regname); i += 2, l += 2)
438 iprint("%s\t%.8p\t%s\t%.8p\n", regname[i], l[0], regname[i+1], l[1]);
439 }
440
441 static void
linkproc(void)442 linkproc(void)
443 {
444 spllo();
445 up->kpfun(up->kparg);
446 pexit("", 0);
447 }
448
449 void
kprocchild(Proc * p,void (* func)(void *),void * arg)450 kprocchild(Proc* p, void (*func)(void*), void* arg)
451 {
452 p->sched.pc = PTR2UINT(linkproc);
453 p->sched.sp = PTR2UINT(p->kstack+KSTACK);
454 p->sched.sp = STACKALIGN(p->sched.sp);
455
456 p->kpfun = func;
457 p->kparg = arg;
458 }
459
460 uintptr
userpc(void)461 userpc(void)
462 {
463 Ureg *ureg = up->dbgreg;
464 return ureg->pc;
465 }
466
467 /*
468 * This routine must save the values of registers the user is not
469 * permitted to write from devproc and then restore the saved values
470 * before returning
471 */
472 void
setregisters(Ureg * ureg,char * pureg,char * uva,int n)473 setregisters(Ureg *ureg, char *pureg, char *uva, int n)
474 {
475 u32int status;
476
477 status = ureg->status;
478 memmove(pureg, uva, n);
479 ureg->status = status;
480 }
481
482 /*
483 * Give enough context in the ureg to produce a kernel stack for
484 * a sleeping process
485 */
486 void
setkernur(Ureg * ureg,Proc * p)487 setkernur(Ureg* ureg, Proc* p)
488 {
489 ureg->pc = p->sched.pc;
490 ureg->sp = p->sched.sp+BY2SE;
491 }
492
493 uintptr
dbgpc(Proc * p)494 dbgpc(Proc* p)
495 {
496 Ureg *ureg;
497
498 ureg = p->dbgreg;
499 if(ureg == 0)
500 return 0;
501 return ureg->pc;
502 }
503
504 vlong
probeaddr(uintptr addr)505 probeaddr(uintptr addr)
506 {
507 vlong v;
508 static Lock fltlck;
509
510 ilock(&fltlck);
511 trapped = 0;
512 probing = 1;
513 barriers();
514
515 v = *(ulong *)addr; /* this may cause a fault */
516 USED(probing);
517 barriers();
518
519 probing = 0;
520 barriers();
521 if (trapped)
522 v = -1;
523 iunlock(&fltlck);
524 return v;
525 }
526