ref: 4ad59914e8a570d869f4e66540578cc3bdbc04eb
dir: /sys/src/9/omap4/trap.c/
#include "u.h" #include "ureg.h" #include "../port/lib.h" #include "../port/error.h" #include "../port/systab.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "io.h" #include "arm.h" #include "tos.h" extern uchar *periph; ulong *intc, *intd; void (*irqhandler[MAXMACH][256])(Ureg*); static char *trapname[] = { "reset", /* wtf */ "undefined instruction", "supervisor call", "prefetch abort", "data abort", "unknown trap", "IRQ", "FIQ", }; void trapinit(void) { extern void _dataabort(), _undefined(), _prefabort(), _irq(), _fiq(), _reset(), _wtftrap(), _syscall(); int i; ulong *trapv; trapv = (ulong *) 0xFFFF0000; for(i = 0; i < 8; i++) trapv[i] = 0xE59FF018; trapv[8] = (ulong) _reset; trapv[9] = (ulong) _undefined; trapv[10] = (ulong) _syscall; trapv[11] = (ulong) _prefabort; trapv[12] = (ulong) _dataabort; trapv[13] = (ulong) _wtftrap; trapv[14] = (ulong) _irq; trapv[15] = (ulong) _fiq; intc = (ulong *) (periph + 0x100); intc[1] = 0; intc[0] |= 1; intd = (ulong *) (periph + 0x1000); intd[0] |= 1; } void intenable(int i, void (*fn)(Ureg *)) { intd[0x40 + (i / 32)] = 1 << (i % 32); irqhandler[m->machno][i] = fn; } void irqroute(int i, void (*fn)(Ureg *)) { ulong x, y, z; intenable(32 + i, fn); x = intd[0x208 + i/4]; y = 0xFF << ((i%4) * 8); z = 1 << (m->machno + (i%4) * 8); x = (x & ~y) | z; intd[0x208 + i/4] = x; // intd[0x200/4 + (i+32)/32] = 1 << (i % 32); } void faultarm(Ureg *ureg) { ulong addr, sr; int user, n, read, nsys; extern ulong getdfsr(void), getifsr(void), getdfar(void), getifar(void); char buf[ERRMAX]; user = (ureg->psr & PsrMask) == PsrMusr; read = 1; if(ureg->type == 3){ sr = getifsr(); addr = getifar(); }else{ sr = getdfsr(); addr = getdfar(); if(sr & (1<<11)) read = 0; } if(!user && addr >= KZERO){ kernel: serialoq = nil; printureg(ureg); panic("kernel fault: addr=%#.8lux pc=%#.8lux lr=%#.8lux sr=%#.8lux", addr, ureg->pc, ureg->r14, sr); } if(up == nil){ serialoq = nil; printureg(ureg); panic("%s fault: up=nil addr=%#.8lux pc=%#.8lux sr=%#.8lux", user ? "user" : "kernel", addr, ureg->pc, sr); } nsys = up->insyscall; up->insyscall = 1; n = fault(addr, read); if(n < 0){ if(!user) goto kernel; spllo(); sprint(buf, "sys: trap: fault %s addr=0x%lux", read ? "read" : "write", addr); postnote(up, 1, buf, NDebug); } up->insyscall = nsys; } void updatetos(void) { Tos *tos; uvlong t; tos = (Tos*) (USTKTOP - sizeof(Tos)); cycles(&t); tos->kcycles += t - up->kentry; tos->pcycles = up->pcycles; tos->pid = up->pid; } void trap(Ureg *ureg) { int user, intn, x; char buf[ERRMAX]; user = (ureg->psr & PsrMask) == PsrMusr; if(user){ fillureguser(ureg); up->dbgreg = ureg; cycles(&up->kentry); } switch(ureg->type){ case 3: case 4: faultarm(ureg); break; case 6: x = intc[3]; intn = x & 0x3FF; if(irqhandler[m->machno][intn] != nil) irqhandler[m->machno][intn](ureg); intc[4] = x; if(intn != 29) preempted(); if(up && up->delaysched && (intn == 29)){ sched(); splhi(); } break; default: if(user){ spllo(); sprint("sys: trap: %s", trapname[ureg->type]); postnote(up, 1, buf, NDebug); }else{ serialoq = nil; printureg(ureg); panic("%s", trapname[ureg->type]); } } if(user){ updatetos(); up->dbgreg = nil; } } void syscall(Ureg *ureg) { int scall, ret; ulong s, sp; char *e; m->syscall++; up->insyscall = 1; up->pc = ureg->pc; up->dbgreg = ureg; cycles(&up->kentry); if(up->procctl == Proc_tracesyscall){ up->procctl = Proc_stopme; procctl(up); } scall = ureg->r0; up->scallnr = scall; // print("%s\n", sysctab[scall]); spllo(); sp = ureg->sp; up->nerrlab = 0; ret = -1; if(!waserror()){ if(scall >= nsyscall){ postnote(up, 1, "sys: bad syscall", NDebug); error(Ebadarg); } validaddr(sp, sizeof(Sargs) + BY2WD, 0); up->s = *((Sargs*)(sp + BY2WD)); up->psstate = sysctab[scall]; ret = systab[scall](up->s.args); poperror(); }else{ e = up->syserrstr; up->syserrstr = up->errstr; up->errstr = e; } if(up->nerrlab != 0) panic("error stack"); ureg->r0 = ret; if(up->procctl == Proc_tracesyscall){ up->procctl = Proc_stopme; s = splhi(); procctl(up); splx(s); } up->insyscall = 0; up->psstate = nil; splhi(); if(up->delaysched){ sched(); splhi(); } updatetos(); up->dbgreg = nil; }