701 lines · 14.0 KB · C
RawDownload
/*  * 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. */ /* * sheevaplug traps, exceptions, interrupts, system calls. */#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 "arm.h" enum {	Debug = 0, 	Ntimevec = 20,			/* # of time buckets for each intr */	Nvecs = 256,}; extern int notify(Ureg*); extern int ldrexvalid; 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[32]; uvlong ninterrupt;uvlong ninterruptticks;ulong intrtimes[Nvecs][Ntimevec]; typedef struct Handler Handler;struct Handler {	void	(*r)(Ureg*, void*);	void	*a;	char	name[KNAMELEN];}; static Handler irqlo[32];static Handler irqhi[32];static Handler irqbridge[32];static Lock irqlock;static int probing, trapped; typedef struct Irq Irq;struct Irq {	ulong	*irq;	ulong	*irqmask;	Handler	*irqvec;	int	nirqvec;	char	*name;};/* irq and irqmask are filled in by trapinit */static Irq irqs[] = {[Irqlo]		{nil, nil, irqlo,	nelem(irqlo),	"lo"},[Irqhi]		{nil, nil, irqhi,	nelem(irqhi),	"hi"},[Irqbridge]	{nil, nil, irqbridge,	nelem(irqbridge), "bridge"},}; /* *  keep histogram of interrupt service times */voidintrtime(Mach*, int vno){	ulong diff, x; 	if (m == nil)		return;	x = perfticks();	diff = x - m->perf.intrts;	m->perf.intrts = x; 	m->perf.inintr += diff;	if(up == nil && m->perf.inidle > diff)		m->perf.inidle -= diff; 	if (m->cpuhz == 0)			/* not set yet? */		return;	diff /= (m->cpuhz/1000000)*100;		/* quantum = 100µsec */	if(diff >= Ntimevec)		diff = Ntimevec-1;	assert(vno >= 0 && vno < Nvecs);	intrtimes[vno][diff]++;} voidintrfmtcounts(char *s, char *se){	USED(s, se);} static voiddumpcounts(void){} voidintrclear(int sort, int v){	*irqs[sort].irq = ~(1 << v);} voidintrmask(int sort, int v){	*irqs[sort].irqmask &= ~(1 << v);} voidintrunmask(int sort, int v){	*irqs[sort].irqmask |= 1 << v;} static voidmaskallints(void){	CpucsReg *cpu = (CpucsReg *)soc.cpu;	IntrReg *intr; 	/* no fiq or ep in use */	intr = (IntrReg *)soc.intr;	intr->lo.irqmask = 0;	intr->hi.irqmask = 0;	cpu->irqmask = 0;	coherence();} voidintrset(Handler *h, void (*f)(Ureg*, void*), void *a, char *name){	if(h->r != nil) {//		iprint("duplicate irq: %s (%#p)\n", h->name, h->r);		return;	}	h->r = f;	h->a = a;	strncpy(h->name, name, KNAMELEN-1);	h->name[KNAMELEN-1] = 0;} voidintrunset(Handler *h){	h->r = nil;	h->a = nil;	h->name[0] = 0;} voidintrdel(Handler *h, void (*f)(Ureg*, void*), void *a, char *name){	if(h->r != f || h->a != a || strcmp(h->name, name) != 0)		return;	intrunset(h);} voidintrenable(int sort, int v, void (*f)(Ureg*, void*), void *a, char *name){//iprint("enabling intr %d vec %d for %s\n", sort, v, name);	ilock(&irqlock);	intrset(&irqs[sort].irqvec[v], f, a, name);	intrunmask(sort, v);	iunlock(&irqlock);} voidintrdisable(int sort, int v, void (*f)(Ureg*, void*), void* a, char *name){	ilock(&irqlock);	intrdel(&irqs[sort].irqvec[v], f, a, name);	intrmask(sort, v);	iunlock(&irqlock);} /* *  called by trap to handle interrupts */static voidintrs(Ureg *ur, int sort){	int i, s;	ulong ibits;	Handler *h;	Irq irq; 	assert(sort >= 0 && sort < nelem(irqs));	irq = irqs[sort];	ibits = *irq.irq;	ibits &= *irq.irqmask; 	for(i = 0; i < irq.nirqvec && ibits; i++)		if(ibits & (1<<i)){			h = &irq.irqvec[i];			if(h->r != nil){				h->r(ur, h->a);				splhi();				intrtime(m, sort*32 + i);				if (sort == Irqbridge && i == IRQcputimer0)					m->inclockintr = 1;				ibits &= ~(1<<i);			}		}	if(ibits != 0) {		iprint("spurious irq%s interrupt: %8.8lux\n", irq.name, ibits);		s = splfhi();		*irq.irq &= ibits;		*irq.irqmask &= ~ibits;		splx(s);	}} voidintrhi(Ureg *ureg, void*){	intrs(ureg, Irqhi);} voidintrbridge(Ureg *ureg, void*){	intrs(ureg, Irqbridge);	intrclear(Irqlo, IRQ0bridge);} voidtrapinit(void){	int i;	CpucsReg *cpu;	IntrReg *intr;	Vectorpage *page0 = (Vectorpage*)HVECTORS; 	intr = (IntrReg *)soc.intr;	cpu = (CpucsReg *)soc.cpu;	irqs[Irqlo].irq = &intr->lo.irq;	irqs[Irqlo].irqmask = &intr->lo.irqmask;	irqs[Irqhi].irq = &intr->hi.irq;	irqs[Irqhi].irqmask = &intr->hi.irqmask;	irqs[Irqbridge].irq = &cpu->irq;	irqs[Irqbridge].irqmask = &cpu->irqmask;	coherence(); 	setr13(PsrMfiq, m->fiqstack + nelem(m->fiqstack));	setr13(PsrMirq, m->irqstack + nelem(m->irqstack));	setr13(PsrMabt, m->abtstack + nelem(m->abtstack));	setr13(PsrMund, m->undstack + nelem(m->undstack)); 	memmove(page0->vectors, vectors, sizeof page0->vectors);	memmove(page0->vtable,  vtable,  sizeof page0->vtable);	cacheuwbinv();	l2cacheuwbinv(); 	cpu->cpucfg &= ~Cfgvecinithi; 	for(i = 0; i < nelem(irqlo); i++)		intrunset(&irqlo[i]);	for(i = 0; i < nelem(irqhi); i++)		intrunset(&irqhi[i]);	for(i = 0; i < nelem(irqbridge); i++)		intrunset(&irqbridge[i]); 	/* disable all interrupts */	intr->lo.fiqmask = intr->hi.fiqmask = 0;	intr->lo.irqmask = intr->hi.irqmask = 0;	intr->lo.epmask =  intr->hi.epmask = 0;	cpu->irqmask = 0;	coherence(); 	/* clear interrupts */	intr->lo.irq = intr->hi.irq = ~0;	cpu->irq = ~0;	coherence(); 	intrenable(Irqlo, IRQ0hisum, intrhi, nil, "hi");	intrenable(Irqlo, IRQ0bridge, intrbridge, nil, "bridge"); 	/* enable watchdog & access-error interrupts */	cpu->irqmask |= 1 << IRQcputimerwd | 1 << IRQaccesserr;	coherence();} static char *trapnames[PsrMask+1] = {	[ PsrMusr ] "user mode",	[ PsrMfiq ] "fiq interrupt",	[ PsrMirq ] "irq interrupt",	[ PsrMsvc ] "svc/swi exception",	[ PsrMabt ] "prefetch abort/data abort",	[ PsrMabt+1 ] "data abort",	[ PsrMund ] "undefined instruction",	[ PsrMsys ] "sys trap",}; static char *trapname(int psr){	char *s; 	s = trapnames[psr & PsrMask];	if(s == nil)		s = "unknown trap number in psr";	return s;} /* this is quite helpful during mmu and cache debugging */static voidckfaultstuck(uintptr va){	static int cnt, lastpid;	static uintptr lastva; 	if (va == lastva && up->pid == lastpid) {		++cnt;		if (cnt >= 2)			/* fault() isn't fixing the underlying cause */			panic("fault: %d consecutive faults for va %#p",				cnt+1, va);	} else {		cnt = 0;		lastva = va;		lastpid = up->pid;	}} /* *  called by trap to handle access faults */static voidfaultarm(Ureg *ureg, uintptr va, int user, int read){	int n, insyscall;	char buf[ERRMAX];	static int cnt, lastpid;	static ulong lastva; 	if(up == nil) {		dumpregs(ureg);		panic("fault: nil up in faultarm, accessing %#p", va);	}	insyscall = up->insyscall;	up->insyscall = 1;	if (Debug)		ckfaultstuck(va); 	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;} /* *  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;} voidtrap(Ureg *ureg){	int user, x, rv, rem;	ulong inst;	u32int fsr;	uintptr va;	char buf[ERRMAX]; 	if(up != nil)		rem = (char*)ureg - up->kstack;	else		rem = (char*)ureg - ((char*)m + sizeof(Mach));	if(rem < 256) {		dumpstack();		panic("trap %d bytes remaining, 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);	} 	if(ureg->type == PsrMabt+1)		ureg->pc -= 8;	else		ureg->pc -= 4; 	m->inclockintr = 0;	switch(ureg->type) {	default:		panic("unknown trap %ld", ureg->type);		break;	case PsrMirq:		ldrexvalid = 0;		// splflo();		/* allow fast interrupts */		intrs(ureg, Irqlo);		m->intr++;		break;	case PsrMabt:			/* prefetch fault */		ldrexvalid = 0;		faultarm(ureg, ureg->pc, user, 1);		if(up->nnote == 0 &&		   (*(u32int*)ureg->pc & ~(0xF<<28)) == 0x01200070)			postnote(up, 1, "sys: breakpoint", NDebug);		break;	case PsrMabt+1:			/* data fault */		ldrexvalid = 0;		va = farget();		inst = *(ulong*)(ureg->pc);		fsr = fsrget() & 0xf;		if (probing && !user) {			if (trapped++ > 0)				panic("trap: recursive probe %#lux", va);			ureg->pc += 4;	/* continue at next instruction */			break;		}		switch(fsr){		case 0x0:			panic("vector exception at %#lux", ureg->pc);			break;		case 0x1:		case 0x3:			if(user){				snprint(buf, sizeof buf,					"sys: alignment: pc %#lux va %#p\n",					ureg->pc, va);				postnote(up, 1, buf, NDebug);			} else				panic("kernel alignment: pc %#lux va %#p", ureg->pc, va);			break;		case 0x2:			panic("terminal exception at %#lux", ureg->pc);			break;		case 0x4:		case 0x6:		case 0x8:		case 0xa:		case 0xc:		case 0xe:			panic("external abort %#ux pc %#lux addr %#px",				fsr, ureg->pc, va);			break;		case 0x5:		/* translation fault, no section entry */		case 0x7:		/* translation fault, no page entry */			faultarm(ureg, va, user, !writetomem(inst));			break;		case 0x9:		case 0xb:			/* domain fault, accessing something we shouldn't */			if(user){				snprint(buf, sizeof buf,					"sys: access violation: pc %#lux va %#p\n",					ureg->pc, va);				postnote(up, 1, buf, NDebug);			} else				panic("kernel access violation: pc %#lux va %#p",					ureg->pc, va);			break;		case 0xd:		case 0xf:			/* permission error, copy on write or real permission error */			faultarm(ureg, va, user, !writetomem(inst));

Lines 1–500 of 701.