📄 trap.c
字号:
#include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "io.h"#include "ureg.h"#include "../port/error.h"#include "tos.h"Intrregs *intrregs;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[32];static Vctl *gpiovctl[27];static int gpioirqref[12];/* * Layout at virtual address 0. */typedef struct Vpage0 { void (*vectors[8])(void); ulong vtable[8];} Vpage0;Vpage0 *vpage0;static int irq(Ureg*);static void gpiointr(Ureg*, void*);/* recover state after power suspend * NB: to help debugging bad suspend code, * I changed some prints below to iprints, * to avoid deadlocks when a panic is being * issued during the suspend/resume handler. */voidtrapresume(void){ vpage0 = (Vpage0*)EVECTORS; memmove(vpage0->vectors, vectors, sizeof(vpage0->vectors)); memmove(vpage0->vtable, vtable, sizeof(vpage0->vtable)); wbflush(); mappedIvecEnable();}/* * set up for exceptions */voidtrapinit(void){ /* set up the exception vectors */ vpage0 = (Vpage0*)EVECTORS; memmove(vpage0->vectors, vectors, sizeof(vpage0->vectors)); memmove(vpage0->vtable, vtable, sizeof(vpage0->vtable)); wbflush(); /* use exception vectors at 0xFFFF0000 */ mappedIvecEnable(); /* set up the stacks for the interrupt modes */ setr13(PsrMfiq, m->sfiq); setr13(PsrMirq, m->sirq); setr13(PsrMabt, m->sabt); setr13(PsrMund, m->sund); /* map in interrupt registers */ intrregs = mapspecial(INTRREGS, sizeof(*intrregs)); /* make all interrupts IRQ (i.e. not FIQ) and disable all interrupts */ intrregs->iclr = 0; intrregs->icmr = 0; /* turn off all gpio interrupts */ gpioregs->rising = 0; gpioregs->falling = 0; gpioregs->edgestatus = gpioregs->edgestatus; /* allow all enabled interrupts to take processor out of sleep mode */ intrregs->iccr = 0;}voidtrapdump(char *tag){ iprint("%s: icip %lux icmr %lux iclr %lux iccr %lux icfp %lux\n", tag, intrregs->icip, intrregs->icmr, intrregs->iclr, intrregs->iccr, intrregs->icfp);}voidwarnregs(Ureg *ur, char *tag){ char buf[1024]; char *e = buf+sizeof(buf); char *p; p = seprint(buf, e, "%s:\n", tag); p = seprint(p, e, "type 0x%.8lux psr 0x%.8lux pc 0x%.8lux\n", ur->type, ur->psr, ur->pc); p = seprint(p, e, "r0 0x%.8lux r1 0x%.8lux r2 0x%.8lux r3 0x%.8lux\n", ur->r0, ur->r1, ur->r2, ur->r3); p = seprint(p, e, "r4 0x%.8lux r5 0x%.8lux r6 0x%.8lux r7 0x%.8lux\n", ur->r4, ur->r5, ur->r6, ur->r7); p = seprint(p, e, "r8 0x%.8lux r9 0x%.8lux r10 0x%.8lux r11 0x%.8lux\n", ur->r8, ur->r9, ur->r10, ur->r11); seprint(p, e, "r12 0x%.8lux r13 0x%.8lux r14 0x%.8lux\n", ur->r12, ur->r13, ur->r14); iprint("%s", buf);}/* * enable an irq interrupt */static voidirqenable(int irq, IntrHandler *f, void* a, char *name){ Vctl *v; if(irq >= nelem(vctl) || irq < 0) panic("intrenable"); v = malloc(sizeof(Vctl)); v->f = f; v->a = a; v->name = xalloc(strlen(name)+1); strcpy(v->name, name); lock(&vctllock); v->next = vctl[irq]; vctl[irq] = v; intrregs->icmr |= 1<<irq; unlock(&vctllock);}/* * disable an irq interrupt */static voidirqdisable(int irq, IntrHandler *f, void* a, char *name){ Vctl **vp, *v; if(irq >= nelem(vctl) || irq < 0) panic("intrdisable"); 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); intrregs->icmr &= ~(1<<irq); } unlock(&vctllock);}/* * enable an interrupt */voidintrenable(int type, int which, IntrHandler *f, void* a, char *name){ int irq; Vctl *v; if(type == IRQ){ irqenable(which, f, a, name); return; } /* from here down, it must be a GPIO edge interrupt */ irq = which; if(which >= nelem(gpiovctl) || which < 0) panic("intrenable"); if(which > 11) irq = 11; /* the pin had better be configured as input */ if((1<<which) & gpioregs->direction) panic("intrenable of output pin %d", which); /* create a second level vctl for the gpio edge interrupt */ v = malloc(sizeof(Vctl)); v->f = f; v->a = a; v->name = xalloc(strlen(name)+1); strcpy(v->name, name); lock(&vctllock); v->next = gpiovctl[which]; gpiovctl[which] = v; /* set edge register to enable interrupt */ switch(type){ case GPIOboth: gpioregs->rising |= 1<<which; gpioregs->falling |= 1<<which; break; case GPIOfalling: gpioregs->falling |= 1<<which; break; case GPIOrising: gpioregs->rising |= 1<<which; break; } unlock(&vctllock); /* point the irq to the gpio interrupt handler */ if(gpioirqref[irq]++ == 0) irqenable(irq, gpiointr, nil, "gpio edge");}/* * disable an interrupt */voidintrdisable(int type, int which, IntrHandler *f, void* a, char *name){ int irq; Vctl **vp, *v; if(type == IRQ){ irqdisable(which, f, a, name); return; } /* from here down, it must be a GPIO edge interrupt */ irq = which; if(which >= nelem(gpiovctl) || which < 0) panic("intrdisable"); if(which > 11) irq = 11; lock(&vctllock); for(vp = &gpiovctl[which]; v = *vp; vp = &v->next) if (v->f == f && v->a == a && strcmp(v->name, name) == 0){ break; } if (gpiovctl[which] == nil){ /* set edge register to enable interrupt */ switch(type){ case GPIOboth: print("intrdisable: gpio-rising+falling clear bit %d\n", which); gpioregs->rising &= ~(1<<which); gpioregs->falling &= ~(1<<which); break; case GPIOfalling: print("intrdisable: gpio-falling clear bit %d\n", which); gpioregs->falling &= ~(1<<which); break; case GPIOrising: print("intrdisable: gpio-rising clear bit %d\n", which); gpioregs->rising &= ~(1<<which); break; } } if (v) { print("intrdisable: removing %s\n", name); *vp = v->next; }else print("intrdisable: which %d, name %s not enabled\n", which, name); unlock(&vctllock); /* disable the gpio interrupt handler if necessary */ if(--gpioirqref[irq] == 0){ print("intrdisable: inrqdisable gpiointr\n"); irqdisable(irq, gpiointr, nil, "gpio edge"); } free(v);}/* * called by trap to handle access faults */static voidfaultarm(Ureg *ureg, ulong va, int user, int read){ int n, insyscall; char buf[ERRMAX]; if (up == nil) { warnregs(ureg, "kernel fault"); panic("fault: nil up in faultarm, accessing 0x%lux\n", va); } insyscall = up->insyscall; up->insyscall = 1; n = fault(va, read); if(n < 0){ if(!user){ warnregs(ureg, "kernel fault"); panic("fault: kernel accessing 0x%lux\n", va); }// warnregs(ureg, "user fault"); sprint(buf, "sys: trap: fault %s va=0x%lux", read ? "read" : "write", va); postnote(up, 1, buf, NDebug); } up->insyscall = insyscall;}/* * 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;}/* * here on all exceptions other than syscall (SWI) */voidtrap(Ureg *ureg){ ulong inst; int clockintr, user, x, rv; ulong va, fsr; char buf[ERRMAX]; int rem; if(up != nil) rem = ((char*)ureg)-up->kstack; else rem = ((char*)ureg)-((char*)(MACHADDR+sizeof(Mach))); if(rem < 256) { dumpstack(); panic("trap %d bytes remaining, up = 0x%lux, ureg = 0x%lux, at pc 0x%lux", rem, up, ureg, ureg->pc); } user = (ureg->psr & PsrMask) == PsrMusr; /* * 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; switch(ureg->type){ default: panic("unknown trap"); break; case PsrMirq: clockintr = irq(ureg); break; case PsrMabt: /* prefetch fault */ faultarm(ureg, ureg->pc, user, 1); break; case PsrMabt+1: /* data fault */ va = getfar(); inst = *(ulong*)(ureg->pc); fsr = getfsr() & 0xf; switch(fsr){ case 0x0: panic("vector exception at %lux\n", ureg->pc); break; case 0x1: case 0x3: if(user){ snprint(buf, sizeof(buf), "sys: alignment: pc 0x%lux va 0x%lux\n", ureg->pc, va); postnote(up, 1, buf, NDebug); } else panic("kernel alignment: pc 0x%lux va 0x%lux", ureg->pc, va); break; case 0x2: panic("terminal exception at %lux\n", ureg->pc); break; case 0x4: case 0x6: case 0x8: case 0xa: case 0xc: case 0xe: panic("external abort 0x%lux pc 0x%lux addr 0x%lux\n", fsr, ureg->pc, va); break; case 0x5: case 0x7: /* translation fault, i.e., no pte entry */ faultarm(ureg, va, user, !writetomem(inst)); break; case 0x9: case 0xb: /* domain fault, accessing something we shouldn't */ if(user){ sprint(buf, "sys: access violation: pc 0x%lux va 0x%lux\n", ureg->pc, va); postnote(up, 1, buf, NDebug); } else panic("kernel access violation: pc 0x%lux va 0x%lux\n", ureg->pc, va); break; case 0xd: case 0xf: /* permission error, copy on write or real permission error */ faultarm(ureg, va, user, !writetomem(inst)); break; } break; case PsrMund: /* undefined instruction */ if (user) { /* look for floating point instructions to interpret */ x = spllo(); rv = fpiarm(ureg); splx(x); if (rv == 0) { sprint(buf, "undefined instruction: pc 0x%lux\n", ureg->pc); postnote(up, 1, buf, NDebug); } }else{ iprint("undefined instruction: pc=0x%lux, inst=0x%lux, 0x%lux, 0x%lux, 0x%lux, 0x%lux\n", ureg->pc, ((ulong*)ureg->pc)[-2], ((ulong*)ureg->pc)[-1], ((ulong*)ureg->pc)[0], ((ulong*)ureg->pc)[1], ((ulong*)ureg->pc)[2]); panic("undefined instruction"); } break; } splhi(); /* delaysched set because we held a lock or because our quantum ended */ if(up && up->delaysched && clockintr){ sched(); splhi(); } if(user){ if(up->procctl || up->nnote) notify(ureg); kexit(ureg); }}/* * here on irq's */static intirq(Ureg *ur){ ulong va;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -