uvlong ninterrupt;
uvlong ninterruptticks;
int irqtooearly = 1;
static volatile int probing, trapped;
static int
irqinuse(uint irq)
{
Intrregs *ip = (Intrregs *)PHYSINTC;
/*
* mir registers are odd: a 0 bit means intr unmasked (i.e.,
* we've unmasked it because it's in use).
*/
return (ip->bits[irq / Bi2long].mir & (1 << (irq % Bi2long))) == 0;
}
for (i = 0; i < 3; i++)
ip->bits[i].mir_clear = ~0;
coherence();
}
static void
intcinvertall(void)
{
int i, s;
ulong bits;
Intrregs *ip = (Intrregs *)PHYSINTC;
s = splhi();
for (i = 0; i < 3; i++) {
bits = ip->bits[i].mir;
ip->bits[i].mir_set = ~0; /* mask all */
coherence();
/* clearing enables only those intrs. that were disabled */
ip->bits[i].mir_clear = bits;
}
coherence();
splx(s);
}
for (i = 0; i < nelem(buf); i++)
buf[i] = ip->bits[i].mir;
coherence();
}
static void
intrrestore(ulong buf[3])
{
int i, s;
Intrregs *ip = (Intrregs *)PHYSINTC;
s = splhi();
for (i = 0; i < nelem(buf); i++) {
ip->bits[i].mir_clear = ~0; /* unmask all */
coherence();
ip->bits[i].mir_set = buf[i]; /* mask previously disabled */
}
coherence();
splx(s);
}
/*
* set up for exceptions
*/
void
trapinit(void)
{
int i;
Intrregs *ip = (Intrregs *)PHYSINTC;
/* set up the exception vectors */
vpage0 = (Vpage0*)HVECTORS;
memmove(vpage0->vectors, vectors, sizeof(vpage0->vectors));
memmove(vpage0->vtable, vtable, sizeof(vpage0->vtable));
cacheuwbinv();
l2cacheuwbinv();
/* set up the stacks for the interrupt modes */
setr13(PsrMfiq, m->sfiq);
setr13(PsrMirq, m->sirq);
setr13(PsrMabt, m->sabt);
setr13(PsrMund, m->sund);
#ifdef HIGH_SECURITY
setr13(PsrMmon, m->smon);
#endif
setr13(PsrMsys, m->ssys);
intcmaskall();
ip->control = 0;
ip->threshold = Prioritythreshold; /* disable threshold */
for (i = 0; i < Nirqs; i++)
ip->ilr[i] = 0<<2 | 0; /* all intrs pri 0 & to irq, not fiq */
irqtooearly = 0;
coherence();
}
++nesting;
for(v = vctl[irqno]; v != nil; v = v->next)
if (v->f) {
if (islo())
panic("trap: pl0 before trap handler for %s",
v->name);
v->f(ureg, v->a);
if (islo())
panic("trap: %s lowered pl", v->name);
// splhi(); /* in case v->f lowered pl */
handled++;
}
if(!handled) {
iprint("unexpected interrupt: irq %d", irqno);
switch (irqno) {
case 56:
case 57:
iprint(" (IC)");
break;
case 83:
case 86:
case 94:
iprint(" (MMC)");
break;
}
/*
* returns 1 if the instruction writes memory, 0 otherwise
*/
int
writetomem(ulong inst)
{
/* swap always write memory */
if((inst & 0x0FC00000) == 0x01000000)
return 1;
/* loads and stores are distinguished by bit 20 */
if(inst & (1<<20))
return 0;
return 1;
}
void prgpmcerrs(void);
/*
* here on all exceptions other than syscall (SWI)
*/
void
trap(Ureg *ureg)
{
int clockintr, user, x, rv, rem;
ulong inst, fsr;
uintptr va;
char buf[ERRMAX];
splhi(); /* paranoia */
if(up != nil)
rem = ((char*)ureg)-up->kstack;
else
rem = ((char*)ureg)-((char*)m+sizeof(Mach));
if(rem < 1024) {
iprint("trap: %d stack bytes left, up %#p ureg %#p at pc %#lux\n",
rem, up, ureg, ureg->pc);
delay(1000);
dumpstack();
panic("trap: %d stack bytes left, up %#p ureg %#p at pc %#lux",
rem, up, ureg, ureg->pc);
}
/*
* All interrupts/exceptions should be resumed at ureg->pc-4,
* except for Data Abort which resumes at ureg->pc-8.
*/
if(ureg->type == (PsrMabt+1))
ureg->pc -= 8;
else
ureg->pc -= 4;
clockintr = 0; /* if set, may call sched() before return */
switch(ureg->type){
default:
panic("unknown trap; type %#lux, psr mode %#lux", ureg->type,
ureg->psr & PsrMask);
break;
case PsrMirq:
ldrexvalid = 0;
clockintr = irq(ureg);
m->intr++;
break;
case PsrMabt: /* prefetch fault */
ldrexvalid = 0;
x = ifsrget();
fsr = (x>>7) & 0x8 | x & 0x7;
switch(fsr){
case 0x02: /* instruction debug event (BKPT) */
if(user){
snprint(buf, sizeof buf, "sys: breakpoint");
postnote(up, 1, buf, NDebug);
}else{
iprint("kernel bkpt: pc %#lux inst %#ux\n",
ureg->pc, *(u32int*)ureg->pc);
panic("kernel bkpt");
}
break;
default:
faultarm(ureg, ureg->pc, user, 1);
break;
}
break;
case PsrMabt+1: /* data fault */
ldrexvalid = 0;
va = farget();
inst = *(ulong*)(ureg->pc);
/* bits 12 and 10 have to be concatenated with status */
x = fsrget();
fsr = (x>>7) & 0x20 | (x>>6) & 0x10 | x & 0xf;
if (probing && !user) {
if (trapped++ > 0)
panic("trap: recursive probe %#lux", va);
ureg->pc += 4; /* continue at next instruction */
break;
}
switch(fsr){
default:
case 0xa: /* ? was under external abort */
panic("unknown data fault, 6b fsr %#lux", fsr);
break;
case 0x0:
panic("vector exception at %#lux", ureg->pc);
break;
case 0x1: /* alignment fault */
case 0x3: /* access flag fault (section) */
if(user){
snprint(buf, sizeof buf,
"sys: alignment: pc %#lux va %#p\n",
ureg->pc, va);
postnote(up, 1, buf, NDebug);
} else
panic("kernel alignment: pc %#lux va %#p", ureg->pc, va);
break;
case 0x2:
panic("terminal exception at %#lux", ureg->pc);
break;
case 0x4: /* icache maint fault */
case 0x6: /* access flag fault (page) */
case 0x8: /* precise external abort, non-xlat'n */
case 0x28:
case 0xc: /* l1 translation, precise ext. abort */
case 0x2c:
case 0xe: /* l2 translation, precise ext. abort */
case 0x2e:
case 0x16: /* imprecise ext. abort, non-xlt'n */
case 0x36:
panic("external abort %#lux pc %#lux addr %#p",
fsr, ureg->pc, va);
break;
case 0x1c: /* l1 translation, precise parity err */
case 0x1e: /* l2 translation, precise parity err */
case 0x18: /* imprecise parity or ecc err */
panic("translation parity error %#lux pc %#lux addr %#p",
fsr, ureg->pc, va);
break;
case 0x5: /* translation fault, no section entry */
case 0x7: /* translation fault, no page entry */
faultarm(ureg, va, user, !writetomem(inst));
break;
case 0x9:
case 0xb:
/* domain fault, accessing something we shouldn't */
if(user){
snprint(buf, sizeof buf,
"sys: access violation: pc %#lux va %#p\n",
ureg->pc, va);
postnote(up, 1, buf, NDebug);
} else
panic("kernel access violation: pc %#lux va %#p",
ureg->pc, va);
break;
case 0xd:
case 0xf:
/* permission error, copy on write or real permission error */
faultarm(ureg, va, user, !writetomem(inst));
break;
}
break;
case PsrMund: /* undefined instruction */
if(user){
if(seg(up, ureg->pc, 0) != nil &&
*(u32int*)ureg->pc == 0xD1200070){
snprint(buf, sizeof buf, "sys: breakpoint");
postnote(up, 1, buf, NDebug);
}else{
/* look for floating point instructions to interpret */
x = spllo();
rv = fpiarm(ureg);
splx(x);
if(rv == 0){
ldrexvalid = 0;
snprint(buf, sizeof buf,
"undefined instruction: pc %#lux\n",
ureg->pc);
postnote(up, 1, buf, NDebug);
}
}
}else{
if (ureg->pc & 3) {
iprint("rounding fault pc %#lux down to word\n",
ureg->pc);
ureg->pc &= ~3;
}
iprint("undefined instruction: pc %#lux inst %#ux\n",
ureg->pc, ((u32int*)ureg->pc)[-2]);
panic("undefined instruction");
}
break;
}
splhi();
/* delaysched set because we held a lock or because our quantum ended */
if(up && up->delaysched && clockintr){
ldrexvalid = 0;
sched(); /* can cause more traps */
splhi();
}
/*
* Fill in enough of Ureg to get a stack trace, and call a function.
* Used by debugging interface rdb.
*/
void
callwithureg(void (*fn)(Ureg*))
{
Ureg ureg;