1*1c9d674cSDavid du Colombier /* ppc440 traps */
2*1c9d674cSDavid du Colombier #include "u.h"
3*1c9d674cSDavid du Colombier #include "../port/lib.h"
4*1c9d674cSDavid du Colombier #include "mem.h"
5*1c9d674cSDavid du Colombier #include "dat.h"
6*1c9d674cSDavid du Colombier #include "fns.h"
7*1c9d674cSDavid du Colombier
8*1c9d674cSDavid du Colombier #include <tos.h>
9*1c9d674cSDavid du Colombier #include "ureg.h"
10*1c9d674cSDavid du Colombier
11*1c9d674cSDavid du Colombier #include "io.h"
12*1c9d674cSDavid du Colombier
13*1c9d674cSDavid du Colombier enum {
14*1c9d674cSDavid du Colombier VECSIZE = 0x100,
15*1c9d674cSDavid du Colombier };
16*1c9d674cSDavid du Colombier
17*1c9d674cSDavid du Colombier extern int notify(Ureg*);
18*1c9d674cSDavid du Colombier extern void syscall(Ureg*);
19*1c9d674cSDavid du Colombier
20*1c9d674cSDavid du Colombier static struct {
21*1c9d674cSDavid du Colombier ulong off;
22*1c9d674cSDavid du Colombier char *name;
23*1c9d674cSDavid du Colombier } intcause[] = {
24*1c9d674cSDavid du Colombier { INT_CI, "critical input" },
25*1c9d674cSDavid du Colombier { INT_MCHECK, "machine check" },
26*1c9d674cSDavid du Colombier { INT_DSI, "data access" },
27*1c9d674cSDavid du Colombier { INT_ISI, "instruction access" },
28*1c9d674cSDavid du Colombier { INT_EI, "external interrupt" },
29*1c9d674cSDavid du Colombier { INT_ALIGN, "alignment" },
30*1c9d674cSDavid du Colombier { INT_PROG, "program exception" },
31*1c9d674cSDavid du Colombier { INT_FPU, "floating-point unavailable" },
32*1c9d674cSDavid du Colombier { INT_DEC, "decrementer" },
33*1c9d674cSDavid du Colombier { INT_SYSCALL, "system call" },
34*1c9d674cSDavid du Colombier { INT_TRACE, "trace trap" },
35*1c9d674cSDavid du Colombier { INT_FPA, "floating point unavailable" },
36*1c9d674cSDavid du Colombier { INT_APU, "auxiliary processor unavailable" },
37*1c9d674cSDavid du Colombier { INT_PIT, "programmable interval timer interrrupt" },
38*1c9d674cSDavid du Colombier { INT_FIT, "fixed interval timer interrupt" },
39*1c9d674cSDavid du Colombier { INT_WDT, "watch dog timer interrupt" },
40*1c9d674cSDavid du Colombier { INT_DMISS, "data TLB miss" },
41*1c9d674cSDavid du Colombier { INT_IMISS, "instruction TLB miss" },
42*1c9d674cSDavid du Colombier { INT_DEBUG, "debug interrupt" },
43*1c9d674cSDavid du Colombier { INT_DEBUG+VECSIZE, "system reset" },
44*1c9d674cSDavid du Colombier { 0, "unknown interrupt" }
45*1c9d674cSDavid du Colombier };
46*1c9d674cSDavid du Colombier
47*1c9d674cSDavid du Colombier static char *excname(ulong, u32int);
48*1c9d674cSDavid du Colombier
49*1c9d674cSDavid du Colombier char *regname[]={
50*1c9d674cSDavid du Colombier "CAUSE","SRR1",
51*1c9d674cSDavid du Colombier "PC", "GOK",
52*1c9d674cSDavid du Colombier "LR", "CR",
53*1c9d674cSDavid du Colombier "XER", "CTR",
54*1c9d674cSDavid du Colombier "R0", "R1",
55*1c9d674cSDavid du Colombier "R2", "R3",
56*1c9d674cSDavid du Colombier "R4", "R5",
57*1c9d674cSDavid du Colombier "R6", "R7",
58*1c9d674cSDavid du Colombier "R8", "R9",
59*1c9d674cSDavid du Colombier "R10", "R11",
60*1c9d674cSDavid du Colombier "R12", "R13",
61*1c9d674cSDavid du Colombier "R14", "R15",
62*1c9d674cSDavid du Colombier "R16", "R17",
63*1c9d674cSDavid du Colombier "R18", "R19",
64*1c9d674cSDavid du Colombier "R20", "R21",
65*1c9d674cSDavid du Colombier "R22", "R23",
66*1c9d674cSDavid du Colombier "R24", "R25",
67*1c9d674cSDavid du Colombier "R26", "R27",
68*1c9d674cSDavid du Colombier "R28", "R29",
69*1c9d674cSDavid du Colombier "R30", "R31",
70*1c9d674cSDavid du Colombier };
71*1c9d674cSDavid du Colombier
72*1c9d674cSDavid du Colombier static int probing, trapped;
73*1c9d674cSDavid du Colombier
74*1c9d674cSDavid du Colombier void init0(void);
75*1c9d674cSDavid du Colombier
76*1c9d674cSDavid du Colombier #define SPR(v) (((v&0x1f)<<16) | (((v>>5)&0x1f)<<11))
77*1c9d674cSDavid du Colombier
78*1c9d674cSDavid du Colombier #define SPR_SPRG0 0x110 /* SPR General 0 */
79*1c9d674cSDavid du Colombier #define SPR_SPRG2 0x112 /* SPR General 2 */
80*1c9d674cSDavid du Colombier #define SPR_SPRG6W 0x116 /* SPR General 6; supervisor W */
81*1c9d674cSDavid du Colombier
82*1c9d674cSDavid du Colombier static void
vecgen(int v,void (* r)(void),int r0spr,int maskce)83*1c9d674cSDavid du Colombier vecgen(int v, void (*r)(void), int r0spr, int maskce)
84*1c9d674cSDavid du Colombier {
85*1c9d674cSDavid du Colombier u32int *vp, o, ra;
86*1c9d674cSDavid du Colombier int i, d;
87*1c9d674cSDavid du Colombier
88*1c9d674cSDavid du Colombier vp = (u32int*)KADDR(v);
89*1c9d674cSDavid du Colombier vp[0] = 0x7c0003a6 | SPR(r0spr); /* MOVW R0, SPR(r0spr) */
90*1c9d674cSDavid du Colombier i = 1;
91*1c9d674cSDavid du Colombier if(maskce){ /* clear CE? this stops crit. intrs. */
92*1c9d674cSDavid du Colombier vp[i++] = 0x7c0000a6; /* MOVW MSR, R0 */
93*1c9d674cSDavid du Colombier vp[i++] = 0x540003da; /* RLWNM $0, R0, ~MSR_CE, R0 */
94*1c9d674cSDavid du Colombier vp[i++] = 0x7c000124; /* MOVW R0, MSR */
95*1c9d674cSDavid du Colombier }
96*1c9d674cSDavid du Colombier vp[i++] = 0x7c0802a6; /* MOVW LR, R0 */
97*1c9d674cSDavid du Colombier vp[i++] = 0x7c0003a6 | SPR(SPR_SPRG2); /* MOVW R0, SPR(SPRG2) */
98*1c9d674cSDavid du Colombier d = (uchar*)r - (uchar*)&vp[i];
99*1c9d674cSDavid du Colombier o = (u32int)d >> 25;
100*1c9d674cSDavid du Colombier if(o != 0 && o != 0x7F){
101*1c9d674cSDavid du Colombier /* a branch too far: running from ROM */
102*1c9d674cSDavid du Colombier ra = (u32int)r;
103*1c9d674cSDavid du Colombier vp[i++] = (15<<26)|(ra>>16); /* MOVW $r&~0xFFFF, R0 */
104*1c9d674cSDavid du Colombier vp[i++] = (24<<26)|(ra&0xFFFF); /* OR $r&0xFFFF, R0 */
105*1c9d674cSDavid du Colombier vp[i++] = 0x7c0803a6; /* MOVW R0, LR */
106*1c9d674cSDavid du Colombier vp[i++] = 0x4e800021; /* BL (LR) */
107*1c9d674cSDavid du Colombier }else
108*1c9d674cSDavid du Colombier vp[i++] = (18<<26)|(d&0x3FFFFFC)|1; /* bl (relative) */
109*1c9d674cSDavid du Colombier dcflush(PTR2UINT(vp), i*sizeof(u32int));
110*1c9d674cSDavid du Colombier }
111*1c9d674cSDavid du Colombier
112*1c9d674cSDavid du Colombier /* populate a normal vector */
113*1c9d674cSDavid du Colombier static void
sethvec(int v,void (* r)(void))114*1c9d674cSDavid du Colombier sethvec(int v, void (*r)(void))
115*1c9d674cSDavid du Colombier {
116*1c9d674cSDavid du Colombier vecgen(v, r, SPR_SPRG0, 1);
117*1c9d674cSDavid du Colombier }
118*1c9d674cSDavid du Colombier
119*1c9d674cSDavid du Colombier /* populate a tlb-miss vector */
120*1c9d674cSDavid du Colombier static void
sethvec2(int v,void (* r)(void))121*1c9d674cSDavid du Colombier sethvec2(int v, void (*r)(void))
122*1c9d674cSDavid du Colombier {
123*1c9d674cSDavid du Colombier ulong *vp;
124*1c9d674cSDavid du Colombier long d;
125*1c9d674cSDavid du Colombier
126*1c9d674cSDavid du Colombier vp = (ulong*)KADDR(v);
127*1c9d674cSDavid du Colombier d = (uchar*)r - (uchar*)&vp[0];
128*1c9d674cSDavid du Colombier if (d >= (1<<26)) {
129*1c9d674cSDavid du Colombier uartlputc('?');
130*1c9d674cSDavid du Colombier iprint("sethvec2: v %#x vp %#p r %#p d %ld\n", v, vp, r, d);
131*1c9d674cSDavid du Colombier iprint("tlb miss handler address too high\n");
132*1c9d674cSDavid du Colombier }
133*1c9d674cSDavid du Colombier vp[0] = (18<<26)|(d & 0x3FFFFFC); /* b (relative) */
134*1c9d674cSDavid du Colombier dcflush(PTR2UINT(vp), sizeof *vp);
135*1c9d674cSDavid du Colombier }
136*1c9d674cSDavid du Colombier
137*1c9d674cSDavid du Colombier static void
faultpower(Ureg * ureg,ulong addr,int read)138*1c9d674cSDavid du Colombier faultpower(Ureg *ureg, ulong addr, int read)
139*1c9d674cSDavid du Colombier {
140*1c9d674cSDavid du Colombier int user, insyscall;
141*1c9d674cSDavid du Colombier char buf[ERRMAX];
142*1c9d674cSDavid du Colombier
143*1c9d674cSDavid du Colombier /*
144*1c9d674cSDavid du Colombier * There must be a user context.
145*1c9d674cSDavid du Colombier * If not, the usual problem is causing a fault during
146*1c9d674cSDavid du Colombier * initialisation before the system is fully up.
147*1c9d674cSDavid du Colombier */
148*1c9d674cSDavid du Colombier user = (ureg->srr1 & MSR_PR) != 0;
149*1c9d674cSDavid du Colombier if(!user){
150*1c9d674cSDavid du Colombier // if(vmapsync(addr))
151*1c9d674cSDavid du Colombier // return;
152*1c9d674cSDavid du Colombier // if(addr >= USTKTOP)
153*1c9d674cSDavid du Colombier // panic("kernel fault: bad address pc=%.8#lux addr=%.8#lux",
154*1c9d674cSDavid du Colombier // ureg->pc, addr);
155*1c9d674cSDavid du Colombier if(up == nil)
156*1c9d674cSDavid du Colombier panic("kernel fault: no user process pc=%.8#lux addr=%.8#lux",
157*1c9d674cSDavid du Colombier ureg->pc, addr);
158*1c9d674cSDavid du Colombier }
159*1c9d674cSDavid du Colombier if(up == nil)
160*1c9d674cSDavid du Colombier panic("user fault: up=0 pc=%.8#lux addr=%.8#lux", ureg->pc, addr);
161*1c9d674cSDavid du Colombier insyscall = up->insyscall;
162*1c9d674cSDavid du Colombier up->insyscall = 1;
163*1c9d674cSDavid du Colombier if(fault(addr, read) < 0){
164*1c9d674cSDavid du Colombier /*
165*1c9d674cSDavid du Colombier * It is possible to get here with !user if, for example,
166*1c9d674cSDavid du Colombier * a process was in a system call accessing a shared
167*1c9d674cSDavid du Colombier * segment but was preempted by another process which shrunk
168*1c9d674cSDavid du Colombier * or deallocated the shared segment; when the original
169*1c9d674cSDavid du Colombier * process resumes it may fault while in kernel mode.
170*1c9d674cSDavid du Colombier * No need to panic this case, post a note to the process
171*1c9d674cSDavid du Colombier * and unwind the error stack. There must be an error stack
172*1c9d674cSDavid du Colombier * (up->nerrlab != 0) if this is a system call, if not then
173*1c9d674cSDavid du Colombier * the game's a bogey.
174*1c9d674cSDavid du Colombier */
175*1c9d674cSDavid du Colombier if(!user && (!insyscall || up->nerrlab == 0)){
176*1c9d674cSDavid du Colombier dumpregs(ureg);
177*1c9d674cSDavid du Colombier panic("fault: %#lux", addr);
178*1c9d674cSDavid du Colombier }
179*1c9d674cSDavid du Colombier sprint(buf, "sys: trap: fault %s addr=%#lux",
180*1c9d674cSDavid du Colombier read? "read": "write", addr);
181*1c9d674cSDavid du Colombier postnote(up, 1, buf, NDebug);
182*1c9d674cSDavid du Colombier if(insyscall)
183*1c9d674cSDavid du Colombier error(buf);
184*1c9d674cSDavid du Colombier }
185*1c9d674cSDavid du Colombier up->insyscall = insyscall;
186*1c9d674cSDavid du Colombier }
187*1c9d674cSDavid du Colombier
188*1c9d674cSDavid du Colombier static void
setlights(int user)189*1c9d674cSDavid du Colombier setlights(int user)
190*1c9d674cSDavid du Colombier {
191*1c9d674cSDavid du Colombier if (up == nil)
192*1c9d674cSDavid du Colombier lightstate(Ledidle);
193*1c9d674cSDavid du Colombier else
194*1c9d674cSDavid du Colombier lightstate(user == 0? Ledkern: Leduser);
195*1c9d674cSDavid du Colombier }
196*1c9d674cSDavid du Colombier
197*1c9d674cSDavid du Colombier void
syncall(void)198*1c9d674cSDavid du Colombier syncall(void)
199*1c9d674cSDavid du Colombier {
200*1c9d674cSDavid du Colombier sync();
201*1c9d674cSDavid du Colombier isync();
202*1c9d674cSDavid du Colombier }
203*1c9d674cSDavid du Colombier
204*1c9d674cSDavid du Colombier void
kexit(Ureg *)205*1c9d674cSDavid du Colombier kexit(Ureg*)
206*1c9d674cSDavid du Colombier {
207*1c9d674cSDavid du Colombier uvlong t;
208*1c9d674cSDavid du Colombier Tos *tos;
209*1c9d674cSDavid du Colombier
210*1c9d674cSDavid du Colombier /* precise time accounting, kernel exit */
211*1c9d674cSDavid du Colombier tos = (Tos*)(USTKTOP-sizeof(Tos));
212*1c9d674cSDavid du Colombier cycles(&t);
213*1c9d674cSDavid du Colombier tos->kcycles += t - up->kentry;
214*1c9d674cSDavid du Colombier tos->pcycles = up->pcycles;
215*1c9d674cSDavid du Colombier tos->pid = up->pid;
216*1c9d674cSDavid du Colombier // surely only need to set tos->pid on rfork and exec?
217*1c9d674cSDavid du Colombier }
218*1c9d674cSDavid du Colombier
219*1c9d674cSDavid du Colombier void
trap(Ureg * ur)220*1c9d674cSDavid du Colombier trap(Ureg *ur)
221*1c9d674cSDavid du Colombier {
222*1c9d674cSDavid du Colombier int ecode, user, v;
223*1c9d674cSDavid du Colombier u32int esr, mcsr;
224*1c9d674cSDavid du Colombier char buf[ERRMAX];
225*1c9d674cSDavid du Colombier
226*1c9d674cSDavid du Colombier if (ur == nil)
227*1c9d674cSDavid du Colombier panic("trap: nil ur");
228*1c9d674cSDavid du Colombier v = ur->cause;
229*1c9d674cSDavid du Colombier ur->cause &= 0xFFE0;
230*1c9d674cSDavid du Colombier ecode = ur->cause;
231*1c9d674cSDavid du Colombier
232*1c9d674cSDavid du Colombier esr = getesr();
233*1c9d674cSDavid du Colombier mcsr = getmcsr();
234*1c9d674cSDavid du Colombier clrmchk();
235*1c9d674cSDavid du Colombier
236*1c9d674cSDavid du Colombier lightstate(Ledtrap);
237*1c9d674cSDavid du Colombier user = (ur->srr1 & MSR_PR) != 0;
238*1c9d674cSDavid du Colombier if(user){
239*1c9d674cSDavid du Colombier cycles(&up->kentry);
240*1c9d674cSDavid du Colombier up->dbgreg = ur;
241*1c9d674cSDavid du Colombier }
242*1c9d674cSDavid du Colombier switch(ecode){
243*1c9d674cSDavid du Colombier case INT_SYSCALL:
244*1c9d674cSDavid du Colombier if(!user)
245*1c9d674cSDavid du Colombier panic("syscall in kernel: srr1 %#4.4luX pc %#p",
246*1c9d674cSDavid du Colombier ur->srr1, ur->pc);
247*1c9d674cSDavid du Colombier syscall(ur);
248*1c9d674cSDavid du Colombier setlights(user);
249*1c9d674cSDavid du Colombier return; /* syscall() calls notify itself */
250*1c9d674cSDavid du Colombier
251*1c9d674cSDavid du Colombier case INT_PIT:
252*1c9d674cSDavid du Colombier m->intr++;
253*1c9d674cSDavid du Colombier clockintr(ur);
254*1c9d674cSDavid du Colombier break;
255*1c9d674cSDavid du Colombier
256*1c9d674cSDavid du Colombier case INT_WDT:
257*1c9d674cSDavid du Colombier puttsr(~0);
258*1c9d674cSDavid du Colombier panic("watchdog timer went off at pc %#lux", ur->pc);
259*1c9d674cSDavid du Colombier break;
260*1c9d674cSDavid du Colombier
261*1c9d674cSDavid du Colombier case INT_MCHECK:
262*1c9d674cSDavid du Colombier if (probing && !user) {
263*1c9d674cSDavid du Colombier if (trapped++ > 0)
264*1c9d674cSDavid du Colombier panic("trap: recursive probe on mcheck");
265*1c9d674cSDavid du Colombier break; /* continue at next instruction */
266*1c9d674cSDavid du Colombier }
267*1c9d674cSDavid du Colombier if(esr & ESR_MCI){
268*1c9d674cSDavid du Colombier iprint("mcheck-mci %lux\n", ur->pc);
269*1c9d674cSDavid du Colombier faultpower(ur, ur->pc, 1);
270*1c9d674cSDavid du Colombier break;
271*1c9d674cSDavid du Colombier }
272*1c9d674cSDavid du Colombier iprint("mcheck %#lux esr=%#ux mcsr=%#ux dear=%#ux\n",
273*1c9d674cSDavid du Colombier ur->pc, esr, mcsr, getdear());
274*1c9d674cSDavid du Colombier ur->pc -= 4; /* back up to faulting instruction */
275*1c9d674cSDavid du Colombier /* fall through */
276*1c9d674cSDavid du Colombier case INT_DSI:
277*1c9d674cSDavid du Colombier case INT_DMISS:
278*1c9d674cSDavid du Colombier faultpower(ur, getdear(), !(esr&ESR_DST));
279*1c9d674cSDavid du Colombier break;
280*1c9d674cSDavid du Colombier
281*1c9d674cSDavid du Colombier case INT_ISI:
282*1c9d674cSDavid du Colombier case INT_IMISS:
283*1c9d674cSDavid du Colombier faultpower(ur, ur->pc, 1);
284*1c9d674cSDavid du Colombier break;
285*1c9d674cSDavid du Colombier
286*1c9d674cSDavid du Colombier case INT_CI:
287*1c9d674cSDavid du Colombier case INT_EI:
288*1c9d674cSDavid du Colombier m->intr++;
289*1c9d674cSDavid du Colombier intr(ur);
290*1c9d674cSDavid du Colombier break;
291*1c9d674cSDavid du Colombier
292*1c9d674cSDavid du Colombier case 0:
293*1c9d674cSDavid du Colombier puttsr(~0);
294*1c9d674cSDavid du Colombier if (v == 0)
295*1c9d674cSDavid du Colombier panic("watchdog reset? probable jump via "
296*1c9d674cSDavid du Colombier "zeroed pointer; pc %#lux lr %#lux",
297*1c9d674cSDavid du Colombier ur->pc, ur->lr);
298*1c9d674cSDavid du Colombier else
299*1c9d674cSDavid du Colombier panic("watchdog reset? interrupt at vector zero; "
300*1c9d674cSDavid du Colombier "pc %#lux lr %#lux", ur->pc, ur->lr);
301*1c9d674cSDavid du Colombier break;
302*1c9d674cSDavid du Colombier
303*1c9d674cSDavid du Colombier case INT_DEBUG:
304*1c9d674cSDavid du Colombier putdbsr(~0); /* extinguish source */
305*1c9d674cSDavid du Colombier print("debug interrupt at pc %#lux\n", ur->pc);
306*1c9d674cSDavid du Colombier break;
307*1c9d674cSDavid du Colombier
308*1c9d674cSDavid du Colombier case INT_DEBUG + VECSIZE:
309*1c9d674cSDavid du Colombier panic("reset");
310*1c9d674cSDavid du Colombier break;
311*1c9d674cSDavid du Colombier
312*1c9d674cSDavid du Colombier case INT_FPA:
313*1c9d674cSDavid du Colombier case INT_FPU:
314*1c9d674cSDavid du Colombier if(fpuavail(ur))
315*1c9d674cSDavid du Colombier break;
316*1c9d674cSDavid du Colombier esr |= ESR_PFP;
317*1c9d674cSDavid du Colombier /* fall through */
318*1c9d674cSDavid du Colombier case INT_PROG:
319*1c9d674cSDavid du Colombier if(esr & ESR_PFP){ /* floating-point enabled exception */
320*1c9d674cSDavid du Colombier fputrap(ur, user);
321*1c9d674cSDavid du Colombier break;
322*1c9d674cSDavid du Colombier }
323*1c9d674cSDavid du Colombier if(esr & ESR_PIL && user){
324*1c9d674cSDavid du Colombier if(fpuemu(ur))
325*1c9d674cSDavid du Colombier break;
326*1c9d674cSDavid du Colombier /* otherwise it's an illegal instruction */
327*1c9d674cSDavid du Colombier }
328*1c9d674cSDavid du Colombier /* fall through */
329*1c9d674cSDavid du Colombier default:
330*1c9d674cSDavid du Colombier if(user){
331*1c9d674cSDavid du Colombier spllo();
332*1c9d674cSDavid du Colombier sprint(buf, "sys: trap: %s", excname(ecode, esr));
333*1c9d674cSDavid du Colombier if(ecode == INT_ALIGN)
334*1c9d674cSDavid du Colombier sprint(buf+strlen(buf), " ea=%#ux", getdear());
335*1c9d674cSDavid du Colombier postnote(up, 1, buf, NDebug);
336*1c9d674cSDavid du Colombier break;
337*1c9d674cSDavid du Colombier }
338*1c9d674cSDavid du Colombier splhi();
339*1c9d674cSDavid du Colombier print("kernel %s; vector=%#ux pc=%#lux\n",
340*1c9d674cSDavid du Colombier excname(ecode, esr), ecode, ur->pc);
341*1c9d674cSDavid du Colombier if (ecode == 0)
342*1c9d674cSDavid du Colombier print("probable jump via zeroed pointer; pc %#lux lr %#lux\n",
343*1c9d674cSDavid du Colombier ur->pc, ur->lr);
344*1c9d674cSDavid du Colombier dumpregs(ur);
345*1c9d674cSDavid du Colombier dumpstack();
346*1c9d674cSDavid du Colombier if(m->machno == 0)
347*1c9d674cSDavid du Colombier spllo();
348*1c9d674cSDavid du Colombier exit(1);
349*1c9d674cSDavid du Colombier }
350*1c9d674cSDavid du Colombier splhi();
351*1c9d674cSDavid du Colombier setlights(user);
352*1c9d674cSDavid du Colombier
353*1c9d674cSDavid du Colombier /* delaysched set because we held a lock or because our quantum ended */
354*1c9d674cSDavid du Colombier if(up && up->delaysched && ecode == INT_PIT){
355*1c9d674cSDavid du Colombier sched();
356*1c9d674cSDavid du Colombier splhi();
357*1c9d674cSDavid du Colombier setlights(user);
358*1c9d674cSDavid du Colombier }
359*1c9d674cSDavid du Colombier
360*1c9d674cSDavid du Colombier if(user){
361*1c9d674cSDavid du Colombier if(up->procctl || up->nnote)
362*1c9d674cSDavid du Colombier notify(ur);
363*1c9d674cSDavid du Colombier kexit(ur);
364*1c9d674cSDavid du Colombier }
365*1c9d674cSDavid du Colombier }
366*1c9d674cSDavid du Colombier
367*1c9d674cSDavid du Colombier void
trapinit(void)368*1c9d674cSDavid du Colombier trapinit(void)
369*1c9d674cSDavid du Colombier {
370*1c9d674cSDavid du Colombier int i;
371*1c9d674cSDavid du Colombier
372*1c9d674cSDavid du Colombier clrmchk();
373*1c9d674cSDavid du Colombier intrinit();
374*1c9d674cSDavid du Colombier
375*1c9d674cSDavid du Colombier /*
376*1c9d674cSDavid du Colombier * set all exceptions to trap by default
377*1c9d674cSDavid du Colombier */
378*1c9d674cSDavid du Colombier for(i = 0; i < INT_DEBUG + VECSIZE; i += VECSIZE)
379*1c9d674cSDavid du Colombier sethvec(VECBASE + i, trapvec);
380*1c9d674cSDavid du Colombier
381*1c9d674cSDavid du Colombier /*
382*1c9d674cSDavid du Colombier * set exception handlers
383*1c9d674cSDavid du Colombier */
384*1c9d674cSDavid du Colombier vecgen(VECBASE + INT_CI, critintrvec, SPR_SPRG6W, 0);
385*1c9d674cSDavid du Colombier sethvec(VECBASE + INT_MCHECK, trapmvec);
386*1c9d674cSDavid du Colombier sethvec(VECBASE + INT_DSI, trapvec);
387*1c9d674cSDavid du Colombier sethvec(VECBASE + INT_ISI, trapvec);
388*1c9d674cSDavid du Colombier sethvec(VECBASE + INT_EI, trapvec);
389*1c9d674cSDavid du Colombier sethvec(VECBASE + INT_ALIGN, trapvec);
390*1c9d674cSDavid du Colombier sethvec(VECBASE + INT_PROG, trapvec);
391*1c9d674cSDavid du Colombier sethvec(VECBASE + INT_FPU, trapvec);
392*1c9d674cSDavid du Colombier sethvec(VECBASE + INT_DEC, trapvec);
393*1c9d674cSDavid du Colombier sethvec(VECBASE + INT_SYSCALL, trapvec);
394*1c9d674cSDavid du Colombier sethvec(VECBASE + INT_TRACE, trapvec);
395*1c9d674cSDavid du Colombier sethvec(VECBASE + INT_FPA, trapvec);
396*1c9d674cSDavid du Colombier sethvec(VECBASE + INT_APU, trapvec);
397*1c9d674cSDavid du Colombier sethvec(VECBASE + INT_PIT, trapvec);
398*1c9d674cSDavid du Colombier // sethvec(VECBASE + INT_FIT, trapvec);
399*1c9d674cSDavid du Colombier vecgen(VECBASE + INT_WDT, critintrvec, SPR_SPRG6W, 0);
400*1c9d674cSDavid du Colombier sethvec2(VECBASE + INT_DMISS, dtlbmiss);
401*1c9d674cSDavid du Colombier sethvec2(VECBASE + INT_IMISS, itlbmiss);
402*1c9d674cSDavid du Colombier vecgen(VECBASE + INT_DEBUG, critintrvec, SPR_SPRG6W, 0);
403*1c9d674cSDavid du Colombier sync();
404*1c9d674cSDavid du Colombier
405*1c9d674cSDavid du Colombier putevpr(KZERO | VECBASE);
406*1c9d674cSDavid du Colombier sync();
407*1c9d674cSDavid du Colombier
408*1c9d674cSDavid du Colombier putmsr(getmsr() | MSR_ME | MSR_DE);
409*1c9d674cSDavid du Colombier sync();
410*1c9d674cSDavid du Colombier }
411*1c9d674cSDavid du Colombier
412*1c9d674cSDavid du Colombier static char*
excname(ulong ivoff,u32int esr)413*1c9d674cSDavid du Colombier excname(ulong ivoff, u32int esr)
414*1c9d674cSDavid du Colombier {
415*1c9d674cSDavid du Colombier int i;
416*1c9d674cSDavid du Colombier
417*1c9d674cSDavid du Colombier if(ivoff == INT_PROG){
418*1c9d674cSDavid du Colombier if(esr & ESR_PIL)
419*1c9d674cSDavid du Colombier return "illegal instruction";
420*1c9d674cSDavid du Colombier if(esr & ESR_PPR)
421*1c9d674cSDavid du Colombier return "privileged";
422*1c9d674cSDavid du Colombier if(esr & ESR_PTR)
423*1c9d674cSDavid du Colombier return "trap with successful compare";
424*1c9d674cSDavid du Colombier if(esr & ESR_PEU)
425*1c9d674cSDavid du Colombier return "unimplemented APU/FPU";
426*1c9d674cSDavid du Colombier if(esr & ESR_PAP)
427*1c9d674cSDavid du Colombier return "APU exception";
428*1c9d674cSDavid du Colombier if(esr & ESR_U0F)
429*1c9d674cSDavid du Colombier return "data storage: u0 fault";
430*1c9d674cSDavid du Colombier }
431*1c9d674cSDavid du Colombier for(i=0; intcause[i].off != 0; i++)
432*1c9d674cSDavid du Colombier if(intcause[i].off == ivoff)
433*1c9d674cSDavid du Colombier break;
434*1c9d674cSDavid du Colombier return intcause[i].name;
435*1c9d674cSDavid du Colombier }
436*1c9d674cSDavid du Colombier
437*1c9d674cSDavid du Colombier /*
438*1c9d674cSDavid du Colombier * Fill in enough of Ureg to get a stack trace, and call a function.
439*1c9d674cSDavid du Colombier * Used by debugging interface rdb.
440*1c9d674cSDavid du Colombier */
441*1c9d674cSDavid du Colombier void
callwithureg(void (* fn)(Ureg *))442*1c9d674cSDavid du Colombier callwithureg(void (*fn)(Ureg*))
443*1c9d674cSDavid du Colombier {
444*1c9d674cSDavid du Colombier Ureg ureg;
445*1c9d674cSDavid du Colombier
446*1c9d674cSDavid du Colombier ureg.pc = getcallerpc(&fn);
447*1c9d674cSDavid du Colombier ureg.sp = PTR2UINT(&fn);
448*1c9d674cSDavid du Colombier fn(&ureg);
449*1c9d674cSDavid du Colombier }
450*1c9d674cSDavid du Colombier
451*1c9d674cSDavid du Colombier void
dumpstack(void)452*1c9d674cSDavid du Colombier dumpstack(void)
453*1c9d674cSDavid du Colombier {
454*1c9d674cSDavid du Colombier ulong l, v;
455*1c9d674cSDavid du Colombier int i;
456*1c9d674cSDavid du Colombier
457*1c9d674cSDavid du Colombier if(up == 0)
458*1c9d674cSDavid du Colombier return;
459*1c9d674cSDavid du Colombier i = 0;
460*1c9d674cSDavid du Colombier for(l=(ulong)&l; l<(ulong)(up->kstack+KSTACK); l+=4){
461*1c9d674cSDavid du Colombier v = *(ulong*)l;
462*1c9d674cSDavid du Colombier if(KTZERO < v && v < (ulong)etext){
463*1c9d674cSDavid du Colombier iprint("%lux=%lux, ", l, v);
464*1c9d674cSDavid du Colombier if(i++ == 4){
465*1c9d674cSDavid du Colombier iprint("\n");
466*1c9d674cSDavid du Colombier i = 0;
467*1c9d674cSDavid du Colombier }
468*1c9d674cSDavid du Colombier }
469*1c9d674cSDavid du Colombier }
470*1c9d674cSDavid du Colombier }
471*1c9d674cSDavid du Colombier
472*1c9d674cSDavid du Colombier void
dumpregs(Ureg * ureg)473*1c9d674cSDavid du Colombier dumpregs(Ureg *ureg)
474*1c9d674cSDavid du Colombier {
475*1c9d674cSDavid du Colombier int i;
476*1c9d674cSDavid du Colombier uintptr *l;
477*1c9d674cSDavid du Colombier
478*1c9d674cSDavid du Colombier splhi(); /* prevent recursive dumps */
479*1c9d674cSDavid du Colombier if(up != nil)
480*1c9d674cSDavid du Colombier iprint("cpu%d: registers for %s %ld\n",
481*1c9d674cSDavid du Colombier m->machno, up->text, up->pid);
482*1c9d674cSDavid du Colombier else
483*1c9d674cSDavid du Colombier iprint("cpu%d: registers for kernel\n", m->machno);
484*1c9d674cSDavid du Colombier
485*1c9d674cSDavid du Colombier if (ureg == nil) {
486*1c9d674cSDavid du Colombier iprint("nil ureg, no dump\n");
487*1c9d674cSDavid du Colombier return;
488*1c9d674cSDavid du Colombier }
489*1c9d674cSDavid du Colombier l = &ureg->cause;
490*1c9d674cSDavid du Colombier for(i = 0; i < nelem(regname); i += 2, l += 2)
491*1c9d674cSDavid du Colombier iprint("%s\t%.8p\t%s\t%.8p\n", regname[i], l[0], regname[i+1], l[1]);
492*1c9d674cSDavid du Colombier }
493*1c9d674cSDavid du Colombier
494*1c9d674cSDavid du Colombier static void
linkproc(void)495*1c9d674cSDavid du Colombier linkproc(void)
496*1c9d674cSDavid du Colombier {
497*1c9d674cSDavid du Colombier spllo();
498*1c9d674cSDavid du Colombier up->kpfun(up->kparg);
499*1c9d674cSDavid du Colombier pexit("", 0);
500*1c9d674cSDavid du Colombier }
501*1c9d674cSDavid du Colombier
502*1c9d674cSDavid du Colombier void
kprocchild(Proc * p,void (* func)(void *),void * arg)503*1c9d674cSDavid du Colombier kprocchild(Proc* p, void (*func)(void*), void* arg)
504*1c9d674cSDavid du Colombier {
505*1c9d674cSDavid du Colombier p->sched.pc = PTR2UINT(linkproc);
506*1c9d674cSDavid du Colombier p->sched.sp = PTR2UINT(p->kstack+KSTACK);
507*1c9d674cSDavid du Colombier p->sched.sp = STACKALIGN(p->sched.sp);
508*1c9d674cSDavid du Colombier
509*1c9d674cSDavid du Colombier p->kpfun = func;
510*1c9d674cSDavid du Colombier p->kparg = arg;
511*1c9d674cSDavid du Colombier }
512*1c9d674cSDavid du Colombier
513*1c9d674cSDavid du Colombier uintptr
userpc(void)514*1c9d674cSDavid du Colombier userpc(void)
515*1c9d674cSDavid du Colombier {
516*1c9d674cSDavid du Colombier Ureg *ureg = up->dbgreg;
517*1c9d674cSDavid du Colombier return ureg->pc;
518*1c9d674cSDavid du Colombier }
519*1c9d674cSDavid du Colombier
520*1c9d674cSDavid du Colombier /*
521*1c9d674cSDavid du Colombier * This routine must save the values of registers the user is not
522*1c9d674cSDavid du Colombier * permitted to write from devproc and then restore the saved values
523*1c9d674cSDavid du Colombier * before returning
524*1c9d674cSDavid du Colombier */
525*1c9d674cSDavid du Colombier void
setregisters(Ureg * ureg,char * pureg,char * uva,int n)526*1c9d674cSDavid du Colombier setregisters(Ureg *ureg, char *pureg, char *uva, int n)
527*1c9d674cSDavid du Colombier {
528*1c9d674cSDavid du Colombier u32int status;
529*1c9d674cSDavid du Colombier
530*1c9d674cSDavid du Colombier status = ureg->status;
531*1c9d674cSDavid du Colombier memmove(pureg, uva, n);
532*1c9d674cSDavid du Colombier ureg->status = status;
533*1c9d674cSDavid du Colombier }
534*1c9d674cSDavid du Colombier
535*1c9d674cSDavid du Colombier /*
536*1c9d674cSDavid du Colombier * Give enough context in the ureg to produce a kernel stack for
537*1c9d674cSDavid du Colombier * a sleeping process
538*1c9d674cSDavid du Colombier */
539*1c9d674cSDavid du Colombier void
setkernur(Ureg * ureg,Proc * p)540*1c9d674cSDavid du Colombier setkernur(Ureg* ureg, Proc* p)
541*1c9d674cSDavid du Colombier {
542*1c9d674cSDavid du Colombier ureg->pc = p->sched.pc;
543*1c9d674cSDavid du Colombier ureg->sp = p->sched.sp+BY2SE;
544*1c9d674cSDavid du Colombier }
545*1c9d674cSDavid du Colombier
546*1c9d674cSDavid du Colombier uintptr
dbgpc(Proc * p)547*1c9d674cSDavid du Colombier dbgpc(Proc* p)
548*1c9d674cSDavid du Colombier {
549*1c9d674cSDavid du Colombier Ureg *ureg;
550*1c9d674cSDavid du Colombier
551*1c9d674cSDavid du Colombier ureg = p->dbgreg;
552*1c9d674cSDavid du Colombier if(ureg == 0)
553*1c9d674cSDavid du Colombier return 0;
554*1c9d674cSDavid du Colombier
555*1c9d674cSDavid du Colombier return ureg->pc;
556*1c9d674cSDavid du Colombier }
557*1c9d674cSDavid du Colombier
558*1c9d674cSDavid du Colombier static Lock mchklck; /* only allow one probe or poke at a time */
559*1c9d674cSDavid du Colombier
560*1c9d674cSDavid du Colombier vlong
probeaddr(uintptr addr)561*1c9d674cSDavid du Colombier probeaddr(uintptr addr)
562*1c9d674cSDavid du Colombier {
563*1c9d674cSDavid du Colombier vlong v;
564*1c9d674cSDavid du Colombier
565*1c9d674cSDavid du Colombier ilock(&mchklck);
566*1c9d674cSDavid du Colombier trapped = 0;
567*1c9d674cSDavid du Colombier probing = 1;
568*1c9d674cSDavid du Colombier
569*1c9d674cSDavid du Colombier syncall();
570*1c9d674cSDavid du Colombier putmsr(getmsr() & ~MSR_ME); /* disable machine check traps */
571*1c9d674cSDavid du Colombier syncall();
572*1c9d674cSDavid du Colombier clrmchk();
573*1c9d674cSDavid du Colombier syncall();
574*1c9d674cSDavid du Colombier
575*1c9d674cSDavid du Colombier if (getesr() & ESR_MCI) /* machine check happened? */
576*1c9d674cSDavid du Colombier iprint("probeaddr: mcheck before probe\n");
577*1c9d674cSDavid du Colombier v = *(ulong *)addr; /* this may cause a machine check */
578*1c9d674cSDavid du Colombier syncall();
579*1c9d674cSDavid du Colombier
580*1c9d674cSDavid du Colombier if (getesr() & ESR_MCI) /* machine check happened? */
581*1c9d674cSDavid du Colombier trapped = 1;
582*1c9d674cSDavid du Colombier syncall();
583*1c9d674cSDavid du Colombier clrmchk();
584*1c9d674cSDavid du Colombier syncall();
585*1c9d674cSDavid du Colombier putmsr(getmsr() | MSR_ME); /* enable machine check traps */
586*1c9d674cSDavid du Colombier syncall();
587*1c9d674cSDavid du Colombier
588*1c9d674cSDavid du Colombier probing = 0;
589*1c9d674cSDavid du Colombier if (trapped)
590*1c9d674cSDavid du Colombier v = -1;
591*1c9d674cSDavid du Colombier //iprint("probeaddr: trapped=%d for addr %lux\n", trapped, addr);
592*1c9d674cSDavid du Colombier iunlock(&mchklck);
593*1c9d674cSDavid du Colombier return v;
594*1c9d674cSDavid du Colombier }
595*1c9d674cSDavid du Colombier
596*1c9d674cSDavid du Colombier vlong
pokeaddr(uintptr addr,uint v1,uint v2)597*1c9d674cSDavid du Colombier pokeaddr(uintptr addr, uint v1, uint v2)
598*1c9d674cSDavid du Colombier {
599*1c9d674cSDavid du Colombier vlong v;
600*1c9d674cSDavid du Colombier ulong *p;
601*1c9d674cSDavid du Colombier
602*1c9d674cSDavid du Colombier //iprint("probing %#lux...", addr);
603*1c9d674cSDavid du Colombier ilock(&mchklck);
604*1c9d674cSDavid du Colombier trapped = 0;
605*1c9d674cSDavid du Colombier probing = 1;
606*1c9d674cSDavid du Colombier
607*1c9d674cSDavid du Colombier syncall();
608*1c9d674cSDavid du Colombier putmsr(getmsr() & ~MSR_ME); /* disable machine check traps */
609*1c9d674cSDavid du Colombier syncall();
610*1c9d674cSDavid du Colombier clrmchk();
611*1c9d674cSDavid du Colombier syncall();
612*1c9d674cSDavid du Colombier
613*1c9d674cSDavid du Colombier if (getesr() & ESR_MCI) /* machine check happened? */
614*1c9d674cSDavid du Colombier iprint("pokeaddr: mcheck before probe\n");
615*1c9d674cSDavid du Colombier
616*1c9d674cSDavid du Colombier p = (ulong *)addr;
617*1c9d674cSDavid du Colombier *p = v1;
618*1c9d674cSDavid du Colombier syncall();
619*1c9d674cSDavid du Colombier v = *p; /* this may cause a machine check */
620*1c9d674cSDavid du Colombier syncall();
621*1c9d674cSDavid du Colombier if (getesr() & ESR_MCI || v != v1) /* machine check happened? */
622*1c9d674cSDavid du Colombier trapped = 1;
623*1c9d674cSDavid du Colombier
624*1c9d674cSDavid du Colombier *p = v2;
625*1c9d674cSDavid du Colombier syncall();
626*1c9d674cSDavid du Colombier v = *p; /* this may cause a machine check */
627*1c9d674cSDavid du Colombier syncall();
628*1c9d674cSDavid du Colombier if (getesr() & ESR_MCI || v != v2) /* machine check happened? */
629*1c9d674cSDavid du Colombier trapped = 1;
630*1c9d674cSDavid du Colombier
631*1c9d674cSDavid du Colombier syncall();
632*1c9d674cSDavid du Colombier clrmchk();
633*1c9d674cSDavid du Colombier syncall();
634*1c9d674cSDavid du Colombier putmsr(getmsr() | MSR_ME); /* enable machine check traps */
635*1c9d674cSDavid du Colombier syncall();
636*1c9d674cSDavid du Colombier
637*1c9d674cSDavid du Colombier probing = 0;
638*1c9d674cSDavid du Colombier if (trapped)
639*1c9d674cSDavid du Colombier v = -1;
640*1c9d674cSDavid du Colombier //iprint("pokeaddr: trapped=%d for addr %lux\n", trapped, addr);
641*1c9d674cSDavid du Colombier iunlock(&mchklck);
642*1c9d674cSDavid du Colombier return v;
643*1c9d674cSDavid du Colombier }
644