1*5c47fe09SDavid du Colombier /*
2*5c47fe09SDavid du Colombier * Adapted from ../teg2/trap.c
3*5c47fe09SDavid du Colombier *
4*5c47fe09SDavid du Colombier * arm mpcore generic interrupt controller (gic) v1
5*5c47fe09SDavid du Colombier * traps, exceptions, interrupts, system calls.
6*5c47fe09SDavid du Colombier *
7*5c47fe09SDavid du Colombier * there are two pieces: the interrupt distributor and the cpu interface.
8*5c47fe09SDavid du Colombier *
9*5c47fe09SDavid du Colombier * memset or memmove on any of the distributor registers generates an
10*5c47fe09SDavid du Colombier * exception like this one:
11*5c47fe09SDavid du Colombier * panic: external abort 0x28 pc 0xc048bf68 addr 0x50041800
12*5c47fe09SDavid du Colombier *
13*5c47fe09SDavid du Colombier * we use l1 and l2 cache ops to force vectors to be visible everywhere.
14*5c47fe09SDavid du Colombier *
15*5c47fe09SDavid du Colombier * apparently irqs 0—15 (SGIs) are always enabled.
16*5c47fe09SDavid du Colombier */
17*5c47fe09SDavid du Colombier #include "u.h"
18*5c47fe09SDavid du Colombier #include "../port/lib.h"
19*5c47fe09SDavid du Colombier #include "mem.h"
20*5c47fe09SDavid du Colombier #include "dat.h"
21*5c47fe09SDavid du Colombier #include "fns.h"
22*5c47fe09SDavid du Colombier #include "io.h"
23*5c47fe09SDavid du Colombier #include "../port/error.h"
24*5c47fe09SDavid du Colombier
25*5c47fe09SDavid du Colombier #include "ureg.h"
26*5c47fe09SDavid du Colombier #include "arm.h"
27*5c47fe09SDavid du Colombier
28*5c47fe09SDavid du Colombier #define IRQLOCAL(irq) ((irq) - IRQlocal + 13 + 16)
29*5c47fe09SDavid du Colombier #define IRQGLOBAL(irq) ((irq) + 64 + 32)
30*5c47fe09SDavid du Colombier
31*5c47fe09SDavid du Colombier #define ISSGI(irq) ((uint)(irq) < Nppi)
32*5c47fe09SDavid du Colombier
33*5c47fe09SDavid du Colombier enum {
34*5c47fe09SDavid du Colombier Debug = 0,
35*5c47fe09SDavid du Colombier
36*5c47fe09SDavid du Colombier Intrdist = 0x41000,
37*5c47fe09SDavid du Colombier Intrcpu = 0x42000,
38*5c47fe09SDavid du Colombier
39*5c47fe09SDavid du Colombier Nvec = 8, /* # of vectors at start of lexception.s */
40*5c47fe09SDavid du Colombier Bi2long = BI2BY * sizeof(long),
41*5c47fe09SDavid du Colombier Nirqs = 1024,
42*5c47fe09SDavid du Colombier Nsgi = 16, /* software-generated (inter-processor) intrs */
43*5c47fe09SDavid du Colombier Nppi = 32, /* sgis + other private peripheral intrs */
44*5c47fe09SDavid du Colombier };
45*5c47fe09SDavid du Colombier
46*5c47fe09SDavid du Colombier typedef struct Intrcpuregs Intrcpuregs;
47*5c47fe09SDavid du Colombier typedef struct Intrdistregs Intrdistregs;
48*5c47fe09SDavid du Colombier
49*5c47fe09SDavid du Colombier /*
50*5c47fe09SDavid du Colombier * almost this entire register set is buggered.
51*5c47fe09SDavid du Colombier * the distributor is supposed to be per-system, not per-cpu,
52*5c47fe09SDavid du Colombier * yet some registers are banked per-cpu, as marked.
53*5c47fe09SDavid du Colombier */
54*5c47fe09SDavid du Colombier struct Intrdistregs { /* distributor */
55*5c47fe09SDavid du Colombier ulong ctl;
56*5c47fe09SDavid du Colombier ulong ctlrtype;
57*5c47fe09SDavid du Colombier ulong distid;
58*5c47fe09SDavid du Colombier uchar _pad0[0x80 - 0xc];
59*5c47fe09SDavid du Colombier
60*5c47fe09SDavid du Colombier /* botch: *[0] are banked per-cpu from here */
61*5c47fe09SDavid du Colombier /* bit maps */
62*5c47fe09SDavid du Colombier ulong grp[32]; /* in group 1 (non-secure) */
63*5c47fe09SDavid du Colombier ulong setena[32]; /* forward to cpu interfaces */
64*5c47fe09SDavid du Colombier ulong clrena[32];
65*5c47fe09SDavid du Colombier ulong setpend[32];
66*5c47fe09SDavid du Colombier ulong clrpend[32];
67*5c47fe09SDavid du Colombier ulong setact[32]; /* active? */
68*5c47fe09SDavid du Colombier ulong clract[32];
69*5c47fe09SDavid du Colombier /* botch: *[0] are banked per-cpu until here */
70*5c47fe09SDavid du Colombier
71*5c47fe09SDavid du Colombier uchar pri[1020]; /* botch: pri[0] — pri[7] are banked per-cpu */
72*5c47fe09SDavid du Colombier ulong _rsrvd1;
73*5c47fe09SDavid du Colombier /* botch: targ[0] through targ[7] are banked per-cpu and RO */
74*5c47fe09SDavid du Colombier uchar targ[1020]; /* byte bit maps: cpu targets indexed by intr */
75*5c47fe09SDavid du Colombier ulong _rsrvd2;
76*5c47fe09SDavid du Colombier /* botch: cfg[1] is banked per-cpu */
77*5c47fe09SDavid du Colombier ulong cfg[64]; /* bit pairs: edge? 1-N? */
78*5c47fe09SDavid du Colombier ulong _pad1[64];
79*5c47fe09SDavid du Colombier ulong nsac[64]; /* bit pairs (v2 only) */
80*5c47fe09SDavid du Colombier
81*5c47fe09SDavid du Colombier /* software-generated intrs (a.k.a. sgi) */
82*5c47fe09SDavid du Colombier ulong swgen; /* intr targets */
83*5c47fe09SDavid du Colombier uchar _pad2[0xf10 - 0xf04];
84*5c47fe09SDavid du Colombier uchar clrsgipend[16]; /* bit map (v2 only) */
85*5c47fe09SDavid du Colombier uchar setsgipend[16]; /* bit map (v2 only) */
86*5c47fe09SDavid du Colombier };
87*5c47fe09SDavid du Colombier
88*5c47fe09SDavid du Colombier enum {
89*5c47fe09SDavid du Colombier /* ctl bits */
90*5c47fe09SDavid du Colombier Forw2cpuif = 1,
91*5c47fe09SDavid du Colombier
92*5c47fe09SDavid du Colombier /* ctlrtype bits */
93*5c47fe09SDavid du Colombier Cpunoshft = 5,
94*5c47fe09SDavid du Colombier Cpunomask = MASK(3),
95*5c47fe09SDavid du Colombier Intrlines = MASK(5),
96*5c47fe09SDavid du Colombier
97*5c47fe09SDavid du Colombier /* cfg bits */
98*5c47fe09SDavid du Colombier Level = 0<<1,
99*5c47fe09SDavid du Colombier Edge = 1<<1, /* edge-, not level-sensitive */
100*5c47fe09SDavid du Colombier Toall = 0<<0,
101*5c47fe09SDavid du Colombier To1 = 1<<0, /* vs. to all */
102*5c47fe09SDavid du Colombier
103*5c47fe09SDavid du Colombier /* swgen bits */
104*5c47fe09SDavid du Colombier Totargets = 0,
105*5c47fe09SDavid du Colombier Tonotme = 1<<24,
106*5c47fe09SDavid du Colombier Tome = 2<<24,
107*5c47fe09SDavid du Colombier };
108*5c47fe09SDavid du Colombier
109*5c47fe09SDavid du Colombier /* each cpu sees its own registers at the same base address ((ARMLOCAL+Intrcpu)) */
110*5c47fe09SDavid du Colombier struct Intrcpuregs {
111*5c47fe09SDavid du Colombier ulong ctl;
112*5c47fe09SDavid du Colombier ulong primask;
113*5c47fe09SDavid du Colombier
114*5c47fe09SDavid du Colombier ulong binpt; /* group pri vs subpri split */
115*5c47fe09SDavid du Colombier ulong ack;
116*5c47fe09SDavid du Colombier ulong end;
117*5c47fe09SDavid du Colombier ulong runpri;
118*5c47fe09SDavid du Colombier ulong hipripend;
119*5c47fe09SDavid du Colombier
120*5c47fe09SDavid du Colombier /* aliased regs (secure, for group 1) */
121*5c47fe09SDavid du Colombier ulong alibinpt;
122*5c47fe09SDavid du Colombier ulong aliack; /* (v2 only) */
123*5c47fe09SDavid du Colombier ulong aliend; /* (v2 only) */
124*5c47fe09SDavid du Colombier ulong alihipripend; /* (v2 only) */
125*5c47fe09SDavid du Colombier
126*5c47fe09SDavid du Colombier uchar _pad0[0xd0 - 0x2c];
127*5c47fe09SDavid du Colombier ulong actpri[4]; /* (v2 only) */
128*5c47fe09SDavid du Colombier ulong nsactpri[4]; /* (v2 only) */
129*5c47fe09SDavid du Colombier
130*5c47fe09SDavid du Colombier uchar _pad0[0xfc - 0xf0];
131*5c47fe09SDavid du Colombier ulong ifid; /* ro */
132*5c47fe09SDavid du Colombier
133*5c47fe09SDavid du Colombier uchar _pad0[0x1000 - 0x100];
134*5c47fe09SDavid du Colombier ulong deact; /* wo (v2 only) */
135*5c47fe09SDavid du Colombier };
136*5c47fe09SDavid du Colombier
137*5c47fe09SDavid du Colombier enum {
138*5c47fe09SDavid du Colombier /* ctl bits */
139*5c47fe09SDavid du Colombier Enable = 1,
140*5c47fe09SDavid du Colombier Eoinodeact = 1<<9, /* (v2 only) */
141*5c47fe09SDavid du Colombier
142*5c47fe09SDavid du Colombier /* (ali) ack/end/hipriend/deact bits */
143*5c47fe09SDavid du Colombier Intrmask = MASK(10),
144*5c47fe09SDavid du Colombier Cpuidshift = 10,
145*5c47fe09SDavid du Colombier Cpuidmask = MASK(3),
146*5c47fe09SDavid du Colombier
147*5c47fe09SDavid du Colombier /* ifid bits */
148*5c47fe09SDavid du Colombier Archversshift = 16,
149*5c47fe09SDavid du Colombier Archversmask = MASK(4),
150*5c47fe09SDavid du Colombier };
151*5c47fe09SDavid du Colombier
152*5c47fe09SDavid du Colombier typedef struct Vctl Vctl;
153*5c47fe09SDavid du Colombier typedef struct Vctl {
154*5c47fe09SDavid du Colombier Vctl* next; /* handlers on this vector */
155*5c47fe09SDavid du Colombier char *name; /* of driver, xallocated */
156*5c47fe09SDavid du Colombier void (*f)(Ureg*, void*); /* handler to call */
157*5c47fe09SDavid du Colombier void* a; /* argument to call it with */
158*5c47fe09SDavid du Colombier } Vctl;
159*5c47fe09SDavid du Colombier
160*5c47fe09SDavid du Colombier static Lock vctllock;
161*5c47fe09SDavid du Colombier static Vctl* vctl[Nirqs];
162*5c47fe09SDavid du Colombier
163*5c47fe09SDavid du Colombier /*
164*5c47fe09SDavid du Colombier * Layout at virtual address 0.
165*5c47fe09SDavid du Colombier */
166*5c47fe09SDavid du Colombier typedef struct Vpage0 {
167*5c47fe09SDavid du Colombier void (*vectors[Nvec])(void);
168*5c47fe09SDavid du Colombier u32int vtable[Nvec];
169*5c47fe09SDavid du Colombier } Vpage0;
170*5c47fe09SDavid du Colombier
171*5c47fe09SDavid du Colombier enum
172*5c47fe09SDavid du Colombier {
173*5c47fe09SDavid du Colombier Ntimevec = 20 /* number of time buckets for each intr */
174*5c47fe09SDavid du Colombier };
175*5c47fe09SDavid du Colombier ulong intrtimes[Nirqs][Ntimevec];
176*5c47fe09SDavid du Colombier
177*5c47fe09SDavid du Colombier int irqtooearly = 0;
178*5c47fe09SDavid du Colombier
179*5c47fe09SDavid du Colombier static ulong shadena[32]; /* copy of enable bits, saved by intcmaskall */
180*5c47fe09SDavid du Colombier static Lock distlock;
181*5c47fe09SDavid du Colombier
182*5c47fe09SDavid du Colombier extern int notify(Ureg*);
183*5c47fe09SDavid du Colombier
184*5c47fe09SDavid du Colombier static void dumpstackwithureg(Ureg *ureg);
185*5c47fe09SDavid du Colombier
186*5c47fe09SDavid du Colombier void
printrs(int base,ulong word)187*5c47fe09SDavid du Colombier printrs(int base, ulong word)
188*5c47fe09SDavid du Colombier {
189*5c47fe09SDavid du Colombier int bit;
190*5c47fe09SDavid du Colombier
191*5c47fe09SDavid du Colombier for (bit = 0; word; bit++, word >>= 1)
192*5c47fe09SDavid du Colombier if (word & 1)
193*5c47fe09SDavid du Colombier iprint(" %d", base + bit);
194*5c47fe09SDavid du Colombier }
195*5c47fe09SDavid du Colombier
196*5c47fe09SDavid du Colombier void
dumpintrs(char * what,ulong * bits)197*5c47fe09SDavid du Colombier dumpintrs(char *what, ulong *bits)
198*5c47fe09SDavid du Colombier {
199*5c47fe09SDavid du Colombier int i, first, some;
200*5c47fe09SDavid du Colombier ulong word;
201*5c47fe09SDavid du Colombier Intrdistregs *idp = (Intrdistregs *)(ARMLOCAL+Intrdist);
202*5c47fe09SDavid du Colombier
203*5c47fe09SDavid du Colombier first = 1;
204*5c47fe09SDavid du Colombier some = 0;
205*5c47fe09SDavid du Colombier USED(idp);
206*5c47fe09SDavid du Colombier for (i = 0; i < nelem(idp->setpend); i++) {
207*5c47fe09SDavid du Colombier word = bits[i];
208*5c47fe09SDavid du Colombier if (word) {
209*5c47fe09SDavid du Colombier if (first) {
210*5c47fe09SDavid du Colombier first = 0;
211*5c47fe09SDavid du Colombier iprint("%s", what);
212*5c47fe09SDavid du Colombier }
213*5c47fe09SDavid du Colombier some = 1;
214*5c47fe09SDavid du Colombier printrs(i * Bi2long, word);
215*5c47fe09SDavid du Colombier }
216*5c47fe09SDavid du Colombier }
217*5c47fe09SDavid du Colombier if (!some)
218*5c47fe09SDavid du Colombier iprint("%s none", what);
219*5c47fe09SDavid du Colombier iprint("\n");
220*5c47fe09SDavid du Colombier }
221*5c47fe09SDavid du Colombier
222*5c47fe09SDavid du Colombier void
dumpintrpend(void)223*5c47fe09SDavid du Colombier dumpintrpend(void)
224*5c47fe09SDavid du Colombier {
225*5c47fe09SDavid du Colombier Intrdistregs *idp = (Intrdistregs *)(ARMLOCAL+Intrdist);
226*5c47fe09SDavid du Colombier
227*5c47fe09SDavid du Colombier iprint("\ncpu%d gic regs:\n", m->machno);
228*5c47fe09SDavid du Colombier dumpintrs("group 1", idp->grp);
229*5c47fe09SDavid du Colombier dumpintrs("enabled", idp->setena);
230*5c47fe09SDavid du Colombier dumpintrs("pending", idp->setpend);
231*5c47fe09SDavid du Colombier dumpintrs("active ", idp->setact);
232*5c47fe09SDavid du Colombier }
233*5c47fe09SDavid du Colombier
234*5c47fe09SDavid du Colombier /*
235*5c47fe09SDavid du Colombier * keep histogram of interrupt service times
236*5c47fe09SDavid du Colombier */
237*5c47fe09SDavid du Colombier void
intrtime(Mach *,int vno)238*5c47fe09SDavid du Colombier intrtime(Mach*, int vno)
239*5c47fe09SDavid du Colombier {
240*5c47fe09SDavid du Colombier ulong diff;
241*5c47fe09SDavid du Colombier ulong x;
242*5c47fe09SDavid du Colombier
243*5c47fe09SDavid du Colombier x = perfticks();
244*5c47fe09SDavid du Colombier diff = x - m->perf.intrts;
245*5c47fe09SDavid du Colombier m->perf.intrts = x;
246*5c47fe09SDavid du Colombier
247*5c47fe09SDavid du Colombier m->perf.inintr += diff;
248*5c47fe09SDavid du Colombier if(up == nil && m->perf.inidle > diff)
249*5c47fe09SDavid du Colombier m->perf.inidle -= diff;
250*5c47fe09SDavid du Colombier
251*5c47fe09SDavid du Colombier if (m->cpumhz == 0)
252*5c47fe09SDavid du Colombier return; /* don't divide by zero */
253*5c47fe09SDavid du Colombier diff /= m->cpumhz*100; /* quantum = 100µsec */
254*5c47fe09SDavid du Colombier if(diff >= Ntimevec)
255*5c47fe09SDavid du Colombier diff = Ntimevec-1;
256*5c47fe09SDavid du Colombier if ((uint)vno >= Nirqs)
257*5c47fe09SDavid du Colombier vno = Nirqs-1;
258*5c47fe09SDavid du Colombier intrtimes[vno][diff]++;
259*5c47fe09SDavid du Colombier }
260*5c47fe09SDavid du Colombier
261*5c47fe09SDavid du Colombier static ulong
intack(Intrcpuregs * icp)262*5c47fe09SDavid du Colombier intack(Intrcpuregs *icp)
263*5c47fe09SDavid du Colombier {
264*5c47fe09SDavid du Colombier return icp->ack & Intrmask;
265*5c47fe09SDavid du Colombier }
266*5c47fe09SDavid du Colombier
267*5c47fe09SDavid du Colombier static void
intdismiss(Intrcpuregs * icp,ulong ack)268*5c47fe09SDavid du Colombier intdismiss(Intrcpuregs *icp, ulong ack)
269*5c47fe09SDavid du Colombier {
270*5c47fe09SDavid du Colombier icp->end = ack;
271*5c47fe09SDavid du Colombier coherence();
272*5c47fe09SDavid du Colombier }
273*5c47fe09SDavid du Colombier
274*5c47fe09SDavid du Colombier static int
irqinuse(uint irq)275*5c47fe09SDavid du Colombier irqinuse(uint irq)
276*5c47fe09SDavid du Colombier {
277*5c47fe09SDavid du Colombier Intrdistregs *idp = (Intrdistregs *)(ARMLOCAL+Intrdist);
278*5c47fe09SDavid du Colombier
279*5c47fe09SDavid du Colombier return idp->setena[irq / Bi2long] & (1 << (irq % Bi2long));
280*5c47fe09SDavid du Colombier }
281*5c47fe09SDavid du Colombier
282*5c47fe09SDavid du Colombier void
intcunmask(uint irq)283*5c47fe09SDavid du Colombier intcunmask(uint irq)
284*5c47fe09SDavid du Colombier {
285*5c47fe09SDavid du Colombier Intrdistregs *idp = (Intrdistregs *)(ARMLOCAL+Intrdist);
286*5c47fe09SDavid du Colombier
287*5c47fe09SDavid du Colombier ilock(&distlock);
288*5c47fe09SDavid du Colombier idp->setena[irq / Bi2long] = 1 << (irq % Bi2long);
289*5c47fe09SDavid du Colombier iunlock(&distlock);
290*5c47fe09SDavid du Colombier }
291*5c47fe09SDavid du Colombier
292*5c47fe09SDavid du Colombier void
intcmask(uint irq)293*5c47fe09SDavid du Colombier intcmask(uint irq)
294*5c47fe09SDavid du Colombier {
295*5c47fe09SDavid du Colombier Intrdistregs *idp = (Intrdistregs *)(ARMLOCAL+Intrdist);
296*5c47fe09SDavid du Colombier
297*5c47fe09SDavid du Colombier ilock(&distlock);
298*5c47fe09SDavid du Colombier idp->clrena[irq / Bi2long] = 1 << (irq % Bi2long);
299*5c47fe09SDavid du Colombier iunlock(&distlock);
300*5c47fe09SDavid du Colombier }
301*5c47fe09SDavid du Colombier
302*5c47fe09SDavid du Colombier static void
intcmaskall(Intrdistregs * idp)303*5c47fe09SDavid du Colombier intcmaskall(Intrdistregs *idp) /* mask all intrs for all cpus */
304*5c47fe09SDavid du Colombier {
305*5c47fe09SDavid du Colombier int i;
306*5c47fe09SDavid du Colombier
307*5c47fe09SDavid du Colombier for (i = 0; i < nelem(idp->setena); i++)
308*5c47fe09SDavid du Colombier shadena[i] = idp->setena[i];
309*5c47fe09SDavid du Colombier for (i = 0; i < nelem(idp->clrena); i++)
310*5c47fe09SDavid du Colombier idp->clrena[i] = ~0;
311*5c47fe09SDavid du Colombier coherence();
312*5c47fe09SDavid du Colombier }
313*5c47fe09SDavid du Colombier
314*5c47fe09SDavid du Colombier static void
intcunmaskall(Intrdistregs * idp)315*5c47fe09SDavid du Colombier intcunmaskall(Intrdistregs *idp) /* unused */
316*5c47fe09SDavid du Colombier {
317*5c47fe09SDavid du Colombier int i;
318*5c47fe09SDavid du Colombier
319*5c47fe09SDavid du Colombier for (i = 0; i < nelem(idp->setena); i++)
320*5c47fe09SDavid du Colombier idp->setena[i] = shadena[i];
321*5c47fe09SDavid du Colombier coherence();
322*5c47fe09SDavid du Colombier }
323*5c47fe09SDavid du Colombier
324*5c47fe09SDavid du Colombier static ulong
permintrs(Intrdistregs * idp,int base,int r)325*5c47fe09SDavid du Colombier permintrs(Intrdistregs *idp, int base, int r)
326*5c47fe09SDavid du Colombier {
327*5c47fe09SDavid du Colombier ulong perms;
328*5c47fe09SDavid du Colombier
329*5c47fe09SDavid du Colombier idp->clrena[r] = ~0; /* disable all */
330*5c47fe09SDavid du Colombier coherence();
331*5c47fe09SDavid du Colombier perms = idp->clrena[r];
332*5c47fe09SDavid du Colombier if (perms) {
333*5c47fe09SDavid du Colombier iprint("perm intrs:");
334*5c47fe09SDavid du Colombier printrs(base, perms);
335*5c47fe09SDavid du Colombier iprint("\n");
336*5c47fe09SDavid du Colombier }
337*5c47fe09SDavid du Colombier return perms;
338*5c47fe09SDavid du Colombier }
339*5c47fe09SDavid du Colombier
340*5c47fe09SDavid du Colombier static void
intrcfg(Intrdistregs * idp)341*5c47fe09SDavid du Colombier intrcfg(Intrdistregs *idp)
342*5c47fe09SDavid du Colombier {
343*5c47fe09SDavid du Colombier int i, cpumask;
344*5c47fe09SDavid du Colombier ulong pat;
345*5c47fe09SDavid du Colombier
346*5c47fe09SDavid du Colombier /* set up all interrupts as level-sensitive, to one cpu (0) */
347*5c47fe09SDavid du Colombier pat = 0;
348*5c47fe09SDavid du Colombier for (i = 0; i < Bi2long; i += 2)
349*5c47fe09SDavid du Colombier pat |= (Level | To1) << i;
350*5c47fe09SDavid du Colombier
351*5c47fe09SDavid du Colombier if (m->machno == 0) { /* system-wide & cpu0 cfg */
352*5c47fe09SDavid du Colombier for (i = 0; i < nelem(idp->grp); i++)
353*5c47fe09SDavid du Colombier idp->grp[i] = 0; /* secure */
354*5c47fe09SDavid du Colombier for (i = 0; i < nelem(idp->pri); i++)
355*5c47fe09SDavid du Colombier idp->pri[i] = 0; /* highest priority */
356*5c47fe09SDavid du Colombier /* set up all interrupts as level-sensitive, to one cpu (0) */
357*5c47fe09SDavid du Colombier for (i = 0; i < nelem(idp->cfg); i++)
358*5c47fe09SDavid du Colombier idp->cfg[i] = pat;
359*5c47fe09SDavid du Colombier /* first Nppi are read-only for SGIs and PPIs */
360*5c47fe09SDavid du Colombier cpumask = 1<<0; /* just cpu 0 */
361*5c47fe09SDavid du Colombier for (i = Nppi; i < sizeof idp->targ; i++)
362*5c47fe09SDavid du Colombier idp->targ[i] = cpumask;
363*5c47fe09SDavid du Colombier coherence();
364*5c47fe09SDavid du Colombier
365*5c47fe09SDavid du Colombier intcmaskall(idp);
366*5c47fe09SDavid du Colombier for (i = 0; i < nelem(idp->clrena); i++) {
367*5c47fe09SDavid du Colombier // permintrs(idp, i * Bi2long, i);
368*5c47fe09SDavid du Colombier idp->clrpend[i] = idp->clract[i] = idp->clrena[i] = ~0;
369*5c47fe09SDavid du Colombier }
370*5c47fe09SDavid du Colombier } else { /* per-cpu config */
371*5c47fe09SDavid du Colombier idp->grp[0] = 0; /* secure */
372*5c47fe09SDavid du Colombier for (i = 0; i < 8; i++)
373*5c47fe09SDavid du Colombier idp->pri[i] = 0; /* highest priority */
374*5c47fe09SDavid du Colombier /* idp->targ[0 through Nppi-1] are supposed to be read-only */
375*5c47fe09SDavid du Colombier for (i = 0; i < Nppi; i++)
376*5c47fe09SDavid du Colombier idp->targ[i] = 1<<m->machno;
377*5c47fe09SDavid du Colombier idp->cfg[1] = pat;
378*5c47fe09SDavid du Colombier coherence();
379*5c47fe09SDavid du Colombier
380*5c47fe09SDavid du Colombier // permintrs(idp, i * Bi2long, i);
381*5c47fe09SDavid du Colombier idp->clrpend[0] = idp->clract[0] = idp->clrena[0] = ~0;
382*5c47fe09SDavid du Colombier /* on cpu1, irq Extpmuirq (118) is always pending here */
383*5c47fe09SDavid du Colombier }
384*5c47fe09SDavid du Colombier coherence();
385*5c47fe09SDavid du Colombier }
386*5c47fe09SDavid du Colombier
387*5c47fe09SDavid du Colombier void
intrto(int cpu,int irq)388*5c47fe09SDavid du Colombier intrto(int cpu, int irq)
389*5c47fe09SDavid du Colombier {
390*5c47fe09SDavid du Colombier Intrdistregs *idp = (Intrdistregs *)(ARMLOCAL+Intrdist);
391*5c47fe09SDavid du Colombier
392*5c47fe09SDavid du Colombier /* first Nppi are read-only for SGIs and the like */
393*5c47fe09SDavid du Colombier ilock(&distlock);
394*5c47fe09SDavid du Colombier idp->targ[irq] = 1 << cpu;
395*5c47fe09SDavid du Colombier iunlock(&distlock);
396*5c47fe09SDavid du Colombier }
397*5c47fe09SDavid du Colombier
398*5c47fe09SDavid du Colombier void
intrsto(int cpu)399*5c47fe09SDavid du Colombier intrsto(int cpu) /* unused */
400*5c47fe09SDavid du Colombier {
401*5c47fe09SDavid du Colombier int i;
402*5c47fe09SDavid du Colombier Intrdistregs *idp = (Intrdistregs *)(ARMLOCAL+Intrdist);
403*5c47fe09SDavid du Colombier
404*5c47fe09SDavid du Colombier /* first Nppi are read-only for SGIs and the like */
405*5c47fe09SDavid du Colombier for (i = Nppi; i < sizeof idp->targ; i++)
406*5c47fe09SDavid du Colombier intrto(cpu, i);
407*5c47fe09SDavid du Colombier USED(idp);
408*5c47fe09SDavid du Colombier }
409*5c47fe09SDavid du Colombier
410*5c47fe09SDavid du Colombier void
intrcpu(int cpu)411*5c47fe09SDavid du Colombier intrcpu(int cpu)
412*5c47fe09SDavid du Colombier {
413*5c47fe09SDavid du Colombier Intrdistregs *idp = (Intrdistregs *)(ARMLOCAL+Intrdist);
414*5c47fe09SDavid du Colombier
415*5c47fe09SDavid du Colombier ilock(&distlock);
416*5c47fe09SDavid du Colombier idp->swgen = Totargets | 1 << (cpu + 16) | m->machno;
417*5c47fe09SDavid du Colombier iunlock(&distlock);
418*5c47fe09SDavid du Colombier }
419*5c47fe09SDavid du Colombier
420*5c47fe09SDavid du Colombier /*
421*5c47fe09SDavid du Colombier * set up for exceptions
422*5c47fe09SDavid du Colombier */
423*5c47fe09SDavid du Colombier void
trapinit(void)424*5c47fe09SDavid du Colombier trapinit(void)
425*5c47fe09SDavid du Colombier {
426*5c47fe09SDavid du Colombier int s;
427*5c47fe09SDavid du Colombier Intrdistregs *idp = (Intrdistregs *)(ARMLOCAL+Intrdist);
428*5c47fe09SDavid du Colombier Intrcpuregs *icp = (Intrcpuregs *)(ARMLOCAL+Intrcpu);
429*5c47fe09SDavid du Colombier Vpage0 *vpage0;
430*5c47fe09SDavid du Colombier enum { Vecsize = sizeof vpage0->vectors + sizeof vpage0->vtable, };
431*5c47fe09SDavid du Colombier
432*5c47fe09SDavid du Colombier /*
433*5c47fe09SDavid du Colombier * set up the exception vectors, high and low.
434*5c47fe09SDavid du Colombier *
435*5c47fe09SDavid du Colombier * we can't use cache ops on HVECTORS address, since they
436*5c47fe09SDavid du Colombier * work on virtual addresses, and only those that have a
437*5c47fe09SDavid du Colombier * physical address == PADDR(virtual).
438*5c47fe09SDavid du Colombier */
439*5c47fe09SDavid du Colombier if (m->machno == 0) {
440*5c47fe09SDavid du Colombier vpage0 = (Vpage0*)HVECTORS;
441*5c47fe09SDavid du Colombier memmove(vpage0->vectors, vectors, sizeof(vpage0->vectors));
442*5c47fe09SDavid du Colombier memmove(vpage0->vtable, vtable, sizeof(vpage0->vtable));
443*5c47fe09SDavid du Colombier
444*5c47fe09SDavid du Colombier vpage0 = (Vpage0*)KADDR(0);
445*5c47fe09SDavid du Colombier memmove(vpage0->vectors, vectors, sizeof(vpage0->vectors));
446*5c47fe09SDavid du Colombier memmove(vpage0->vtable, vtable, sizeof(vpage0->vtable));
447*5c47fe09SDavid du Colombier
448*5c47fe09SDavid du Colombier cacheuwbinv();
449*5c47fe09SDavid du Colombier l2cacheuwbinv();
450*5c47fe09SDavid du Colombier }
451*5c47fe09SDavid du Colombier
452*5c47fe09SDavid du Colombier /*
453*5c47fe09SDavid du Colombier * set up the stack pointers for the exception modes for this cpu.
454*5c47fe09SDavid du Colombier * they point to small `save areas' in Mach, not actual stacks.
455*5c47fe09SDavid du Colombier */
456*5c47fe09SDavid du Colombier s = splhi(); /* make these modes ignore intrs too */
457*5c47fe09SDavid du Colombier setr13(PsrMfiq, (u32int*)(FIQSTKTOP));
458*5c47fe09SDavid du Colombier setr13(PsrMirq, m->sirq);
459*5c47fe09SDavid du Colombier setr13(PsrMabt, m->sabt);
460*5c47fe09SDavid du Colombier setr13(PsrMund, m->sund);
461*5c47fe09SDavid du Colombier setr13(PsrMsys, m->ssys);
462*5c47fe09SDavid du Colombier splx(s);
463*5c47fe09SDavid du Colombier
464*5c47fe09SDavid du Colombier assert((idp->distid & MASK(12)) == 0x43b); /* made by arm */
465*5c47fe09SDavid du Colombier assert((icp->ifid & MASK(12)) == 0x43b); /* made by arm */
466*5c47fe09SDavid du Colombier
467*5c47fe09SDavid du Colombier ilock(&distlock);
468*5c47fe09SDavid du Colombier idp->ctl = 0;
469*5c47fe09SDavid du Colombier icp->ctl = 0;
470*5c47fe09SDavid du Colombier coherence();
471*5c47fe09SDavid du Colombier
472*5c47fe09SDavid du Colombier intrcfg(idp); /* some per-cpu cfg here */
473*5c47fe09SDavid du Colombier
474*5c47fe09SDavid du Colombier icp->ctl = Enable;
475*5c47fe09SDavid du Colombier icp->primask = (uchar)~0; /* let all priorities through */
476*5c47fe09SDavid du Colombier coherence();
477*5c47fe09SDavid du Colombier
478*5c47fe09SDavid du Colombier idp->ctl = Forw2cpuif;
479*5c47fe09SDavid du Colombier iunlock(&distlock);
480*5c47fe09SDavid du Colombier }
481*5c47fe09SDavid du Colombier
482*5c47fe09SDavid du Colombier void
intrsoff(void)483*5c47fe09SDavid du Colombier intrsoff(void)
484*5c47fe09SDavid du Colombier {
485*5c47fe09SDavid du Colombier ilock(&distlock);
486*5c47fe09SDavid du Colombier intcmaskall((Intrdistregs *)(ARMLOCAL+Intrdist));
487*5c47fe09SDavid du Colombier iunlock(&distlock);
488*5c47fe09SDavid du Colombier }
489*5c47fe09SDavid du Colombier
490*5c47fe09SDavid du Colombier void
intrcpushutdown(void)491*5c47fe09SDavid du Colombier intrcpushutdown(void)
492*5c47fe09SDavid du Colombier {
493*5c47fe09SDavid du Colombier Intrcpuregs *icp = (Intrcpuregs *)(ARMLOCAL+Intrcpu);
494*5c47fe09SDavid du Colombier
495*5c47fe09SDavid du Colombier icp->ctl = 0;
496*5c47fe09SDavid du Colombier icp->primask = 0; /* let no priorities through */
497*5c47fe09SDavid du Colombier coherence();
498*5c47fe09SDavid du Colombier }
499*5c47fe09SDavid du Colombier
500*5c47fe09SDavid du Colombier /* called from cpu0 after other cpus are shutdown */
501*5c47fe09SDavid du Colombier void
intrshutdown(void)502*5c47fe09SDavid du Colombier intrshutdown(void)
503*5c47fe09SDavid du Colombier {
504*5c47fe09SDavid du Colombier Intrdistregs *idp = (Intrdistregs *)(ARMLOCAL+Intrdist);
505*5c47fe09SDavid du Colombier
506*5c47fe09SDavid du Colombier intrsoff();
507*5c47fe09SDavid du Colombier idp->ctl = 0;
508*5c47fe09SDavid du Colombier intrcpushutdown();
509*5c47fe09SDavid du Colombier }
510*5c47fe09SDavid du Colombier
511*5c47fe09SDavid du Colombier /*
512*5c47fe09SDavid du Colombier * enable an irq interrupt
513*5c47fe09SDavid du Colombier * note that the same private interrupt may be enabled on multiple cpus
514*5c47fe09SDavid du Colombier */
515*5c47fe09SDavid du Colombier void
irqenable(int irq,void (* f)(Ureg *,void *),void * a)516*5c47fe09SDavid du Colombier irqenable(int irq, void (*f)(Ureg*, void*), void* a)
517*5c47fe09SDavid du Colombier {
518*5c47fe09SDavid du Colombier Vctl *v;
519*5c47fe09SDavid du Colombier int ena;
520*5c47fe09SDavid du Colombier static char name[] = "anon";
521*5c47fe09SDavid du Colombier
522*5c47fe09SDavid du Colombier /* permute irq numbers for pi4 */
523*5c47fe09SDavid du Colombier if(irq >= IRQlocal)
524*5c47fe09SDavid du Colombier irq = IRQLOCAL(irq);
525*5c47fe09SDavid du Colombier else
526*5c47fe09SDavid du Colombier irq = IRQGLOBAL(irq);
527*5c47fe09SDavid du Colombier if(irq >= nelem(vctl))
528*5c47fe09SDavid du Colombier panic("irqenable irq %d", irq);
529*5c47fe09SDavid du Colombier
530*5c47fe09SDavid du Colombier if (irqtooearly) {
531*5c47fe09SDavid du Colombier iprint("irqenable for %d %s called too early\n", irq, name);
532*5c47fe09SDavid du Colombier return;
533*5c47fe09SDavid du Colombier }
534*5c47fe09SDavid du Colombier
535*5c47fe09SDavid du Colombier /*
536*5c47fe09SDavid du Colombier * if in use, could be a private interrupt on a secondary cpu,
537*5c47fe09SDavid du Colombier * or a shared irq number (eg emmc and sdhc)
538*5c47fe09SDavid du Colombier */
539*5c47fe09SDavid du Colombier ena = 1;
540*5c47fe09SDavid du Colombier if(!ISSGI(irq) || vctl[irq] == nil) {
541*5c47fe09SDavid du Colombier v = malloc(sizeof(Vctl));
542*5c47fe09SDavid du Colombier if (v == nil)
543*5c47fe09SDavid du Colombier panic("irqenable: malloc Vctl");
544*5c47fe09SDavid du Colombier v->f = f;
545*5c47fe09SDavid du Colombier v->a = a;
546*5c47fe09SDavid du Colombier v->name = malloc(strlen(name)+1);
547*5c47fe09SDavid du Colombier if (v->name == nil)
548*5c47fe09SDavid du Colombier panic("irqenable: malloc name");
549*5c47fe09SDavid du Colombier strcpy(v->name, name);
550*5c47fe09SDavid du Colombier
551*5c47fe09SDavid du Colombier lock(&vctllock);
552*5c47fe09SDavid du Colombier v->next = vctl[irq];
553*5c47fe09SDavid du Colombier if (v->next == nil)
554*5c47fe09SDavid du Colombier vctl[irq] = v;
555*5c47fe09SDavid du Colombier else if (!ISSGI(irq)) {
556*5c47fe09SDavid du Colombier /* shared irq number */
557*5c47fe09SDavid du Colombier vctl[irq] = v;
558*5c47fe09SDavid du Colombier ena = 0;
559*5c47fe09SDavid du Colombier } else {
560*5c47fe09SDavid du Colombier /* allocation race: someone else did it first */
561*5c47fe09SDavid du Colombier free(v->name);
562*5c47fe09SDavid du Colombier free(v);
563*5c47fe09SDavid du Colombier }
564*5c47fe09SDavid du Colombier unlock(&vctllock);
565*5c47fe09SDavid du Colombier }
566*5c47fe09SDavid du Colombier if (ena) {
567*5c47fe09SDavid du Colombier intdismiss((Intrcpuregs *)(ARMLOCAL+Intrcpu), irq);
568*5c47fe09SDavid du Colombier intcunmask(irq);
569*5c47fe09SDavid du Colombier }
570*5c47fe09SDavid du Colombier }
571*5c47fe09SDavid du Colombier
572*5c47fe09SDavid du Colombier /*
573*5c47fe09SDavid du Colombier * called by trap to handle access faults
574*5c47fe09SDavid du Colombier */
575*5c47fe09SDavid du Colombier static void
faultarm(Ureg * ureg,uintptr va,int user,int read)576*5c47fe09SDavid du Colombier faultarm(Ureg *ureg, uintptr va, int user, int read)
577*5c47fe09SDavid du Colombier {
578*5c47fe09SDavid du Colombier int n, insyscall;
579*5c47fe09SDavid du Colombier
580*5c47fe09SDavid du Colombier if(up == nil) {
581*5c47fe09SDavid du Colombier dumpstackwithureg(ureg);
582*5c47fe09SDavid du Colombier panic("faultarm: cpu%d: nil up, %sing %#p at %#p",
583*5c47fe09SDavid du Colombier m->machno, (read? "read": "writ"), va, ureg->pc);
584*5c47fe09SDavid du Colombier }
585*5c47fe09SDavid du Colombier insyscall = up->insyscall;
586*5c47fe09SDavid du Colombier up->insyscall = 1;
587*5c47fe09SDavid du Colombier
588*5c47fe09SDavid du Colombier n = fault(va, read); /* goes spllo */
589*5c47fe09SDavid du Colombier splhi();
590*5c47fe09SDavid du Colombier if(n < 0){
591*5c47fe09SDavid du Colombier char buf[ERRMAX];
592*5c47fe09SDavid du Colombier
593*5c47fe09SDavid du Colombier if(!user){
594*5c47fe09SDavid du Colombier dumpstackwithureg(ureg);
595*5c47fe09SDavid du Colombier panic("fault: cpu%d: kernel %sing %#p at %#p",
596*5c47fe09SDavid du Colombier m->machno, read? "read": "writ", va, ureg->pc);
597*5c47fe09SDavid du Colombier }
598*5c47fe09SDavid du Colombier /* don't dump registers; programs suicide all the time */
599*5c47fe09SDavid du Colombier snprint(buf, sizeof buf, "sys: trap: fault %s va=%#p",
600*5c47fe09SDavid du Colombier read? "read": "write", va);
601*5c47fe09SDavid du Colombier postnote(up, 1, buf, NDebug);
602*5c47fe09SDavid du Colombier }
603*5c47fe09SDavid du Colombier up->insyscall = insyscall;
604*5c47fe09SDavid du Colombier }
605*5c47fe09SDavid du Colombier
606*5c47fe09SDavid du Colombier /*
607*5c47fe09SDavid du Colombier * called by trap to handle interrupts.
608*5c47fe09SDavid du Colombier * returns true iff a clock interrupt, thus maybe reschedule.
609*5c47fe09SDavid du Colombier */
610*5c47fe09SDavid du Colombier static int
irq(Ureg * ureg)611*5c47fe09SDavid du Colombier irq(Ureg* ureg)
612*5c47fe09SDavid du Colombier {
613*5c47fe09SDavid du Colombier int clockintr, ack;
614*5c47fe09SDavid du Colombier uint irqno, handled;
615*5c47fe09SDavid du Colombier Intrcpuregs *icp = (Intrcpuregs *)(ARMLOCAL+Intrcpu);
616*5c47fe09SDavid du Colombier Vctl *v;
617*5c47fe09SDavid du Colombier
618*5c47fe09SDavid du Colombier clockintr = 0;
619*5c47fe09SDavid du Colombier again:
620*5c47fe09SDavid du Colombier ack = intack(icp);
621*5c47fe09SDavid du Colombier irqno = ack & Intrmask;
622*5c47fe09SDavid du Colombier
623*5c47fe09SDavid du Colombier if(irqno == 1023)
624*5c47fe09SDavid du Colombier return clockintr;
625*5c47fe09SDavid du Colombier if(irqno == IRQGLOBAL(IRQclock) || irqno == IRQLOCAL(IRQcntpns))
626*5c47fe09SDavid du Colombier clockintr = 1;
627*5c47fe09SDavid du Colombier
628*5c47fe09SDavid du Colombier handled = 0;
629*5c47fe09SDavid du Colombier for(v = vctl[irqno]; v != nil; v = v->next)
630*5c47fe09SDavid du Colombier if (v->f) {
631*5c47fe09SDavid du Colombier if (islo())
632*5c47fe09SDavid du Colombier panic("trap: pl0 before trap handler for %s",
633*5c47fe09SDavid du Colombier v->name);
634*5c47fe09SDavid du Colombier coherence();
635*5c47fe09SDavid du Colombier v->f(ureg, v->a);
636*5c47fe09SDavid du Colombier coherence();
637*5c47fe09SDavid du Colombier if (islo())
638*5c47fe09SDavid du Colombier panic("trap: %s lowered pl", v->name);
639*5c47fe09SDavid du Colombier // splhi(); /* in case v->f lowered pl */
640*5c47fe09SDavid du Colombier handled++;
641*5c47fe09SDavid du Colombier }
642*5c47fe09SDavid du Colombier if(!handled){
643*5c47fe09SDavid du Colombier if (irqno >= 1022){
644*5c47fe09SDavid du Colombier iprint("cpu%d: ignoring spurious interrupt\n", m->machno);
645*5c47fe09SDavid du Colombier return clockintr;
646*5c47fe09SDavid du Colombier }else {
647*5c47fe09SDavid du Colombier intcmask(irqno);
648*5c47fe09SDavid du Colombier iprint("cpu%d: unexpected interrupt %d, now masked\n",
649*5c47fe09SDavid du Colombier m->machno, irqno);
650*5c47fe09SDavid du Colombier }
651*5c47fe09SDavid du Colombier }
652*5c47fe09SDavid du Colombier
653*5c47fe09SDavid du Colombier intdismiss(icp, ack);
654*5c47fe09SDavid du Colombier intrtime(m, irqno);
655*5c47fe09SDavid du Colombier goto again;
656*5c47fe09SDavid du Colombier }
657*5c47fe09SDavid du Colombier
658*5c47fe09SDavid du Colombier /*
659*5c47fe09SDavid du Colombier * returns 1 if the instruction writes memory, 0 otherwise
660*5c47fe09SDavid du Colombier */
661*5c47fe09SDavid du Colombier int
writetomem(ulong inst)662*5c47fe09SDavid du Colombier writetomem(ulong inst)
663*5c47fe09SDavid du Colombier {
664*5c47fe09SDavid du Colombier /* swap always write memory */
665*5c47fe09SDavid du Colombier if((inst & 0x0FC00000) == 0x01000000)
666*5c47fe09SDavid du Colombier return 1;
667*5c47fe09SDavid du Colombier
668*5c47fe09SDavid du Colombier /* loads and stores are distinguished by bit 20 */
669*5c47fe09SDavid du Colombier if(inst & (1<<20))
670*5c47fe09SDavid du Colombier return 0;
671*5c47fe09SDavid du Colombier
672*5c47fe09SDavid du Colombier return 1;
673*5c47fe09SDavid du Colombier }
674*5c47fe09SDavid du Colombier
675*5c47fe09SDavid du Colombier static void
datafault(Ureg * ureg,int user)676*5c47fe09SDavid du Colombier datafault(Ureg *ureg, int user)
677*5c47fe09SDavid du Colombier {
678*5c47fe09SDavid du Colombier int x;
679*5c47fe09SDavid du Colombier ulong inst, fsr;
680*5c47fe09SDavid du Colombier uintptr va;
681*5c47fe09SDavid du Colombier
682*5c47fe09SDavid du Colombier va = farget();
683*5c47fe09SDavid du Colombier
684*5c47fe09SDavid du Colombier inst = *(ulong*)(ureg->pc);
685*5c47fe09SDavid du Colombier /* bits 12 and 10 have to be concatenated with status */
686*5c47fe09SDavid du Colombier x = fsrget();
687*5c47fe09SDavid du Colombier fsr = (x>>7) & 0x20 | (x>>6) & 0x10 | x & 0xf;
688*5c47fe09SDavid du Colombier switch(fsr){
689*5c47fe09SDavid du Colombier default:
690*5c47fe09SDavid du Colombier case 0xa: /* ? was under external abort */
691*5c47fe09SDavid du Colombier panic("unknown data fault, 6b fsr %#lux", fsr);
692*5c47fe09SDavid du Colombier break;
693*5c47fe09SDavid du Colombier case 0x0:
694*5c47fe09SDavid du Colombier panic("vector exception at %#lux", ureg->pc);
695*5c47fe09SDavid du Colombier break;
696*5c47fe09SDavid du Colombier case 0x1: /* alignment fault */
697*5c47fe09SDavid du Colombier case 0x3: /* access flag fault (section) */
698*5c47fe09SDavid du Colombier if(user){
699*5c47fe09SDavid du Colombier char buf[ERRMAX];
700*5c47fe09SDavid du Colombier
701*5c47fe09SDavid du Colombier snprint(buf, sizeof buf,
702*5c47fe09SDavid du Colombier "sys: alignment: pc %#lux va %#p\n",
703*5c47fe09SDavid du Colombier ureg->pc, va);
704*5c47fe09SDavid du Colombier postnote(up, 1, buf, NDebug);
705*5c47fe09SDavid du Colombier } else {
706*5c47fe09SDavid du Colombier dumpstackwithureg(ureg);
707*5c47fe09SDavid du Colombier panic("kernel alignment: pc %#lux va %#p", ureg->pc, va);
708*5c47fe09SDavid du Colombier }
709*5c47fe09SDavid du Colombier break;
710*5c47fe09SDavid du Colombier case 0x2:
711*5c47fe09SDavid du Colombier panic("terminal exception at %#lux", ureg->pc);
712*5c47fe09SDavid du Colombier break;
713*5c47fe09SDavid du Colombier case 0x4: /* icache maint fault */
714*5c47fe09SDavid du Colombier case 0x6: /* access flag fault (page) */
715*5c47fe09SDavid du Colombier case 0x8: /* precise external abort, non-xlat'n */
716*5c47fe09SDavid du Colombier case 0x28:
717*5c47fe09SDavid du Colombier case 0x16: /* imprecise ext. abort, non-xlt'n */
718*5c47fe09SDavid du Colombier case 0x36:
719*5c47fe09SDavid du Colombier panic("external non-translation abort %#lux pc %#lux addr %#p",
720*5c47fe09SDavid du Colombier fsr, ureg->pc, va);
721*5c47fe09SDavid du Colombier break;
722*5c47fe09SDavid du Colombier case 0xc: /* l1 translation, precise ext. abort */
723*5c47fe09SDavid du Colombier case 0x2c:
724*5c47fe09SDavid du Colombier case 0xe: /* l2 translation, precise ext. abort */
725*5c47fe09SDavid du Colombier case 0x2e:
726*5c47fe09SDavid du Colombier panic("external translation abort %#lux pc %#lux addr %#p",
727*5c47fe09SDavid du Colombier fsr, ureg->pc, va);
728*5c47fe09SDavid du Colombier break;
729*5c47fe09SDavid du Colombier case 0x1c: /* l1 translation, precise parity err */
730*5c47fe09SDavid du Colombier case 0x1e: /* l2 translation, precise parity err */
731*5c47fe09SDavid du Colombier case 0x18: /* imprecise parity or ecc err */
732*5c47fe09SDavid du Colombier panic("translation parity error %#lux pc %#lux addr %#p",
733*5c47fe09SDavid du Colombier fsr, ureg->pc, va);
734*5c47fe09SDavid du Colombier break;
735*5c47fe09SDavid du Colombier case 0x5: /* translation fault, no section entry */
736*5c47fe09SDavid du Colombier case 0x7: /* translation fault, no page entry */
737*5c47fe09SDavid du Colombier faultarm(ureg, va, user, !writetomem(inst));
738*5c47fe09SDavid du Colombier break;
739*5c47fe09SDavid du Colombier case 0x9:
740*5c47fe09SDavid du Colombier case 0xb:
741*5c47fe09SDavid du Colombier /* domain fault, accessing something we shouldn't */
742*5c47fe09SDavid du Colombier if(user){
743*5c47fe09SDavid du Colombier char buf[ERRMAX];
744*5c47fe09SDavid du Colombier
745*5c47fe09SDavid du Colombier snprint(buf, sizeof buf,
746*5c47fe09SDavid du Colombier "sys: access violation: pc %#lux va %#p\n",
747*5c47fe09SDavid du Colombier ureg->pc, va);
748*5c47fe09SDavid du Colombier postnote(up, 1, buf, NDebug);
749*5c47fe09SDavid du Colombier } else
750*5c47fe09SDavid du Colombier panic("kernel access violation: pc %#lux va %#p",
751*5c47fe09SDavid du Colombier ureg->pc, va);
752*5c47fe09SDavid du Colombier break;
753*5c47fe09SDavid du Colombier case 0xd:
754*5c47fe09SDavid du Colombier case 0xf:
755*5c47fe09SDavid du Colombier /* permission error, copy on write or real permission error */
756*5c47fe09SDavid du Colombier faultarm(ureg, va, user, !writetomem(inst));
757*5c47fe09SDavid du Colombier break;
758*5c47fe09SDavid du Colombier }
759*5c47fe09SDavid du Colombier }
760*5c47fe09SDavid du Colombier
761*5c47fe09SDavid du Colombier /*
762*5c47fe09SDavid du Colombier * here on all exceptions other than syscall (SWI) and reset
763*5c47fe09SDavid du Colombier */
764*5c47fe09SDavid du Colombier void
trap(Ureg * ureg)765*5c47fe09SDavid du Colombier trap(Ureg *ureg)
766*5c47fe09SDavid du Colombier {
767*5c47fe09SDavid du Colombier int clockintr, user, rem;
768*5c47fe09SDavid du Colombier uintptr va, ifsr;
769*5c47fe09SDavid du Colombier
770*5c47fe09SDavid du Colombier splhi(); /* paranoia */
771*5c47fe09SDavid du Colombier if(up != nil)
772*5c47fe09SDavid du Colombier rem = ((char*)ureg)-up->kstack;
773*5c47fe09SDavid du Colombier else
774*5c47fe09SDavid du Colombier rem = ((char*)ureg)-((char*)m+sizeof(Mach));
775*5c47fe09SDavid du Colombier if(rem < 1024) {
776*5c47fe09SDavid du Colombier iprint("trap: %d stack bytes left, up %#p ureg %#p m %#p cpu%d at pc %#lux\n",
777*5c47fe09SDavid du Colombier rem, up, ureg, m, m->machno, ureg->pc);
778*5c47fe09SDavid du Colombier dumpstackwithureg(ureg);
779*5c47fe09SDavid du Colombier panic("trap: %d stack bytes left, up %#p ureg %#p at pc %#lux",
780*5c47fe09SDavid du Colombier rem, up, ureg, ureg->pc);
781*5c47fe09SDavid du Colombier }
782*5c47fe09SDavid du Colombier
783*5c47fe09SDavid du Colombier m->perf.intrts = perfticks();
784*5c47fe09SDavid du Colombier user = (ureg->psr & PsrMask) == PsrMusr;
785*5c47fe09SDavid du Colombier if(user){
786*5c47fe09SDavid du Colombier up->dbgreg = ureg;
787*5c47fe09SDavid du Colombier cycles(&up->kentry);
788*5c47fe09SDavid du Colombier }
789*5c47fe09SDavid du Colombier
790*5c47fe09SDavid du Colombier /*
791*5c47fe09SDavid du Colombier * All interrupts/exceptions should be resumed at ureg->pc-4,
792*5c47fe09SDavid du Colombier * except for Data Abort which resumes at ureg->pc-8.
793*5c47fe09SDavid du Colombier */
794*5c47fe09SDavid du Colombier if(ureg->type == (PsrMabt+1))
795*5c47fe09SDavid du Colombier ureg->pc -= 8;
796*5c47fe09SDavid du Colombier else
797*5c47fe09SDavid du Colombier ureg->pc -= 4;
798*5c47fe09SDavid du Colombier
799*5c47fe09SDavid du Colombier clockintr = 0; /* if set, may call sched() before return */
800*5c47fe09SDavid du Colombier switch(ureg->type){
801*5c47fe09SDavid du Colombier default:
802*5c47fe09SDavid du Colombier panic("unknown trap; type %#lux, psr mode %#lux", ureg->type,
803*5c47fe09SDavid du Colombier ureg->psr & PsrMask);
804*5c47fe09SDavid du Colombier break;
805*5c47fe09SDavid du Colombier case PsrMirq:
806*5c47fe09SDavid du Colombier m->intr++;
807*5c47fe09SDavid du Colombier clockintr = irq(ureg);
808*5c47fe09SDavid du Colombier if(0 && up && !clockintr)
809*5c47fe09SDavid du Colombier preempted(); /* this causes spurious suicides */
810*5c47fe09SDavid du Colombier break;
811*5c47fe09SDavid du Colombier case PsrMabt: /* prefetch (instruction) fault */
812*5c47fe09SDavid du Colombier va = ureg->pc;
813*5c47fe09SDavid du Colombier ifsr = ifsrget();
814*5c47fe09SDavid du Colombier ifsr = (ifsr>>7) & 0x8 | ifsr & 0x7;
815*5c47fe09SDavid du Colombier switch(ifsr){
816*5c47fe09SDavid du Colombier case 0x02: /* instruction debug event (BKPT) */
817*5c47fe09SDavid du Colombier if(user)
818*5c47fe09SDavid du Colombier postnote(up, 1, "sys: breakpoint", NDebug);
819*5c47fe09SDavid du Colombier else{
820*5c47fe09SDavid du Colombier iprint("kernel bkpt: pc %#lux inst %#ux\n",
821*5c47fe09SDavid du Colombier va, *(u32int*)va);
822*5c47fe09SDavid du Colombier panic("kernel bkpt");
823*5c47fe09SDavid du Colombier }
824*5c47fe09SDavid du Colombier break;
825*5c47fe09SDavid du Colombier default:
826*5c47fe09SDavid du Colombier faultarm(ureg, va, user, 1);
827*5c47fe09SDavid du Colombier break;
828*5c47fe09SDavid du Colombier }
829*5c47fe09SDavid du Colombier break;
830*5c47fe09SDavid du Colombier case PsrMabt+1: /* data fault */
831*5c47fe09SDavid du Colombier datafault(ureg, user);
832*5c47fe09SDavid du Colombier break;
833*5c47fe09SDavid du Colombier case PsrMund: /* undefined instruction */
834*5c47fe09SDavid du Colombier if(!user) {
835*5c47fe09SDavid du Colombier if (ureg->pc & 3) {
836*5c47fe09SDavid du Colombier iprint("rounding fault pc %#lux down to word\n",
837*5c47fe09SDavid du Colombier ureg->pc);
838*5c47fe09SDavid du Colombier ureg->pc &= ~3;
839*5c47fe09SDavid du Colombier }
840*5c47fe09SDavid du Colombier if (Debug)
841*5c47fe09SDavid du Colombier iprint("mathemu: cpu%d fpon %d instr %#8.8lux at %#p\n",
842*5c47fe09SDavid du Colombier m->machno, m->fpon, *(ulong *)ureg->pc,
843*5c47fe09SDavid du Colombier ureg->pc);
844*5c47fe09SDavid du Colombier dumpstackwithureg(ureg);
845*5c47fe09SDavid du Colombier panic("cpu%d: undefined instruction: pc %#lux inst %#ux",
846*5c47fe09SDavid du Colombier m->machno, ureg->pc, ((u32int*)ureg->pc)[0]);
847*5c47fe09SDavid du Colombier } else if(seg(up, ureg->pc, 0) != nil &&
848*5c47fe09SDavid du Colombier *(u32int*)ureg->pc == 0xD1200070)
849*5c47fe09SDavid du Colombier postnote(up, 1, "sys: breakpoint", NDebug);
850*5c47fe09SDavid du Colombier else if(fpuemu(ureg) == 0){ /* didn't find any FP instrs? */
851*5c47fe09SDavid du Colombier char buf[ERRMAX];
852*5c47fe09SDavid du Colombier
853*5c47fe09SDavid du Colombier snprint(buf, sizeof buf,
854*5c47fe09SDavid du Colombier "undefined instruction: pc %#lux instr %#8.8lux\n",
855*5c47fe09SDavid du Colombier ureg->pc, *(ulong *)ureg->pc);
856*5c47fe09SDavid du Colombier postnote(up, 1, buf, NDebug);
857*5c47fe09SDavid du Colombier }
858*5c47fe09SDavid du Colombier break;
859*5c47fe09SDavid du Colombier }
860*5c47fe09SDavid du Colombier splhi();
861*5c47fe09SDavid du Colombier
862*5c47fe09SDavid du Colombier /* delaysched set because we held a lock or because our quantum ended */
863*5c47fe09SDavid du Colombier if(up && up->delaysched && clockintr){
864*5c47fe09SDavid du Colombier sched(); /* can cause more traps */
865*5c47fe09SDavid du Colombier splhi();
866*5c47fe09SDavid du Colombier }
867*5c47fe09SDavid du Colombier
868*5c47fe09SDavid du Colombier if(user){
869*5c47fe09SDavid du Colombier if(up->procctl || up->nnote)
870*5c47fe09SDavid du Colombier notify(ureg);
871*5c47fe09SDavid du Colombier kexit(ureg);
872*5c47fe09SDavid du Colombier }
873*5c47fe09SDavid du Colombier }
874*5c47fe09SDavid du Colombier
875*5c47fe09SDavid du Colombier /*
876*5c47fe09SDavid du Colombier * Fill in enough of Ureg to get a stack trace, and call a function.
877*5c47fe09SDavid du Colombier * Used by debugging interface rdb.
878*5c47fe09SDavid du Colombier */
879*5c47fe09SDavid du Colombier void
callwithureg(void (* fn)(Ureg *))880*5c47fe09SDavid du Colombier callwithureg(void (*fn)(Ureg*))
881*5c47fe09SDavid du Colombier {
882*5c47fe09SDavid du Colombier Ureg ureg;
883*5c47fe09SDavid du Colombier
884*5c47fe09SDavid du Colombier memset(&ureg, 0, sizeof ureg);
885*5c47fe09SDavid du Colombier ureg.pc = getcallerpc(&fn);
886*5c47fe09SDavid du Colombier ureg.sp = PTR2UINT(&fn);
887*5c47fe09SDavid du Colombier fn(&ureg);
888*5c47fe09SDavid du Colombier }
889*5c47fe09SDavid du Colombier
890*5c47fe09SDavid du Colombier static void
dumpstackwithureg(Ureg * ureg)891*5c47fe09SDavid du Colombier dumpstackwithureg(Ureg *ureg)
892*5c47fe09SDavid du Colombier {
893*5c47fe09SDavid du Colombier int x;
894*5c47fe09SDavid du Colombier uintptr l, v, i, estack;
895*5c47fe09SDavid du Colombier char *s;
896*5c47fe09SDavid du Colombier
897*5c47fe09SDavid du Colombier dumpregs(ureg);
898*5c47fe09SDavid du Colombier if((s = getconf("*nodumpstack")) != nil && strcmp(s, "0") != 0){
899*5c47fe09SDavid du Colombier iprint("dumpstack disabled\n");
900*5c47fe09SDavid du Colombier return;
901*5c47fe09SDavid du Colombier }
902*5c47fe09SDavid du Colombier delay(1000);
903*5c47fe09SDavid du Colombier iprint("dumpstack\n");
904*5c47fe09SDavid du Colombier
905*5c47fe09SDavid du Colombier x = 0;
906*5c47fe09SDavid du Colombier x += iprint("ktrace /kernel/path %#.8lux %#.8lux %#.8lux # pc, sp, link\n",
907*5c47fe09SDavid du Colombier ureg->pc, ureg->sp, ureg->r14);
908*5c47fe09SDavid du Colombier delay(20);
909*5c47fe09SDavid du Colombier i = 0;
910*5c47fe09SDavid du Colombier if(up
911*5c47fe09SDavid du Colombier && (uintptr)&l >= (uintptr)up->kstack
912*5c47fe09SDavid du Colombier && (uintptr)&l <= (uintptr)up->kstack+KSTACK)
913*5c47fe09SDavid du Colombier estack = (uintptr)up->kstack+KSTACK;
914*5c47fe09SDavid du Colombier else if((uintptr)&l >= (uintptr)m->stack
915*5c47fe09SDavid du Colombier && (uintptr)&l <= (uintptr)m+MACHSIZE)
916*5c47fe09SDavid du Colombier estack = (uintptr)m+MACHSIZE;
917*5c47fe09SDavid du Colombier else
918*5c47fe09SDavid du Colombier return;
919*5c47fe09SDavid du Colombier x += iprint("estackx %p\n", estack);
920*5c47fe09SDavid du Colombier
921*5c47fe09SDavid du Colombier for(l = (uintptr)&l; l < estack; l += sizeof(uintptr)){
922*5c47fe09SDavid du Colombier v = *(uintptr*)l;
923*5c47fe09SDavid du Colombier if((KTZERO < v && v < (uintptr)etext) || estack-l < 32){
924*5c47fe09SDavid du Colombier x += iprint("%.8p ", v);
925*5c47fe09SDavid du Colombier delay(20);
926*5c47fe09SDavid du Colombier i++;
927*5c47fe09SDavid du Colombier }
928*5c47fe09SDavid du Colombier if(i == 8){
929*5c47fe09SDavid du Colombier i = 0;
930*5c47fe09SDavid du Colombier x += iprint("\n");
931*5c47fe09SDavid du Colombier delay(20);
932*5c47fe09SDavid du Colombier }
933*5c47fe09SDavid du Colombier }
934*5c47fe09SDavid du Colombier if(i)
935*5c47fe09SDavid du Colombier iprint("\n");
936*5c47fe09SDavid du Colombier delay(3000);
937*5c47fe09SDavid du Colombier }
938*5c47fe09SDavid du Colombier
939*5c47fe09SDavid du Colombier void
dumpstack(void)940*5c47fe09SDavid du Colombier dumpstack(void)
941*5c47fe09SDavid du Colombier {
942*5c47fe09SDavid du Colombier callwithureg(dumpstackwithureg);
943*5c47fe09SDavid du Colombier }
944*5c47fe09SDavid du Colombier
945*5c47fe09SDavid du Colombier /*
946*5c47fe09SDavid du Colombier * dump general registers
947*5c47fe09SDavid du Colombier */
948*5c47fe09SDavid du Colombier static void
dumpgpr(Ureg * ureg)949*5c47fe09SDavid du Colombier dumpgpr(Ureg* ureg)
950*5c47fe09SDavid du Colombier {
951*5c47fe09SDavid du Colombier if(up != nil)
952*5c47fe09SDavid du Colombier iprint("cpu%d: registers for %s %lud\n",
953*5c47fe09SDavid du Colombier m->machno, up->text, up->pid);
954*5c47fe09SDavid du Colombier else
955*5c47fe09SDavid du Colombier iprint("cpu%d: registers for kernel\n", m->machno);
956*5c47fe09SDavid du Colombier
957*5c47fe09SDavid du Colombier delay(20);
958*5c47fe09SDavid du Colombier iprint("%#8.8lux\tr0\n", ureg->r0);
959*5c47fe09SDavid du Colombier iprint("%#8.8lux\tr1\n", ureg->r1);
960*5c47fe09SDavid du Colombier iprint("%#8.8lux\tr2\n", ureg->r2);
961*5c47fe09SDavid du Colombier delay(20);
962*5c47fe09SDavid du Colombier iprint("%#8.8lux\tr3\n", ureg->r3);
963*5c47fe09SDavid du Colombier iprint("%#8.8lux\tr4\n", ureg->r4);
964*5c47fe09SDavid du Colombier iprint("%#8.8lux\tr5\n", ureg->r5);
965*5c47fe09SDavid du Colombier delay(20);
966*5c47fe09SDavid du Colombier iprint("%#8.8lux\tr6\n", ureg->r6);
967*5c47fe09SDavid du Colombier iprint("%#8.8lux\tr7\n", ureg->r7);
968*5c47fe09SDavid du Colombier iprint("%#8.8lux\tr8\n", ureg->r8);
969*5c47fe09SDavid du Colombier delay(20);
970*5c47fe09SDavid du Colombier iprint("%#8.8lux\tr9 (up)\n", ureg->r9);
971*5c47fe09SDavid du Colombier iprint("%#8.8lux\tr10 (m)\n", ureg->r10);
972*5c47fe09SDavid du Colombier iprint("%#8.8lux\tr11 (loader temporary)\n", ureg->r11);
973*5c47fe09SDavid du Colombier iprint("%#8.8lux\tr12 (SB)\n", ureg->r12);
974*5c47fe09SDavid du Colombier delay(20);
975*5c47fe09SDavid du Colombier iprint("%#8.8lux\tr13 (sp)\n", ureg->r13);
976*5c47fe09SDavid du Colombier iprint("%#8.8lux\tr14 (link)\n", ureg->r14);
977*5c47fe09SDavid du Colombier iprint("%#8.8lux\tr15 (pc)\n", ureg->pc);
978*5c47fe09SDavid du Colombier delay(20);
979*5c47fe09SDavid du Colombier iprint("%10.10lud\ttype\n", ureg->type);
980*5c47fe09SDavid du Colombier iprint("%#8.8lux\tpsr\n", ureg->psr);
981*5c47fe09SDavid du Colombier delay(500);
982*5c47fe09SDavid du Colombier }
983*5c47fe09SDavid du Colombier
984*5c47fe09SDavid du Colombier void
dumpregs(Ureg * ureg)985*5c47fe09SDavid du Colombier dumpregs(Ureg* ureg)
986*5c47fe09SDavid du Colombier {
987*5c47fe09SDavid du Colombier dumpgpr(ureg);
988*5c47fe09SDavid du Colombier }
989*5c47fe09SDavid du Colombier
990*5c47fe09SDavid du Colombier void
fiq(Ureg *)991*5c47fe09SDavid du Colombier fiq(Ureg *)
992*5c47fe09SDavid du Colombier {
993*5c47fe09SDavid du Colombier }
994