/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ /* * 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 intirqinuse(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 voidintcmask(uint irq){ Intrregs *ip = (Intrregs *)PHYSINTC; ip->bits[irq / Bi2long].mir_set = 1 << (irq % Bi2long); coherence();} static voidintcunmask(uint irq){ Intrregs *ip = (Intrregs *)PHYSINTC; ip->bits[irq / Bi2long].mir_clear = 1 << (irq % Bi2long); coherence();} static voidintcmaskall(void){ int i; Intrregs *ip = (Intrregs *)PHYSINTC; for (i = 0; i < 3; i++) ip->bits[i].mir_set = ~0; coherence();} static voidintcunmaskall(void){ int i; Intrregs *ip = (Intrregs *)PHYSINTC; for (i = 0; i < 3; i++) ip->bits[i].mir_clear = ~0; coherence();} static voidintcinvertall(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 voidintrsave(ulong buf[3]){ int i; Intrregs *ip = (Intrregs *)PHYSINTC; for (i = 0; i < nelem(buf); i++) buf[i] = ip->bits[i].mir; coherence();} static voidintrrestore(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 */voidtrapinit(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();} voidintrsoff(void){ Intrregs *ip = (Intrregs *)PHYSINTC; intcmaskall(); ip->control = Newirqagr; /* dismiss interrupt */ coherence();} /* * enable an irq interrupt */intirqenable(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 */intirqdisable(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 voidfaultarm(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 intirq(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 */intwritetomem(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) */voidtrap(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);Lines 1–500 of 800. Load more
/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ /* * 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);