770 lines
16 KiB
C
770 lines
16 KiB
C
|
/*
|
||
|
* omap3530 traps, exceptions, interrupts, system calls.
|
||
|
*/
|
||
|
#include "u.h"
|
||
|
#include "../port/lib.h"
|
||
|
#include "mem.h"
|
||
|
#include "dat.h"
|
||
|
#include "fns.h"
|
||
|
#include "../port/error.h"
|
||
|
|
||
|
#include "ureg.h"
|
||
|
#include "arm.h"
|
||
|
|
||
|
enum {
|
||
|
Nirqs = 96,
|
||
|
Nvec = 8, /* # of vectors at start of lexception.s */
|
||
|
Bi2long = BI2BY * sizeof(long),
|
||
|
};
|
||
|
|
||
|
extern int notify(Ureg*);
|
||
|
|
||
|
extern int ldrexvalid;
|
||
|
|
||
|
/* omap35x intc (aka mpu_intc) */
|
||
|
typedef struct Intrregs Intrregs;
|
||
|
struct Intrregs {
|
||
|
/*
|
||
|
* the manual inserts "INTCPS_" before each register name;
|
||
|
* we'll just assume the prefix.
|
||
|
*/
|
||
|
uchar _pad0[4*4];
|
||
|
ulong sysconfig;
|
||
|
ulong sysstatus; /* ro */
|
||
|
uchar _pad1[0x40 - 0x18];
|
||
|
ulong sir_irq; /* ro */
|
||
|
ulong sir_fiq; /* ro */
|
||
|
ulong control;
|
||
|
ulong protection;
|
||
|
ulong idle;
|
||
|
uchar _pad2[0x60 - 0x54];
|
||
|
ulong irq_priority;
|
||
|
ulong fiq_priority;
|
||
|
ulong threshold;
|
||
|
uchar _pad3[0x80 - 0x6c];
|
||
|
struct Bits { /* bitmaps */
|
||
|
ulong itr; /* ro: pending intrs (no mask) */
|
||
|
ulong mir; /* interrupt mask: 1 means masked */
|
||
|
ulong mir_clear; /* wo: 1 sets the bit */
|
||
|
ulong mir_set; /* wo: 1 clears the bit */
|
||
|
ulong isr_set; /* software interrupts */
|
||
|
ulong isr_clear; /* wo */
|
||
|
ulong pending_irq; /* ro */
|
||
|
ulong pending_fiq; /* ro */
|
||
|
} bits[3]; /* 3*32 = 96 (Nirqs) */
|
||
|
ulong ilr[Nirqs];
|
||
|
};
|
||
|
|
||
|
enum {
|
||
|
/* sysconfig bits */
|
||
|
Softreset = 1<<1,
|
||
|
|
||
|
/* sysstatus bits */
|
||
|
Resetdone = 1<<0,
|
||
|
|
||
|
/* sir_irq/fiq bits */
|
||
|
Activeirq = MASK(7),
|
||
|
|
||
|
/* control bits */
|
||
|
Newirqagr = 1<<0,
|
||
|
|
||
|
/* protection bits */
|
||
|
Protection = 1<<0,
|
||
|
|
||
|
/* irq/fiq_priority bits */
|
||
|
Irqpriority = MASK(6),
|
||
|
|
||
|
/* threshold bits */
|
||
|
Prioritythreshold = MASK(8),
|
||
|
|
||
|
/* ilr bits */
|
||
|
Priority = MASK(8) - MASK(2),
|
||
|
};
|
||
|
|
||
|
typedef struct Vctl Vctl;
|
||
|
typedef struct Vctl {
|
||
|
Vctl* next; /* handlers on this vector */
|
||
|
char *name; /* of driver, xallocated */
|
||
|
void (*f)(Ureg*, void*); /* handler to call */
|
||
|
void* a; /* argument to call it with */
|
||
|
} Vctl;
|
||
|
|
||
|
static Lock vctllock;
|
||
|
static Vctl* vctl[Nirqs];
|
||
|
|
||
|
/*
|
||
|
* Layout at virtual address 0.
|
||
|
*/
|
||
|
typedef struct Vpage0 {
|
||
|
void (*vectors[Nvec])(void);
|
||
|
u32int vtable[Nvec];
|
||
|
} Vpage0;
|
||
|
static Vpage0 *vpage0;
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
intcmask(uint irq)
|
||
|
{
|
||
|
Intrregs *ip = (Intrregs *)PHYSINTC;
|
||
|
|
||
|
ip->bits[irq / Bi2long].mir_set = 1 << (irq % Bi2long);
|
||
|
coherence();
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
intcunmask(uint irq)
|
||
|
{
|
||
|
Intrregs *ip = (Intrregs *)PHYSINTC;
|
||
|
|
||
|
ip->bits[irq / Bi2long].mir_clear = 1 << (irq % Bi2long);
|
||
|
coherence();
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
intcmaskall(void)
|
||
|
{
|
||
|
int i;
|
||
|
Intrregs *ip = (Intrregs *)PHYSINTC;
|
||
|
|
||
|
for (i = 0; i < 3; i++)
|
||
|
ip->bits[i].mir_set = ~0;
|
||
|
coherence();
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
intcunmaskall(void)
|
||
|
{
|
||
|
int i;
|
||
|
Intrregs *ip = (Intrregs *)PHYSINTC;
|
||
|
|
||
|
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);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
intrsave(ulong buf[3])
|
||
|
{
|
||
|
int i;
|
||
|
Intrregs *ip = (Intrregs *)PHYSINTC;
|
||
|
|
||
|
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();
|
||
|
}
|
||
|
|
||
|
void
|
||
|
intrsoff(void)
|
||
|
{
|
||
|
Intrregs *ip = (Intrregs *)PHYSINTC;
|
||
|
|
||
|
intcmaskall();
|
||
|
ip->control = Newirqagr; /* dismiss interrupt */
|
||
|
coherence();
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* enable an irq interrupt
|
||
|
*/
|
||
|
int
|
||
|
irqenable(int irq, void (*f)(Ureg*, void*), void* a, char *name)
|
||
|
{
|
||
|
Vctl *v;
|
||
|
|
||
|
if(irq >= nelem(vctl) || irq < 0)
|
||
|
panic("irqenable irq %d", irq);
|
||
|
|
||
|
if (irqtooearly) {
|
||
|
iprint("irqenable for %d %s called too early\n", irq, name);
|
||
|
return -1;
|
||
|
}
|
||
|
if(irqinuse(irq))
|
||
|
print("irqenable: %s: irq %d already in use, chaining\n",
|
||
|
name, irq);
|
||
|
v = malloc(sizeof(Vctl));
|
||
|
if (v == nil)
|
||
|
panic("irqenable: malloc Vctl");
|
||
|
v->f = f;
|
||
|
v->a = a;
|
||
|
v->name = malloc(strlen(name)+1);
|
||
|
if (v->name == nil)
|
||
|
panic("irqenable: malloc name");
|
||
|
strcpy(v->name, name);
|
||
|
|
||
|
lock(&vctllock);
|
||
|
v->next = vctl[irq];
|
||
|
vctl[irq] = v;
|
||
|
|
||
|
intcunmask(irq);
|
||
|
unlock(&vctllock);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* disable an irq interrupt
|
||
|
*/
|
||
|
int
|
||
|
irqdisable(int irq, void (*f)(Ureg*, void*), void* a, char *name)
|
||
|
{
|
||
|
Vctl **vp, *v;
|
||
|
|
||
|
if(irq >= nelem(vctl) || irq < 0)
|
||
|
panic("irqdisable irq %d", irq);
|
||
|
|
||
|
lock(&vctllock);
|
||
|
for(vp = &vctl[irq]; v = *vp; vp = &v->next)
|
||
|
if (v->f == f && v->a == a && strcmp(v->name, name) == 0){
|
||
|
print("irqdisable: remove %s\n", name);
|
||
|
*vp = v->next;
|
||
|
free(v);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if(v == nil)
|
||
|
print("irqdisable: irq %d, name %s not enabled\n", irq, name);
|
||
|
if(vctl[irq] == nil){
|
||
|
print("irqdisable: clear icmr bit %d\n", irq);
|
||
|
intcmask(irq);
|
||
|
}
|
||
|
unlock(&vctllock);
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* called by trap to handle access faults
|
||
|
*/
|
||
|
static void
|
||
|
faultarm(Ureg *ureg, uintptr va, int user, int read)
|
||
|
{
|
||
|
int n, insyscall;
|
||
|
char buf[ERRMAX];
|
||
|
|
||
|
if(up == nil) {
|
||
|
dumpregs(ureg);
|
||
|
panic("fault: nil up in faultarm, accessing %#p", va);
|
||
|
}
|
||
|
insyscall = up->insyscall;
|
||
|
up->insyscall = 1;
|
||
|
n = fault(va, read);
|
||
|
if(n < 0){
|
||
|
if(!user){
|
||
|
dumpregs(ureg);
|
||
|
panic("fault: kernel accessing %#p", va);
|
||
|
}
|
||
|
/* don't dump registers; programs suicide all the time */
|
||
|
snprint(buf, sizeof buf, "sys: trap: fault %s va=%#p",
|
||
|
read? "read": "write", va);
|
||
|
postnote(up, 1, buf, NDebug);
|
||
|
}
|
||
|
up->insyscall = insyscall;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* called by trap to handle interrupts.
|
||
|
* returns true iff a clock interrupt, thus maybe reschedule.
|
||
|
*/
|
||
|
static int
|
||
|
irq(Ureg* ureg)
|
||
|
{
|
||
|
int clockintr;
|
||
|
uint irqno, handled, t, ticks = perfticks();
|
||
|
Intrregs *ip = (Intrregs *)PHYSINTC;
|
||
|
Vctl *v;
|
||
|
static int nesting, lastirq = -1;
|
||
|
|
||
|
handled = 0;
|
||
|
irqno = ip->sir_irq & Activeirq;
|
||
|
|
||
|
if (irqno >= 37 && irqno <= 47) /* this is a clock intr? */
|
||
|
m->inclockintr++; /* yes, count nesting */
|
||
|
lastirq = irqno;
|
||
|
|
||
|
if (irqno >= nelem(vctl)) {
|
||
|
iprint("trap: irq %d >= # vectors (%d)\n", irqno, nelem(vctl));
|
||
|
ip->control = Newirqagr; /* dismiss interrupt */
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
++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;
|
||
|
}
|
||
|
|
||
|
if(irqno < nelem(vctl)) {
|
||
|
intcmask(irqno);
|
||
|
iprint(", now masked");
|
||
|
}
|
||
|
iprint("\n");
|
||
|
}
|
||
|
t = perfticks();
|
||
|
ninterrupt++;
|
||
|
if(t < ticks)
|
||
|
ninterruptticks += ticks-t;
|
||
|
else
|
||
|
ninterruptticks += t-ticks;
|
||
|
ip->control = Newirqagr; /* dismiss interrupt */
|
||
|
coherence();
|
||
|
|
||
|
--nesting;
|
||
|
clockintr = m->inclockintr == 1;
|
||
|
if (irqno >= 37 && irqno <= 47)
|
||
|
m->inclockintr--;
|
||
|
return clockintr;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* 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);
|
||
|
}
|
||
|
|
||
|
user = (ureg->psr & PsrMask) == PsrMusr;
|
||
|
if(user){
|
||
|
up->dbgreg = ureg;
|
||
|
cycles(&up->kentry);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* 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;
|
||
|
faultarm(ureg, ureg->pc, user, 1);
|
||
|
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){
|
||
|
/* 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();
|
||
|
}
|
||
|
|
||
|
if(user){
|
||
|
if(up->procctl || up->nnote)
|
||
|
notify(ureg);
|
||
|
kexit(ureg);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* 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;
|
||
|
|
||
|
ureg.pc = getcallerpc(&fn);
|
||
|
ureg.sp = PTR2UINT(&fn);
|
||
|
fn(&ureg);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
dumpstackwithureg(Ureg *ureg)
|
||
|
{
|
||
|
int x;
|
||
|
uintptr l, v, i, estack;
|
||
|
char *s;
|
||
|
|
||
|
dumpregs(ureg);
|
||
|
if((s = getconf("*nodumpstack")) != nil && strcmp(s, "0") != 0){
|
||
|
iprint("dumpstack disabled\n");
|
||
|
return;
|
||
|
}
|
||
|
iprint("dumpstack\n");
|
||
|
|
||
|
x = 0;
|
||
|
x += iprint("ktrace /kernel/path %#.8lux %#.8lux %#.8lux # pc, sp, link\n",
|
||
|
ureg->pc, ureg->sp, ureg->r14);
|
||
|
delay(20);
|
||
|
i = 0;
|
||
|
if(up
|
||
|
&& (uintptr)&l >= (uintptr)up->kstack
|
||
|
&& (uintptr)&l <= (uintptr)up->kstack+KSTACK)
|
||
|
estack = (uintptr)up->kstack+KSTACK;
|
||
|
else if((uintptr)&l >= (uintptr)m->stack
|
||
|
&& (uintptr)&l <= (uintptr)m+MACHSIZE)
|
||
|
estack = (uintptr)m+MACHSIZE;
|
||
|
else
|
||
|
return;
|
||
|
x += iprint("estackx %p\n", estack);
|
||
|
|
||
|
for(l = (uintptr)&l; l < estack; l += sizeof(uintptr)){
|
||
|
v = *(uintptr*)l;
|
||
|
if((KTZERO < v && v < (uintptr)etext) || estack-l < 32){
|
||
|
x += iprint("%.8p ", v);
|
||
|
delay(20);
|
||
|
i++;
|
||
|
}
|
||
|
if(i == 8){
|
||
|
i = 0;
|
||
|
x += iprint("\n");
|
||
|
delay(20);
|
||
|
}
|
||
|
}
|
||
|
if(i)
|
||
|
iprint("\n");
|
||
|
}
|
||
|
|
||
|
void
|
||
|
dumpstack(void)
|
||
|
{
|
||
|
callwithureg(dumpstackwithureg);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* dump system control coprocessor registers
|
||
|
*/
|
||
|
static void
|
||
|
dumpscr(void)
|
||
|
{
|
||
|
iprint("0:\t%#8.8ux id\n", cpidget());
|
||
|
iprint("\t%8.8#ux ct\n", cpctget());
|
||
|
iprint("1:\t%#8.8ux control\n", controlget());
|
||
|
iprint("2:\t%#8.8ux ttb\n", ttbget());
|
||
|
iprint("3:\t%#8.8ux dac\n", dacget());
|
||
|
iprint("4:\t(reserved)\n");
|
||
|
iprint("5:\t%#8.8ux fsr\n", fsrget());
|
||
|
iprint("6:\t%#8.8ux far\n", farget());
|
||
|
iprint("7:\twrite-only cache\n");
|
||
|
iprint("8:\twrite-only tlb\n");
|
||
|
iprint("13:\t%#8.8ux pid\n", pidget());
|
||
|
delay(10);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* dump general registers
|
||
|
*/
|
||
|
static void
|
||
|
dumpgpr(Ureg* ureg)
|
||
|
{
|
||
|
if(up != nil)
|
||
|
iprint("cpu%d: registers for %s %lud\n",
|
||
|
m->machno, up->text, up->pid);
|
||
|
else
|
||
|
iprint("cpu%d: registers for kernel\n", m->machno);
|
||
|
|
||
|
delay(20);
|
||
|
iprint("%#8.8lux\tr0\n", ureg->r0);
|
||
|
iprint("%#8.8lux\tr1\n", ureg->r1);
|
||
|
iprint("%#8.8lux\tr2\n", ureg->r2);
|
||
|
delay(20);
|
||
|
iprint("%#8.8lux\tr3\n", ureg->r3);
|
||
|
iprint("%#8.8lux\tr4\n", ureg->r4);
|
||
|
iprint("%#8.8lux\tr5\n", ureg->r5);
|
||
|
delay(20);
|
||
|
iprint("%#8.8lux\tr6\n", ureg->r6);
|
||
|
iprint("%#8.8lux\tr7\n", ureg->r7);
|
||
|
iprint("%#8.8lux\tr8\n", ureg->r8);
|
||
|
delay(20);
|
||
|
iprint("%#8.8lux\tr9 (up)\n", ureg->r9);
|
||
|
iprint("%#8.8lux\tr10 (m)\n", ureg->r10);
|
||
|
iprint("%#8.8lux\tr11 (loader temporary)\n", ureg->r11);
|
||
|
iprint("%#8.8lux\tr12 (SB)\n", ureg->r12);
|
||
|
delay(20);
|
||
|
iprint("%#8.8lux\tr13 (sp)\n", ureg->r13);
|
||
|
iprint("%#8.8lux\tr14 (link)\n", ureg->r14);
|
||
|
iprint("%#8.8lux\tr15 (pc)\n", ureg->pc);
|
||
|
delay(20);
|
||
|
iprint("%10.10lud\ttype\n", ureg->type);
|
||
|
iprint("%#8.8lux\tpsr\n", ureg->psr);
|
||
|
delay(20);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
dumpregs(Ureg* ureg)
|
||
|
{
|
||
|
dumpgpr(ureg);
|
||
|
dumpscr();
|
||
|
}
|
||
|
|
||
|
vlong
|
||
|
probeaddr(uintptr addr)
|
||
|
{
|
||
|
vlong v;
|
||
|
static Lock fltlck;
|
||
|
|
||
|
ilock(&fltlck);
|
||
|
trapped = 0;
|
||
|
probing = 1;
|
||
|
coherence();
|
||
|
|
||
|
v = *(ulong *)addr; /* this may cause a fault */
|
||
|
USED(probing);
|
||
|
coherence();
|
||
|
|
||
|
probing = 0;
|
||
|
coherence();
|
||
|
if (trapped)
|
||
|
v = -1;
|
||
|
iunlock(&fltlck);
|
||
|
return v;
|
||
|
}
|