800 lines · 16.7 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. */ /* * 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(" (I⁲C)");			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.