2 * traps, exceptions, interrupts, system calls.
5 #include "../port/lib.h"
11 #include "../port/error.h"
15 #define INTREGS (VIRTIO+0xB200)
17 typedef struct Intregs Intregs;
18 typedef struct Vctl Vctl;
21 Nvec = 8, /* # of vectors at start of lexception.s */
26 * Layout at virtual address KZERO (double mapped at HVECTORS).
28 typedef struct Vpage0 {
29 void (*vectors[Nvec])(void);
34 * interrupt control registers
51 void (*f)(Ureg*, void*);
55 static Vctl *vctl, *vfiq;
57 static char *trapnames[PsrMask+1] = {
58 [ PsrMusr ] "user mode",
59 [ PsrMfiq ] "fiq interrupt",
60 [ PsrMirq ] "irq interrupt",
61 [ PsrMsvc ] "svc/swi exception",
62 [ PsrMabt ] "prefetch abort/data abort",
63 [ PsrMabt+1 ] "data abort",
64 [ PsrMund ] "undefined instruction",
65 [ PsrMsys ] "sys trap",
68 extern int notify(Ureg*);
71 * set up for exceptions
78 /* disable everything */
81 /* set up the exception vectors */
82 vpage0 = (Vpage0*)HVECTORS;
83 memmove(vpage0->vectors, vectors, sizeof(vpage0->vectors));
84 memmove(vpage0->vtable, vtable, sizeof(vpage0->vtable));
87 /* set up the stacks for the interrupt modes */
88 setr13(PsrMfiq, (u32int*)(FIQSTKTOP));
89 setr13(PsrMirq, m->sirq);
90 setr13(PsrMabt, m->sabt);
91 setr13(PsrMund, m->sund);
92 setr13(PsrMsys, m->ssys);
103 ip = (Intregs*)INTREGS;
105 ip->GPUdisable[0] = disable;
106 ip->GPUdisable[1] = disable;
107 ip->ARMdisable = disable;
112 * called by trap to handle irq interrupts.
113 * returns true iff a clock interrupt, thus maybe reschedule.
122 for(v = vctl; v; v = v->next)
123 if(*v->reg & v->mask){
127 if(v->irq == IRQclock)
134 * called direct from lexception.s to handle fiq interrupt.
143 panic("unexpected item in bagging area");
152 irqenable(int irq, void (*f)(Ureg*, void*), void* a)
158 ip = (Intregs*)INTREGS;
159 v = (Vctl*)malloc(sizeof(Vctl));
161 panic("irqenable: no mem");
164 enable = &ip->ARMenable;
165 v->reg = &ip->ARMpending;
166 v->mask = 1 << (irq - IRQbasic);
168 enable = &ip->GPUenable[irq/32];
169 v->reg = &ip->GPUpending[irq/32];
170 v->mask = 1 << (irq % 32);
175 assert((ip->FIQctl & Fiqenable) == 0);
176 assert((*enable & v->mask) == 0);
178 ip->FIQctl = Fiqenable | irq;
191 s = trapnames[psr & PsrMask];
193 s = "unknown trap number in psr";
198 * called by trap to handle access faults
201 faultarm(Ureg *ureg, uintptr va, int user, int read)
205 static int cnt, lastpid;
210 panic("fault: nil up in faultarm, accessing %#p", va);
212 insyscall = up->insyscall;
214 /* this is quite helpful during mmu and cache debugging */
215 if(va == lastva && up->pid == lastpid) {
218 /* fault() isn't fixing the underlying cause */
219 panic("fault: %d consecutive faults for va %#lux",
231 panic("fault: kernel accessing %#p", va);
233 /* don't dump registers; programs suicide all the time */
234 snprint(buf, sizeof buf, "sys: trap: fault %s va=%#p",
235 read? "read": "write", va);
236 postnote(up, 1, buf, NDebug);
238 up->insyscall = insyscall;
242 * returns 1 if the instruction writes memory, 0 otherwise
245 writetomem(ulong inst)
247 /* swap always write memory */
248 if((inst & 0x0FC00000) == 0x01000000)
251 /* loads and stores are distinguished by bit 20 */
259 * here on all exceptions other than syscall (SWI) and fiq
264 int clockintr, user, x, rv, rem;
271 rem = ((char*)ureg)-up->kstack;
273 rem = ((char*)ureg)-((char*)m+sizeof(Mach));
275 iprint("trap: %d stack bytes left, up %#p ureg %#p at pc %#lux\n",
276 rem, up, ureg, ureg->pc);
279 panic("trap: %d stack bytes left, up %#p ureg %#p at pc %#lux",
280 rem, up, ureg, ureg->pc);
283 user = (ureg->psr & PsrMask) == PsrMusr;
290 * All interrupts/exceptions should be resumed at ureg->pc-4,
291 * except for Data Abort which resumes at ureg->pc-8.
293 if(ureg->type == (PsrMabt+1))
298 clockintr = 0; /* if set, may call sched() before return */
301 panic("unknown trap; type %#lux, psr mode %#lux", ureg->type,
302 ureg->psr & PsrMask);
305 clockintr = irq(ureg);
308 case PsrMabt: /* prefetch fault */
310 fsr = (x>>7) & 0x8 | x & 0x7;
312 case 0x02: /* instruction debug event (BKPT) */
314 snprint(buf, sizeof buf, "sys: breakpoint");
315 postnote(up, 1, buf, NDebug);
317 iprint("kernel bkpt: pc %#lux inst %#ux\n",
318 ureg->pc, *(u32int*)ureg->pc);
319 panic("kernel bkpt");
323 faultarm(ureg, ureg->pc, user, 1);
327 case PsrMabt+1: /* data fault */
329 inst = *(ulong*)(ureg->pc);
330 /* bits 12 and 10 have to be concatenated with status */
332 fsr = (x>>7) & 0x20 | (x>>6) & 0x10 | x & 0xf;
335 case 0xa: /* ? was under external abort */
336 panic("unknown data fault, 6b fsr %#lux", fsr);
339 panic("vector exception at %#lux", ureg->pc);
341 case 0x1: /* alignment fault */
342 case 0x3: /* access flag fault (section) */
344 snprint(buf, sizeof buf,
345 "sys: alignment: pc %#lux va %#p\n",
347 postnote(up, 1, buf, NDebug);
349 panic("kernel alignment: pc %#lux va %#p", ureg->pc, va);
352 panic("terminal exception at %#lux", ureg->pc);
354 case 0x4: /* icache maint fault */
355 case 0x6: /* access flag fault (page) */
356 case 0x8: /* precise external abort, non-xlat'n */
358 case 0xc: /* l1 translation, precise ext. abort */
360 case 0xe: /* l2 translation, precise ext. abort */
362 case 0x16: /* imprecise ext. abort, non-xlt'n */
364 panic("external abort %#lux pc %#lux addr %#p",
367 case 0x1c: /* l1 translation, precise parity err */
368 case 0x1e: /* l2 translation, precise parity err */
369 case 0x18: /* imprecise parity or ecc err */
370 panic("translation parity error %#lux pc %#lux addr %#p",
373 case 0x5: /* translation fault, no section entry */
374 case 0x7: /* translation fault, no page entry */
375 faultarm(ureg, va, user, !writetomem(inst));
379 /* domain fault, accessing something we shouldn't */
381 snprint(buf, sizeof buf,
382 "sys: access violation: pc %#lux va %#p\n",
384 postnote(up, 1, buf, NDebug);
386 panic("kernel access violation: pc %#lux va %#p",
391 /* permission error, copy on write or real permission error */
392 faultarm(ureg, va, user, !writetomem(inst));
396 case PsrMund: /* undefined instruction */
398 if(seg(up, ureg->pc, 0) != nil &&
399 *(u32int*)ureg->pc == 0xD1200070)
400 postnote(up, 1, "sys: breakpoint", NDebug);
402 /* look for floating point instructions to interpret */
405 snprint(buf, sizeof buf,
406 "undefined instruction: pc %#lux\n",
408 postnote(up, 1, buf, NDebug);
413 iprint("rounding fault pc %#lux down to word\n",
417 iprint("undefined instruction: pc %#lux inst %#ux\n",
418 ureg->pc, *(u32int*)ureg->pc);
419 panic("undefined instruction");
425 /* delaysched set because we held a lock or because our quantum ended */
426 if(up && up->delaysched && clockintr){
427 sched(); /* can cause more traps */
432 if(up->procctl || up->nnote)
441 return (uintptr)v >= KZERO;
445 dumplongs(char *msg, ulong *v, int n)
450 iprint("%s at %.8p: ", msg, v);
453 iprint("\n %.8p: ", v);
457 iprint(" %.8lux", *v++);
468 dumpstackwithureg(Ureg *ureg)
470 uintptr l, i, v, estack;
474 if((s = getconf("*nodumpstack")) != nil && strcmp(s, "0") != 0){
475 iprint("dumpstack disabled\n");
478 iprint("ktrace /kernel/path %#.8lux %#.8lux %#.8lux # pc, sp, link\n",
479 ureg->pc, ureg->sp, ureg->r14);
482 if(up != nil && (uintptr)&l <= (uintptr)up->kstack+KSTACK)
483 estack = (uintptr)up->kstack+KSTACK;
484 else if((uintptr)&l >= (uintptr)m->stack
485 && (uintptr)&l <= (uintptr)m+MACHSIZE)
486 estack = (uintptr)m+MACHSIZE;
489 iprint("&up->kstack %#p &l %#p\n", up->kstack, &l);
491 iprint("&m %#p &l %#p\n", m, &l);
494 for(l = (uintptr)&l; l < estack; l += sizeof(uintptr)){
496 if(KTZERO < v && v < (uintptr)etext && !(v & 3)){
497 v -= sizeof(u32int); /* back up an instr */
499 if((*p & 0x0f000000) == 0x0b000000){ /* BL instr? */
500 iprint("%#8.8lux=%#8.8lux ", l, v);
514 * Fill in enough of Ureg to get a stack trace, and call a function.
515 * Used by debugging interface rdb.
518 callwithureg(void (*fn)(Ureg*))
522 ureg.pc = getcallerpc(&fn);
523 ureg.sp = PTR2UINT(&fn);
530 callwithureg(dumpstackwithureg);
539 iprint("trap: no user process\n");
543 iprint("trap: %s", trapname(ureg->type));
544 if(ureg != nil && (ureg->psr & PsrMask) != PsrMsvc)
545 iprint(" in %s", trapname(ureg->psr));
547 iprint("psr %8.8lux type %2.2lux pc %8.8lux link %8.8lux\n",
548 ureg->psr, ureg->type, ureg->pc, ureg->link);
549 iprint("R14 %8.8lux R13 %8.8lux R12 %8.8lux R11 %8.8lux R10 %8.8lux\n",
550 ureg->r14, ureg->r13, ureg->r12, ureg->r11, ureg->r10);
551 iprint("R9 %8.8lux R8 %8.8lux R7 %8.8lux R6 %8.8lux R5 %8.8lux\n",
552 ureg->r9, ureg->r8, ureg->r7, ureg->r6, ureg->r5);
553 iprint("R4 %8.8lux R3 %8.8lux R2 %8.8lux R1 %8.8lux R0 %8.8lux\n",
554 ureg->r4, ureg->r3, ureg->r2, ureg->r1, ureg->r0);
555 iprint("stack is at %#p\n", ureg);
556 iprint("pc %#lux link %#lux\n", ureg->pc, ureg->link);
559 iprint("user stack: %#p-%#p\n", up->kstack, up->kstack+KSTACK-4);
561 iprint("kernel stack: %8.8lux-%8.8lux\n",
562 (ulong)(m+1), (ulong)m+BY2PG-4);
563 dumplongs("stack", (ulong *)(ureg + 1), 16);