2 * omap3530 traps, exceptions, interrupts, system calls.
5 #include "../port/lib.h"
9 #include "../port/error.h"
16 Nvec = 8, /* # of vectors at start of lexception.s */
17 Bi2long = BI2BY * sizeof(long),
20 extern int notify(Ureg*);
22 extern int ldrexvalid;
24 /* omap35x intc (aka mpu_intc) */
25 typedef struct Intrregs Intrregs;
28 * the manual inserts "INTCPS_" before each register name;
29 * we'll just assume the prefix.
33 ulong sysstatus; /* ro */
34 uchar _pad1[0x40 - 0x18];
35 ulong sir_irq; /* ro */
36 ulong sir_fiq; /* ro */
40 uchar _pad2[0x60 - 0x54];
44 uchar _pad3[0x80 - 0x6c];
45 struct Bits { /* bitmaps */
46 ulong itr; /* ro: pending intrs (no mask) */
47 ulong mir; /* interrupt mask: 1 means masked */
48 ulong mir_clear; /* wo: 1 sets the bit */
49 ulong mir_set; /* wo: 1 clears the bit */
50 ulong isr_set; /* software interrupts */
51 ulong isr_clear; /* wo */
52 ulong pending_irq; /* ro */
53 ulong pending_fiq; /* ro */
54 } bits[3]; /* 3*32 = 96 (Nirqs) */
65 /* sir_irq/fiq bits */
74 /* irq/fiq_priority bits */
75 Irqpriority = MASK(6),
78 Prioritythreshold = MASK(8),
81 Priority = MASK(8) - MASK(2),
84 typedef struct Vctl Vctl;
86 Vctl* next; /* handlers on this vector */
87 char *name; /* of driver, xallocated */
88 void (*f)(Ureg*, void*); /* handler to call */
89 void* a; /* argument to call it with */
93 static Vctl* vctl[Nirqs];
96 * Layout at virtual address 0.
98 typedef struct Vpage0 {
99 void (*vectors[Nvec])(void);
102 static Vpage0 *vpage0;
105 uvlong ninterruptticks;
108 static volatile int probing, trapped;
113 Intrregs *ip = (Intrregs *)PHYSINTC;
116 * mir registers are odd: a 0 bit means intr unmasked (i.e.,
117 * we've unmasked it because it's in use).
119 return (ip->bits[irq / Bi2long].mir & (1 << (irq % Bi2long))) == 0;
125 Intrregs *ip = (Intrregs *)PHYSINTC;
127 ip->bits[irq / Bi2long].mir_set = 1 << (irq % Bi2long);
134 Intrregs *ip = (Intrregs *)PHYSINTC;
136 ip->bits[irq / Bi2long].mir_clear = 1 << (irq % Bi2long);
144 Intrregs *ip = (Intrregs *)PHYSINTC;
146 for (i = 0; i < 3; i++)
147 ip->bits[i].mir_set = ~0;
155 Intrregs *ip = (Intrregs *)PHYSINTC;
157 for (i = 0; i < 3; i++)
158 ip->bits[i].mir_clear = ~0;
167 Intrregs *ip = (Intrregs *)PHYSINTC;
170 for (i = 0; i < 3; i++) {
171 bits = ip->bits[i].mir;
172 ip->bits[i].mir_set = ~0; /* mask all */
174 /* clearing enables only those intrs. that were disabled */
175 ip->bits[i].mir_clear = bits;
182 intrsave(ulong buf[3])
185 Intrregs *ip = (Intrregs *)PHYSINTC;
187 for (i = 0; i < nelem(buf); i++)
188 buf[i] = ip->bits[i].mir;
193 intrrestore(ulong buf[3])
196 Intrregs *ip = (Intrregs *)PHYSINTC;
199 for (i = 0; i < nelem(buf); i++) {
200 ip->bits[i].mir_clear = ~0; /* unmask all */
202 ip->bits[i].mir_set = buf[i]; /* mask previously disabled */
209 * set up for exceptions
215 Intrregs *ip = (Intrregs *)PHYSINTC;
217 /* set up the exception vectors */
218 vpage0 = (Vpage0*)HVECTORS;
219 memmove(vpage0->vectors, vectors, sizeof(vpage0->vectors));
220 memmove(vpage0->vtable, vtable, sizeof(vpage0->vtable));
224 /* set up the stacks for the interrupt modes */
225 setr13(PsrMfiq, m->sfiq);
226 setr13(PsrMirq, m->sirq);
227 setr13(PsrMabt, m->sabt);
228 setr13(PsrMund, m->sund);
230 setr13(PsrMmon, m->smon);
232 setr13(PsrMsys, m->ssys);
236 ip->threshold = Prioritythreshold; /* disable threshold */
237 for (i = 0; i < Nirqs; i++)
238 ip->ilr[i] = 0<<2 | 0; /* all intrs pri 0 & to irq, not fiq */
246 Intrregs *ip = (Intrregs *)PHYSINTC;
249 ip->control = Newirqagr; /* dismiss interrupt */
254 * enable an irq interrupt
257 irqenable(int irq, void (*f)(Ureg*, void*), void* a, char *name)
261 if(irq >= nelem(vctl) || irq < 0)
262 panic("irqenable irq %d", irq);
265 iprint("irqenable for %d %s called too early\n", irq, name);
269 print("irqenable: %s: irq %d already in use, chaining\n",
271 v = malloc(sizeof(Vctl));
273 panic("irqenable: malloc Vctl");
276 v->name = malloc(strlen(name)+1);
278 panic("irqenable: malloc name");
279 strcpy(v->name, name);
291 * disable an irq interrupt
294 irqdisable(int irq, void (*f)(Ureg*, void*), void* a, char *name)
298 if(irq >= nelem(vctl) || irq < 0)
299 panic("irqdisable irq %d", irq);
302 for(vp = &vctl[irq]; v = *vp; vp = &v->next)
303 if (v->f == f && v->a == a && strcmp(v->name, name) == 0){
304 print("irqdisable: remove %s\n", name);
311 print("irqdisable: irq %d, name %s not enabled\n", irq, name);
312 if(vctl[irq] == nil){
313 print("irqdisable: clear icmr bit %d\n", irq);
322 * called by trap to handle access faults
325 faultarm(Ureg *ureg, uintptr va, int user, int read)
332 panic("fault: nil up in faultarm, accessing %#p", va);
334 insyscall = up->insyscall;
340 panic("fault: kernel accessing %#p", va);
342 /* don't dump registers; programs suicide all the time */
343 snprint(buf, sizeof buf, "sys: trap: fault %s va=%#p",
344 read? "read": "write", va);
345 postnote(up, 1, buf, NDebug);
347 up->insyscall = insyscall;
351 * called by trap to handle interrupts.
352 * returns true iff a clock interrupt, thus maybe reschedule.
358 uint irqno, handled, t, ticks = perfticks();
359 Intrregs *ip = (Intrregs *)PHYSINTC;
361 static int nesting, lastirq = -1;
364 irqno = ip->sir_irq & Activeirq;
366 if (irqno >= 37 && irqno <= 47) /* this is a clock intr? */
367 m->inclockintr++; /* yes, count nesting */
370 if (irqno >= nelem(vctl)) {
371 iprint("trap: irq %d >= # vectors (%d)\n", irqno, nelem(vctl));
372 ip->control = Newirqagr; /* dismiss interrupt */
377 for(v = vctl[irqno]; v != nil; v = v->next)
380 panic("trap: pl0 before trap handler for %s",
384 panic("trap: %s lowered pl", v->name);
385 // splhi(); /* in case v->f lowered pl */
389 iprint("unexpected interrupt: irq %d", irqno);
402 if(irqno < nelem(vctl)) {
404 iprint(", now masked");
411 ninterruptticks += ticks-t;
413 ninterruptticks += t-ticks;
414 ip->control = Newirqagr; /* dismiss interrupt */
418 clockintr = m->inclockintr == 1;
419 if (irqno >= 37 && irqno <= 47)
425 * returns 1 if the instruction writes memory, 0 otherwise
428 writetomem(ulong inst)
430 /* swap always write memory */
431 if((inst & 0x0FC00000) == 0x01000000)
434 /* loads and stores are distinguished by bit 20 */
441 void prgpmcerrs(void);
444 * here on all exceptions other than syscall (SWI)
449 int clockintr, user, x, rv, rem;
454 splhi(); /* paranoia */
456 rem = ((char*)ureg)-up->kstack;
458 rem = ((char*)ureg)-((char*)m+sizeof(Mach));
460 iprint("trap: %d stack bytes left, up %#p ureg %#p at pc %#lux\n",
461 rem, up, ureg, ureg->pc);
464 panic("trap: %d stack bytes left, up %#p ureg %#p at pc %#lux",
465 rem, up, ureg, ureg->pc);
468 user = (ureg->psr & PsrMask) == PsrMusr;
475 * All interrupts/exceptions should be resumed at ureg->pc-4,
476 * except for Data Abort which resumes at ureg->pc-8.
478 if(ureg->type == (PsrMabt+1))
483 clockintr = 0; /* if set, may call sched() before return */
486 panic("unknown trap; type %#lux, psr mode %#lux", ureg->type,
487 ureg->psr & PsrMask);
491 clockintr = irq(ureg);
494 case PsrMabt: /* prefetch fault */
497 fsr = (x>>7) & 0x8 | x & 0x7;
499 case 0x02: /* instruction debug event (BKPT) */
501 snprint(buf, sizeof buf, "sys: breakpoint");
502 postnote(up, 1, buf, NDebug);
504 iprint("kernel bkpt: pc %#lux inst %#ux\n",
505 ureg->pc, *(u32int*)ureg->pc);
506 panic("kernel bkpt");
510 faultarm(ureg, ureg->pc, user, 1);
514 case PsrMabt+1: /* data fault */
517 inst = *(ulong*)(ureg->pc);
518 /* bits 12 and 10 have to be concatenated with status */
520 fsr = (x>>7) & 0x20 | (x>>6) & 0x10 | x & 0xf;
521 if (probing && !user) {
523 panic("trap: recursive probe %#lux", va);
524 ureg->pc += 4; /* continue at next instruction */
529 case 0xa: /* ? was under external abort */
530 panic("unknown data fault, 6b fsr %#lux", fsr);
533 panic("vector exception at %#lux", ureg->pc);
535 case 0x1: /* alignment fault */
536 case 0x3: /* access flag fault (section) */
538 snprint(buf, sizeof buf,
539 "sys: alignment: pc %#lux va %#p\n",
541 postnote(up, 1, buf, NDebug);
543 panic("kernel alignment: pc %#lux va %#p", ureg->pc, va);
546 panic("terminal exception at %#lux", ureg->pc);
548 case 0x4: /* icache maint fault */
549 case 0x6: /* access flag fault (page) */
550 case 0x8: /* precise external abort, non-xlat'n */
552 case 0xc: /* l1 translation, precise ext. abort */
554 case 0xe: /* l2 translation, precise ext. abort */
556 case 0x16: /* imprecise ext. abort, non-xlt'n */
558 panic("external abort %#lux pc %#lux addr %#p",
561 case 0x1c: /* l1 translation, precise parity err */
562 case 0x1e: /* l2 translation, precise parity err */
563 case 0x18: /* imprecise parity or ecc err */
564 panic("translation parity error %#lux pc %#lux addr %#p",
567 case 0x5: /* translation fault, no section entry */
568 case 0x7: /* translation fault, no page entry */
569 faultarm(ureg, va, user, !writetomem(inst));
573 /* domain fault, accessing something we shouldn't */
575 snprint(buf, sizeof buf,
576 "sys: access violation: pc %#lux va %#p\n",
578 postnote(up, 1, buf, NDebug);
580 panic("kernel access violation: pc %#lux va %#p",
585 /* permission error, copy on write or real permission error */
586 faultarm(ureg, va, user, !writetomem(inst));
590 case PsrMund: /* undefined instruction */
592 /* look for floating point instructions to interpret */
598 snprint(buf, sizeof buf,
599 "undefined instruction: pc %#lux\n",
601 postnote(up, 1, buf, NDebug);
605 iprint("rounding fault pc %#lux down to word\n",
609 iprint("undefined instruction: pc %#lux inst %#ux\n",
610 ureg->pc, ((u32int*)ureg->pc)[-2]);
611 panic("undefined instruction");
617 /* delaysched set because we held a lock or because our quantum ended */
618 if(up && up->delaysched && clockintr){
620 sched(); /* can cause more traps */
625 if(up->procctl || up->nnote)
632 * Fill in enough of Ureg to get a stack trace, and call a function.
633 * Used by debugging interface rdb.
636 callwithureg(void (*fn)(Ureg*))
640 ureg.pc = getcallerpc(&fn);
641 ureg.sp = PTR2UINT(&fn);
646 dumpstackwithureg(Ureg *ureg)
649 uintptr l, v, i, estack;
653 if((s = getconf("*nodumpstack")) != nil && strcmp(s, "0") != 0){
654 iprint("dumpstack disabled\n");
657 iprint("dumpstack\n");
660 x += iprint("ktrace /kernel/path %#.8lux %#.8lux %#.8lux # pc, sp, link\n",
661 ureg->pc, ureg->sp, ureg->r14);
665 && (uintptr)&l >= (uintptr)up->kstack
666 && (uintptr)&l <= (uintptr)up->kstack+KSTACK)
667 estack = (uintptr)up->kstack+KSTACK;
668 else if((uintptr)&l >= (uintptr)m->stack
669 && (uintptr)&l <= (uintptr)m+MACHSIZE)
670 estack = (uintptr)m+MACHSIZE;
673 x += iprint("estackx %p\n", estack);
675 for(l = (uintptr)&l; l < estack; l += sizeof(uintptr)){
677 if((KTZERO < v && v < (uintptr)etext) || estack-l < 32){
678 x += iprint("%.8p ", v);
695 callwithureg(dumpstackwithureg);
699 * dump system control coprocessor registers
704 iprint("0:\t%#8.8ux id\n", cpidget());
705 iprint("\t%8.8#ux ct\n", cpctget());
706 iprint("1:\t%#8.8ux control\n", controlget());
707 iprint("2:\t%#8.8ux ttb\n", ttbget());
708 iprint("3:\t%#8.8ux dac\n", dacget());
709 iprint("4:\t(reserved)\n");
710 iprint("5:\t%#8.8ux fsr\n", fsrget());
711 iprint("6:\t%#8.8ux far\n", farget());
712 iprint("7:\twrite-only cache\n");
713 iprint("8:\twrite-only tlb\n");
714 iprint("13:\t%#8.8ux pid\n", pidget());
719 * dump general registers
725 iprint("cpu%d: registers for %s %lud\n",
726 m->machno, up->text, up->pid);
728 iprint("cpu%d: registers for kernel\n", m->machno);
731 iprint("%#8.8lux\tr0\n", ureg->r0);
732 iprint("%#8.8lux\tr1\n", ureg->r1);
733 iprint("%#8.8lux\tr2\n", ureg->r2);
735 iprint("%#8.8lux\tr3\n", ureg->r3);
736 iprint("%#8.8lux\tr4\n", ureg->r4);
737 iprint("%#8.8lux\tr5\n", ureg->r5);
739 iprint("%#8.8lux\tr6\n", ureg->r6);
740 iprint("%#8.8lux\tr7\n", ureg->r7);
741 iprint("%#8.8lux\tr8\n", ureg->r8);
743 iprint("%#8.8lux\tr9 (up)\n", ureg->r9);
744 iprint("%#8.8lux\tr10 (m)\n", ureg->r10);
745 iprint("%#8.8lux\tr11 (loader temporary)\n", ureg->r11);
746 iprint("%#8.8lux\tr12 (SB)\n", ureg->r12);
748 iprint("%#8.8lux\tr13 (sp)\n", ureg->r13);
749 iprint("%#8.8lux\tr14 (link)\n", ureg->r14);
750 iprint("%#8.8lux\tr15 (pc)\n", ureg->pc);
752 iprint("%10.10lud\ttype\n", ureg->type);
753 iprint("%#8.8lux\tpsr\n", ureg->psr);
765 probeaddr(uintptr addr)
775 v = *(ulong *)addr; /* this may cause a fault */