xref: /plan9/sys/src/9/teg2/trap.c (revision 0591a7c1821da27d40a0fa8bed7304fc2fa2b020)
13de6a9c0SDavid du Colombier /*
23de6a9c0SDavid du Colombier  * arm mpcore generic interrupt controller (gic) v1
33de6a9c0SDavid du Colombier  * traps, exceptions, interrupts, system calls.
43de6a9c0SDavid du Colombier  *
53de6a9c0SDavid du Colombier  * there are two pieces: the interrupt distributor and the cpu interface.
63de6a9c0SDavid du Colombier  *
73de6a9c0SDavid du Colombier  * memset or memmove on any of the distributor registers generates an
83de6a9c0SDavid du Colombier  * exception like this one:
93de6a9c0SDavid du Colombier  *	panic: external abort 0x28 pc 0xc048bf68 addr 0x50041800
103de6a9c0SDavid du Colombier  *
113de6a9c0SDavid du Colombier  * we use l1 and l2 cache ops to force vectors to be visible everywhere.
123de6a9c0SDavid du Colombier  *
133de6a9c0SDavid du Colombier  * apparently irqs 0—15 (SGIs) are always enabled.
143de6a9c0SDavid du Colombier  */
153de6a9c0SDavid du Colombier #include "u.h"
163de6a9c0SDavid du Colombier #include "../port/lib.h"
173de6a9c0SDavid du Colombier #include "mem.h"
183de6a9c0SDavid du Colombier #include "dat.h"
193de6a9c0SDavid du Colombier #include "fns.h"
203de6a9c0SDavid du Colombier #include "../port/error.h"
213de6a9c0SDavid du Colombier 
223de6a9c0SDavid du Colombier #include "ureg.h"
233de6a9c0SDavid du Colombier #include "arm.h"
243de6a9c0SDavid du Colombier 
253de6a9c0SDavid du Colombier #define ISSGI(irq)	((uint)(irq) < Nsgi)
263de6a9c0SDavid du Colombier 
273de6a9c0SDavid du Colombier enum {
283de6a9c0SDavid du Colombier 	Debug = 0,
293de6a9c0SDavid du Colombier 
303de6a9c0SDavid du Colombier 	Nvec = 8,		/* # of vectors at start of lexception.s */
313de6a9c0SDavid du Colombier 	Bi2long = BI2BY * sizeof(long),
323de6a9c0SDavid du Colombier 	Nirqs = 1024,
333de6a9c0SDavid du Colombier 	Nsgi =	16,		/* software-generated (inter-processor) intrs */
343de6a9c0SDavid du Colombier 	Nppi =	32,		/* sgis + other private peripheral intrs */
353de6a9c0SDavid du Colombier };
363de6a9c0SDavid du Colombier 
373de6a9c0SDavid du Colombier typedef struct Intrcpuregs Intrcpuregs;
383de6a9c0SDavid du Colombier typedef struct Intrdistregs Intrdistregs;
393de6a9c0SDavid du Colombier 
403de6a9c0SDavid du Colombier /*
413de6a9c0SDavid du Colombier  * almost this entire register set is buggered.
423de6a9c0SDavid du Colombier  * the distributor is supposed to be per-system, not per-cpu,
433de6a9c0SDavid du Colombier  * yet some registers are banked per-cpu, as marked.
443de6a9c0SDavid du Colombier  */
453de6a9c0SDavid du Colombier struct Intrdistregs {			/* distributor */
463de6a9c0SDavid du Colombier 	ulong	ctl;
473de6a9c0SDavid du Colombier 	ulong	ctlrtype;
483de6a9c0SDavid du Colombier 	ulong	distid;
493de6a9c0SDavid du Colombier 	uchar	_pad0[0x80 - 0xc];
503de6a9c0SDavid du Colombier 
513de6a9c0SDavid du Colombier 	/* botch: *[0] are banked per-cpu from here */
523de6a9c0SDavid du Colombier 	/* bit maps */
533de6a9c0SDavid du Colombier 	ulong	grp[32];		/* in group 1 (non-secure) */
543de6a9c0SDavid du Colombier 	ulong	setena[32];		/* forward to cpu interfaces */
553de6a9c0SDavid du Colombier 	ulong	clrena[32];
563de6a9c0SDavid du Colombier 	ulong	setpend[32];
573de6a9c0SDavid du Colombier 	ulong	clrpend[32];
583de6a9c0SDavid du Colombier 	ulong	setact[32];		/* active? */
593de6a9c0SDavid du Colombier 	ulong	clract[32];
603de6a9c0SDavid du Colombier 	/* botch: *[0] are banked per-cpu until here */
613de6a9c0SDavid du Colombier 
623de6a9c0SDavid du Colombier 	uchar	pri[1020];	/* botch: pri[0] — pri[7] are banked per-cpu */
633de6a9c0SDavid du Colombier 	ulong	_rsrvd1;
643de6a9c0SDavid du Colombier 	/* botch: targ[0] through targ[7] are banked per-cpu and RO */
653de6a9c0SDavid du Colombier 	uchar	targ[1020];	/* byte bit maps: cpu targets indexed by intr */
663de6a9c0SDavid du Colombier 	ulong	_rsrvd2;
673de6a9c0SDavid du Colombier 	/* botch: cfg[1] is banked per-cpu */
683de6a9c0SDavid du Colombier 	ulong	cfg[64];		/* bit pairs: edge? 1-N? */
693de6a9c0SDavid du Colombier 	ulong	_pad1[64];
703de6a9c0SDavid du Colombier 	ulong	nsac[64];		/* bit pairs (v2 only) */
713de6a9c0SDavid du Colombier 
723de6a9c0SDavid du Colombier 	/* software-generated intrs (a.k.a. sgi) */
733de6a9c0SDavid du Colombier 	ulong	swgen;			/* intr targets */
743de6a9c0SDavid du Colombier 	uchar	_pad2[0xf10 - 0xf04];
753de6a9c0SDavid du Colombier 	uchar	clrsgipend[16];		/* bit map (v2 only) */
763de6a9c0SDavid du Colombier 	uchar	setsgipend[16];		/* bit map (v2 only) */
773de6a9c0SDavid du Colombier };
783de6a9c0SDavid du Colombier 
793de6a9c0SDavid du Colombier enum {
803de6a9c0SDavid du Colombier 	/* ctl bits */
813de6a9c0SDavid du Colombier 	Forw2cpuif =	1,
823de6a9c0SDavid du Colombier 
833de6a9c0SDavid du Colombier 	/* ctlrtype bits */
843de6a9c0SDavid du Colombier 	Cpunoshft =	5,
853de6a9c0SDavid du Colombier 	Cpunomask =	MASK(3),
863de6a9c0SDavid du Colombier 	Intrlines =	MASK(5),
873de6a9c0SDavid du Colombier 
883de6a9c0SDavid du Colombier 	/* cfg bits */
893de6a9c0SDavid du Colombier 	Level =		0<<1,
903de6a9c0SDavid du Colombier 	Edge =		1<<1,		/* edge-, not level-sensitive */
913de6a9c0SDavid du Colombier 	Toall =		0<<0,
923de6a9c0SDavid du Colombier 	To1 =		1<<0,		/* vs. to all */
933de6a9c0SDavid du Colombier 
943de6a9c0SDavid du Colombier 	/* swgen bits */
953de6a9c0SDavid du Colombier 	Totargets =	0,
963de6a9c0SDavid du Colombier 	Tonotme =	1<<24,
973de6a9c0SDavid du Colombier 	Tome =		2<<24,
983de6a9c0SDavid du Colombier };
993de6a9c0SDavid du Colombier 
1003de6a9c0SDavid du Colombier /* each cpu sees its own registers at the same base address (soc.intr) */
1013de6a9c0SDavid du Colombier struct Intrcpuregs {
1023de6a9c0SDavid du Colombier 	ulong	ctl;
1033de6a9c0SDavid du Colombier 	ulong	primask;
1043de6a9c0SDavid du Colombier 
1053de6a9c0SDavid du Colombier 	ulong	binpt;			/* group pri vs subpri split */
1063de6a9c0SDavid du Colombier 	ulong	ack;
1073de6a9c0SDavid du Colombier 	ulong	end;
1083de6a9c0SDavid du Colombier 	ulong	runpri;
1093de6a9c0SDavid du Colombier 	ulong	hipripend;
1103de6a9c0SDavid du Colombier 
1113de6a9c0SDavid du Colombier 	/* aliased regs (secure, for group 1) */
1123de6a9c0SDavid du Colombier 	ulong	alibinpt;
1133de6a9c0SDavid du Colombier 	ulong	aliack;			/* (v2 only) */
1143de6a9c0SDavid du Colombier 	ulong	aliend;			/* (v2 only) */
1153de6a9c0SDavid du Colombier 	ulong	alihipripend;		/* (v2 only) */
1163de6a9c0SDavid du Colombier 
1173de6a9c0SDavid du Colombier 	uchar	_pad0[0xd0 - 0x2c];
1183de6a9c0SDavid du Colombier 	ulong	actpri[4];		/* (v2 only) */
1193de6a9c0SDavid du Colombier 	ulong	nsactpri[4];		/* (v2 only) */
1203de6a9c0SDavid du Colombier 
1213de6a9c0SDavid du Colombier 	uchar	_pad0[0xfc - 0xf0];
1223de6a9c0SDavid du Colombier 	ulong	ifid;			/* ro */
1233de6a9c0SDavid du Colombier 
1243de6a9c0SDavid du Colombier 	uchar	_pad0[0x1000 - 0x100];
1253de6a9c0SDavid du Colombier 	ulong	deact;			/* wo (v2 only) */
1263de6a9c0SDavid du Colombier };
1273de6a9c0SDavid du Colombier 
1283de6a9c0SDavid du Colombier enum {
1293de6a9c0SDavid du Colombier 	/* ctl bits */
1303de6a9c0SDavid du Colombier 	Enable =	1,
1313de6a9c0SDavid du Colombier 	Eoinodeact =	1<<9,		/* (v2 only) */
1323de6a9c0SDavid du Colombier 
1333de6a9c0SDavid du Colombier 	/* (ali) ack/end/hipriend/deact bits */
1343de6a9c0SDavid du Colombier 	Intrmask =	MASK(10),
1353de6a9c0SDavid du Colombier 	Cpuidshift =	10,
1363de6a9c0SDavid du Colombier 	Cpuidmask =	MASK(3),
1373de6a9c0SDavid du Colombier 
1383de6a9c0SDavid du Colombier 	/* ifid bits */
1393de6a9c0SDavid du Colombier 	Archversshift =	16,
1403de6a9c0SDavid du Colombier 	Archversmask =	MASK(4),
1413de6a9c0SDavid du Colombier };
1423de6a9c0SDavid du Colombier 
1433de6a9c0SDavid du Colombier typedef struct Vctl Vctl;
1443de6a9c0SDavid du Colombier typedef struct Vctl {
1453de6a9c0SDavid du Colombier 	Vctl*	next;		/* handlers on this vector */
1463de6a9c0SDavid du Colombier 	char	*name;		/* of driver, xallocated */
1473de6a9c0SDavid du Colombier 	void	(*f)(Ureg*, void*);	/* handler to call */
1483de6a9c0SDavid du Colombier 	void*	a;		/* argument to call it with */
1493de6a9c0SDavid du Colombier } Vctl;
1503de6a9c0SDavid du Colombier 
1513de6a9c0SDavid du Colombier static Lock vctllock;
1523de6a9c0SDavid du Colombier static Vctl* vctl[Nirqs];
1533de6a9c0SDavid du Colombier 
1543de6a9c0SDavid du Colombier /*
1553de6a9c0SDavid du Colombier  *   Layout at virtual address 0.
1563de6a9c0SDavid du Colombier  */
1573de6a9c0SDavid du Colombier typedef struct Vpage0 {
1583de6a9c0SDavid du Colombier 	void	(*vectors[Nvec])(void);
1593de6a9c0SDavid du Colombier 	u32int	vtable[Nvec];
1603de6a9c0SDavid du Colombier } Vpage0;
1613de6a9c0SDavid du Colombier 
1623de6a9c0SDavid du Colombier enum
1633de6a9c0SDavid du Colombier {
1643de6a9c0SDavid du Colombier 	Ntimevec = 20		/* number of time buckets for each intr */
1653de6a9c0SDavid du Colombier };
1663de6a9c0SDavid du Colombier ulong intrtimes[Nirqs][Ntimevec];
1673de6a9c0SDavid du Colombier 
1683de6a9c0SDavid du Colombier uvlong ninterrupt;
1693de6a9c0SDavid du Colombier uvlong ninterruptticks;
1703de6a9c0SDavid du Colombier int irqtooearly = 1;
1713de6a9c0SDavid du Colombier 
1723de6a9c0SDavid du Colombier static ulong shadena[32];	/* copy of enable bits, saved by intcmaskall */
1733de6a9c0SDavid du Colombier static Lock distlock, nintrlock;
1743de6a9c0SDavid du Colombier 
1753de6a9c0SDavid du Colombier extern int notify(Ureg*);
1763de6a9c0SDavid du Colombier 
1773de6a9c0SDavid du Colombier static void dumpstackwithureg(Ureg *ureg);
1783de6a9c0SDavid du Colombier 
1793de6a9c0SDavid du Colombier void
printrs(int base,ulong word)1803de6a9c0SDavid du Colombier printrs(int base, ulong word)
1813de6a9c0SDavid du Colombier {
1823de6a9c0SDavid du Colombier 	int bit;
1833de6a9c0SDavid du Colombier 
1843de6a9c0SDavid du Colombier 	for (bit = 0; word; bit++, word >>= 1)
1853de6a9c0SDavid du Colombier 		if (word & 1)
1863de6a9c0SDavid du Colombier 			iprint(" %d", base + bit);
1873de6a9c0SDavid du Colombier }
1883de6a9c0SDavid du Colombier 
1893de6a9c0SDavid du Colombier void
dumpintrs(char * what,ulong * bits)1903de6a9c0SDavid du Colombier dumpintrs(char *what, ulong *bits)
1913de6a9c0SDavid du Colombier {
1923de6a9c0SDavid du Colombier 	int i, first, some;
1933de6a9c0SDavid du Colombier 	ulong word;
1943de6a9c0SDavid du Colombier 	Intrdistregs *idp = (Intrdistregs *)soc.intrdist;
1953de6a9c0SDavid du Colombier 
1963de6a9c0SDavid du Colombier 	first = 1;
1973de6a9c0SDavid du Colombier 	some = 0;
1983de6a9c0SDavid du Colombier 	USED(idp);
1993de6a9c0SDavid du Colombier 	for (i = 0; i < nelem(idp->setpend); i++) {
2003de6a9c0SDavid du Colombier 		word = bits[i];
2013de6a9c0SDavid du Colombier 		if (word) {
2023de6a9c0SDavid du Colombier 			if (first) {
2033de6a9c0SDavid du Colombier 				first = 0;
2043de6a9c0SDavid du Colombier 				iprint("%s", what);
2053de6a9c0SDavid du Colombier 			}
2063de6a9c0SDavid du Colombier 			some = 1;
2073de6a9c0SDavid du Colombier 			printrs(i * Bi2long, word);
2083de6a9c0SDavid du Colombier 		}
2093de6a9c0SDavid du Colombier 	}
2103de6a9c0SDavid du Colombier 	if (!some)
2113de6a9c0SDavid du Colombier 		iprint("%s none", what);
2123de6a9c0SDavid du Colombier 	iprint("\n");
2133de6a9c0SDavid du Colombier }
2143de6a9c0SDavid du Colombier 
2153de6a9c0SDavid du Colombier void
dumpintrpend(void)2163de6a9c0SDavid du Colombier dumpintrpend(void)
2173de6a9c0SDavid du Colombier {
2183de6a9c0SDavid du Colombier 	Intrdistregs *idp = (Intrdistregs *)soc.intrdist;
2193de6a9c0SDavid du Colombier 
2203de6a9c0SDavid du Colombier 	iprint("\ncpu%d gic regs:\n", m->machno);
2213de6a9c0SDavid du Colombier 	dumpintrs("group 1", idp->grp);
2223de6a9c0SDavid du Colombier 	dumpintrs("enabled", idp->setena);
2233de6a9c0SDavid du Colombier 	dumpintrs("pending", idp->setpend);
2243de6a9c0SDavid du Colombier 	dumpintrs("active ", idp->setact);
2253de6a9c0SDavid du Colombier }
2263de6a9c0SDavid du Colombier 
2273de6a9c0SDavid du Colombier /*
2283de6a9c0SDavid du Colombier  *  keep histogram of interrupt service times
2293de6a9c0SDavid du Colombier  */
2303de6a9c0SDavid du Colombier void
intrtime(Mach *,int vno)2313de6a9c0SDavid du Colombier intrtime(Mach*, int vno)
2323de6a9c0SDavid du Colombier {
2333de6a9c0SDavid du Colombier 	ulong diff;
2343de6a9c0SDavid du Colombier 	ulong x;
2353de6a9c0SDavid du Colombier 
2363de6a9c0SDavid du Colombier 	x = perfticks();
2373de6a9c0SDavid du Colombier 	diff = x - m->perf.intrts;
2383de6a9c0SDavid du Colombier 	m->perf.intrts = x;
2393de6a9c0SDavid du Colombier 
2403de6a9c0SDavid du Colombier 	m->perf.inintr += diff;
2413de6a9c0SDavid du Colombier 	if(up == nil && m->perf.inidle > diff)
2423de6a9c0SDavid du Colombier 		m->perf.inidle -= diff;
2433de6a9c0SDavid du Colombier 
2443de6a9c0SDavid du Colombier 	if (m->cpumhz == 0)
2453de6a9c0SDavid du Colombier 		return;			/* don't divide by zero */
2463de6a9c0SDavid du Colombier 	diff /= m->cpumhz*100;		/* quantum = 100µsec */
2473de6a9c0SDavid du Colombier 	if(diff >= Ntimevec)
2483de6a9c0SDavid du Colombier 		diff = Ntimevec-1;
2493de6a9c0SDavid du Colombier 	if ((uint)vno >= Nirqs)
2503de6a9c0SDavid du Colombier 		vno = Nirqs-1;
2513de6a9c0SDavid du Colombier 	intrtimes[vno][diff]++;
2523de6a9c0SDavid du Colombier }
2533de6a9c0SDavid du Colombier 
2543de6a9c0SDavid du Colombier static ulong
intack(Intrcpuregs * icp)2553de6a9c0SDavid du Colombier intack(Intrcpuregs *icp)
2563de6a9c0SDavid du Colombier {
2573de6a9c0SDavid du Colombier 	return icp->ack & Intrmask;
2583de6a9c0SDavid du Colombier }
2593de6a9c0SDavid du Colombier 
2603de6a9c0SDavid du Colombier static void
intdismiss(Intrcpuregs * icp,ulong ack)2613de6a9c0SDavid du Colombier intdismiss(Intrcpuregs *icp, ulong ack)
2623de6a9c0SDavid du Colombier {
2633de6a9c0SDavid du Colombier 	icp->end = ack;
2643de6a9c0SDavid du Colombier 	coherence();
2653de6a9c0SDavid du Colombier }
2663de6a9c0SDavid du Colombier 
2673de6a9c0SDavid du Colombier static int
irqinuse(uint irq)2683de6a9c0SDavid du Colombier irqinuse(uint irq)
2693de6a9c0SDavid du Colombier {
2703de6a9c0SDavid du Colombier 	Intrdistregs *idp = (Intrdistregs *)soc.intrdist;
2713de6a9c0SDavid du Colombier 
2723de6a9c0SDavid du Colombier 	return idp->setena[irq / Bi2long] & (1 << (irq % Bi2long));
2733de6a9c0SDavid du Colombier }
2743de6a9c0SDavid du Colombier 
2753de6a9c0SDavid du Colombier void
intcunmask(uint irq)2763de6a9c0SDavid du Colombier intcunmask(uint irq)
2773de6a9c0SDavid du Colombier {
2783de6a9c0SDavid du Colombier 	Intrdistregs *idp = (Intrdistregs *)soc.intrdist;
2793de6a9c0SDavid du Colombier 
2803de6a9c0SDavid du Colombier 	ilock(&distlock);
2813de6a9c0SDavid du Colombier 	idp->setena[irq / Bi2long] = 1 << (irq % Bi2long);
2823de6a9c0SDavid du Colombier 	iunlock(&distlock);
2833de6a9c0SDavid du Colombier }
2843de6a9c0SDavid du Colombier 
2853de6a9c0SDavid du Colombier void
intcmask(uint irq)2863de6a9c0SDavid du Colombier intcmask(uint irq)
2873de6a9c0SDavid du Colombier {
2883de6a9c0SDavid du Colombier 	Intrdistregs *idp = (Intrdistregs *)soc.intrdist;
2893de6a9c0SDavid du Colombier 
2903de6a9c0SDavid du Colombier 	ilock(&distlock);
2913de6a9c0SDavid du Colombier 	idp->clrena[irq / Bi2long] = 1 << (irq % Bi2long);
2923de6a9c0SDavid du Colombier 	iunlock(&distlock);
2933de6a9c0SDavid du Colombier }
2943de6a9c0SDavid du Colombier 
2953de6a9c0SDavid du Colombier static void
intcmaskall(Intrdistregs * idp)2963de6a9c0SDavid du Colombier intcmaskall(Intrdistregs *idp)		/* mask all intrs for all cpus */
2973de6a9c0SDavid du Colombier {
2983de6a9c0SDavid du Colombier 	int i;
2993de6a9c0SDavid du Colombier 
3003de6a9c0SDavid du Colombier 	for (i = 0; i < nelem(idp->setena); i++)
3013de6a9c0SDavid du Colombier 		shadena[i] = idp->setena[i];
3023de6a9c0SDavid du Colombier 	for (i = 0; i < nelem(idp->clrena); i++)
3033de6a9c0SDavid du Colombier 		idp->clrena[i] = ~0;
3043de6a9c0SDavid du Colombier 	coherence();
3053de6a9c0SDavid du Colombier }
3063de6a9c0SDavid du Colombier 
3073de6a9c0SDavid du Colombier static void
intcunmaskall(Intrdistregs * idp)3083de6a9c0SDavid du Colombier intcunmaskall(Intrdistregs *idp)	/* unused */
3093de6a9c0SDavid du Colombier {
3103de6a9c0SDavid du Colombier 	int i;
3113de6a9c0SDavid du Colombier 
3123de6a9c0SDavid du Colombier 	for (i = 0; i < nelem(idp->setena); i++)
3133de6a9c0SDavid du Colombier 		idp->setena[i] = shadena[i];
3143de6a9c0SDavid du Colombier 	coherence();
3153de6a9c0SDavid du Colombier }
3163de6a9c0SDavid du Colombier 
3173de6a9c0SDavid du Colombier static ulong
permintrs(Intrdistregs * idp,int base,int r)3183de6a9c0SDavid du Colombier permintrs(Intrdistregs *idp, int base, int r)
3193de6a9c0SDavid du Colombier {
3203de6a9c0SDavid du Colombier 	ulong perms;
3213de6a9c0SDavid du Colombier 
3223de6a9c0SDavid du Colombier 	idp->clrena[r] = ~0;		/* disable all */
3233de6a9c0SDavid du Colombier 	coherence();
3243de6a9c0SDavid du Colombier 	perms = idp->clrena[r];
3253de6a9c0SDavid du Colombier 	if (perms) {
3263de6a9c0SDavid du Colombier 		iprint("perm intrs:");
3273de6a9c0SDavid du Colombier 		printrs(base, perms);
3283de6a9c0SDavid du Colombier 		iprint("\n");
3293de6a9c0SDavid du Colombier 	}
3303de6a9c0SDavid du Colombier 	return perms;
3313de6a9c0SDavid du Colombier }
3323de6a9c0SDavid du Colombier 
3333de6a9c0SDavid du Colombier static void
intrcfg(Intrdistregs * idp)3343de6a9c0SDavid du Colombier intrcfg(Intrdistregs *idp)
3353de6a9c0SDavid du Colombier {
3363de6a9c0SDavid du Colombier 	int i, cpumask;
3373de6a9c0SDavid du Colombier 	ulong pat;
3383de6a9c0SDavid du Colombier 
3393de6a9c0SDavid du Colombier 	/* set up all interrupts as level-sensitive, to one cpu (0) */
3403de6a9c0SDavid du Colombier 	pat = 0;
3413de6a9c0SDavid du Colombier 	for (i = 0; i < Bi2long; i += 2)
3423de6a9c0SDavid du Colombier 		pat |= (Level | To1) << i;
3433de6a9c0SDavid du Colombier 
3443de6a9c0SDavid du Colombier 	if (m->machno == 0) {			/* system-wide & cpu0 cfg */
3453de6a9c0SDavid du Colombier 		for (i = 0; i < nelem(idp->grp); i++)
3463de6a9c0SDavid du Colombier 			idp->grp[i] = 0;		/* secure */
3473de6a9c0SDavid du Colombier 		for (i = 0; i < nelem(idp->pri); i++)
3483de6a9c0SDavid du Colombier 			idp->pri[i] = 0;		/* highest priority */
3493de6a9c0SDavid du Colombier 		/* set up all interrupts as level-sensitive, to one cpu (0) */
3503de6a9c0SDavid du Colombier 		for (i = 0; i < nelem(idp->cfg); i++)
3513de6a9c0SDavid du Colombier 			idp->cfg[i] = pat;
3523de6a9c0SDavid du Colombier 		/* first Nppi are read-only for SGIs and PPIs */
3533de6a9c0SDavid du Colombier 		cpumask = 1<<0;				/* just cpu 0 */
3543de6a9c0SDavid du Colombier 		navailcpus = getncpus();
3553de6a9c0SDavid du Colombier 		for (i = Nppi; i < sizeof idp->targ; i++)
3563de6a9c0SDavid du Colombier 			idp->targ[i] = cpumask;
3573de6a9c0SDavid du Colombier 		coherence();
3583de6a9c0SDavid du Colombier 
3593de6a9c0SDavid du Colombier 		intcmaskall(idp);
3603de6a9c0SDavid du Colombier 		for (i = 0; i < nelem(idp->clrena); i++) {
3613de6a9c0SDavid du Colombier 			// permintrs(idp, i * Bi2long, i);
3623de6a9c0SDavid du Colombier 			idp->clrpend[i] = idp->clract[i] = idp->clrena[i] = ~0;
3633de6a9c0SDavid du Colombier 		}
3643de6a9c0SDavid du Colombier 	} else {				/* per-cpu config */
3653de6a9c0SDavid du Colombier 		idp->grp[0] = 0;		/* secure */
3663de6a9c0SDavid du Colombier 		for (i = 0; i < 8; i++)
3673de6a9c0SDavid du Colombier 			idp->pri[i] = 0;	/* highest priority */
3683de6a9c0SDavid du Colombier 		/* idp->targ[0 through Nppi-1] are supposed to be read-only */
3693de6a9c0SDavid du Colombier 		for (i = 0; i < Nppi; i++)
3703de6a9c0SDavid du Colombier 			idp->targ[i] = 1<<m->machno;
3713de6a9c0SDavid du Colombier 		idp->cfg[1] = pat;
3723de6a9c0SDavid du Colombier 		coherence();
3733de6a9c0SDavid du Colombier 
3743de6a9c0SDavid du Colombier 		// permintrs(idp, i * Bi2long, i);
3753de6a9c0SDavid du Colombier 		idp->clrpend[0] = idp->clract[0] = idp->clrena[0] = ~0;
3763de6a9c0SDavid du Colombier 		/* on cpu1, irq Extpmuirq (118) is always pending here */
3773de6a9c0SDavid du Colombier 	}
3783de6a9c0SDavid du Colombier 	coherence();
3793de6a9c0SDavid du Colombier }
3803de6a9c0SDavid du Colombier 
3813de6a9c0SDavid du Colombier void
intrto(int cpu,int irq)3823de6a9c0SDavid du Colombier intrto(int cpu, int irq)
3833de6a9c0SDavid du Colombier {
3843de6a9c0SDavid du Colombier 	Intrdistregs *idp = (Intrdistregs *)soc.intrdist;
3853de6a9c0SDavid du Colombier 
3863de6a9c0SDavid du Colombier 	/* first Nppi are read-only for SGIs and the like */
3873de6a9c0SDavid du Colombier 	ilock(&distlock);
3883de6a9c0SDavid du Colombier 	idp->targ[irq] = 1 << cpu;
3893de6a9c0SDavid du Colombier 	iunlock(&distlock);
3903de6a9c0SDavid du Colombier }
3913de6a9c0SDavid du Colombier 
3923de6a9c0SDavid du Colombier void
intrsto(int cpu)3933de6a9c0SDavid du Colombier intrsto(int cpu)			/* unused */
3943de6a9c0SDavid du Colombier {
3953de6a9c0SDavid du Colombier 	int i;
3963de6a9c0SDavid du Colombier 	Intrdistregs *idp = (Intrdistregs *)soc.intrdist;
3973de6a9c0SDavid du Colombier 
3983de6a9c0SDavid du Colombier 	/* first Nppi are read-only for SGIs and the like */
3993de6a9c0SDavid du Colombier 	for (i = Nppi; i < sizeof idp->targ; i++)
4003de6a9c0SDavid du Colombier 		intrto(cpu, i);
4013de6a9c0SDavid du Colombier 	USED(idp);
4023de6a9c0SDavid du Colombier }
4033de6a9c0SDavid du Colombier 
4043de6a9c0SDavid du Colombier void
intrcpu(int cpu)4053de6a9c0SDavid du Colombier intrcpu(int cpu)
4063de6a9c0SDavid du Colombier {
4073de6a9c0SDavid du Colombier 	Intrdistregs *idp = (Intrdistregs *)soc.intrdist;
4083de6a9c0SDavid du Colombier 
4093de6a9c0SDavid du Colombier 	ilock(&distlock);
4103de6a9c0SDavid du Colombier 	idp->swgen = Totargets | 1 << (cpu + 16) | m->machno;
4113de6a9c0SDavid du Colombier 	iunlock(&distlock);
4123de6a9c0SDavid du Colombier }
4133de6a9c0SDavid du Colombier 
4143de6a9c0SDavid du Colombier /*
4153de6a9c0SDavid du Colombier  *  set up for exceptions
4163de6a9c0SDavid du Colombier  */
4173de6a9c0SDavid du Colombier void
trapinit(void)4183de6a9c0SDavid du Colombier trapinit(void)
4193de6a9c0SDavid du Colombier {
4203de6a9c0SDavid du Colombier 	int s;
4213de6a9c0SDavid du Colombier 	Intrdistregs *idp = (Intrdistregs *)soc.intrdist;
4223de6a9c0SDavid du Colombier 	Intrcpuregs *icp = (Intrcpuregs *)soc.intr;
4233de6a9c0SDavid du Colombier 	Vpage0 *vpage0;
4243de6a9c0SDavid du Colombier 	enum { Vecsize = sizeof vpage0->vectors + sizeof vpage0->vtable, };
4253de6a9c0SDavid du Colombier 
4263de6a9c0SDavid du Colombier 	/*
4273de6a9c0SDavid du Colombier 	 * set up the exception vectors, high and low.
4283de6a9c0SDavid du Colombier 	 *
4293de6a9c0SDavid du Colombier 	 * we can't use cache ops on HVECTORS address, since they
4303de6a9c0SDavid du Colombier 	 * work on virtual addresses, and only those that have a
4313de6a9c0SDavid du Colombier 	 * physical address == PADDR(virtual).
4323de6a9c0SDavid du Colombier 	 */
4333de6a9c0SDavid du Colombier 	if (m->machno == 0) {
4343de6a9c0SDavid du Colombier 		vpage0 = (Vpage0*)HVECTORS;
4353de6a9c0SDavid du Colombier 		memmove(vpage0->vectors, vectors, sizeof(vpage0->vectors));
4363de6a9c0SDavid du Colombier 		memmove(vpage0->vtable, vtable, sizeof(vpage0->vtable));
4373de6a9c0SDavid du Colombier 
4383de6a9c0SDavid du Colombier 		vpage0 = (Vpage0*)KADDR(0);
4393de6a9c0SDavid du Colombier 		memmove(vpage0->vectors, vectors, sizeof(vpage0->vectors));
4403de6a9c0SDavid du Colombier 		memmove(vpage0->vtable, vtable, sizeof(vpage0->vtable));
4413de6a9c0SDavid du Colombier 
4423de6a9c0SDavid du Colombier 		allcache->wbse(vpage0, Vecsize);
4433de6a9c0SDavid du Colombier 		cacheiinv();
4443de6a9c0SDavid du Colombier 	}
4453de6a9c0SDavid du Colombier 
4463de6a9c0SDavid du Colombier 	/*
4473de6a9c0SDavid du Colombier 	 * set up the stack pointers for the exception modes for this cpu.
4483de6a9c0SDavid du Colombier 	 * they point to small `save areas' in Mach, not actual stacks.
4493de6a9c0SDavid du Colombier 	 */
4503de6a9c0SDavid du Colombier 	s = splhi();			/* make these modes ignore intrs too */
4513de6a9c0SDavid du Colombier 	setr13(PsrMfiq, m->sfiq);
4523de6a9c0SDavid du Colombier 	setr13(PsrMirq, m->sirq);
4533de6a9c0SDavid du Colombier 	setr13(PsrMmon, m->smon);
4543de6a9c0SDavid du Colombier 	setr13(PsrMabt, m->sabt);
4553de6a9c0SDavid du Colombier 	setr13(PsrMund, m->sund);
4563de6a9c0SDavid du Colombier 	setr13(PsrMsys, m->ssys);
4573de6a9c0SDavid du Colombier 	splx(s);
4583de6a9c0SDavid du Colombier 
4593de6a9c0SDavid du Colombier 	assert((idp->distid & MASK(12)) == 0x43b);	/* made by arm */
4603de6a9c0SDavid du Colombier 	assert((icp->ifid   & MASK(12)) == 0x43b);	/* made by arm */
4613de6a9c0SDavid du Colombier 
4623de6a9c0SDavid du Colombier 	ilock(&distlock);
4633de6a9c0SDavid du Colombier 	idp->ctl = 0;
4643de6a9c0SDavid du Colombier 	icp->ctl = 0;
4653de6a9c0SDavid du Colombier 	coherence();
4663de6a9c0SDavid du Colombier 
4673de6a9c0SDavid du Colombier 	intrcfg(idp);			/* some per-cpu cfg here */
4683de6a9c0SDavid du Colombier 
4693de6a9c0SDavid du Colombier 	icp->ctl = Enable;
4703de6a9c0SDavid du Colombier 	icp->primask = (uchar)~0;	/* let all priorities through */
4713de6a9c0SDavid du Colombier 	coherence();
4723de6a9c0SDavid du Colombier 
4733de6a9c0SDavid du Colombier 	idp->ctl = Forw2cpuif;
4743de6a9c0SDavid du Colombier 	iunlock(&distlock);
4753de6a9c0SDavid du Colombier }
4763de6a9c0SDavid du Colombier 
4773de6a9c0SDavid du Colombier void
intrsoff(void)4783de6a9c0SDavid du Colombier intrsoff(void)
4793de6a9c0SDavid du Colombier {
4803de6a9c0SDavid du Colombier 	ilock(&distlock);
4813de6a9c0SDavid du Colombier 	intcmaskall((Intrdistregs *)soc.intrdist);
4823de6a9c0SDavid du Colombier 	iunlock(&distlock);
4833de6a9c0SDavid du Colombier }
4843de6a9c0SDavid du Colombier 
4853de6a9c0SDavid du Colombier void
intrcpushutdown(void)4863de6a9c0SDavid du Colombier intrcpushutdown(void)
4873de6a9c0SDavid du Colombier {
4883de6a9c0SDavid du Colombier 	Intrcpuregs *icp = (Intrcpuregs *)soc.intr;
4893de6a9c0SDavid du Colombier 
4903de6a9c0SDavid du Colombier 	icp->ctl = 0;
4913de6a9c0SDavid du Colombier 	icp->primask = 0;	/* let no priorities through */
4923de6a9c0SDavid du Colombier 	coherence();
4933de6a9c0SDavid du Colombier }
4943de6a9c0SDavid du Colombier 
4953de6a9c0SDavid du Colombier /* called from cpu0 after other cpus are shutdown */
4963de6a9c0SDavid du Colombier void
intrshutdown(void)4973de6a9c0SDavid du Colombier intrshutdown(void)
4983de6a9c0SDavid du Colombier {
4993de6a9c0SDavid du Colombier 	Intrdistregs *idp = (Intrdistregs *)soc.intrdist;
5003de6a9c0SDavid du Colombier 
5013de6a9c0SDavid du Colombier 	intrsoff();
5023de6a9c0SDavid du Colombier 	idp->ctl = 0;
5033de6a9c0SDavid du Colombier 	intrcpushutdown();
5043de6a9c0SDavid du Colombier }
5053de6a9c0SDavid du Colombier 
5063de6a9c0SDavid du Colombier /*
5073de6a9c0SDavid du Colombier  *  enable an irq interrupt
5083de6a9c0SDavid du Colombier  *  note that the same private interrupt may be enabled on multiple cpus
5093de6a9c0SDavid du Colombier  */
5103de6a9c0SDavid du Colombier int
irqenable(uint irq,void (* f)(Ureg *,void *),void * a,char * name)5113de6a9c0SDavid du Colombier irqenable(uint irq, void (*f)(Ureg*, void*), void* a, char *name)
5123de6a9c0SDavid du Colombier {
5133de6a9c0SDavid du Colombier 	Vctl *v;
5143de6a9c0SDavid du Colombier 
5153de6a9c0SDavid du Colombier 	if(irq >= nelem(vctl))
5163de6a9c0SDavid du Colombier 		panic("irqenable irq %d", irq);
5173de6a9c0SDavid du Colombier 
5183de6a9c0SDavid du Colombier 	if (irqtooearly) {
5193de6a9c0SDavid du Colombier 		iprint("irqenable for %d %s called too early\n", irq, name);
5203de6a9c0SDavid du Colombier 		return -1;
5213de6a9c0SDavid du Colombier 	}
5223de6a9c0SDavid du Colombier 	/*
5233de6a9c0SDavid du Colombier 	 * if in use, could be a private interrupt on a secondary cpu,
5243de6a9c0SDavid du Colombier 	 * so don't add anything to the vector chain.  irqs should
5253de6a9c0SDavid du Colombier 	 * otherwise be one-to-one with devices.
5263de6a9c0SDavid du Colombier 	 */
5273de6a9c0SDavid du Colombier 	if(!ISSGI(irq) && irqinuse(irq)) {
5283de6a9c0SDavid du Colombier 		lock(&vctllock);
5293de6a9c0SDavid du Colombier 		if (vctl[irq] == nil) {
5303de6a9c0SDavid du Colombier 			dumpintrpend();
5313de6a9c0SDavid du Colombier 			panic("non-sgi irq %d in use yet no Vctl allocated", irq);
5323de6a9c0SDavid du Colombier 		}
5333de6a9c0SDavid du Colombier 		unlock(&vctllock);
5343de6a9c0SDavid du Colombier 	}
5353de6a9c0SDavid du Colombier 	/* could be 1st use of this irq or could be an sgi (always in use) */
5363de6a9c0SDavid du Colombier 	else if (vctl[irq] == nil) {
5373de6a9c0SDavid du Colombier 		v = malloc(sizeof(Vctl));
5383de6a9c0SDavid du Colombier 		if (v == nil)
5393de6a9c0SDavid du Colombier 			panic("irqenable: malloc Vctl");
5403de6a9c0SDavid du Colombier 		v->f = f;
5413de6a9c0SDavid du Colombier 		v->a = a;
5423de6a9c0SDavid du Colombier 		v->name = malloc(strlen(name)+1);
5433de6a9c0SDavid du Colombier 		if (v->name == nil)
5443de6a9c0SDavid du Colombier 			panic("irqenable: malloc name");
5453de6a9c0SDavid du Colombier 		strcpy(v->name, name);
5463de6a9c0SDavid du Colombier 
5473de6a9c0SDavid du Colombier 		lock(&vctllock);
5483de6a9c0SDavid du Colombier 		if (vctl[irq] != nil) {
5493de6a9c0SDavid du Colombier 			/* allocation race: someone else did it first */
5503de6a9c0SDavid du Colombier 			free(v->name);
5513de6a9c0SDavid du Colombier 			free(v);
5523de6a9c0SDavid du Colombier 		} else {
5533de6a9c0SDavid du Colombier 			v->next = vctl[irq];
5543de6a9c0SDavid du Colombier 			vctl[irq] = v;
5553de6a9c0SDavid du Colombier 		}
5563de6a9c0SDavid du Colombier 		unlock(&vctllock);
5573de6a9c0SDavid du Colombier 	}
5583de6a9c0SDavid du Colombier 	intcunmask(irq);
5593de6a9c0SDavid du Colombier 	return 0;
5603de6a9c0SDavid du Colombier }
5613de6a9c0SDavid du Colombier 
5623de6a9c0SDavid du Colombier /*
5633de6a9c0SDavid du Colombier  *  disable an irq interrupt
5643de6a9c0SDavid du Colombier  */
5653de6a9c0SDavid du Colombier int
irqdisable(uint irq,void (* f)(Ureg *,void *),void * a,char * name)5663de6a9c0SDavid du Colombier irqdisable(uint irq, void (*f)(Ureg*, void*), void* a, char *name)
5673de6a9c0SDavid du Colombier {
5683de6a9c0SDavid du Colombier 	Vctl **vp, *v;
5693de6a9c0SDavid du Colombier 
5703de6a9c0SDavid du Colombier 	if(irq >= nelem(vctl))
5713de6a9c0SDavid du Colombier 		panic("irqdisable irq %d", irq);
5723de6a9c0SDavid du Colombier 
5733de6a9c0SDavid du Colombier 	lock(&vctllock);
5743de6a9c0SDavid du Colombier 	for(vp = &vctl[irq]; v = *vp; vp = &v->next)
5753de6a9c0SDavid du Colombier 		if (v->f == f && v->a == a && strcmp(v->name, name) == 0){
576*0591a7c1SDavid du Colombier 			if(Debug)
5773de6a9c0SDavid du Colombier 				print("irqdisable: remove %s\n", name);
5783de6a9c0SDavid du Colombier 			*vp = v->next;
5793de6a9c0SDavid du Colombier 			free(v->name);
5803de6a9c0SDavid du Colombier 			free(v);
5813de6a9c0SDavid du Colombier 			break;
5823de6a9c0SDavid du Colombier 		}
5833de6a9c0SDavid du Colombier 
5843de6a9c0SDavid du Colombier 	if(v == nil)
5853de6a9c0SDavid du Colombier 		print("irqdisable: irq %d, name %s not enabled\n", irq, name);
5863de6a9c0SDavid du Colombier 	if(vctl[irq] == nil){
587*0591a7c1SDavid du Colombier 		if(Debug)
5883de6a9c0SDavid du Colombier 			print("irqdisable: clear icmr bit %d\n", irq);
5893de6a9c0SDavid du Colombier 		intcmask(irq);
5903de6a9c0SDavid du Colombier 	}
5913de6a9c0SDavid du Colombier 	unlock(&vctllock);
5923de6a9c0SDavid du Colombier 
5933de6a9c0SDavid du Colombier 	return 0;
5943de6a9c0SDavid du Colombier }
5953de6a9c0SDavid du Colombier 
5963de6a9c0SDavid du Colombier /*
5973de6a9c0SDavid du Colombier  *  called by trap to handle access faults
5983de6a9c0SDavid du Colombier  */
5993de6a9c0SDavid du Colombier static void
faultarm(Ureg * ureg,uintptr va,int user,int read)6003de6a9c0SDavid du Colombier faultarm(Ureg *ureg, uintptr va, int user, int read)
6013de6a9c0SDavid du Colombier {
6023de6a9c0SDavid du Colombier 	int n, insyscall;
6033de6a9c0SDavid du Colombier 
6043de6a9c0SDavid du Colombier 	if(up == nil) {
6053de6a9c0SDavid du Colombier 		dumpstackwithureg(ureg);
6063de6a9c0SDavid du Colombier 		panic("faultarm: cpu%d: nil up, %sing %#p at %#p",
6073de6a9c0SDavid du Colombier 			m->machno, (read? "read": "writ"), va, ureg->pc);
6083de6a9c0SDavid du Colombier 	}
6093de6a9c0SDavid du Colombier 	insyscall = up->insyscall;
6103de6a9c0SDavid du Colombier 	up->insyscall = 1;
6113de6a9c0SDavid du Colombier 
6123de6a9c0SDavid du Colombier 	n = fault(va, read);		/* goes spllo */
6133de6a9c0SDavid du Colombier 	splhi();
6143de6a9c0SDavid du Colombier 	if(n < 0){
6153de6a9c0SDavid du Colombier 		char buf[ERRMAX];
6163de6a9c0SDavid du Colombier 
6173de6a9c0SDavid du Colombier 		if(!user){
6183de6a9c0SDavid du Colombier 			dumpstackwithureg(ureg);
6193de6a9c0SDavid du Colombier 			panic("fault: cpu%d: kernel %sing %#p at %#p",
6203de6a9c0SDavid du Colombier 				m->machno, read? "read": "writ", va, ureg->pc);
6213de6a9c0SDavid du Colombier 		}
6223de6a9c0SDavid du Colombier 		/* don't dump registers; programs suicide all the time */
6233de6a9c0SDavid du Colombier 		snprint(buf, sizeof buf, "sys: trap: fault %s va=%#p",
6243de6a9c0SDavid du Colombier 			read? "read": "write", va);
6253de6a9c0SDavid du Colombier 		postnote(up, 1, buf, NDebug);
6263de6a9c0SDavid du Colombier 	}
6273de6a9c0SDavid du Colombier 	up->insyscall = insyscall;
6283de6a9c0SDavid du Colombier }
6293de6a9c0SDavid du Colombier 
6303de6a9c0SDavid du Colombier /*
6313de6a9c0SDavid du Colombier  *  called by trap to handle interrupts.
6323de6a9c0SDavid du Colombier  *  returns true iff a clock interrupt, thus maybe reschedule.
6333de6a9c0SDavid du Colombier  */
6343de6a9c0SDavid du Colombier static int
irq(Ureg * ureg)6353de6a9c0SDavid du Colombier irq(Ureg* ureg)
6363de6a9c0SDavid du Colombier {
6373de6a9c0SDavid du Colombier 	int clockintr, ack;
6383de6a9c0SDavid du Colombier 	uint irqno, handled, t, ticks;
6393de6a9c0SDavid du Colombier 	Intrcpuregs *icp = (Intrcpuregs *)soc.intr;
6403de6a9c0SDavid du Colombier 	Vctl *v;
6413de6a9c0SDavid du Colombier 
6423de6a9c0SDavid du Colombier 	ticks = perfticks();
6433de6a9c0SDavid du Colombier 	handled = 0;
6443de6a9c0SDavid du Colombier 	ack = intack(icp);
6453de6a9c0SDavid du Colombier 	irqno = ack & Intrmask;
6463de6a9c0SDavid du Colombier 
6473de6a9c0SDavid du Colombier 	if (irqno >= nelem(vctl)) {
6483de6a9c0SDavid du Colombier 		iprint("trap: irq %d >= # vectors (%d)\n", irqno, nelem(vctl));
6493de6a9c0SDavid du Colombier 		intdismiss(icp, ack);
6503de6a9c0SDavid du Colombier 		return 0;
6513de6a9c0SDavid du Colombier 	}
6523de6a9c0SDavid du Colombier 
6533de6a9c0SDavid du Colombier 	if (irqno == Loctmrirq)			/* this is a clock intr? */
6543de6a9c0SDavid du Colombier 		m->inclockintr++;		/* yes, count nesting */
6553de6a9c0SDavid du Colombier 	if(m->machno && m->inclockintr > 1) {
6563de6a9c0SDavid du Colombier 		iprint("cpu%d: nested clock intrs\n", m->machno);
6573de6a9c0SDavid du Colombier 		m->inclockintr--;
6583de6a9c0SDavid du Colombier 		intdismiss(icp, ack);
6593de6a9c0SDavid du Colombier 		return 0;
6603de6a9c0SDavid du Colombier 	}
6613de6a9c0SDavid du Colombier 
6623de6a9c0SDavid du Colombier 	for(v = vctl[irqno]; v != nil; v = v->next)
6633de6a9c0SDavid du Colombier 		if (v->f) {
6643de6a9c0SDavid du Colombier 			if (islo())
6653de6a9c0SDavid du Colombier 				panic("trap: pl0 before trap handler for %s",
6663de6a9c0SDavid du Colombier 					v->name);
6673de6a9c0SDavid du Colombier 			v->f(ureg, v->a);
6683de6a9c0SDavid du Colombier 			if (islo())
6693de6a9c0SDavid du Colombier 				panic("trap: %s lowered pl", v->name);
6703de6a9c0SDavid du Colombier //			splhi();		/* in case v->f lowered pl */
6713de6a9c0SDavid du Colombier 			handled++;
6723de6a9c0SDavid du Colombier 		}
6733de6a9c0SDavid du Colombier 	if(!handled)
6743de6a9c0SDavid du Colombier 		if (irqno >= 1022)
6753de6a9c0SDavid du Colombier 			iprint("cpu%d: ignoring spurious interrupt\n", m->machno);
6763de6a9c0SDavid du Colombier 		else {
6773de6a9c0SDavid du Colombier 			intcmask(irqno);
6783de6a9c0SDavid du Colombier 			iprint("cpu%d: unexpected interrupt %d, now masked\n",
6793de6a9c0SDavid du Colombier 				m->machno, irqno);
6803de6a9c0SDavid du Colombier 		}
6813de6a9c0SDavid du Colombier 	t = perfticks();
6823de6a9c0SDavid du Colombier 	if (0) {			/* left over from another port? */
6833de6a9c0SDavid du Colombier 		ilock(&nintrlock);
6843de6a9c0SDavid du Colombier 		ninterrupt++;
6853de6a9c0SDavid du Colombier 		if(t < ticks)
6863de6a9c0SDavid du Colombier 			ninterruptticks += ticks-t;
6873de6a9c0SDavid du Colombier 		else
6883de6a9c0SDavid du Colombier 			ninterruptticks += t-ticks;
6893de6a9c0SDavid du Colombier 		iunlock(&nintrlock);
6903de6a9c0SDavid du Colombier 	}
6913de6a9c0SDavid du Colombier 	USED(t, ticks);
6923de6a9c0SDavid du Colombier 	clockintr = m->inclockintr == 1;
6933de6a9c0SDavid du Colombier 	if (irqno == Loctmrirq)
6943de6a9c0SDavid du Colombier 		m->inclockintr--;
6953de6a9c0SDavid du Colombier 
6963de6a9c0SDavid du Colombier 	intdismiss(icp, ack);
6973de6a9c0SDavid du Colombier 	intrtime(m, irqno);
6983de6a9c0SDavid du Colombier 	return clockintr;
6993de6a9c0SDavid du Colombier }
7003de6a9c0SDavid du Colombier 
7013de6a9c0SDavid du Colombier /*
7023de6a9c0SDavid du Colombier  *  returns 1 if the instruction writes memory, 0 otherwise
7033de6a9c0SDavid du Colombier  */
7043de6a9c0SDavid du Colombier int
writetomem(ulong inst)7053de6a9c0SDavid du Colombier writetomem(ulong inst)
7063de6a9c0SDavid du Colombier {
7073de6a9c0SDavid du Colombier 	/* swap always write memory */
7083de6a9c0SDavid du Colombier 	if((inst & 0x0FC00000) == 0x01000000)
7093de6a9c0SDavid du Colombier 		return 1;
7103de6a9c0SDavid du Colombier 
7113de6a9c0SDavid du Colombier 	/* loads and stores are distinguished by bit 20 */
7123de6a9c0SDavid du Colombier 	if(inst & (1<<20))
7133de6a9c0SDavid du Colombier 		return 0;
7143de6a9c0SDavid du Colombier 
7153de6a9c0SDavid du Colombier 	return 1;
7163de6a9c0SDavid du Colombier }
7173de6a9c0SDavid du Colombier 
7183de6a9c0SDavid du Colombier static void
datafault(Ureg * ureg,int user)7193de6a9c0SDavid du Colombier datafault(Ureg *ureg, int user)
7203de6a9c0SDavid du Colombier {
7213de6a9c0SDavid du Colombier 	int x;
7223de6a9c0SDavid du Colombier 	ulong inst, fsr;
7233de6a9c0SDavid du Colombier 	uintptr va;
7243de6a9c0SDavid du Colombier 
7253de6a9c0SDavid du Colombier 	va = farget();
7263de6a9c0SDavid du Colombier 
7273de6a9c0SDavid du Colombier 	if (m->probing && !user) {
7283de6a9c0SDavid du Colombier 		if (m->trapped++ > 0) {
7293de6a9c0SDavid du Colombier 			dumpstackwithureg(ureg);
7303de6a9c0SDavid du Colombier 			panic("trap: recursive probe %#lux", va);
7313de6a9c0SDavid du Colombier 		}
7323de6a9c0SDavid du Colombier 		ureg->pc += 4;	/* continue after faulting instr'n */
7333de6a9c0SDavid du Colombier 		return;
7343de6a9c0SDavid du Colombier 	}
7353de6a9c0SDavid du Colombier 
7363de6a9c0SDavid du Colombier 	inst = *(ulong*)(ureg->pc);
7373de6a9c0SDavid du Colombier 	/* bits 12 and 10 have to be concatenated with status */
7383de6a9c0SDavid du Colombier 	x = fsrget();
7393de6a9c0SDavid du Colombier 	fsr = (x>>7) & 0x20 | (x>>6) & 0x10 | x & 0xf;
7403de6a9c0SDavid du Colombier 	switch(fsr){
7413de6a9c0SDavid du Colombier 	default:
7423de6a9c0SDavid du Colombier 	case 0xa:		/* ? was under external abort */
7433de6a9c0SDavid du Colombier 		panic("unknown data fault, 6b fsr %#lux", fsr);
7443de6a9c0SDavid du Colombier 		break;
7453de6a9c0SDavid du Colombier 	case 0x0:
7463de6a9c0SDavid du Colombier 		panic("vector exception at %#lux", ureg->pc);
7473de6a9c0SDavid du Colombier 		break;
7483de6a9c0SDavid du Colombier 	case 0x1:		/* alignment fault */
7493de6a9c0SDavid du Colombier 	case 0x3:		/* access flag fault (section) */
7503de6a9c0SDavid du Colombier 		if(user){
7513de6a9c0SDavid du Colombier 			char buf[ERRMAX];
7523de6a9c0SDavid du Colombier 
7533de6a9c0SDavid du Colombier 			snprint(buf, sizeof buf,
7543de6a9c0SDavid du Colombier 				"sys: alignment: pc %#lux va %#p\n",
7553de6a9c0SDavid du Colombier 				ureg->pc, va);
7563de6a9c0SDavid du Colombier 			postnote(up, 1, buf, NDebug);
7573de6a9c0SDavid du Colombier 		} else {
7583de6a9c0SDavid du Colombier 			dumpstackwithureg(ureg);
7593de6a9c0SDavid du Colombier 			panic("kernel alignment: pc %#lux va %#p", ureg->pc, va);
7603de6a9c0SDavid du Colombier 		}
7613de6a9c0SDavid du Colombier 		break;
7623de6a9c0SDavid du Colombier 	case 0x2:
7633de6a9c0SDavid du Colombier 		panic("terminal exception at %#lux", ureg->pc);
7643de6a9c0SDavid du Colombier 		break;
7653de6a9c0SDavid du Colombier 	case 0x4:		/* icache maint fault */
7663de6a9c0SDavid du Colombier 	case 0x6:		/* access flag fault (page) */
7673de6a9c0SDavid du Colombier 	case 0x8:		/* precise external abort, non-xlat'n */
7683de6a9c0SDavid du Colombier 	case 0x28:
7693de6a9c0SDavid du Colombier 	case 0x16:		/* imprecise ext. abort, non-xlt'n */
7703de6a9c0SDavid du Colombier 	case 0x36:
7713de6a9c0SDavid du Colombier 		panic("external non-translation abort %#lux pc %#lux addr %#p",
7723de6a9c0SDavid du Colombier 			fsr, ureg->pc, va);
7733de6a9c0SDavid du Colombier 		break;
7743de6a9c0SDavid du Colombier 	case 0xc:		/* l1 translation, precise ext. abort */
7753de6a9c0SDavid du Colombier 	case 0x2c:
7763de6a9c0SDavid du Colombier 	case 0xe:		/* l2 translation, precise ext. abort */
7773de6a9c0SDavid du Colombier 	case 0x2e:
7783de6a9c0SDavid du Colombier 		panic("external translation abort %#lux pc %#lux addr %#p",
7793de6a9c0SDavid du Colombier 			fsr, ureg->pc, va);
7803de6a9c0SDavid du Colombier 		break;
7813de6a9c0SDavid du Colombier 	case 0x1c:		/* l1 translation, precise parity err */
7823de6a9c0SDavid du Colombier 	case 0x1e:		/* l2 translation, precise parity err */
7833de6a9c0SDavid du Colombier 	case 0x18:		/* imprecise parity or ecc err */
7843de6a9c0SDavid du Colombier 		panic("translation parity error %#lux pc %#lux addr %#p",
7853de6a9c0SDavid du Colombier 			fsr, ureg->pc, va);
7863de6a9c0SDavid du Colombier 		break;
7873de6a9c0SDavid du Colombier 	case 0x5:		/* translation fault, no section entry */
7883de6a9c0SDavid du Colombier 	case 0x7:		/* translation fault, no page entry */
7893de6a9c0SDavid du Colombier 		faultarm(ureg, va, user, !writetomem(inst));
7903de6a9c0SDavid du Colombier 		break;
7913de6a9c0SDavid du Colombier 	case 0x9:
7923de6a9c0SDavid du Colombier 	case 0xb:
7933de6a9c0SDavid du Colombier 		/* domain fault, accessing something we shouldn't */
7943de6a9c0SDavid du Colombier 		if(user){
7953de6a9c0SDavid du Colombier 			char buf[ERRMAX];
7963de6a9c0SDavid du Colombier 
7973de6a9c0SDavid du Colombier 			snprint(buf, sizeof buf,
7983de6a9c0SDavid du Colombier 				"sys: access violation: pc %#lux va %#p\n",
7993de6a9c0SDavid du Colombier 				ureg->pc, va);
8003de6a9c0SDavid du Colombier 			postnote(up, 1, buf, NDebug);
8013de6a9c0SDavid du Colombier 		} else
8023de6a9c0SDavid du Colombier 			panic("kernel access violation: pc %#lux va %#p",
8033de6a9c0SDavid du Colombier 				ureg->pc, va);
8043de6a9c0SDavid du Colombier 		break;
8053de6a9c0SDavid du Colombier 	case 0xd:
8063de6a9c0SDavid du Colombier 	case 0xf:
8073de6a9c0SDavid du Colombier 		/* permission error, copy on write or real permission error */
8083de6a9c0SDavid du Colombier 		faultarm(ureg, va, user, !writetomem(inst));
8093de6a9c0SDavid du Colombier 		break;
8103de6a9c0SDavid du Colombier 	}
8113de6a9c0SDavid du Colombier }
8123de6a9c0SDavid du Colombier 
8133de6a9c0SDavid du Colombier /*
8143de6a9c0SDavid du Colombier  *  here on all exceptions other than syscall (SWI) and reset
8153de6a9c0SDavid du Colombier  */
8163de6a9c0SDavid du Colombier void
trap(Ureg * ureg)8173de6a9c0SDavid du Colombier trap(Ureg *ureg)
8183de6a9c0SDavid du Colombier {
8193de6a9c0SDavid du Colombier 	int clockintr, user, rem;
8209b7bf7dfSDavid du Colombier 	uintptr va, ifar, ifsr;
8213de6a9c0SDavid du Colombier 
8223de6a9c0SDavid du Colombier 	splhi();			/* paranoia */
8233de6a9c0SDavid du Colombier 	if(up != nil)
8243de6a9c0SDavid du Colombier 		rem = ((char*)ureg)-up->kstack;
8253de6a9c0SDavid du Colombier 	else
8263de6a9c0SDavid du Colombier 		rem = ((char*)ureg)-((char*)m+sizeof(Mach));
8273de6a9c0SDavid du Colombier 	if(rem < 1024) {
8283de6a9c0SDavid du Colombier 		iprint("trap: %d stack bytes left, up %#p ureg %#p m %#p cpu%d at pc %#lux\n",
8293de6a9c0SDavid du Colombier 			rem, up, ureg, m, m->machno, ureg->pc);
8303de6a9c0SDavid du Colombier 		dumpstackwithureg(ureg);
8313de6a9c0SDavid du Colombier 		panic("trap: %d stack bytes left, up %#p ureg %#p at pc %#lux",
8323de6a9c0SDavid du Colombier 			rem, up, ureg, ureg->pc);
8333de6a9c0SDavid du Colombier 	}
8343de6a9c0SDavid du Colombier 
8353de6a9c0SDavid du Colombier 	m->perf.intrts = perfticks();
8363de6a9c0SDavid du Colombier 	user = (ureg->psr & PsrMask) == PsrMusr;
8373de6a9c0SDavid du Colombier 	if(user){
8383de6a9c0SDavid du Colombier 		up->dbgreg = ureg;
8393de6a9c0SDavid du Colombier 		cycles(&up->kentry);
8403de6a9c0SDavid du Colombier 	}
8413de6a9c0SDavid du Colombier 
8423de6a9c0SDavid du Colombier 	/*
8433de6a9c0SDavid du Colombier 	 * All interrupts/exceptions should be resumed at ureg->pc-4,
8443de6a9c0SDavid du Colombier 	 * except for Data Abort which resumes at ureg->pc-8.
8453de6a9c0SDavid du Colombier 	 */
8463de6a9c0SDavid du Colombier 	if(ureg->type == (PsrMabt+1))
8473de6a9c0SDavid du Colombier 		ureg->pc -= 8;
8483de6a9c0SDavid du Colombier 	else
8493de6a9c0SDavid du Colombier 		ureg->pc -= 4;
8503de6a9c0SDavid du Colombier 
8513de6a9c0SDavid du Colombier 	clockintr = 0;		/* if set, may call sched() before return */
8523de6a9c0SDavid du Colombier 	switch(ureg->type){
8533de6a9c0SDavid du Colombier 	default:
8543de6a9c0SDavid du Colombier 		panic("unknown trap; type %#lux, psr mode %#lux", ureg->type,
8553de6a9c0SDavid du Colombier 			ureg->psr & PsrMask);
8563de6a9c0SDavid du Colombier 		break;
8573de6a9c0SDavid du Colombier 	case PsrMirq:
8583de6a9c0SDavid du Colombier 		m->intr++;
8593de6a9c0SDavid du Colombier 		clockintr = irq(ureg);
8603de6a9c0SDavid du Colombier 		if(0 && up && !clockintr)
8613de6a9c0SDavid du Colombier 			preempted();	/* this causes spurious suicides */
8623de6a9c0SDavid du Colombier 		break;
8633de6a9c0SDavid du Colombier 	case PsrMabt:			/* prefetch (instruction) fault */
8643de6a9c0SDavid du Colombier 		va = ureg->pc;
8659b7bf7dfSDavid du Colombier 		ifsr = cprdsc(0, CpFSR, 0, CpIFSR);
8669b7bf7dfSDavid du Colombier 		ifsr = (ifsr>>7) & 0x8 | ifsr & 0x7;
8679b7bf7dfSDavid du Colombier 		switch(ifsr){
8689b7bf7dfSDavid du Colombier 		case 0x02:		/* instruction debug event (BKPT) */
8699b7bf7dfSDavid du Colombier 			if(user)
8709b7bf7dfSDavid du Colombier 				postnote(up, 1, "sys: breakpoint", NDebug);
8719b7bf7dfSDavid du Colombier 			else{
8729b7bf7dfSDavid du Colombier 				iprint("kernel bkpt: pc %#lux inst %#ux\n",
8739b7bf7dfSDavid du Colombier 					va, *(u32int*)va);
8749b7bf7dfSDavid du Colombier 				panic("kernel bkpt");
8759b7bf7dfSDavid du Colombier 			}
8769b7bf7dfSDavid du Colombier 			break;
8779b7bf7dfSDavid du Colombier 		default:
8783de6a9c0SDavid du Colombier 			ifar = cprdsc(0, CpFAR, 0, CpIFAR);
8793de6a9c0SDavid du Colombier 			if (va != ifar)
8803de6a9c0SDavid du Colombier 				iprint("trap: cpu%d: i-fault va %#p != ifar %#p\n",
8813de6a9c0SDavid du Colombier 					m->machno, va, ifar);
8823de6a9c0SDavid du Colombier 			faultarm(ureg, va, user, 1);
8833de6a9c0SDavid du Colombier 			break;
8849b7bf7dfSDavid du Colombier 		}
8859b7bf7dfSDavid du Colombier 		break;
8863de6a9c0SDavid du Colombier 	case PsrMabt+1:			/* data fault */
8873de6a9c0SDavid du Colombier 		datafault(ureg, user);
8883de6a9c0SDavid du Colombier 		break;
8893de6a9c0SDavid du Colombier 	case PsrMund:			/* undefined instruction */
8903de6a9c0SDavid du Colombier 		if(!user) {
8913de6a9c0SDavid du Colombier 			if (ureg->pc & 3) {
8923de6a9c0SDavid du Colombier 				iprint("rounding fault pc %#lux down to word\n",
8933de6a9c0SDavid du Colombier 					ureg->pc);
8943de6a9c0SDavid du Colombier 				ureg->pc &= ~3;
8953de6a9c0SDavid du Colombier 			}
8963de6a9c0SDavid du Colombier 			if (Debug)
8973de6a9c0SDavid du Colombier 				iprint("mathemu: cpu%d fpon %d instr %#8.8lux at %#p\n",
8983de6a9c0SDavid du Colombier 					m->machno, m->fpon, *(ulong *)ureg->pc,
8993de6a9c0SDavid du Colombier 				ureg->pc);
9003de6a9c0SDavid du Colombier 			dumpstackwithureg(ureg);
9013de6a9c0SDavid du Colombier 			panic("cpu%d: undefined instruction: pc %#lux inst %#ux",
9023de6a9c0SDavid du Colombier 				m->machno, ureg->pc, ((u32int*)ureg->pc)[0]);
9033de6a9c0SDavid du Colombier 		} else if(seg(up, ureg->pc, 0) != nil &&
9043de6a9c0SDavid du Colombier 		   *(u32int*)ureg->pc == 0xD1200070)
9053de6a9c0SDavid du Colombier 			postnote(up, 1, "sys: breakpoint", NDebug);
9063de6a9c0SDavid du Colombier 		else if(fpuemu(ureg) == 0){	/* didn't find any FP instrs? */
9073de6a9c0SDavid du Colombier 			char buf[ERRMAX];
9083de6a9c0SDavid du Colombier 
9093de6a9c0SDavid du Colombier 			snprint(buf, sizeof buf,
9103de6a9c0SDavid du Colombier 				"undefined instruction: pc %#lux instr %#8.8lux\n",
9113de6a9c0SDavid du Colombier 				ureg->pc, *(ulong *)ureg->pc);
9123de6a9c0SDavid du Colombier 			postnote(up, 1, buf, NDebug);
9133de6a9c0SDavid du Colombier 		}
9143de6a9c0SDavid du Colombier 		break;
9153de6a9c0SDavid du Colombier 	}
9163de6a9c0SDavid du Colombier 	splhi();
9173de6a9c0SDavid du Colombier 
9183de6a9c0SDavid du Colombier 	/* delaysched set because we held a lock or because our quantum ended */
9193de6a9c0SDavid du Colombier 	if(up && up->delaysched && clockintr){
9203de6a9c0SDavid du Colombier 		sched();		/* can cause more traps */
9213de6a9c0SDavid du Colombier 		splhi();
9223de6a9c0SDavid du Colombier 	}
9233de6a9c0SDavid du Colombier 
9243de6a9c0SDavid du Colombier 	if(user){
9253de6a9c0SDavid du Colombier 		if(up->procctl || up->nnote)
9263de6a9c0SDavid du Colombier 			notify(ureg);
9273de6a9c0SDavid du Colombier 		kexit(ureg);
9283de6a9c0SDavid du Colombier 	}
9293de6a9c0SDavid du Colombier }
9303de6a9c0SDavid du Colombier 
9313de6a9c0SDavid du Colombier /*
9323de6a9c0SDavid du Colombier  * Fill in enough of Ureg to get a stack trace, and call a function.
9333de6a9c0SDavid du Colombier  * Used by debugging interface rdb.
9343de6a9c0SDavid du Colombier  */
9353de6a9c0SDavid du Colombier void
callwithureg(void (* fn)(Ureg *))9363de6a9c0SDavid du Colombier callwithureg(void (*fn)(Ureg*))
9373de6a9c0SDavid du Colombier {
9383de6a9c0SDavid du Colombier 	Ureg ureg;
9393de6a9c0SDavid du Colombier 
9403de6a9c0SDavid du Colombier 	memset(&ureg, 0, sizeof ureg);
9413de6a9c0SDavid du Colombier 	ureg.pc = getcallerpc(&fn);
9423de6a9c0SDavid du Colombier 	ureg.sp = PTR2UINT(&fn);
9433de6a9c0SDavid du Colombier 	fn(&ureg);
9443de6a9c0SDavid du Colombier }
9453de6a9c0SDavid du Colombier 
9463de6a9c0SDavid du Colombier static void
dumpstackwithureg(Ureg * ureg)9473de6a9c0SDavid du Colombier dumpstackwithureg(Ureg *ureg)
9483de6a9c0SDavid du Colombier {
9493de6a9c0SDavid du Colombier 	int x;
9503de6a9c0SDavid du Colombier 	uintptr l, v, i, estack;
9513de6a9c0SDavid du Colombier 	char *s;
9523de6a9c0SDavid du Colombier 
9533de6a9c0SDavid du Colombier 	dumpregs(ureg);
9543de6a9c0SDavid du Colombier 	if((s = getconf("*nodumpstack")) != nil && strcmp(s, "0") != 0){
9553de6a9c0SDavid du Colombier 		iprint("dumpstack disabled\n");
9563de6a9c0SDavid du Colombier 		return;
9573de6a9c0SDavid du Colombier 	}
9583de6a9c0SDavid du Colombier 	delay(1000);
9593de6a9c0SDavid du Colombier 	iprint("dumpstack\n");
9603de6a9c0SDavid du Colombier 
9613de6a9c0SDavid du Colombier 	x = 0;
9623de6a9c0SDavid du Colombier 	x += iprint("ktrace /kernel/path %#.8lux %#.8lux %#.8lux # pc, sp, link\n",
9633de6a9c0SDavid du Colombier 		ureg->pc, ureg->sp, ureg->r14);
9643de6a9c0SDavid du Colombier 	delay(20);
9653de6a9c0SDavid du Colombier 	i = 0;
9663de6a9c0SDavid du Colombier 	if(up
9673de6a9c0SDavid du Colombier 	&& (uintptr)&l >= (uintptr)up->kstack
9683de6a9c0SDavid du Colombier 	&& (uintptr)&l <= (uintptr)up->kstack+KSTACK)
9693de6a9c0SDavid du Colombier 		estack = (uintptr)up->kstack+KSTACK;
9703de6a9c0SDavid du Colombier 	else if((uintptr)&l >= (uintptr)m->stack
9713de6a9c0SDavid du Colombier 	&& (uintptr)&l <= (uintptr)m+MACHSIZE)
9723de6a9c0SDavid du Colombier 		estack = (uintptr)m+MACHSIZE;
9733de6a9c0SDavid du Colombier 	else
9743de6a9c0SDavid du Colombier 		return;
9753de6a9c0SDavid du Colombier 	x += iprint("estackx %p\n", estack);
9763de6a9c0SDavid du Colombier 
9773de6a9c0SDavid du Colombier 	for(l = (uintptr)&l; l < estack; l += sizeof(uintptr)){
9783de6a9c0SDavid du Colombier 		v = *(uintptr*)l;
9793de6a9c0SDavid du Colombier 		if((KTZERO < v && v < (uintptr)etext) || estack-l < 32){
9803de6a9c0SDavid du Colombier 			x += iprint("%.8p ", v);
9813de6a9c0SDavid du Colombier 			delay(20);
9823de6a9c0SDavid du Colombier 			i++;
9833de6a9c0SDavid du Colombier 		}
9843de6a9c0SDavid du Colombier 		if(i == 8){
9853de6a9c0SDavid du Colombier 			i = 0;
9863de6a9c0SDavid du Colombier 			x += iprint("\n");
9873de6a9c0SDavid du Colombier 			delay(20);
9883de6a9c0SDavid du Colombier 		}
9893de6a9c0SDavid du Colombier 	}
9903de6a9c0SDavid du Colombier 	if(i)
9913de6a9c0SDavid du Colombier 		iprint("\n");
9923de6a9c0SDavid du Colombier 	delay(3000);
9933de6a9c0SDavid du Colombier }
9943de6a9c0SDavid du Colombier 
9953de6a9c0SDavid du Colombier void
dumpstack(void)9963de6a9c0SDavid du Colombier dumpstack(void)
9973de6a9c0SDavid du Colombier {
9983de6a9c0SDavid du Colombier 	callwithureg(dumpstackwithureg);
9993de6a9c0SDavid du Colombier }
10003de6a9c0SDavid du Colombier 
10013de6a9c0SDavid du Colombier /*
10023de6a9c0SDavid du Colombier  * dump system control coprocessor registers
10033de6a9c0SDavid du Colombier  */
10043de6a9c0SDavid du Colombier static void
dumpscr(void)10053de6a9c0SDavid du Colombier dumpscr(void)
10063de6a9c0SDavid du Colombier {
10073de6a9c0SDavid du Colombier 	iprint("0:\t%#8.8ux id\n", cpidget());
10083de6a9c0SDavid du Colombier 	iprint("\t%8.8#ux ct\n", cpctget());
10093de6a9c0SDavid du Colombier 	iprint("1:\t%#8.8ux control\n", controlget());
10103de6a9c0SDavid du Colombier 	iprint("2:\t%#8.8ux ttb\n", ttbget());
10113de6a9c0SDavid du Colombier 	iprint("3:\t%#8.8ux dac\n", dacget());
10123de6a9c0SDavid du Colombier 	iprint("4:\t(reserved)\n");
10133de6a9c0SDavid du Colombier 	iprint("5:\t%#8.8ux fsr\n", fsrget());
10143de6a9c0SDavid du Colombier 	iprint("6:\t%#8.8ux far\n", farget());
10153de6a9c0SDavid du Colombier 	iprint("7:\twrite-only cache\n");
10163de6a9c0SDavid du Colombier 	iprint("8:\twrite-only tlb\n");
10173de6a9c0SDavid du Colombier 	iprint("13:\t%#8.8ux pid\n", pidget());
10183de6a9c0SDavid du Colombier 	delay(10);
10193de6a9c0SDavid du Colombier }
10203de6a9c0SDavid du Colombier 
10213de6a9c0SDavid du Colombier /*
10223de6a9c0SDavid du Colombier  * dump general registers
10233de6a9c0SDavid du Colombier  */
10243de6a9c0SDavid du Colombier static void
dumpgpr(Ureg * ureg)10253de6a9c0SDavid du Colombier dumpgpr(Ureg* ureg)
10263de6a9c0SDavid du Colombier {
10273de6a9c0SDavid du Colombier 	if(up != nil)
10283de6a9c0SDavid du Colombier 		iprint("cpu%d: registers for %s %lud\n",
10293de6a9c0SDavid du Colombier 			m->machno, up->text, up->pid);
10303de6a9c0SDavid du Colombier 	else
10313de6a9c0SDavid du Colombier 		iprint("cpu%d: registers for kernel\n", m->machno);
10323de6a9c0SDavid du Colombier 
10333de6a9c0SDavid du Colombier 	delay(20);
10343de6a9c0SDavid du Colombier 	iprint("%#8.8lux\tr0\n", ureg->r0);
10353de6a9c0SDavid du Colombier 	iprint("%#8.8lux\tr1\n", ureg->r1);
10363de6a9c0SDavid du Colombier 	iprint("%#8.8lux\tr2\n", ureg->r2);
10373de6a9c0SDavid du Colombier 	delay(20);
10383de6a9c0SDavid du Colombier 	iprint("%#8.8lux\tr3\n", ureg->r3);
10393de6a9c0SDavid du Colombier 	iprint("%#8.8lux\tr4\n", ureg->r4);
10403de6a9c0SDavid du Colombier 	iprint("%#8.8lux\tr5\n", ureg->r5);
10413de6a9c0SDavid du Colombier 	delay(20);
10423de6a9c0SDavid du Colombier 	iprint("%#8.8lux\tr6\n", ureg->r6);
10433de6a9c0SDavid du Colombier 	iprint("%#8.8lux\tr7\n", ureg->r7);
10443de6a9c0SDavid du Colombier 	iprint("%#8.8lux\tr8\n", ureg->r8);
10453de6a9c0SDavid du Colombier 	delay(20);
10463de6a9c0SDavid du Colombier 	iprint("%#8.8lux\tr9 (up)\n", ureg->r9);
10473de6a9c0SDavid du Colombier 	iprint("%#8.8lux\tr10 (m)\n", ureg->r10);
10483de6a9c0SDavid du Colombier 	iprint("%#8.8lux\tr11 (loader temporary)\n", ureg->r11);
10493de6a9c0SDavid du Colombier 	iprint("%#8.8lux\tr12 (SB)\n", ureg->r12);
10503de6a9c0SDavid du Colombier 	delay(20);
10513de6a9c0SDavid du Colombier 	iprint("%#8.8lux\tr13 (sp)\n", ureg->r13);
10523de6a9c0SDavid du Colombier 	iprint("%#8.8lux\tr14 (link)\n", ureg->r14);
10533de6a9c0SDavid du Colombier 	iprint("%#8.8lux\tr15 (pc)\n", ureg->pc);
10543de6a9c0SDavid du Colombier 	delay(20);
10553de6a9c0SDavid du Colombier 	iprint("%10.10lud\ttype\n", ureg->type);
10563de6a9c0SDavid du Colombier 	iprint("%#8.8lux\tpsr\n", ureg->psr);
10573de6a9c0SDavid du Colombier 	delay(500);
10583de6a9c0SDavid du Colombier }
10593de6a9c0SDavid du Colombier 
10603de6a9c0SDavid du Colombier void
dumpregs(Ureg * ureg)10613de6a9c0SDavid du Colombier dumpregs(Ureg* ureg)
10623de6a9c0SDavid du Colombier {
10633de6a9c0SDavid du Colombier 	dumpgpr(ureg);
10643de6a9c0SDavid du Colombier 	dumpscr();
10653de6a9c0SDavid du Colombier }
10663de6a9c0SDavid du Colombier 
10673de6a9c0SDavid du Colombier vlong
probeaddr(uintptr addr)10683de6a9c0SDavid du Colombier probeaddr(uintptr addr)
10693de6a9c0SDavid du Colombier {
10703de6a9c0SDavid du Colombier 	vlong v;
10713de6a9c0SDavid du Colombier 
10723de6a9c0SDavid du Colombier 	ilock(&m->probelock);
10733de6a9c0SDavid du Colombier 	m->trapped = 0;
10743de6a9c0SDavid du Colombier 	m->probing = 1;
10753de6a9c0SDavid du Colombier 	coherence();
10763de6a9c0SDavid du Colombier 
10773de6a9c0SDavid du Colombier 	v = *(ulong *)addr;	/* this may cause a fault */
10783de6a9c0SDavid du Colombier 	coherence();
10793de6a9c0SDavid du Colombier 
10803de6a9c0SDavid du Colombier 	m->probing = 0;
10813de6a9c0SDavid du Colombier 	if (m->trapped)
10823de6a9c0SDavid du Colombier 		v = -1;
10833de6a9c0SDavid du Colombier 	iunlock(&m->probelock);
10843de6a9c0SDavid du Colombier 	return v;
10853de6a9c0SDavid du Colombier }
1086