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