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