18e32b400SDavid du Colombier /*
28e32b400SDavid du Colombier * omap3530 traps, exceptions, interrupts, system calls.
38e32b400SDavid du Colombier */
48e32b400SDavid du Colombier #include "u.h"
58e32b400SDavid du Colombier #include "../port/lib.h"
68e32b400SDavid du Colombier #include "mem.h"
78e32b400SDavid du Colombier #include "dat.h"
88e32b400SDavid du Colombier #include "fns.h"
98e32b400SDavid du Colombier #include "../port/error.h"
108e32b400SDavid du Colombier
118e32b400SDavid du Colombier #include "ureg.h"
128e32b400SDavid du Colombier #include "arm.h"
138e32b400SDavid du Colombier
148e32b400SDavid du Colombier enum {
158e32b400SDavid du Colombier Nirqs = 96,
168e32b400SDavid du Colombier Nvec = 8, /* # of vectors at start of lexception.s */
178e32b400SDavid du Colombier Bi2long = BI2BY * sizeof(long),
188e32b400SDavid du Colombier };
198e32b400SDavid du Colombier
208e32b400SDavid du Colombier extern int notify(Ureg*);
218e32b400SDavid du Colombier
228e32b400SDavid du Colombier extern int ldrexvalid;
238e32b400SDavid du Colombier
248e32b400SDavid du Colombier /* omap35x intc (aka mpu_intc) */
258e32b400SDavid du Colombier typedef struct Intrregs Intrregs;
268e32b400SDavid du Colombier struct Intrregs {
278e32b400SDavid du Colombier /*
288e32b400SDavid du Colombier * the manual inserts "INTCPS_" before each register name;
298e32b400SDavid du Colombier * we'll just assume the prefix.
308e32b400SDavid du Colombier */
318e32b400SDavid du Colombier uchar _pad0[4*4];
328e32b400SDavid du Colombier ulong sysconfig;
338e32b400SDavid du Colombier ulong sysstatus; /* ro */
348e32b400SDavid du Colombier uchar _pad1[0x40 - 0x18];
358e32b400SDavid du Colombier ulong sir_irq; /* ro */
368e32b400SDavid du Colombier ulong sir_fiq; /* ro */
378e32b400SDavid du Colombier ulong control;
388e32b400SDavid du Colombier ulong protection;
398e32b400SDavid du Colombier ulong idle;
408e32b400SDavid du Colombier uchar _pad2[0x60 - 0x54];
418e32b400SDavid du Colombier ulong irq_priority;
428e32b400SDavid du Colombier ulong fiq_priority;
438e32b400SDavid du Colombier ulong threshold;
448e32b400SDavid du Colombier uchar _pad3[0x80 - 0x6c];
458e32b400SDavid du Colombier struct Bits { /* bitmaps */
468e32b400SDavid du Colombier ulong itr; /* ro: pending intrs (no mask) */
478e32b400SDavid du Colombier ulong mir; /* interrupt mask: 1 means masked */
488e32b400SDavid du Colombier ulong mir_clear; /* wo: 1 sets the bit */
498e32b400SDavid du Colombier ulong mir_set; /* wo: 1 clears the bit */
508e32b400SDavid du Colombier ulong isr_set; /* software interrupts */
518e32b400SDavid du Colombier ulong isr_clear; /* wo */
528e32b400SDavid du Colombier ulong pending_irq; /* ro */
538e32b400SDavid du Colombier ulong pending_fiq; /* ro */
548e32b400SDavid du Colombier } bits[3]; /* 3*32 = 96 (Nirqs) */
558e32b400SDavid du Colombier ulong ilr[Nirqs];
568e32b400SDavid du Colombier };
578e32b400SDavid du Colombier
588e32b400SDavid du Colombier enum {
598e32b400SDavid du Colombier /* sysconfig bits */
608e32b400SDavid du Colombier Softreset = 1<<1,
618e32b400SDavid du Colombier
628e32b400SDavid du Colombier /* sysstatus bits */
638e32b400SDavid du Colombier Resetdone = 1<<0,
648e32b400SDavid du Colombier
658e32b400SDavid du Colombier /* sir_irq/fiq bits */
668e32b400SDavid du Colombier Activeirq = MASK(7),
678e32b400SDavid du Colombier
688e32b400SDavid du Colombier /* control bits */
698e32b400SDavid du Colombier Newirqagr = 1<<0,
708e32b400SDavid du Colombier
718e32b400SDavid du Colombier /* protection bits */
728e32b400SDavid du Colombier Protection = 1<<0,
738e32b400SDavid du Colombier
748e32b400SDavid du Colombier /* irq/fiq_priority bits */
758e32b400SDavid du Colombier Irqpriority = MASK(6),
768e32b400SDavid du Colombier
778e32b400SDavid du Colombier /* threshold bits */
788e32b400SDavid du Colombier Prioritythreshold = MASK(8),
798e32b400SDavid du Colombier
808e32b400SDavid du Colombier /* ilr bits */
818e32b400SDavid du Colombier Priority = MASK(8) - MASK(2),
828e32b400SDavid du Colombier };
838e32b400SDavid du Colombier
848e32b400SDavid du Colombier typedef struct Vctl Vctl;
858e32b400SDavid du Colombier typedef struct Vctl {
868e32b400SDavid du Colombier Vctl* next; /* handlers on this vector */
878e32b400SDavid du Colombier char *name; /* of driver, xallocated */
888e32b400SDavid du Colombier void (*f)(Ureg*, void*); /* handler to call */
898e32b400SDavid du Colombier void* a; /* argument to call it with */
908e32b400SDavid du Colombier } Vctl;
918e32b400SDavid du Colombier
928e32b400SDavid du Colombier static Lock vctllock;
938e32b400SDavid du Colombier static Vctl* vctl[Nirqs];
948e32b400SDavid du Colombier
958e32b400SDavid du Colombier /*
968e32b400SDavid du Colombier * Layout at virtual address 0.
978e32b400SDavid du Colombier */
988e32b400SDavid du Colombier typedef struct Vpage0 {
998e32b400SDavid du Colombier void (*vectors[Nvec])(void);
1008e32b400SDavid du Colombier u32int vtable[Nvec];
1018e32b400SDavid du Colombier } Vpage0;
1028e32b400SDavid du Colombier static Vpage0 *vpage0;
1038e32b400SDavid du Colombier
1048e32b400SDavid du Colombier uvlong ninterrupt;
1058e32b400SDavid du Colombier uvlong ninterruptticks;
1068e32b400SDavid du Colombier int irqtooearly = 1;
1078e32b400SDavid du Colombier
1088e32b400SDavid du Colombier static volatile int probing, trapped;
1098e32b400SDavid du Colombier
1108e32b400SDavid du Colombier static int
irqinuse(uint irq)1118e32b400SDavid du Colombier irqinuse(uint irq)
1128e32b400SDavid du Colombier {
1138e32b400SDavid du Colombier Intrregs *ip = (Intrregs *)PHYSINTC;
1148e32b400SDavid du Colombier
1158e32b400SDavid du Colombier /*
1168e32b400SDavid du Colombier * mir registers are odd: a 0 bit means intr unmasked (i.e.,
1178e32b400SDavid du Colombier * we've unmasked it because it's in use).
1188e32b400SDavid du Colombier */
1198e32b400SDavid du Colombier return (ip->bits[irq / Bi2long].mir & (1 << (irq % Bi2long))) == 0;
1208e32b400SDavid du Colombier }
1218e32b400SDavid du Colombier
1228e32b400SDavid du Colombier static void
intcmask(uint irq)1238e32b400SDavid du Colombier intcmask(uint irq)
1248e32b400SDavid du Colombier {
1258e32b400SDavid du Colombier Intrregs *ip = (Intrregs *)PHYSINTC;
1268e32b400SDavid du Colombier
1278e32b400SDavid du Colombier ip->bits[irq / Bi2long].mir_set = 1 << (irq % Bi2long);
1288e32b400SDavid du Colombier coherence();
1298e32b400SDavid du Colombier }
1308e32b400SDavid du Colombier
1318e32b400SDavid du Colombier static void
intcunmask(uint irq)1328e32b400SDavid du Colombier intcunmask(uint irq)
1338e32b400SDavid du Colombier {
1348e32b400SDavid du Colombier Intrregs *ip = (Intrregs *)PHYSINTC;
1358e32b400SDavid du Colombier
1368e32b400SDavid du Colombier ip->bits[irq / Bi2long].mir_clear = 1 << (irq % Bi2long);
1378e32b400SDavid du Colombier coherence();
1388e32b400SDavid du Colombier }
1398e32b400SDavid du Colombier
1408e32b400SDavid du Colombier static void
intcmaskall(void)1418e32b400SDavid du Colombier intcmaskall(void)
1428e32b400SDavid du Colombier {
1438e32b400SDavid du Colombier int i;
1448e32b400SDavid du Colombier Intrregs *ip = (Intrregs *)PHYSINTC;
1458e32b400SDavid du Colombier
1468e32b400SDavid du Colombier for (i = 0; i < 3; i++)
1478e32b400SDavid du Colombier ip->bits[i].mir_set = ~0;
1488e32b400SDavid du Colombier coherence();
1498e32b400SDavid du Colombier }
1508e32b400SDavid du Colombier
1518e32b400SDavid du Colombier static void
intcunmaskall(void)1528e32b400SDavid du Colombier intcunmaskall(void)
1538e32b400SDavid du Colombier {
1548e32b400SDavid du Colombier int i;
1558e32b400SDavid du Colombier Intrregs *ip = (Intrregs *)PHYSINTC;
1568e32b400SDavid du Colombier
1578e32b400SDavid du Colombier for (i = 0; i < 3; i++)
1588e32b400SDavid du Colombier ip->bits[i].mir_clear = ~0;
1598e32b400SDavid du Colombier coherence();
1608e32b400SDavid du Colombier }
1618e32b400SDavid du Colombier
1628e32b400SDavid du Colombier static void
intcinvertall(void)1638e32b400SDavid du Colombier intcinvertall(void)
1648e32b400SDavid du Colombier {
1658e32b400SDavid du Colombier int i, s;
1668e32b400SDavid du Colombier ulong bits;
1678e32b400SDavid du Colombier Intrregs *ip = (Intrregs *)PHYSINTC;
1688e32b400SDavid du Colombier
1698e32b400SDavid du Colombier s = splhi();
1708e32b400SDavid du Colombier for (i = 0; i < 3; i++) {
1718e32b400SDavid du Colombier bits = ip->bits[i].mir;
1728e32b400SDavid du Colombier ip->bits[i].mir_set = ~0; /* mask all */
1738e32b400SDavid du Colombier coherence();
1748e32b400SDavid du Colombier /* clearing enables only those intrs. that were disabled */
1758e32b400SDavid du Colombier ip->bits[i].mir_clear = bits;
1768e32b400SDavid du Colombier }
1778e32b400SDavid du Colombier coherence();
1788e32b400SDavid du Colombier splx(s);
1798e32b400SDavid du Colombier }
1808e32b400SDavid du Colombier
1818e32b400SDavid du Colombier static void
intrsave(ulong buf[3])1828e32b400SDavid du Colombier intrsave(ulong buf[3])
1838e32b400SDavid du Colombier {
1848e32b400SDavid du Colombier int i;
1858e32b400SDavid du Colombier Intrregs *ip = (Intrregs *)PHYSINTC;
1868e32b400SDavid du Colombier
1878e32b400SDavid du Colombier for (i = 0; i < nelem(buf); i++)
1888e32b400SDavid du Colombier buf[i] = ip->bits[i].mir;
1898e32b400SDavid du Colombier coherence();
1908e32b400SDavid du Colombier }
1918e32b400SDavid du Colombier
1928e32b400SDavid du Colombier static void
intrrestore(ulong buf[3])1938e32b400SDavid du Colombier intrrestore(ulong buf[3])
1948e32b400SDavid du Colombier {
1958e32b400SDavid du Colombier int i, s;
1968e32b400SDavid du Colombier Intrregs *ip = (Intrregs *)PHYSINTC;
1978e32b400SDavid du Colombier
1988e32b400SDavid du Colombier s = splhi();
1998e32b400SDavid du Colombier for (i = 0; i < nelem(buf); i++) {
2008e32b400SDavid du Colombier ip->bits[i].mir_clear = ~0; /* unmask all */
2018e32b400SDavid du Colombier coherence();
2028e32b400SDavid du Colombier ip->bits[i].mir_set = buf[i]; /* mask previously disabled */
2038e32b400SDavid du Colombier }
2048e32b400SDavid du Colombier coherence();
2058e32b400SDavid du Colombier splx(s);
2068e32b400SDavid du Colombier }
2078e32b400SDavid du Colombier
2088e32b400SDavid du Colombier /*
2098e32b400SDavid du Colombier * set up for exceptions
2108e32b400SDavid du Colombier */
2118e32b400SDavid du Colombier void
trapinit(void)2128e32b400SDavid du Colombier trapinit(void)
2138e32b400SDavid du Colombier {
2148e32b400SDavid du Colombier int i;
2158e32b400SDavid du Colombier Intrregs *ip = (Intrregs *)PHYSINTC;
2168e32b400SDavid du Colombier
2178e32b400SDavid du Colombier /* set up the exception vectors */
2188e32b400SDavid du Colombier vpage0 = (Vpage0*)HVECTORS;
2198e32b400SDavid du Colombier memmove(vpage0->vectors, vectors, sizeof(vpage0->vectors));
2208e32b400SDavid du Colombier memmove(vpage0->vtable, vtable, sizeof(vpage0->vtable));
2218e32b400SDavid du Colombier cacheuwbinv();
2228e32b400SDavid du Colombier l2cacheuwbinv();
2238e32b400SDavid du Colombier
2248e32b400SDavid du Colombier /* set up the stacks for the interrupt modes */
2258e32b400SDavid du Colombier setr13(PsrMfiq, m->sfiq);
2268e32b400SDavid du Colombier setr13(PsrMirq, m->sirq);
2278e32b400SDavid du Colombier setr13(PsrMabt, m->sabt);
2288e32b400SDavid du Colombier setr13(PsrMund, m->sund);
2298e32b400SDavid du Colombier #ifdef HIGH_SECURITY
2308e32b400SDavid du Colombier setr13(PsrMmon, m->smon);
2318e32b400SDavid du Colombier #endif
2328e32b400SDavid du Colombier setr13(PsrMsys, m->ssys);
2338e32b400SDavid du Colombier
2348e32b400SDavid du Colombier intcmaskall();
2358e32b400SDavid du Colombier ip->control = 0;
2368e32b400SDavid du Colombier ip->threshold = Prioritythreshold; /* disable threshold */
2378e32b400SDavid du Colombier for (i = 0; i < Nirqs; i++)
2388e32b400SDavid du Colombier ip->ilr[i] = 0<<2 | 0; /* all intrs pri 0 & to irq, not fiq */
2398e32b400SDavid du Colombier irqtooearly = 0;
2408e32b400SDavid du Colombier coherence();
2418e32b400SDavid du Colombier }
2428e32b400SDavid du Colombier
2438e32b400SDavid du Colombier void
intrsoff(void)2448e32b400SDavid du Colombier intrsoff(void)
2458e32b400SDavid du Colombier {
2468e32b400SDavid du Colombier Intrregs *ip = (Intrregs *)PHYSINTC;
2478e32b400SDavid du Colombier
2488e32b400SDavid du Colombier intcmaskall();
2498e32b400SDavid du Colombier ip->control = Newirqagr; /* dismiss interrupt */
2508e32b400SDavid du Colombier coherence();
2518e32b400SDavid du Colombier }
2528e32b400SDavid du Colombier
2538e32b400SDavid du Colombier /*
2548e32b400SDavid du Colombier * enable an irq interrupt
2558e32b400SDavid du Colombier */
2568e32b400SDavid du Colombier int
irqenable(int irq,void (* f)(Ureg *,void *),void * a,char * name)2578e32b400SDavid du Colombier irqenable(int irq, void (*f)(Ureg*, void*), void* a, char *name)
2588e32b400SDavid du Colombier {
2598e32b400SDavid du Colombier Vctl *v;
2608e32b400SDavid du Colombier
2618e32b400SDavid du Colombier if(irq >= nelem(vctl) || irq < 0)
2628e32b400SDavid du Colombier panic("irqenable irq %d", irq);
2638e32b400SDavid du Colombier
2648e32b400SDavid du Colombier if (irqtooearly) {
2658e32b400SDavid du Colombier iprint("irqenable for %d %s called too early\n", irq, name);
2668e32b400SDavid du Colombier return -1;
2678e32b400SDavid du Colombier }
2688e32b400SDavid du Colombier if(irqinuse(irq))
2698e32b400SDavid du Colombier print("irqenable: %s: irq %d already in use, chaining\n",
2708e32b400SDavid du Colombier name, irq);
2718e32b400SDavid du Colombier v = malloc(sizeof(Vctl));
2728e32b400SDavid du Colombier if (v == nil)
2738e32b400SDavid du Colombier panic("irqenable: malloc Vctl");
2748e32b400SDavid du Colombier v->f = f;
2758e32b400SDavid du Colombier v->a = a;
2768e32b400SDavid du Colombier v->name = malloc(strlen(name)+1);
2778e32b400SDavid du Colombier if (v->name == nil)
2788e32b400SDavid du Colombier panic("irqenable: malloc name");
2798e32b400SDavid du Colombier strcpy(v->name, name);
2808e32b400SDavid du Colombier
2818e32b400SDavid du Colombier lock(&vctllock);
2828e32b400SDavid du Colombier v->next = vctl[irq];
2838e32b400SDavid du Colombier vctl[irq] = v;
2848e32b400SDavid du Colombier
2858e32b400SDavid du Colombier intcunmask(irq);
2868e32b400SDavid du Colombier unlock(&vctllock);
2878e32b400SDavid du Colombier return 0;
2888e32b400SDavid du Colombier }
2898e32b400SDavid du Colombier
2908e32b400SDavid du Colombier /*
2918e32b400SDavid du Colombier * disable an irq interrupt
2928e32b400SDavid du Colombier */
2938e32b400SDavid du Colombier int
irqdisable(int irq,void (* f)(Ureg *,void *),void * a,char * name)2948e32b400SDavid du Colombier irqdisable(int irq, void (*f)(Ureg*, void*), void* a, char *name)
2958e32b400SDavid du Colombier {
2968e32b400SDavid du Colombier Vctl **vp, *v;
2978e32b400SDavid du Colombier
2988e32b400SDavid du Colombier if(irq >= nelem(vctl) || irq < 0)
2998e32b400SDavid du Colombier panic("irqdisable irq %d", irq);
3008e32b400SDavid du Colombier
3018e32b400SDavid du Colombier lock(&vctllock);
3028e32b400SDavid du Colombier for(vp = &vctl[irq]; v = *vp; vp = &v->next)
3038e32b400SDavid du Colombier if (v->f == f && v->a == a && strcmp(v->name, name) == 0){
3048e32b400SDavid du Colombier print("irqdisable: remove %s\n", name);
3058e32b400SDavid du Colombier *vp = v->next;
3068e32b400SDavid du Colombier free(v);
3078e32b400SDavid du Colombier break;
3088e32b400SDavid du Colombier }
3098e32b400SDavid du Colombier
3108e32b400SDavid du Colombier if(v == nil)
3118e32b400SDavid du Colombier print("irqdisable: irq %d, name %s not enabled\n", irq, name);
3128e32b400SDavid du Colombier if(vctl[irq] == nil){
3138e32b400SDavid du Colombier print("irqdisable: clear icmr bit %d\n", irq);
3148e32b400SDavid du Colombier intcmask(irq);
3158e32b400SDavid du Colombier }
3168e32b400SDavid du Colombier unlock(&vctllock);
3178e32b400SDavid du Colombier
3188e32b400SDavid du Colombier return 0;
3198e32b400SDavid du Colombier }
3208e32b400SDavid du Colombier
3218e32b400SDavid du Colombier /*
3228e32b400SDavid du Colombier * called by trap to handle access faults
3238e32b400SDavid du Colombier */
3248e32b400SDavid du Colombier static void
faultarm(Ureg * ureg,uintptr va,int user,int read)3258e32b400SDavid du Colombier faultarm(Ureg *ureg, uintptr va, int user, int read)
3268e32b400SDavid du Colombier {
3278e32b400SDavid du Colombier int n, insyscall;
3288e32b400SDavid du Colombier char buf[ERRMAX];
3298e32b400SDavid du Colombier
3308e32b400SDavid du Colombier if(up == nil) {
3318e32b400SDavid du Colombier dumpregs(ureg);
3328e32b400SDavid du Colombier panic("fault: nil up in faultarm, accessing %#p", va);
3338e32b400SDavid du Colombier }
3348e32b400SDavid du Colombier insyscall = up->insyscall;
3358e32b400SDavid du Colombier up->insyscall = 1;
3368e32b400SDavid du Colombier n = fault(va, read);
3378e32b400SDavid du Colombier if(n < 0){
3388e32b400SDavid du Colombier if(!user){
3398e32b400SDavid du Colombier dumpregs(ureg);
3408e32b400SDavid du Colombier panic("fault: kernel accessing %#p", va);
3418e32b400SDavid du Colombier }
3428e32b400SDavid du Colombier /* don't dump registers; programs suicide all the time */
3438e32b400SDavid du Colombier snprint(buf, sizeof buf, "sys: trap: fault %s va=%#p",
3448e32b400SDavid du Colombier read? "read": "write", va);
3458e32b400SDavid du Colombier postnote(up, 1, buf, NDebug);
3468e32b400SDavid du Colombier }
3478e32b400SDavid du Colombier up->insyscall = insyscall;
3488e32b400SDavid du Colombier }
3498e32b400SDavid du Colombier
3508e32b400SDavid du Colombier /*
3518e32b400SDavid du Colombier * called by trap to handle interrupts.
3528e32b400SDavid du Colombier * returns true iff a clock interrupt, thus maybe reschedule.
3538e32b400SDavid du Colombier */
3548e32b400SDavid du Colombier static int
irq(Ureg * ureg)3558e32b400SDavid du Colombier irq(Ureg* ureg)
3568e32b400SDavid du Colombier {
3578e32b400SDavid du Colombier int clockintr;
3588e32b400SDavid du Colombier uint irqno, handled, t, ticks = perfticks();
3598e32b400SDavid du Colombier Intrregs *ip = (Intrregs *)PHYSINTC;
3608e32b400SDavid du Colombier Vctl *v;
3618e32b400SDavid du Colombier static int nesting, lastirq = -1;
3628e32b400SDavid du Colombier
3638e32b400SDavid du Colombier handled = 0;
3648e32b400SDavid du Colombier irqno = ip->sir_irq & Activeirq;
3658e32b400SDavid du Colombier
3668e32b400SDavid du Colombier if (irqno >= 37 && irqno <= 47) /* this is a clock intr? */
3678e32b400SDavid du Colombier m->inclockintr++; /* yes, count nesting */
3688e32b400SDavid du Colombier lastirq = irqno;
3698e32b400SDavid du Colombier
3708e32b400SDavid du Colombier if (irqno >= nelem(vctl)) {
3718e32b400SDavid du Colombier iprint("trap: irq %d >= # vectors (%d)\n", irqno, nelem(vctl));
3728e32b400SDavid du Colombier ip->control = Newirqagr; /* dismiss interrupt */
3738e32b400SDavid du Colombier return 0;
3748e32b400SDavid du Colombier }
3758e32b400SDavid du Colombier
3768e32b400SDavid du Colombier ++nesting;
3778e32b400SDavid du Colombier for(v = vctl[irqno]; v != nil; v = v->next)
3788e32b400SDavid du Colombier if (v->f) {
3798e32b400SDavid du Colombier if (islo())
3808e32b400SDavid du Colombier panic("trap: pl0 before trap handler for %s",
3818e32b400SDavid du Colombier v->name);
3828e32b400SDavid du Colombier v->f(ureg, v->a);
3838e32b400SDavid du Colombier if (islo())
3848e32b400SDavid du Colombier panic("trap: %s lowered pl", v->name);
3858e32b400SDavid du Colombier // splhi(); /* in case v->f lowered pl */
3868e32b400SDavid du Colombier handled++;
3878e32b400SDavid du Colombier }
3888bfb44c2SDavid du Colombier if(!handled) {
389436938c0SDavid du Colombier iprint("unexpected interrupt: irq %d", irqno);
390436938c0SDavid du Colombier switch (irqno) {
391436938c0SDavid du Colombier case 56:
392436938c0SDavid du Colombier case 57:
393436938c0SDavid du Colombier iprint(" (IC)");
394436938c0SDavid du Colombier break;
395436938c0SDavid du Colombier case 83:
396436938c0SDavid du Colombier case 86:
397436938c0SDavid du Colombier case 94:
398436938c0SDavid du Colombier iprint(" (MMC)");
399436938c0SDavid du Colombier break;
400436938c0SDavid du Colombier }
401436938c0SDavid du Colombier
4028bfb44c2SDavid du Colombier if(irqno < nelem(vctl)) {
4038bfb44c2SDavid du Colombier intcmask(irqno);
404436938c0SDavid du Colombier iprint(", now masked");
4058bfb44c2SDavid du Colombier }
406436938c0SDavid du Colombier iprint("\n");
4078bfb44c2SDavid du Colombier }
4088e32b400SDavid du Colombier t = perfticks();
4098e32b400SDavid du Colombier ninterrupt++;
4108e32b400SDavid du Colombier if(t < ticks)
4118e32b400SDavid du Colombier ninterruptticks += ticks-t;
4128e32b400SDavid du Colombier else
4138e32b400SDavid du Colombier ninterruptticks += t-ticks;
4148e32b400SDavid du Colombier ip->control = Newirqagr; /* dismiss interrupt */
4158e32b400SDavid du Colombier coherence();
4168e32b400SDavid du Colombier
4178e32b400SDavid du Colombier --nesting;
4188e32b400SDavid du Colombier clockintr = m->inclockintr == 1;
4198e32b400SDavid du Colombier if (irqno >= 37 && irqno <= 47)
4208e32b400SDavid du Colombier m->inclockintr--;
4218e32b400SDavid du Colombier return clockintr;
4228e32b400SDavid du Colombier }
4238e32b400SDavid du Colombier
4248e32b400SDavid du Colombier /*
4258e32b400SDavid du Colombier * returns 1 if the instruction writes memory, 0 otherwise
4268e32b400SDavid du Colombier */
4278e32b400SDavid du Colombier int
writetomem(ulong inst)4288e32b400SDavid du Colombier writetomem(ulong inst)
4298e32b400SDavid du Colombier {
4308e32b400SDavid du Colombier /* swap always write memory */
4318e32b400SDavid du Colombier if((inst & 0x0FC00000) == 0x01000000)
4328e32b400SDavid du Colombier return 1;
4338e32b400SDavid du Colombier
4348e32b400SDavid du Colombier /* loads and stores are distinguished by bit 20 */
4358e32b400SDavid du Colombier if(inst & (1<<20))
4368e32b400SDavid du Colombier return 0;
4378e32b400SDavid du Colombier
4388e32b400SDavid du Colombier return 1;
4398e32b400SDavid du Colombier }
4408e32b400SDavid du Colombier
441b3b810bfSDavid du Colombier void prgpmcerrs(void);
442b3b810bfSDavid du Colombier
4438e32b400SDavid du Colombier /*
4448e32b400SDavid du Colombier * here on all exceptions other than syscall (SWI)
4458e32b400SDavid du Colombier */
4468e32b400SDavid du Colombier void
trap(Ureg * ureg)4478e32b400SDavid du Colombier trap(Ureg *ureg)
4488e32b400SDavid du Colombier {
4498e32b400SDavid du Colombier int clockintr, user, x, rv, rem;
4508e32b400SDavid du Colombier ulong inst, fsr;
4518e32b400SDavid du Colombier uintptr va;
4528e32b400SDavid du Colombier char buf[ERRMAX];
4538e32b400SDavid du Colombier
4548e32b400SDavid du Colombier splhi(); /* paranoia */
4558e32b400SDavid du Colombier if(up != nil)
4568e32b400SDavid du Colombier rem = ((char*)ureg)-up->kstack;
4578e32b400SDavid du Colombier else
4588e32b400SDavid du Colombier rem = ((char*)ureg)-((char*)m+sizeof(Mach));
4598e32b400SDavid du Colombier if(rem < 1024) {
4608e32b400SDavid du Colombier iprint("trap: %d stack bytes left, up %#p ureg %#p at pc %#lux\n",
4618e32b400SDavid du Colombier rem, up, ureg, ureg->pc);
4628e32b400SDavid du Colombier delay(1000);
4638e32b400SDavid du Colombier dumpstack();
4648e32b400SDavid du Colombier panic("trap: %d stack bytes left, up %#p ureg %#p at pc %#lux",
4658e32b400SDavid du Colombier rem, up, ureg, ureg->pc);
4668e32b400SDavid du Colombier }
4678e32b400SDavid du Colombier
4688e32b400SDavid du Colombier user = (ureg->psr & PsrMask) == PsrMusr;
4698e32b400SDavid du Colombier if(user){
4708e32b400SDavid du Colombier up->dbgreg = ureg;
4718e32b400SDavid du Colombier cycles(&up->kentry);
4728e32b400SDavid du Colombier }
4738e32b400SDavid du Colombier
4748e32b400SDavid du Colombier /*
4758e32b400SDavid du Colombier * All interrupts/exceptions should be resumed at ureg->pc-4,
4768e32b400SDavid du Colombier * except for Data Abort which resumes at ureg->pc-8.
4778e32b400SDavid du Colombier */
4788e32b400SDavid du Colombier if(ureg->type == (PsrMabt+1))
4798e32b400SDavid du Colombier ureg->pc -= 8;
4808e32b400SDavid du Colombier else
4818e32b400SDavid du Colombier ureg->pc -= 4;
4828e32b400SDavid du Colombier
4838e32b400SDavid du Colombier clockintr = 0; /* if set, may call sched() before return */
4848e32b400SDavid du Colombier switch(ureg->type){
4858e32b400SDavid du Colombier default:
4868e32b400SDavid du Colombier panic("unknown trap; type %#lux, psr mode %#lux", ureg->type,
4878e32b400SDavid du Colombier ureg->psr & PsrMask);
4888e32b400SDavid du Colombier break;
4898e32b400SDavid du Colombier case PsrMirq:
4908e32b400SDavid du Colombier ldrexvalid = 0;
4918e32b400SDavid du Colombier clockintr = irq(ureg);
492634d7e5aSDavid du Colombier m->intr++;
4938e32b400SDavid du Colombier break;
4948e32b400SDavid du Colombier case PsrMabt: /* prefetch fault */
4958e32b400SDavid du Colombier ldrexvalid = 0;
496*9b7bf7dfSDavid du Colombier x = ifsrget();
497*9b7bf7dfSDavid du Colombier fsr = (x>>7) & 0x8 | x & 0x7;
498*9b7bf7dfSDavid du Colombier switch(fsr){
499*9b7bf7dfSDavid du Colombier case 0x02: /* instruction debug event (BKPT) */
500*9b7bf7dfSDavid du Colombier if(user){
501*9b7bf7dfSDavid du Colombier snprint(buf, sizeof buf, "sys: breakpoint");
502*9b7bf7dfSDavid du Colombier postnote(up, 1, buf, NDebug);
503*9b7bf7dfSDavid du Colombier }else{
504*9b7bf7dfSDavid du Colombier iprint("kernel bkpt: pc %#lux inst %#ux\n",
505*9b7bf7dfSDavid du Colombier ureg->pc, *(u32int*)ureg->pc);
506*9b7bf7dfSDavid du Colombier panic("kernel bkpt");
507*9b7bf7dfSDavid du Colombier }
508*9b7bf7dfSDavid du Colombier break;
509*9b7bf7dfSDavid du Colombier default:
5108e32b400SDavid du Colombier faultarm(ureg, ureg->pc, user, 1);
5118e32b400SDavid du Colombier break;
512*9b7bf7dfSDavid du Colombier }
513*9b7bf7dfSDavid du Colombier break;
5148e32b400SDavid du Colombier case PsrMabt+1: /* data fault */
5158e32b400SDavid du Colombier ldrexvalid = 0;
5168e32b400SDavid du Colombier va = farget();
5178e32b400SDavid du Colombier inst = *(ulong*)(ureg->pc);
518b3b810bfSDavid du Colombier /* bits 12 and 10 have to be concatenated with status */
519b3b810bfSDavid du Colombier x = fsrget();
520b3b810bfSDavid du Colombier fsr = (x>>7) & 0x20 | (x>>6) & 0x10 | x & 0xf;
5218e32b400SDavid du Colombier if (probing && !user) {
5228e32b400SDavid du Colombier if (trapped++ > 0)
5238e32b400SDavid du Colombier panic("trap: recursive probe %#lux", va);
5248e32b400SDavid du Colombier ureg->pc += 4; /* continue at next instruction */
5258e32b400SDavid du Colombier break;
5268e32b400SDavid du Colombier }
5278e32b400SDavid du Colombier switch(fsr){
528b3b810bfSDavid du Colombier default:
529b3b810bfSDavid du Colombier case 0xa: /* ? was under external abort */
530b3b810bfSDavid du Colombier panic("unknown data fault, 6b fsr %#lux", fsr);
531b3b810bfSDavid du Colombier break;
5328e32b400SDavid du Colombier case 0x0:
5338e32b400SDavid du Colombier panic("vector exception at %#lux", ureg->pc);
5348e32b400SDavid du Colombier break;
535b3b810bfSDavid du Colombier case 0x1: /* alignment fault */
536b3b810bfSDavid du Colombier case 0x3: /* access flag fault (section) */
5378e32b400SDavid du Colombier if(user){
5388e32b400SDavid du Colombier snprint(buf, sizeof buf,
5398e32b400SDavid du Colombier "sys: alignment: pc %#lux va %#p\n",
5408e32b400SDavid du Colombier ureg->pc, va);
5418e32b400SDavid du Colombier postnote(up, 1, buf, NDebug);
5428e32b400SDavid du Colombier } else
5438e32b400SDavid du Colombier panic("kernel alignment: pc %#lux va %#p", ureg->pc, va);
5448e32b400SDavid du Colombier break;
5458e32b400SDavid du Colombier case 0x2:
5468e32b400SDavid du Colombier panic("terminal exception at %#lux", ureg->pc);
5478e32b400SDavid du Colombier break;
548b3b810bfSDavid du Colombier case 0x4: /* icache maint fault */
549b3b810bfSDavid du Colombier case 0x6: /* access flag fault (page) */
550b3b810bfSDavid du Colombier case 0x8: /* precise external abort, non-xlat'n */
551b3b810bfSDavid du Colombier case 0x28:
552b3b810bfSDavid du Colombier case 0xc: /* l1 translation, precise ext. abort */
553b3b810bfSDavid du Colombier case 0x2c:
554b3b810bfSDavid du Colombier case 0xe: /* l2 translation, precise ext. abort */
555b3b810bfSDavid du Colombier case 0x2e:
556b3b810bfSDavid du Colombier case 0x16: /* imprecise ext. abort, non-xlt'n */
557b3b810bfSDavid du Colombier case 0x36:
5588e32b400SDavid du Colombier panic("external abort %#lux pc %#lux addr %#p",
5598e32b400SDavid du Colombier fsr, ureg->pc, va);
5608e32b400SDavid du Colombier break;
561b3b810bfSDavid du Colombier case 0x1c: /* l1 translation, precise parity err */
562b3b810bfSDavid du Colombier case 0x1e: /* l2 translation, precise parity err */
563b3b810bfSDavid du Colombier case 0x18: /* imprecise parity or ecc err */
564b3b810bfSDavid du Colombier panic("translation parity error %#lux pc %#lux addr %#p",
565b3b810bfSDavid du Colombier fsr, ureg->pc, va);
566b3b810bfSDavid du Colombier break;
5678e32b400SDavid du Colombier case 0x5: /* translation fault, no section entry */
5688e32b400SDavid du Colombier case 0x7: /* translation fault, no page entry */
5698e32b400SDavid du Colombier faultarm(ureg, va, user, !writetomem(inst));
5708e32b400SDavid du Colombier break;
5718e32b400SDavid du Colombier case 0x9:
5728e32b400SDavid du Colombier case 0xb:
5738e32b400SDavid du Colombier /* domain fault, accessing something we shouldn't */
5748e32b400SDavid du Colombier if(user){
5758e32b400SDavid du Colombier snprint(buf, sizeof buf,
5768e32b400SDavid du Colombier "sys: access violation: pc %#lux va %#p\n",
5778e32b400SDavid du Colombier ureg->pc, va);
5788e32b400SDavid du Colombier postnote(up, 1, buf, NDebug);
5798e32b400SDavid du Colombier } else
5808e32b400SDavid du Colombier panic("kernel access violation: pc %#lux va %#p",
5818e32b400SDavid du Colombier ureg->pc, va);
5828e32b400SDavid du Colombier break;
5838e32b400SDavid du Colombier case 0xd:
5848e32b400SDavid du Colombier case 0xf:
5858e32b400SDavid du Colombier /* permission error, copy on write or real permission error */
5868e32b400SDavid du Colombier faultarm(ureg, va, user, !writetomem(inst));
5878e32b400SDavid du Colombier break;
5888e32b400SDavid du Colombier }
5898e32b400SDavid du Colombier break;
5908e32b400SDavid du Colombier case PsrMund: /* undefined instruction */
5918e32b400SDavid du Colombier if(user){
592a4b9e815SDavid du Colombier if(seg(up, ureg->pc, 0) != nil &&
593a4b9e815SDavid du Colombier *(u32int*)ureg->pc == 0xD1200070){
594a4b9e815SDavid du Colombier snprint(buf, sizeof buf, "sys: breakpoint");
595a4b9e815SDavid du Colombier postnote(up, 1, buf, NDebug);
596a4b9e815SDavid du Colombier }else{
5978e32b400SDavid du Colombier /* look for floating point instructions to interpret */
5988e32b400SDavid du Colombier x = spllo();
5998e32b400SDavid du Colombier rv = fpiarm(ureg);
6008e32b400SDavid du Colombier splx(x);
6018e32b400SDavid du Colombier if(rv == 0){
6028e32b400SDavid du Colombier ldrexvalid = 0;
6038e32b400SDavid du Colombier snprint(buf, sizeof buf,
6048e32b400SDavid du Colombier "undefined instruction: pc %#lux\n",
6058e32b400SDavid du Colombier ureg->pc);
6068e32b400SDavid du Colombier postnote(up, 1, buf, NDebug);
6078e32b400SDavid du Colombier }
608a4b9e815SDavid du Colombier }
6098e32b400SDavid du Colombier }else{
6108e32b400SDavid du Colombier if (ureg->pc & 3) {
6118e32b400SDavid du Colombier iprint("rounding fault pc %#lux down to word\n",
6128e32b400SDavid du Colombier ureg->pc);
6138e32b400SDavid du Colombier ureg->pc &= ~3;
6148e32b400SDavid du Colombier }
6158e32b400SDavid du Colombier iprint("undefined instruction: pc %#lux inst %#ux\n",
6168e32b400SDavid du Colombier ureg->pc, ((u32int*)ureg->pc)[-2]);
6178e32b400SDavid du Colombier panic("undefined instruction");
6188e32b400SDavid du Colombier }
6198e32b400SDavid du Colombier break;
6208e32b400SDavid du Colombier }
6218e32b400SDavid du Colombier splhi();
6228e32b400SDavid du Colombier
6238e32b400SDavid du Colombier /* delaysched set because we held a lock or because our quantum ended */
6248e32b400SDavid du Colombier if(up && up->delaysched && clockintr){
6258e32b400SDavid du Colombier ldrexvalid = 0;
6268e32b400SDavid du Colombier sched(); /* can cause more traps */
6278e32b400SDavid du Colombier splhi();
6288e32b400SDavid du Colombier }
6298e32b400SDavid du Colombier
6308e32b400SDavid du Colombier if(user){
6318e32b400SDavid du Colombier if(up->procctl || up->nnote)
6328e32b400SDavid du Colombier notify(ureg);
6338e32b400SDavid du Colombier kexit(ureg);
6348e32b400SDavid du Colombier }
6358e32b400SDavid du Colombier }
6368e32b400SDavid du Colombier
6378e32b400SDavid du Colombier /*
6388e32b400SDavid du Colombier * Fill in enough of Ureg to get a stack trace, and call a function.
6398e32b400SDavid du Colombier * Used by debugging interface rdb.
6408e32b400SDavid du Colombier */
6418e32b400SDavid du Colombier void
callwithureg(void (* fn)(Ureg *))6428e32b400SDavid du Colombier callwithureg(void (*fn)(Ureg*))
6438e32b400SDavid du Colombier {
6448e32b400SDavid du Colombier Ureg ureg;
6458e32b400SDavid du Colombier
6468e32b400SDavid du Colombier ureg.pc = getcallerpc(&fn);
6478e32b400SDavid du Colombier ureg.sp = PTR2UINT(&fn);
6488e32b400SDavid du Colombier fn(&ureg);
6498e32b400SDavid du Colombier }
6508e32b400SDavid du Colombier
6518e32b400SDavid du Colombier static void
dumpstackwithureg(Ureg * ureg)6528e32b400SDavid du Colombier dumpstackwithureg(Ureg *ureg)
6538e32b400SDavid du Colombier {
6548e32b400SDavid du Colombier int x;
6558e32b400SDavid du Colombier uintptr l, v, i, estack;
6568e32b400SDavid du Colombier char *s;
6578e32b400SDavid du Colombier
6588e32b400SDavid du Colombier dumpregs(ureg);
6598e32b400SDavid du Colombier if((s = getconf("*nodumpstack")) != nil && strcmp(s, "0") != 0){
6608e32b400SDavid du Colombier iprint("dumpstack disabled\n");
6618e32b400SDavid du Colombier return;
6628e32b400SDavid du Colombier }
6638e32b400SDavid du Colombier iprint("dumpstack\n");
6648e32b400SDavid du Colombier
6658e32b400SDavid du Colombier x = 0;
6668e32b400SDavid du Colombier x += iprint("ktrace /kernel/path %#.8lux %#.8lux %#.8lux # pc, sp, link\n",
6678e32b400SDavid du Colombier ureg->pc, ureg->sp, ureg->r14);
6688e32b400SDavid du Colombier delay(20);
6698e32b400SDavid du Colombier i = 0;
6708e32b400SDavid du Colombier if(up
6718e32b400SDavid du Colombier && (uintptr)&l >= (uintptr)up->kstack
6728e32b400SDavid du Colombier && (uintptr)&l <= (uintptr)up->kstack+KSTACK)
6738e32b400SDavid du Colombier estack = (uintptr)up->kstack+KSTACK;
6748e32b400SDavid du Colombier else if((uintptr)&l >= (uintptr)m->stack
6758e32b400SDavid du Colombier && (uintptr)&l <= (uintptr)m+MACHSIZE)
6768e32b400SDavid du Colombier estack = (uintptr)m+MACHSIZE;
6778e32b400SDavid du Colombier else
6788e32b400SDavid du Colombier return;
6798e32b400SDavid du Colombier x += iprint("estackx %p\n", estack);
6808e32b400SDavid du Colombier
6818e32b400SDavid du Colombier for(l = (uintptr)&l; l < estack; l += sizeof(uintptr)){
6828e32b400SDavid du Colombier v = *(uintptr*)l;
6838e32b400SDavid du Colombier if((KTZERO < v && v < (uintptr)etext) || estack-l < 32){
6848e32b400SDavid du Colombier x += iprint("%.8p ", v);
6858e32b400SDavid du Colombier delay(20);
6868e32b400SDavid du Colombier i++;
6878e32b400SDavid du Colombier }
6888e32b400SDavid du Colombier if(i == 8){
6898e32b400SDavid du Colombier i = 0;
6908e32b400SDavid du Colombier x += iprint("\n");
6918e32b400SDavid du Colombier delay(20);
6928e32b400SDavid du Colombier }
6938e32b400SDavid du Colombier }
6948e32b400SDavid du Colombier if(i)
6958e32b400SDavid du Colombier iprint("\n");
6968e32b400SDavid du Colombier }
6978e32b400SDavid du Colombier
6988e32b400SDavid du Colombier void
dumpstack(void)6998e32b400SDavid du Colombier dumpstack(void)
7008e32b400SDavid du Colombier {
7018e32b400SDavid du Colombier callwithureg(dumpstackwithureg);
7028e32b400SDavid du Colombier }
7038e32b400SDavid du Colombier
7048e32b400SDavid du Colombier /*
7058e32b400SDavid du Colombier * dump system control coprocessor registers
7068e32b400SDavid du Colombier */
7078e32b400SDavid du Colombier static void
dumpscr(void)7088e32b400SDavid du Colombier dumpscr(void)
7098e32b400SDavid du Colombier {
7108e32b400SDavid du Colombier iprint("0:\t%#8.8ux id\n", cpidget());
7118e32b400SDavid du Colombier iprint("\t%8.8#ux ct\n", cpctget());
7128e32b400SDavid du Colombier iprint("1:\t%#8.8ux control\n", controlget());
7138e32b400SDavid du Colombier iprint("2:\t%#8.8ux ttb\n", ttbget());
7148e32b400SDavid du Colombier iprint("3:\t%#8.8ux dac\n", dacget());
7158e32b400SDavid du Colombier iprint("4:\t(reserved)\n");
7168e32b400SDavid du Colombier iprint("5:\t%#8.8ux fsr\n", fsrget());
7178e32b400SDavid du Colombier iprint("6:\t%#8.8ux far\n", farget());
7188e32b400SDavid du Colombier iprint("7:\twrite-only cache\n");
7198e32b400SDavid du Colombier iprint("8:\twrite-only tlb\n");
7208e32b400SDavid du Colombier iprint("13:\t%#8.8ux pid\n", pidget());
7218e32b400SDavid du Colombier delay(10);
7228e32b400SDavid du Colombier }
7238e32b400SDavid du Colombier
7248e32b400SDavid du Colombier /*
7258e32b400SDavid du Colombier * dump general registers
7268e32b400SDavid du Colombier */
7278e32b400SDavid du Colombier static void
dumpgpr(Ureg * ureg)7288e32b400SDavid du Colombier dumpgpr(Ureg* ureg)
7298e32b400SDavid du Colombier {
7308e32b400SDavid du Colombier if(up != nil)
7318e32b400SDavid du Colombier iprint("cpu%d: registers for %s %lud\n",
7328e32b400SDavid du Colombier m->machno, up->text, up->pid);
7338e32b400SDavid du Colombier else
7348e32b400SDavid du Colombier iprint("cpu%d: registers for kernel\n", m->machno);
7358e32b400SDavid du Colombier
7368e32b400SDavid du Colombier delay(20);
7378e32b400SDavid du Colombier iprint("%#8.8lux\tr0\n", ureg->r0);
7388e32b400SDavid du Colombier iprint("%#8.8lux\tr1\n", ureg->r1);
7398e32b400SDavid du Colombier iprint("%#8.8lux\tr2\n", ureg->r2);
7408e32b400SDavid du Colombier delay(20);
7418e32b400SDavid du Colombier iprint("%#8.8lux\tr3\n", ureg->r3);
7428e32b400SDavid du Colombier iprint("%#8.8lux\tr4\n", ureg->r4);
7438e32b400SDavid du Colombier iprint("%#8.8lux\tr5\n", ureg->r5);
7448e32b400SDavid du Colombier delay(20);
7458e32b400SDavid du Colombier iprint("%#8.8lux\tr6\n", ureg->r6);
7468e32b400SDavid du Colombier iprint("%#8.8lux\tr7\n", ureg->r7);
7478e32b400SDavid du Colombier iprint("%#8.8lux\tr8\n", ureg->r8);
7488e32b400SDavid du Colombier delay(20);
7498e32b400SDavid du Colombier iprint("%#8.8lux\tr9 (up)\n", ureg->r9);
7508e32b400SDavid du Colombier iprint("%#8.8lux\tr10 (m)\n", ureg->r10);
7518e32b400SDavid du Colombier iprint("%#8.8lux\tr11 (loader temporary)\n", ureg->r11);
7528e32b400SDavid du Colombier iprint("%#8.8lux\tr12 (SB)\n", ureg->r12);
7538e32b400SDavid du Colombier delay(20);
7548e32b400SDavid du Colombier iprint("%#8.8lux\tr13 (sp)\n", ureg->r13);
7558e32b400SDavid du Colombier iprint("%#8.8lux\tr14 (link)\n", ureg->r14);
7568e32b400SDavid du Colombier iprint("%#8.8lux\tr15 (pc)\n", ureg->pc);
7578e32b400SDavid du Colombier delay(20);
7588e32b400SDavid du Colombier iprint("%10.10lud\ttype\n", ureg->type);
7598e32b400SDavid du Colombier iprint("%#8.8lux\tpsr\n", ureg->psr);
7608e32b400SDavid du Colombier delay(20);
7618e32b400SDavid du Colombier }
7628e32b400SDavid du Colombier
7638e32b400SDavid du Colombier void
dumpregs(Ureg * ureg)7648e32b400SDavid du Colombier dumpregs(Ureg* ureg)
7658e32b400SDavid du Colombier {
7668e32b400SDavid du Colombier dumpgpr(ureg);
7678e32b400SDavid du Colombier dumpscr();
7688e32b400SDavid du Colombier }
7698e32b400SDavid du Colombier
7708e32b400SDavid du Colombier vlong
probeaddr(uintptr addr)7718e32b400SDavid du Colombier probeaddr(uintptr addr)
7728e32b400SDavid du Colombier {
7738e32b400SDavid du Colombier vlong v;
7748e32b400SDavid du Colombier static Lock fltlck;
7758e32b400SDavid du Colombier
7768e32b400SDavid du Colombier ilock(&fltlck);
7778e32b400SDavid du Colombier trapped = 0;
7788e32b400SDavid du Colombier probing = 1;
7798e32b400SDavid du Colombier coherence();
7808e32b400SDavid du Colombier
7818e32b400SDavid du Colombier v = *(ulong *)addr; /* this may cause a fault */
7828e32b400SDavid du Colombier USED(probing);
7838e32b400SDavid du Colombier coherence();
7848e32b400SDavid du Colombier
7858e32b400SDavid du Colombier probing = 0;
7868e32b400SDavid du Colombier coherence();
7878e32b400SDavid du Colombier if (trapped)
7888e32b400SDavid du Colombier v = -1;
7898e32b400SDavid du Colombier iunlock(&fltlck);
7908e32b400SDavid du Colombier return v;
7918e32b400SDavid du Colombier }
792