2 * sheevaplug traps, exceptions, interrupts, system calls.
5 #include "../port/lib.h"
11 #include "../port/error.h"
16 Ntimevec = 20, /* # of time buckets for each intr */
20 extern int notify(Ureg*);
22 extern int ldrexvalid;
24 typedef struct Vctl Vctl;
26 Vctl* next; /* handlers on this vector */
27 char *name; /* of driver, xallocated */
28 void (*f)(Ureg*, void*); /* handler to call */
29 void* a; /* argument to call it with */
33 static Vctl* vctl[32];
36 uvlong ninterruptticks;
37 ulong intrtimes[Nvecs][Ntimevec];
39 typedef struct Handler Handler;
41 void (*r)(Ureg*, void*);
46 static Handler irqlo[32];
47 static Handler irqhi[32];
48 static Handler irqbridge[32];
50 static int probing, trapped;
52 typedef struct Irq Irq;
60 /* irq and irqmask are filled in by trapinit */
62 [Irqlo] {nil, nil, irqlo, nelem(irqlo), "lo"},
63 [Irqhi] {nil, nil, irqhi, nelem(irqhi), "hi"},
64 [Irqbridge] {nil, nil, irqbridge, nelem(irqbridge), "bridge"},
68 * keep histogram of interrupt service times
71 intrtime(Mach*, int vno)
78 diff = x - m->perf.intrts;
81 m->perf.inintr += diff;
82 if(up == nil && m->perf.inidle > diff)
83 m->perf.inidle -= diff;
85 if (m->cpuhz == 0) /* not set yet? */
87 diff /= (m->cpuhz/1000000)*100; /* quantum = 100µsec */
90 assert(vno >= 0 && vno < Nvecs);
91 intrtimes[vno][diff]++;
95 intrfmtcounts(char *s, char *se)
106 intrclear(int sort, int v)
108 *irqs[sort].irq = ~(1 << v);
112 intrmask(int sort, int v)
114 *irqs[sort].irqmask &= ~(1 << v);
118 intrunmask(int sort, int v)
120 *irqs[sort].irqmask |= 1 << v;
126 CpucsReg *cpu = (CpucsReg *)soc.cpu;
129 /* no fiq or ep in use */
130 intr = (IntrReg *)soc.intr;
131 intr->lo.irqmask = 0;
132 intr->hi.irqmask = 0;
138 intrset(Handler *h, void (*f)(Ureg*, void*), void *a, char *name)
141 // iprint("duplicate irq: %s (%#p)\n", h->name, h->r);
146 strncpy(h->name, name, KNAMELEN-1);
147 h->name[KNAMELEN-1] = 0;
151 intrunset(Handler *h)
159 intrdel(Handler *h, void (*f)(Ureg*, void*), void *a, char *name)
161 if(h->r != f || h->a != a || strcmp(h->name, name) != 0)
167 intrenable(int sort, int v, void (*f)(Ureg*, void*), void *a, char *name)
169 //iprint("enabling intr %d vec %d for %s\n", sort, v, name);
171 intrset(&irqs[sort].irqvec[v], f, a, name);
177 intrdisable(int sort, int v, void (*f)(Ureg*, void*), void* a, char *name)
180 intrdel(&irqs[sort].irqvec[v], f, a, name);
186 * called by trap to handle interrupts
189 intrs(Ureg *ur, int sort)
196 assert(sort >= 0 && sort < nelem(irqs));
199 ibits &= *irq.irqmask;
201 for(i = 0; i < irq.nirqvec && ibits; i++)
207 intrtime(m, sort*32 + i);
208 if (sort == Irqbridge && i == IRQcputimer0)
214 iprint("spurious irq%s interrupt: %8.8lux\n", irq.name, ibits);
217 *irq.irqmask &= ~ibits;
223 intrhi(Ureg *ureg, void*)
229 intrbridge(Ureg *ureg, void*)
231 intrs(ureg, Irqbridge);
232 intrclear(Irqlo, IRQ0bridge);
241 Vectorpage *page0 = (Vectorpage*)HVECTORS;
243 intr = (IntrReg *)soc.intr;
244 cpu = (CpucsReg *)soc.cpu;
245 irqs[Irqlo].irq = &intr->lo.irq;
246 irqs[Irqlo].irqmask = &intr->lo.irqmask;
247 irqs[Irqhi].irq = &intr->hi.irq;
248 irqs[Irqhi].irqmask = &intr->hi.irqmask;
249 irqs[Irqbridge].irq = &cpu->irq;
250 irqs[Irqbridge].irqmask = &cpu->irqmask;
253 setr13(PsrMfiq, m->fiqstack + nelem(m->fiqstack));
254 setr13(PsrMirq, m->irqstack + nelem(m->irqstack));
255 setr13(PsrMabt, m->abtstack + nelem(m->abtstack));
256 setr13(PsrMund, m->undstack + nelem(m->undstack));
258 memmove(page0->vectors, vectors, sizeof page0->vectors);
259 memmove(page0->vtable, vtable, sizeof page0->vtable);
263 cpu->cpucfg &= ~Cfgvecinithi;
265 for(i = 0; i < nelem(irqlo); i++)
266 intrunset(&irqlo[i]);
267 for(i = 0; i < nelem(irqhi); i++)
268 intrunset(&irqhi[i]);
269 for(i = 0; i < nelem(irqbridge); i++)
270 intrunset(&irqbridge[i]);
272 /* disable all interrupts */
273 intr->lo.fiqmask = intr->hi.fiqmask = 0;
274 intr->lo.irqmask = intr->hi.irqmask = 0;
275 intr->lo.epmask = intr->hi.epmask = 0;
279 /* clear interrupts */
280 intr->lo.irq = intr->hi.irq = ~0;
284 intrenable(Irqlo, IRQ0hisum, intrhi, nil, "hi");
285 intrenable(Irqlo, IRQ0bridge, intrbridge, nil, "bridge");
287 /* enable watchdog & access-error interrupts */
288 cpu->irqmask |= 1 << IRQcputimerwd | 1 << IRQaccesserr;
292 static char *trapnames[PsrMask+1] = {
293 [ PsrMusr ] "user mode",
294 [ PsrMfiq ] "fiq interrupt",
295 [ PsrMirq ] "irq interrupt",
296 [ PsrMsvc ] "svc/swi exception",
297 [ PsrMabt ] "prefetch abort/data abort",
298 [ PsrMabt+1 ] "data abort",
299 [ PsrMund ] "undefined instruction",
300 [ PsrMsys ] "sys trap",
308 s = trapnames[psr & PsrMask];
310 s = "unknown trap number in psr";
315 * called by trap to handle access faults
318 faultarm(Ureg *ureg, uintptr va, int user, int read)
322 static int cnt, lastpid;
327 panic("fault: nil up in faultarm, accessing %#p", va);
329 insyscall = up->insyscall;
332 /* this is quite helpful during mmu and cache debugging */
333 if(va == lastva && up->pid == lastpid) {
336 /* fault() isn't fixing the underlying cause */
337 panic("fault: %d consecutive faults for va %#lux",
349 panic("fault: kernel accessing %#p", va);
351 /* don't dump registers; programs suicide all the time */
352 snprint(buf, sizeof buf, "sys: trap: fault %s va=%#p",
353 read? "read": "write", va);
354 postnote(up, 1, buf, NDebug);
356 up->insyscall = insyscall;
360 * returns 1 if the instruction writes memory, 0 otherwise
363 writetomem(ulong inst)
365 /* swap always write memory */
366 if((inst & 0x0FC00000) == 0x01000000)
369 /* loads and stores are distinguished by bit 20 */
379 int user, x, rv, rem;
386 rem = (char*)ureg - up->kstack;
388 rem = (char*)ureg - ((char*)m + sizeof(Mach));
391 panic("trap %d bytes remaining, up %#p ureg %#p at pc %#lux",
392 rem, up, ureg, ureg->pc);
395 user = (ureg->psr & PsrMask) == PsrMusr;
401 if(ureg->type == PsrMabt+1)
409 panic("unknown trap %ld", ureg->type);
413 // splflo(); /* allow fast interrupts */
417 case PsrMabt: /* prefetch fault */
419 faultarm(ureg, ureg->pc, user, 1);
421 (*(u32int*)ureg->pc & ~(0xF<<28)) == 0x01200070)
422 postnote(up, 1, "sys: breakpoint", NDebug);
424 case PsrMabt+1: /* data fault */
427 inst = *(ulong*)(ureg->pc);
428 fsr = fsrget() & 0xf;
429 if (probing && !user) {
431 panic("trap: recursive probe %#lux", va);
432 ureg->pc += 4; /* continue at next instruction */
437 panic("vector exception at %#lux", ureg->pc);
442 snprint(buf, sizeof buf,
443 "sys: alignment: pc %#lux va %#p\n",
445 postnote(up, 1, buf, NDebug);
447 panic("kernel alignment: pc %#lux va %#p", ureg->pc, va);
450 panic("terminal exception at %#lux", ureg->pc);
458 panic("external abort %#ux pc %#lux addr %#px",
461 case 0x5: /* translation fault, no section entry */
462 case 0x7: /* translation fault, no page entry */
463 faultarm(ureg, va, user, !writetomem(inst));
467 /* domain fault, accessing something we shouldn't */
469 snprint(buf, sizeof buf,
470 "sys: access violation: pc %#lux va %#p\n",
472 postnote(up, 1, buf, NDebug);
474 panic("kernel access violation: pc %#lux va %#p",
479 /* permission error, copy on write or real permission error */
480 faultarm(ureg, va, user, !writetomem(inst));
484 case PsrMund: /* undefined instruction */
486 if(seg(up, ureg->pc, 0) != nil &&
487 (*(u32int*)ureg->pc & ~(0xF<<28)) == 0x01200070)
488 postnote(up, 1, "sys: breakpoint", NDebug);
490 /* look for floating point instructions to interpret */
496 snprint(buf, sizeof buf,
497 "undefined instruction: pc %#lux",
499 postnote(up, 1, buf, NDebug);
503 iprint("undefined instruction: pc %#lux inst %#ux\n",
504 ureg->pc, ((u32int*)ureg->pc)[-2]);
505 panic("undefined instruction");
511 /* delaysched set because we held a lock or because our quantum ended */
512 if(up && up->delaysched && m->inclockintr){
519 if(up->procctl || up->nnote)
528 return (uintptr)v >= KZERO;
532 dumplongs(char *msg, ulong *v, int n)
537 iprint("%s at %.8p: ", msg, v);
540 iprint("\n %.8p: ", v);
544 iprint(" %.8lux", *v++);
555 dumpstackwithureg(Ureg *ureg)
557 uintptr l, i, v, estack;
560 iprint("ktrace /kernel/path %#.8lux %#.8lux %#.8lux # pc, sp, link\n",
561 ureg->pc, ureg->sp, ureg->r14);
564 if(up != nil && (uintptr)&l <= (uintptr)up->kstack+KSTACK)
565 estack = (uintptr)up->kstack+KSTACK;
566 else if((uintptr)&l >= (uintptr)m->stack
567 && (uintptr)&l <= (uintptr)m+MACHSIZE)
568 estack = (uintptr)m+MACHSIZE;
571 iprint("&up->kstack %#p &l %#p\n", up->kstack, &l);
573 iprint("&m %#p &l %#p\n", m, &l);
576 for(l = (uintptr)&l; l < estack; l += sizeof(uintptr)){
578 if(KTZERO < v && v < (uintptr)etext && !(v & 3)){
579 v -= sizeof(u32int); /* back up an instr */
581 if((*p & 0x0f000000) == 0x0b000000){ /* BL instr? */
582 iprint("%#8.8lux=%#8.8lux ", l, v);
596 * Fill in enough of Ureg to get a stack trace, and call a function.
597 * Used by debugging interface rdb.
600 callwithureg(void (*fn)(Ureg*))
604 ureg.pc = getcallerpc(&fn);
605 ureg.sp = PTR2UINT(&fn);
612 callwithureg(dumpstackwithureg);
621 iprint("trap: no user process\n");
625 iprint("trap: %s", trapname(ureg->type));
626 if(ureg != nil && (ureg->psr & PsrMask) != PsrMsvc)
627 iprint(" in %s", trapname(ureg->psr));
629 iprint("psr %8.8lux type %2.2lux pc %8.8lux link %8.8lux\n",
630 ureg->psr, ureg->type, ureg->pc, ureg->link);
631 iprint("R14 %8.8lux R13 %8.8lux R12 %8.8lux R11 %8.8lux R10 %8.8lux\n",
632 ureg->r14, ureg->r13, ureg->r12, ureg->r11, ureg->r10);
633 iprint("R9 %8.8lux R8 %8.8lux R7 %8.8lux R6 %8.8lux R5 %8.8lux\n",
634 ureg->r9, ureg->r8, ureg->r7, ureg->r6, ureg->r5);
635 iprint("R4 %8.8lux R3 %8.8lux R2 %8.8lux R1 %8.8lux R0 %8.8lux\n",
636 ureg->r4, ureg->r3, ureg->r2, ureg->r1, ureg->r0);
637 iprint("stack is at %#p\n", ureg);
638 iprint("pc %#lux link %#lux\n", ureg->pc, ureg->link);
641 iprint("user stack: %#p-%#p\n", up->kstack, up->kstack+KSTACK-4);
643 iprint("kernel stack: %8.8lux-%8.8lux\n",
644 (ulong)(m+1), (ulong)m+BY2PG-4);
645 dumplongs("stack", (ulong *)(ureg + 1), 16);
654 extern void _idlehands(void);
660 probeaddr(uintptr addr)
670 v = *(ulong *)addr; /* this may cause a fault */