15d9de2d3SDavid du Colombier /*
25d9de2d3SDavid du Colombier * traps, exceptions, interrupts, system calls.
35d9de2d3SDavid du Colombier */
45d9de2d3SDavid du Colombier #include "u.h"
55d9de2d3SDavid du Colombier #include "../port/lib.h"
65d9de2d3SDavid du Colombier #include "mem.h"
75d9de2d3SDavid du Colombier #include "dat.h"
85d9de2d3SDavid du Colombier #include "fns.h"
95d9de2d3SDavid du Colombier #include "io.h"
105d9de2d3SDavid du Colombier #include "ureg.h"
115d9de2d3SDavid du Colombier #include "../port/error.h"
125d9de2d3SDavid du Colombier
135d9de2d3SDavid du Colombier #include "arm.h"
145d9de2d3SDavid du Colombier
155d9de2d3SDavid du Colombier #define INTREGS (VIRTIO+0xB200)
165d9de2d3SDavid du Colombier
175d9de2d3SDavid du Colombier typedef struct Intregs Intregs;
185d9de2d3SDavid du Colombier typedef struct Vctl Vctl;
195d9de2d3SDavid du Colombier
205d9de2d3SDavid du Colombier enum {
21*8153b942SDavid du Colombier Debug = 0,
22*8153b942SDavid du Colombier
235d9de2d3SDavid du Colombier Nvec = 8, /* # of vectors at start of lexception.s */
245d9de2d3SDavid du Colombier Fiqenable = 1<<7,
255d9de2d3SDavid du Colombier };
265d9de2d3SDavid du Colombier
275d9de2d3SDavid du Colombier /*
285d9de2d3SDavid du Colombier * Layout at virtual address KZERO (double mapped at HVECTORS).
295d9de2d3SDavid du Colombier */
305d9de2d3SDavid du Colombier typedef struct Vpage0 {
315d9de2d3SDavid du Colombier void (*vectors[Nvec])(void);
325d9de2d3SDavid du Colombier u32int vtable[Nvec];
335d9de2d3SDavid du Colombier } Vpage0;
345d9de2d3SDavid du Colombier
355d9de2d3SDavid du Colombier /*
365d9de2d3SDavid du Colombier * interrupt control registers
375d9de2d3SDavid du Colombier */
385d9de2d3SDavid du Colombier struct Intregs {
395d9de2d3SDavid du Colombier u32int ARMpending;
405d9de2d3SDavid du Colombier u32int GPUpending[2];
415d9de2d3SDavid du Colombier u32int FIQctl;
425d9de2d3SDavid du Colombier u32int GPUenable[2];
435d9de2d3SDavid du Colombier u32int ARMenable;
445d9de2d3SDavid du Colombier u32int GPUdisable[2];
455d9de2d3SDavid du Colombier u32int ARMdisable;
465d9de2d3SDavid du Colombier };
475d9de2d3SDavid du Colombier
485d9de2d3SDavid du Colombier struct Vctl {
495d9de2d3SDavid du Colombier Vctl *next;
505d9de2d3SDavid du Colombier int irq;
515d9de2d3SDavid du Colombier u32int *reg;
525d9de2d3SDavid du Colombier u32int mask;
535d9de2d3SDavid du Colombier void (*f)(Ureg*, void*);
545d9de2d3SDavid du Colombier void *a;
555d9de2d3SDavid du Colombier };
565d9de2d3SDavid du Colombier
575d9de2d3SDavid du Colombier static Vctl *vctl, *vfiq;
585d9de2d3SDavid du Colombier
595d9de2d3SDavid du Colombier static char *trapnames[PsrMask+1] = {
605d9de2d3SDavid du Colombier [ PsrMusr ] "user mode",
615d9de2d3SDavid du Colombier [ PsrMfiq ] "fiq interrupt",
625d9de2d3SDavid du Colombier [ PsrMirq ] "irq interrupt",
635d9de2d3SDavid du Colombier [ PsrMsvc ] "svc/swi exception",
645d9de2d3SDavid du Colombier [ PsrMabt ] "prefetch abort/data abort",
655d9de2d3SDavid du Colombier [ PsrMabt+1 ] "data abort",
665d9de2d3SDavid du Colombier [ PsrMund ] "undefined instruction",
675d9de2d3SDavid du Colombier [ PsrMsys ] "sys trap",
685d9de2d3SDavid du Colombier };
695d9de2d3SDavid du Colombier
705d9de2d3SDavid du Colombier extern int notify(Ureg*);
715d9de2d3SDavid du Colombier
725d9de2d3SDavid du Colombier /*
735d9de2d3SDavid du Colombier * set up for exceptions
745d9de2d3SDavid du Colombier */
755d9de2d3SDavid du Colombier void
trapinit(void)765d9de2d3SDavid du Colombier trapinit(void)
775d9de2d3SDavid du Colombier {
785d9de2d3SDavid du Colombier Vpage0 *vpage0;
795d9de2d3SDavid du Colombier
805d9de2d3SDavid du Colombier /* disable everything */
815d9de2d3SDavid du Colombier intrsoff();
825d9de2d3SDavid du Colombier
835d9de2d3SDavid du Colombier /* set up the exception vectors */
845d9de2d3SDavid du Colombier vpage0 = (Vpage0*)HVECTORS;
855d9de2d3SDavid du Colombier memmove(vpage0->vectors, vectors, sizeof(vpage0->vectors));
865d9de2d3SDavid du Colombier memmove(vpage0->vtable, vtable, sizeof(vpage0->vtable));
875d9de2d3SDavid du Colombier cacheuwbinv();
885d9de2d3SDavid du Colombier
895d9de2d3SDavid du Colombier /* set up the stacks for the interrupt modes */
905d9de2d3SDavid du Colombier setr13(PsrMfiq, (u32int*)(FIQSTKTOP));
915d9de2d3SDavid du Colombier setr13(PsrMirq, m->sirq);
925d9de2d3SDavid du Colombier setr13(PsrMabt, m->sabt);
935d9de2d3SDavid du Colombier setr13(PsrMund, m->sund);
945d9de2d3SDavid du Colombier setr13(PsrMsys, m->ssys);
955d9de2d3SDavid du Colombier
965d9de2d3SDavid du Colombier coherence();
975d9de2d3SDavid du Colombier }
985d9de2d3SDavid du Colombier
995d9de2d3SDavid du Colombier void
intrsoff(void)1005d9de2d3SDavid du Colombier intrsoff(void)
1015d9de2d3SDavid du Colombier {
1025d9de2d3SDavid du Colombier Intregs *ip;
1035d9de2d3SDavid du Colombier int disable;
1045d9de2d3SDavid du Colombier
1055d9de2d3SDavid du Colombier ip = (Intregs*)INTREGS;
1065d9de2d3SDavid du Colombier disable = ~0;
1075d9de2d3SDavid du Colombier ip->GPUdisable[0] = disable;
1085d9de2d3SDavid du Colombier ip->GPUdisable[1] = disable;
1095d9de2d3SDavid du Colombier ip->ARMdisable = disable;
1105d9de2d3SDavid du Colombier ip->FIQctl = 0;
1115d9de2d3SDavid du Colombier }
1125d9de2d3SDavid du Colombier
1135d9de2d3SDavid du Colombier /*
1145d9de2d3SDavid du Colombier * called by trap to handle irq interrupts.
1155d9de2d3SDavid du Colombier * returns true iff a clock interrupt, thus maybe reschedule.
1165d9de2d3SDavid du Colombier */
1175d9de2d3SDavid du Colombier static int
irq(Ureg * ureg)1185d9de2d3SDavid du Colombier irq(Ureg* ureg)
1195d9de2d3SDavid du Colombier {
1205d9de2d3SDavid du Colombier Vctl *v;
1215d9de2d3SDavid du Colombier int clockintr;
1225d9de2d3SDavid du Colombier
1235d9de2d3SDavid du Colombier clockintr = 0;
1245d9de2d3SDavid du Colombier for(v = vctl; v; v = v->next)
1255d9de2d3SDavid du Colombier if(*v->reg & v->mask){
1265d9de2d3SDavid du Colombier coherence();
1275d9de2d3SDavid du Colombier v->f(ureg, v->a);
1285d9de2d3SDavid du Colombier coherence();
1295d9de2d3SDavid du Colombier if(v->irq == IRQclock)
1305d9de2d3SDavid du Colombier clockintr = 1;
1315d9de2d3SDavid du Colombier }
1325d9de2d3SDavid du Colombier return clockintr;
1335d9de2d3SDavid du Colombier }
1345d9de2d3SDavid du Colombier
1355d9de2d3SDavid du Colombier /*
1365d9de2d3SDavid du Colombier * called direct from lexception.s to handle fiq interrupt.
1375d9de2d3SDavid du Colombier */
1385d9de2d3SDavid du Colombier void
fiq(Ureg * ureg)1395d9de2d3SDavid du Colombier fiq(Ureg *ureg)
1405d9de2d3SDavid du Colombier {
1415d9de2d3SDavid du Colombier Vctl *v;
1425d9de2d3SDavid du Colombier
1435d9de2d3SDavid du Colombier v = vfiq;
1445d9de2d3SDavid du Colombier if(v == nil)
1455d9de2d3SDavid du Colombier panic("unexpected item in bagging area");
1465d9de2d3SDavid du Colombier m->intr++;
1475d9de2d3SDavid du Colombier ureg->pc -= 4;
1485d9de2d3SDavid du Colombier coherence();
1495d9de2d3SDavid du Colombier v->f(ureg, v->a);
1505d9de2d3SDavid du Colombier coherence();
1515d9de2d3SDavid du Colombier }
1525d9de2d3SDavid du Colombier
1535d9de2d3SDavid du Colombier void
irqenable(int irq,void (* f)(Ureg *,void *),void * a)1545d9de2d3SDavid du Colombier irqenable(int irq, void (*f)(Ureg*, void*), void* a)
1555d9de2d3SDavid du Colombier {
1565d9de2d3SDavid du Colombier Vctl *v;
1575d9de2d3SDavid du Colombier Intregs *ip;
1585d9de2d3SDavid du Colombier u32int *enable;
1595d9de2d3SDavid du Colombier
1605d9de2d3SDavid du Colombier ip = (Intregs*)INTREGS;
1615d9de2d3SDavid du Colombier v = (Vctl*)malloc(sizeof(Vctl));
1625d9de2d3SDavid du Colombier if(v == nil)
1635d9de2d3SDavid du Colombier panic("irqenable: no mem");
1645d9de2d3SDavid du Colombier v->irq = irq;
1655d9de2d3SDavid du Colombier if(irq >= IRQbasic){
1665d9de2d3SDavid du Colombier enable = &ip->ARMenable;
1675d9de2d3SDavid du Colombier v->reg = &ip->ARMpending;
1685d9de2d3SDavid du Colombier v->mask = 1 << (irq - IRQbasic);
1695d9de2d3SDavid du Colombier }else{
1705d9de2d3SDavid du Colombier enable = &ip->GPUenable[irq/32];
1715d9de2d3SDavid du Colombier v->reg = &ip->GPUpending[irq/32];
1725d9de2d3SDavid du Colombier v->mask = 1 << (irq % 32);
1735d9de2d3SDavid du Colombier }
1745d9de2d3SDavid du Colombier v->f = f;
1755d9de2d3SDavid du Colombier v->a = a;
1765d9de2d3SDavid du Colombier if(irq == IRQfiq){
1775d9de2d3SDavid du Colombier assert((ip->FIQctl & Fiqenable) == 0);
1785d9de2d3SDavid du Colombier assert((*enable & v->mask) == 0);
1795d9de2d3SDavid du Colombier vfiq = v;
1805d9de2d3SDavid du Colombier ip->FIQctl = Fiqenable | irq;
1815d9de2d3SDavid du Colombier }else{
1825d9de2d3SDavid du Colombier v->next = vctl;
1835d9de2d3SDavid du Colombier vctl = v;
1845d9de2d3SDavid du Colombier *enable = v->mask;
1855d9de2d3SDavid du Colombier }
1865d9de2d3SDavid du Colombier }
1875d9de2d3SDavid du Colombier
1885d9de2d3SDavid du Colombier static char *
trapname(int psr)1895d9de2d3SDavid du Colombier trapname(int psr)
1905d9de2d3SDavid du Colombier {
1915d9de2d3SDavid du Colombier char *s;
1925d9de2d3SDavid du Colombier
1935d9de2d3SDavid du Colombier s = trapnames[psr & PsrMask];
1945d9de2d3SDavid du Colombier if(s == nil)
1955d9de2d3SDavid du Colombier s = "unknown trap number in psr";
1965d9de2d3SDavid du Colombier return s;
1975d9de2d3SDavid du Colombier }
1985d9de2d3SDavid du Colombier
199*8153b942SDavid du Colombier /* this is quite helpful during mmu and cache debugging */
200*8153b942SDavid du Colombier static void
ckfaultstuck(uintptr va)201*8153b942SDavid du Colombier ckfaultstuck(uintptr va)
202*8153b942SDavid du Colombier {
203*8153b942SDavid du Colombier static int cnt, lastpid;
204*8153b942SDavid du Colombier static uintptr lastva;
205*8153b942SDavid du Colombier
206*8153b942SDavid du Colombier if (va == lastva && up->pid == lastpid) {
207*8153b942SDavid du Colombier ++cnt;
208*8153b942SDavid du Colombier if (cnt >= 2)
209*8153b942SDavid du Colombier /* fault() isn't fixing the underlying cause */
210*8153b942SDavid du Colombier panic("fault: %d consecutive faults for va %#p",
211*8153b942SDavid du Colombier cnt+1, va);
212*8153b942SDavid du Colombier } else {
213*8153b942SDavid du Colombier cnt = 0;
214*8153b942SDavid du Colombier lastva = va;
215*8153b942SDavid du Colombier lastpid = up->pid;
216*8153b942SDavid du Colombier }
217*8153b942SDavid du Colombier }
218*8153b942SDavid du Colombier
2195d9de2d3SDavid du Colombier /*
2205d9de2d3SDavid du Colombier * called by trap to handle access faults
2215d9de2d3SDavid du Colombier */
2225d9de2d3SDavid du Colombier static void
faultarm(Ureg * ureg,uintptr va,int user,int read)2235d9de2d3SDavid du Colombier faultarm(Ureg *ureg, uintptr va, int user, int read)
2245d9de2d3SDavid du Colombier {
2255d9de2d3SDavid du Colombier int n, insyscall;
2265d9de2d3SDavid du Colombier char buf[ERRMAX];
2275d9de2d3SDavid du Colombier
2285d9de2d3SDavid du Colombier if(up == nil) {
2295d9de2d3SDavid du Colombier dumpregs(ureg);
2305d9de2d3SDavid du Colombier panic("fault: nil up in faultarm, accessing %#p", va);
2315d9de2d3SDavid du Colombier }
2325d9de2d3SDavid du Colombier insyscall = up->insyscall;
2335d9de2d3SDavid du Colombier up->insyscall = 1;
234*8153b942SDavid du Colombier if (Debug)
235*8153b942SDavid du Colombier ckfaultstuck(va);
2365d9de2d3SDavid du Colombier
2375d9de2d3SDavid du Colombier n = fault(va, read);
2385d9de2d3SDavid du Colombier if(n < 0){
2395d9de2d3SDavid du Colombier if(!user){
2405d9de2d3SDavid du Colombier dumpregs(ureg);
2415d9de2d3SDavid du Colombier panic("fault: kernel accessing %#p", va);
2425d9de2d3SDavid du Colombier }
2435d9de2d3SDavid du Colombier /* don't dump registers; programs suicide all the time */
2445d9de2d3SDavid du Colombier snprint(buf, sizeof buf, "sys: trap: fault %s va=%#p",
2455d9de2d3SDavid du Colombier read? "read": "write", va);
2465d9de2d3SDavid du Colombier postnote(up, 1, buf, NDebug);
2475d9de2d3SDavid du Colombier }
2485d9de2d3SDavid du Colombier up->insyscall = insyscall;
2495d9de2d3SDavid du Colombier }
2505d9de2d3SDavid du Colombier
2515d9de2d3SDavid du Colombier /*
2525d9de2d3SDavid du Colombier * returns 1 if the instruction writes memory, 0 otherwise
2535d9de2d3SDavid du Colombier */
2545d9de2d3SDavid du Colombier int
writetomem(ulong inst)2555d9de2d3SDavid du Colombier writetomem(ulong inst)
2565d9de2d3SDavid du Colombier {
2575d9de2d3SDavid du Colombier /* swap always write memory */
2585d9de2d3SDavid du Colombier if((inst & 0x0FC00000) == 0x01000000)
2595d9de2d3SDavid du Colombier return 1;
2605d9de2d3SDavid du Colombier
2615d9de2d3SDavid du Colombier /* loads and stores are distinguished by bit 20 */
2625d9de2d3SDavid du Colombier if(inst & (1<<20))
2635d9de2d3SDavid du Colombier return 0;
2645d9de2d3SDavid du Colombier
2655d9de2d3SDavid du Colombier return 1;
2665d9de2d3SDavid du Colombier }
2675d9de2d3SDavid du Colombier
2685d9de2d3SDavid du Colombier /*
2695d9de2d3SDavid du Colombier * here on all exceptions other than syscall (SWI) and fiq
2705d9de2d3SDavid du Colombier */
2715d9de2d3SDavid du Colombier void
trap(Ureg * ureg)2725d9de2d3SDavid du Colombier trap(Ureg *ureg)
2735d9de2d3SDavid du Colombier {
2745d9de2d3SDavid du Colombier int clockintr, user, x, rv, rem;
2755d9de2d3SDavid du Colombier ulong inst, fsr;
2765d9de2d3SDavid du Colombier uintptr va;
2775d9de2d3SDavid du Colombier char buf[ERRMAX];
2785d9de2d3SDavid du Colombier
2795d9de2d3SDavid du Colombier assert(!islo());
2805d9de2d3SDavid du Colombier if(up != nil)
2815d9de2d3SDavid du Colombier rem = ((char*)ureg)-up->kstack;
2825d9de2d3SDavid du Colombier else
2835d9de2d3SDavid du Colombier rem = ((char*)ureg)-((char*)m+sizeof(Mach));
2845d9de2d3SDavid du Colombier if(rem < 256) {
2855d9de2d3SDavid du Colombier iprint("trap: %d stack bytes left, up %#p ureg %#p at pc %#lux\n",
2865d9de2d3SDavid du Colombier rem, up, ureg, ureg->pc);
2875d9de2d3SDavid du Colombier delay(1000);
2885d9de2d3SDavid du Colombier dumpstack();
2895d9de2d3SDavid du Colombier panic("trap: %d stack bytes left, up %#p ureg %#p at pc %#lux",
2905d9de2d3SDavid du Colombier rem, up, ureg, ureg->pc);
2915d9de2d3SDavid du Colombier }
2925d9de2d3SDavid du Colombier
2935d9de2d3SDavid du Colombier user = (ureg->psr & PsrMask) == PsrMusr;
2945d9de2d3SDavid du Colombier if(user){
2955d9de2d3SDavid du Colombier up->dbgreg = ureg;
2965d9de2d3SDavid du Colombier cycles(&up->kentry);
2975d9de2d3SDavid du Colombier }
2985d9de2d3SDavid du Colombier
2995d9de2d3SDavid du Colombier /*
3005d9de2d3SDavid du Colombier * All interrupts/exceptions should be resumed at ureg->pc-4,
3015d9de2d3SDavid du Colombier * except for Data Abort which resumes at ureg->pc-8.
3025d9de2d3SDavid du Colombier */
3035d9de2d3SDavid du Colombier if(ureg->type == (PsrMabt+1))
3045d9de2d3SDavid du Colombier ureg->pc -= 8;
3055d9de2d3SDavid du Colombier else
3065d9de2d3SDavid du Colombier ureg->pc -= 4;
3075d9de2d3SDavid du Colombier
3085d9de2d3SDavid du Colombier clockintr = 0; /* if set, may call sched() before return */
3095d9de2d3SDavid du Colombier switch(ureg->type){
3105d9de2d3SDavid du Colombier default:
3115d9de2d3SDavid du Colombier panic("unknown trap; type %#lux, psr mode %#lux", ureg->type,
3125d9de2d3SDavid du Colombier ureg->psr & PsrMask);
3135d9de2d3SDavid du Colombier break;
3145d9de2d3SDavid du Colombier case PsrMirq:
3155d9de2d3SDavid du Colombier clockintr = irq(ureg);
3165d9de2d3SDavid du Colombier m->intr++;
3175d9de2d3SDavid du Colombier break;
3185d9de2d3SDavid du Colombier case PsrMabt: /* prefetch fault */
3195d9de2d3SDavid du Colombier x = ifsrget();
3205d9de2d3SDavid du Colombier fsr = (x>>7) & 0x8 | x & 0x7;
3215d9de2d3SDavid du Colombier switch(fsr){
3225d9de2d3SDavid du Colombier case 0x02: /* instruction debug event (BKPT) */
3235d9de2d3SDavid du Colombier if(user){
3245d9de2d3SDavid du Colombier snprint(buf, sizeof buf, "sys: breakpoint");
3255d9de2d3SDavid du Colombier postnote(up, 1, buf, NDebug);
3265d9de2d3SDavid du Colombier }else{
3275d9de2d3SDavid du Colombier iprint("kernel bkpt: pc %#lux inst %#ux\n",
3285d9de2d3SDavid du Colombier ureg->pc, *(u32int*)ureg->pc);
3295d9de2d3SDavid du Colombier panic("kernel bkpt");
3305d9de2d3SDavid du Colombier }
3315d9de2d3SDavid du Colombier break;
3325d9de2d3SDavid du Colombier default:
3335d9de2d3SDavid du Colombier faultarm(ureg, ureg->pc, user, 1);
3345d9de2d3SDavid du Colombier break;
3355d9de2d3SDavid du Colombier }
3365d9de2d3SDavid du Colombier break;
3375d9de2d3SDavid du Colombier case PsrMabt+1: /* data fault */
3385d9de2d3SDavid du Colombier va = farget();
3395d9de2d3SDavid du Colombier inst = *(ulong*)(ureg->pc);
3405d9de2d3SDavid du Colombier /* bits 12 and 10 have to be concatenated with status */
3415d9de2d3SDavid du Colombier x = fsrget();
3425d9de2d3SDavid du Colombier fsr = (x>>7) & 0x20 | (x>>6) & 0x10 | x & 0xf;
3435d9de2d3SDavid du Colombier switch(fsr){
3445d9de2d3SDavid du Colombier default:
3455d9de2d3SDavid du Colombier case 0xa: /* ? was under external abort */
3465d9de2d3SDavid du Colombier panic("unknown data fault, 6b fsr %#lux", fsr);
3475d9de2d3SDavid du Colombier break;
3485d9de2d3SDavid du Colombier case 0x0:
3495d9de2d3SDavid du Colombier panic("vector exception at %#lux", ureg->pc);
3505d9de2d3SDavid du Colombier break;
3515d9de2d3SDavid du Colombier case 0x1: /* alignment fault */
3525d9de2d3SDavid du Colombier case 0x3: /* access flag fault (section) */
3535d9de2d3SDavid du Colombier if(user){
3545d9de2d3SDavid du Colombier snprint(buf, sizeof buf,
3555d9de2d3SDavid du Colombier "sys: alignment: pc %#lux va %#p\n",
3565d9de2d3SDavid du Colombier ureg->pc, va);
3575d9de2d3SDavid du Colombier postnote(up, 1, buf, NDebug);
3585d9de2d3SDavid du Colombier } else
3595d9de2d3SDavid du Colombier panic("kernel alignment: pc %#lux va %#p", ureg->pc, va);
3605d9de2d3SDavid du Colombier break;
3615d9de2d3SDavid du Colombier case 0x2:
3625d9de2d3SDavid du Colombier panic("terminal exception at %#lux", ureg->pc);
3635d9de2d3SDavid du Colombier break;
3645d9de2d3SDavid du Colombier case 0x4: /* icache maint fault */
3655d9de2d3SDavid du Colombier case 0x6: /* access flag fault (page) */
3665d9de2d3SDavid du Colombier case 0x8: /* precise external abort, non-xlat'n */
3675d9de2d3SDavid du Colombier case 0x28:
3685d9de2d3SDavid du Colombier case 0xc: /* l1 translation, precise ext. abort */
3695d9de2d3SDavid du Colombier case 0x2c:
3705d9de2d3SDavid du Colombier case 0xe: /* l2 translation, precise ext. abort */
3715d9de2d3SDavid du Colombier case 0x2e:
3725d9de2d3SDavid du Colombier case 0x16: /* imprecise ext. abort, non-xlt'n */
3735d9de2d3SDavid du Colombier case 0x36:
3745d9de2d3SDavid du Colombier panic("external abort %#lux pc %#lux addr %#p",
3755d9de2d3SDavid du Colombier fsr, ureg->pc, va);
3765d9de2d3SDavid du Colombier break;
3775d9de2d3SDavid du Colombier case 0x1c: /* l1 translation, precise parity err */
3785d9de2d3SDavid du Colombier case 0x1e: /* l2 translation, precise parity err */
3795d9de2d3SDavid du Colombier case 0x18: /* imprecise parity or ecc err */
3805d9de2d3SDavid du Colombier panic("translation parity error %#lux pc %#lux addr %#p",
3815d9de2d3SDavid du Colombier fsr, ureg->pc, va);
3825d9de2d3SDavid du Colombier break;
3835d9de2d3SDavid du Colombier case 0x5: /* translation fault, no section entry */
3845d9de2d3SDavid du Colombier case 0x7: /* translation fault, no page entry */
3855d9de2d3SDavid du Colombier faultarm(ureg, va, user, !writetomem(inst));
3865d9de2d3SDavid du Colombier break;
3875d9de2d3SDavid du Colombier case 0x9:
3885d9de2d3SDavid du Colombier case 0xb:
3895d9de2d3SDavid du Colombier /* domain fault, accessing something we shouldn't */
3905d9de2d3SDavid du Colombier if(user){
3915d9de2d3SDavid du Colombier snprint(buf, sizeof buf,
3925d9de2d3SDavid du Colombier "sys: access violation: pc %#lux va %#p\n",
3935d9de2d3SDavid du Colombier ureg->pc, va);
3945d9de2d3SDavid du Colombier postnote(up, 1, buf, NDebug);
3955d9de2d3SDavid du Colombier } else
3965d9de2d3SDavid du Colombier panic("kernel access violation: pc %#lux va %#p",
3975d9de2d3SDavid du Colombier ureg->pc, va);
3985d9de2d3SDavid du Colombier break;
3995d9de2d3SDavid du Colombier case 0xd:
4005d9de2d3SDavid du Colombier case 0xf:
4015d9de2d3SDavid du Colombier /* permission error, copy on write or real permission error */
4025d9de2d3SDavid du Colombier faultarm(ureg, va, user, !writetomem(inst));
4035d9de2d3SDavid du Colombier break;
4045d9de2d3SDavid du Colombier }
4055d9de2d3SDavid du Colombier break;
4065d9de2d3SDavid du Colombier case PsrMund: /* undefined instruction */
4075d9de2d3SDavid du Colombier if(user){
4085d9de2d3SDavid du Colombier if(seg(up, ureg->pc, 0) != nil &&
4095d9de2d3SDavid du Colombier *(u32int*)ureg->pc == 0xD1200070)
4105d9de2d3SDavid du Colombier postnote(up, 1, "sys: breakpoint", NDebug);
4115d9de2d3SDavid du Colombier else{
4125d9de2d3SDavid du Colombier /* look for floating point instructions to interpret */
4135d9de2d3SDavid du Colombier rv = fpuemu(ureg);
4145d9de2d3SDavid du Colombier if(rv == 0){
4155d9de2d3SDavid du Colombier snprint(buf, sizeof buf,
4165d9de2d3SDavid du Colombier "undefined instruction: pc %#lux\n",
4175d9de2d3SDavid du Colombier ureg->pc);
4185d9de2d3SDavid du Colombier postnote(up, 1, buf, NDebug);
4195d9de2d3SDavid du Colombier }
4205d9de2d3SDavid du Colombier }
4215d9de2d3SDavid du Colombier }else{
4225d9de2d3SDavid du Colombier if (ureg->pc & 3) {
4235d9de2d3SDavid du Colombier iprint("rounding fault pc %#lux down to word\n",
4245d9de2d3SDavid du Colombier ureg->pc);
4255d9de2d3SDavid du Colombier ureg->pc &= ~3;
4265d9de2d3SDavid du Colombier }
4275d9de2d3SDavid du Colombier iprint("undefined instruction: pc %#lux inst %#ux\n",
4285d9de2d3SDavid du Colombier ureg->pc, *(u32int*)ureg->pc);
4295d9de2d3SDavid du Colombier panic("undefined instruction");
4305d9de2d3SDavid du Colombier }
4315d9de2d3SDavid du Colombier break;
4325d9de2d3SDavid du Colombier }
4335d9de2d3SDavid du Colombier splhi();
4345d9de2d3SDavid du Colombier
4355d9de2d3SDavid du Colombier /* delaysched set because we held a lock or because our quantum ended */
4365d9de2d3SDavid du Colombier if(up && up->delaysched && clockintr){
4375d9de2d3SDavid du Colombier sched(); /* can cause more traps */
4385d9de2d3SDavid du Colombier splhi();
4395d9de2d3SDavid du Colombier }
4405d9de2d3SDavid du Colombier
4415d9de2d3SDavid du Colombier if(user){
4425d9de2d3SDavid du Colombier if(up->procctl || up->nnote)
4435d9de2d3SDavid du Colombier notify(ureg);
4445d9de2d3SDavid du Colombier kexit(ureg);
4455d9de2d3SDavid du Colombier }
4465d9de2d3SDavid du Colombier }
4475d9de2d3SDavid du Colombier
4485d9de2d3SDavid du Colombier int
isvalidaddr(void * v)4495d9de2d3SDavid du Colombier isvalidaddr(void *v)
4505d9de2d3SDavid du Colombier {
4515d9de2d3SDavid du Colombier return (uintptr)v >= KZERO;
4525d9de2d3SDavid du Colombier }
4535d9de2d3SDavid du Colombier
4545d9de2d3SDavid du Colombier static void
dumplongs(char * msg,ulong * v,int n)4555d9de2d3SDavid du Colombier dumplongs(char *msg, ulong *v, int n)
4565d9de2d3SDavid du Colombier {
4575d9de2d3SDavid du Colombier int i, l;
4585d9de2d3SDavid du Colombier
4595d9de2d3SDavid du Colombier l = 0;
4605d9de2d3SDavid du Colombier iprint("%s at %.8p: ", msg, v);
4615d9de2d3SDavid du Colombier for(i=0; i<n; i++){
4625d9de2d3SDavid du Colombier if(l >= 4){
4635d9de2d3SDavid du Colombier iprint("\n %.8p: ", v);
4645d9de2d3SDavid du Colombier l = 0;
4655d9de2d3SDavid du Colombier }
4665d9de2d3SDavid du Colombier if(isvalidaddr(v)){
4675d9de2d3SDavid du Colombier iprint(" %.8lux", *v++);
4685d9de2d3SDavid du Colombier l++;
4695d9de2d3SDavid du Colombier }else{
4705d9de2d3SDavid du Colombier iprint(" invalid");
4715d9de2d3SDavid du Colombier break;
4725d9de2d3SDavid du Colombier }
4735d9de2d3SDavid du Colombier }
4745d9de2d3SDavid du Colombier iprint("\n");
4755d9de2d3SDavid du Colombier }
4765d9de2d3SDavid du Colombier
4775d9de2d3SDavid du Colombier static void
dumpstackwithureg(Ureg * ureg)4785d9de2d3SDavid du Colombier dumpstackwithureg(Ureg *ureg)
4795d9de2d3SDavid du Colombier {
4805d9de2d3SDavid du Colombier uintptr l, i, v, estack;
4815d9de2d3SDavid du Colombier u32int *p;
4825d9de2d3SDavid du Colombier char *s;
4835d9de2d3SDavid du Colombier
4845d9de2d3SDavid du Colombier if((s = getconf("*nodumpstack")) != nil && strcmp(s, "0") != 0){
4855d9de2d3SDavid du Colombier iprint("dumpstack disabled\n");
4865d9de2d3SDavid du Colombier return;
4875d9de2d3SDavid du Colombier }
4885d9de2d3SDavid du Colombier iprint("ktrace /kernel/path %#.8lux %#.8lux %#.8lux # pc, sp, link\n",
4895d9de2d3SDavid du Colombier ureg->pc, ureg->sp, ureg->r14);
4905d9de2d3SDavid du Colombier delay(2000);
4915d9de2d3SDavid du Colombier i = 0;
4925d9de2d3SDavid du Colombier if(up != nil && (uintptr)&l <= (uintptr)up->kstack+KSTACK)
4935d9de2d3SDavid du Colombier estack = (uintptr)up->kstack+KSTACK;
4945d9de2d3SDavid du Colombier else if((uintptr)&l >= (uintptr)m->stack
4955d9de2d3SDavid du Colombier && (uintptr)&l <= (uintptr)m+MACHSIZE)
4965d9de2d3SDavid du Colombier estack = (uintptr)m+MACHSIZE;
4975d9de2d3SDavid du Colombier else{
4985d9de2d3SDavid du Colombier if(up != nil)
4995d9de2d3SDavid du Colombier iprint("&up->kstack %#p &l %#p\n", up->kstack, &l);
5005d9de2d3SDavid du Colombier else
5015d9de2d3SDavid du Colombier iprint("&m %#p &l %#p\n", m, &l);
5025d9de2d3SDavid du Colombier return;
5035d9de2d3SDavid du Colombier }
5045d9de2d3SDavid du Colombier for(l = (uintptr)&l; l < estack; l += sizeof(uintptr)){
5055d9de2d3SDavid du Colombier v = *(uintptr*)l;
5065d9de2d3SDavid du Colombier if(KTZERO < v && v < (uintptr)etext && !(v & 3)){
5075d9de2d3SDavid du Colombier v -= sizeof(u32int); /* back up an instr */
5085d9de2d3SDavid du Colombier p = (u32int*)v;
5095d9de2d3SDavid du Colombier if((*p & 0x0f000000) == 0x0b000000){ /* BL instr? */
5105d9de2d3SDavid du Colombier iprint("%#8.8lux=%#8.8lux ", l, v);
5115d9de2d3SDavid du Colombier i++;
5125d9de2d3SDavid du Colombier }
5135d9de2d3SDavid du Colombier }
5145d9de2d3SDavid du Colombier if(i == 4){
5155d9de2d3SDavid du Colombier i = 0;
5165d9de2d3SDavid du Colombier iprint("\n");
5175d9de2d3SDavid du Colombier }
5185d9de2d3SDavid du Colombier }
5195d9de2d3SDavid du Colombier if(i)
5205d9de2d3SDavid du Colombier iprint("\n");
5215d9de2d3SDavid du Colombier }
5225d9de2d3SDavid du Colombier
5235d9de2d3SDavid du Colombier /*
5245d9de2d3SDavid du Colombier * Fill in enough of Ureg to get a stack trace, and call a function.
5255d9de2d3SDavid du Colombier * Used by debugging interface rdb.
5265d9de2d3SDavid du Colombier */
5275d9de2d3SDavid du Colombier void
callwithureg(void (* fn)(Ureg *))5285d9de2d3SDavid du Colombier callwithureg(void (*fn)(Ureg*))
5295d9de2d3SDavid du Colombier {
5305d9de2d3SDavid du Colombier Ureg ureg;
5315d9de2d3SDavid du Colombier
5325d9de2d3SDavid du Colombier ureg.pc = getcallerpc(&fn);
5335d9de2d3SDavid du Colombier ureg.sp = PTR2UINT(&fn);
5345d9de2d3SDavid du Colombier fn(&ureg);
5355d9de2d3SDavid du Colombier }
5365d9de2d3SDavid du Colombier
5375d9de2d3SDavid du Colombier void
dumpstack(void)5385d9de2d3SDavid du Colombier dumpstack(void)
5395d9de2d3SDavid du Colombier {
5405d9de2d3SDavid du Colombier callwithureg(dumpstackwithureg);
5415d9de2d3SDavid du Colombier }
5425d9de2d3SDavid du Colombier
5435d9de2d3SDavid du Colombier void
dumpregs(Ureg * ureg)5445d9de2d3SDavid du Colombier dumpregs(Ureg* ureg)
5455d9de2d3SDavid du Colombier {
5465d9de2d3SDavid du Colombier int s;
5475d9de2d3SDavid du Colombier
5485d9de2d3SDavid du Colombier if (ureg == nil) {
5495d9de2d3SDavid du Colombier iprint("trap: no user process\n");
5505d9de2d3SDavid du Colombier return;
5515d9de2d3SDavid du Colombier }
5525d9de2d3SDavid du Colombier s = splhi();
5535d9de2d3SDavid du Colombier iprint("trap: %s", trapname(ureg->type));
5545d9de2d3SDavid du Colombier if(ureg != nil && (ureg->psr & PsrMask) != PsrMsvc)
5555d9de2d3SDavid du Colombier iprint(" in %s", trapname(ureg->psr));
5565d9de2d3SDavid du Colombier iprint("\n");
5575d9de2d3SDavid du Colombier iprint("psr %8.8lux type %2.2lux pc %8.8lux link %8.8lux\n",
5585d9de2d3SDavid du Colombier ureg->psr, ureg->type, ureg->pc, ureg->link);
5595d9de2d3SDavid du Colombier iprint("R14 %8.8lux R13 %8.8lux R12 %8.8lux R11 %8.8lux R10 %8.8lux\n",
5605d9de2d3SDavid du Colombier ureg->r14, ureg->r13, ureg->r12, ureg->r11, ureg->r10);
5615d9de2d3SDavid du Colombier iprint("R9 %8.8lux R8 %8.8lux R7 %8.8lux R6 %8.8lux R5 %8.8lux\n",
5625d9de2d3SDavid du Colombier ureg->r9, ureg->r8, ureg->r7, ureg->r6, ureg->r5);
5635d9de2d3SDavid du Colombier iprint("R4 %8.8lux R3 %8.8lux R2 %8.8lux R1 %8.8lux R0 %8.8lux\n",
5645d9de2d3SDavid du Colombier ureg->r4, ureg->r3, ureg->r2, ureg->r1, ureg->r0);
5655d9de2d3SDavid du Colombier iprint("stack is at %#p\n", ureg);
5665d9de2d3SDavid du Colombier iprint("pc %#lux link %#lux\n", ureg->pc, ureg->link);
5675d9de2d3SDavid du Colombier
5685d9de2d3SDavid du Colombier if(up)
5695d9de2d3SDavid du Colombier iprint("user stack: %#p-%#p\n", up->kstack, up->kstack+KSTACK-4);
5705d9de2d3SDavid du Colombier else
5715d9de2d3SDavid du Colombier iprint("kernel stack: %8.8lux-%8.8lux\n",
5725d9de2d3SDavid du Colombier (ulong)(m+1), (ulong)m+BY2PG-4);
5735d9de2d3SDavid du Colombier dumplongs("stack", (ulong *)(ureg + 1), 16);
5745d9de2d3SDavid du Colombier delay(2000);
5755d9de2d3SDavid du Colombier dumpstack();
5765d9de2d3SDavid du Colombier splx(s);
5775d9de2d3SDavid du Colombier }
578