xref: /plan9-contrib/sys/src/9/bcm/trap4.c (revision 5c47fe09a0cc86dfb02c0ea4a2b6aec7eda2361f)
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