1084 lines · 21.8 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. */ /* * traps, exceptions, faults and interrupts on ar7161 */#include	"u.h"#include	"../port/lib.h"#include	"mem.h"#include	"dat.h"#include	"fns.h"#include	"ureg.h"#include	"io.h"#include	<tos.h>#include	"../port/error.h" #define setstatus(v)	/* experiment: delete this to enable recursive traps */ typedef struct Handler Handler; struct Handler {	void	(*handler)(void *);	void	*arg;	Handler	*next;			/* at this interrupt level */	ulong	intrs;}; ulong offintrs;ulong intrcauses[ILmax+1]; int	intr(Ureg*);void	kernfault(Ureg*, int);void	noted(Ureg*, Ureg**, ulong);void	rfnote(Ureg**); char *excname[] ={	"trap: external interrupt",	"trap: TLB modification (store to unwritable)",	"trap: TLB miss (load or fetch)",	"trap: TLB miss (store)",	"trap: address error (load or fetch)",	"trap: address error (store)",	"trap: bus error (fetch)",	"trap: bus error (data load or store)",	"trap: system call",	"breakpoint",	"trap: reserved instruction",	"trap: coprocessor unusable",	"trap: arithmetic overflow",	"trap: TRAP exception",	"trap: VCE (instruction)",	"trap: floating-point exception",	"trap: coprocessor 2 implementation-specific", /* used as sys call for debugger */	"trap: corextend unusable",	"trap: precise coprocessor 2 exception",	"trap: TLB read-inhibit",	"trap: TLB execute-inhibit",	"trap: undefined 21",	"trap: undefined 22",	"trap: WATCH exception",	"trap: machine checkcore",	"trap: undefined 25",	"trap: undefined 26",	"trap: undefined 27",	"trap: undefined 28",	"trap: undefined 29",	"trap: cache error",	"trap: VCE (data)",}; char *fpcause[] ={	"inexact operation",	"underflow",	"overflow",	"division by zero",	"invalid operation",};char	*fpexcname(Ureg*, ulong, char*, uint);#define FPEXPMASK	(0x3f<<12)	/* Floating exception bits in fcr31 */ struct {	char	*name;	uint	off;} regname[] = {	"STATUS", Ureg_status,	"PC",	Ureg_pc,	"SP",	Ureg_sp,	"CAUSE",Ureg_cause,	"BADADDR", Ureg_badvaddr,	"TLBVIRT", Ureg_tlbvirt,	"HI",	Ureg_hi,	"LO",	Ureg_lo,	"R31",	Ureg_r31,	"R30",	Ureg_r30,	"R28",	Ureg_r28,	"R27",	Ureg_r27,	"R26",	Ureg_r26,	"R25",	Ureg_r25,	"R24",	Ureg_r24,	"R23",	Ureg_r23,	"R22",	Ureg_r22,	"R21",	Ureg_r21,	"R20",	Ureg_r20,	"R19",	Ureg_r19,	"R18",	Ureg_r18,	"R17",	Ureg_r17,	"R16",	Ureg_r16,	"R15",	Ureg_r15,	"R14",	Ureg_r14,	"R13",	Ureg_r13,	"R12",	Ureg_r12,	"R11",	Ureg_r11,	"R10",	Ureg_r10,	"R9",	Ureg_r9,	"R8",	Ureg_r8,	"R7",	Ureg_r7,	"R6",	Ureg_r6,	"R5",	Ureg_r5,	"R4",	Ureg_r4,	"R3",	Ureg_r3,	"R2",	Ureg_r2,	"R1",	Ureg_r1,}; static Lock intrlock;static Handler handlers[ILmax+1]; static char *ptlb(ulong phys){	static char buf[4][32];	static int k;	char *p; 	k = (k+1)&3;	p = buf[k];	p += snprint(p, sizeof buf[k] - (p - buf[k]), "(%#lux %lud ",		(phys<<6) & ~(BY2PG-1), (phys>>3)&7);	if(phys & 4)		*p++ = 'd';	if(phys & 2)		*p++ = 'v';	if(phys & 1)		*p++ = 'g';	*p++ = ')';	*p = 0;	return buf[k];} static voidkpteprint(Ureg *ur){	ulong i, tlbstuff[3];	KMap *k; 	i = (ur->badvaddr & ~(2*BY2PG-1)) | TLBPID(tlbvirt());	print("tlbvirt=%#lux\n", i);	i = gettlbp(i, tlbstuff);	print("i=%lud v=%#lux p0=%s p1=%s\n",		i, tlbstuff[0], ptlb(tlbstuff[1]), ptlb(tlbstuff[2])); 	i = (ur->badvaddr & ~KMAPADDR)>>15;	if(i > KPTESIZE){		print("kpte index = %lud ?\n", i);		return;	}	k = &kpte[i];	print("i=%lud, &k=%#p, k={v=%#lux, p0=%s, p1=%s, pg=%#p}\n",		i, k, k->virt, ptlb(k->phys0), ptlb(k->phys1), k->pg);	print("pg={pa=%#lux, va=%#lux}\n", k->pg->pa, k->pg->va);} voidkvce(Ureg *ur, int ecode){	char c;	Pte **p;	Page **pg;	Segment *s;	ulong addr, soff; 	c = 'D';	if(ecode == CVCEI)		c = 'I';	print("Trap: VCE%c: addr=%#lux\n", c, ur->badvaddr);	if((ur->badvaddr & KSEGM) == KSEG3) {		kpteprint(ur);		return;	}	if(up && !(ur->badvaddr & KSEGM)) {		addr = ur->badvaddr;		s = seg(up, addr, 0);		if(s == 0){			print("kvce: no seg for %#lux\n", addr);			for(;;)				;		}		addr &= ~(BY2PG-1);		soff = addr - s->base;		p = &s->map[soff/PTEMAPMEM];		if(*p){			pg = &(*p)->pages[(soff&(PTEMAPMEM-1))/BY2PG];			if(*pg)				print("kvce: pa=%#lux, va=%#lux\n",					(*pg)->pa, (*pg)->va);			else				print("kvce: no *pg\n");		}else			print("kvce: no *p\n");	}} /* prepare to go to user space */voidkexit(Ureg*){	Tos *tos; 	/* precise time accounting, kernel exit */	tos = (Tos*)(USTKTOP-sizeof(Tos));	tos->kcycles += fastticks(&tos->cyclefreq) - up->kentry;	tos->pcycles = up->pcycles;	tos->pid = up->pid;} voidtrap(Ureg *ur){	int ecode, clockintr, user, cop, x, fpchk;	ulong fpfcr31;	char buf[2*ERRMAX], buf1[ERRMAX], *fpexcep;	static int dumps; 	ecode = (ur->cause>>2)&EXCMASK;	user = ur->status&KUSER;	if (ur->cause & TS)		panic("trap: tlb shutdown"); 	fpchk = 0;	if(user){		up->dbgreg = ur;		cycles(&up->kentry);		/* no fpu, so no fp state to save */	} 	if (up && (char *)(ur) - up->kstack < 1024 && dumps++ == 0) {		iprint("trap: proc %ld kernel stack getting full\n", up->pid);		dumpregs(ur);		dumpstack();	}	if (up == nil &&	    (char *)(ur) - (char *)m->stack < 1024 && dumps++ == 0) {		iprint("trap: cpu%d kernel stack getting full\n", m->machno);		dumpregs(ur);		dumpstack();	} //	splhi();		/* for the experiment: make it explicit */	/* clear EXL in status */	setstatus(getstatus() & ~EXL); 	clockintr = 0;	switch(ecode){	case CINT:		clockintr = intr(ur);		break; 	case CFPE:		panic("FP exception but no FPU");#ifdef OLD_MIPS_EXAMPLE		fptrap(ur);		clrfpintr();		fpchk = 1;#endif		break; 	case CTLBM:	case CTLBL:	case CTLBS:		/* user tlb entries assumed not overwritten during startup */		if(up == 0)			kernfault(ur, ecode); 		if(!user && (ur->badvaddr & KSEGM) == KSEG3) {			kfault(ur);			break;		}		x = up->insyscall;		up->insyscall = 1;		spllo();		faultmips(ur, user, ecode);		up->insyscall = x;		break; 	case CVCEI:	case CVCED:		kvce(ur, ecode);		goto Default; 	case CWATCH:		if(!user)			panic("watchpoint trap from kernel mode pc=%#p",				ur->pc);		fpwatch(ur);		break; 	case CCPU:		cop = (ur->cause>>28)&3;		if(user && up && cop == 1) {			if(up->fpstate & FPillegal) {				/* someone used floating point in a note handler */				postnote(up, 1,					"sys: floating point in note handler",					NDebug);				break;			}			/* no fpu, so we can only emulate fp ins'ns */			if (fpuemu(ur) < 0)				postnote(up, 1,					"sys: fp instruction not emulated",					NDebug);			else				fpchk = 1;			break;		}		/* Fallthrough */ 	Default:	default:		if(user) {			spllo();			snprint(buf, sizeof buf, "sys: %s", excname[ecode]);			postnote(up, 1, buf, NDebug);			break;		}		if (ecode == CADREL || ecode == CADRES)			iprint("kernel addr exception for va %#p pid %#ld %s\n",				ur->badvaddr, (up? up->pid: 0),				(up? up->text: ""));		print("cpu%d: kernel %s pc=%#lux\n",			m->machno, excname[ecode], ur->pc);		dumpregs(ur);		dumpstack();		if(m->machno == 0)			spllo();		exit(1);	} 	if(fpchk) {		fpfcr31 = up->fpsave.fpstatus;		if((fpfcr31>>12) & ((fpfcr31>>7)|0x20) & 0x3f) {			spllo();			fpexcep	= fpexcname(ur, fpfcr31, buf1, sizeof buf1);			snprint(buf, sizeof buf, "sys: fp: %s", fpexcep);			postnote(up, 1, buf, NDebug);		}	} 	splhi(); 	/* delaysched set because we held a lock or because our quantum ended */	if(up && up->delaysched && clockintr){		sched();		splhi();	} 	if(user){		notify(ur);		/* no fpu, so no fp state to restore */		kexit(ur);	} 	/* restore EXL in status */	setstatus(getstatus() | EXL);} /* periodically zero all the interrupt counts */static voidresetcounts(void){	int i;	Handler *hp; 	ilock(&intrlock);	for (i = 0; i < nelem(handlers); i++)		for (hp = &handlers[i]; hp != nil; hp = hp->next)			hp->intrs = 0;	iunlock(&intrlock);} /* *  set handlers */voidintrenable(int irq, void (*h)(void *), void *arg){	Handler *hp;	static int resetclock; 	if (h == nil)		panic("intrenable: nil handler intr %d", irq);	if(irq < ILmin || irq >= nelem(handlers))		panic("intrenable: bad handler intr %d %#p", irq, h); 	hp = &handlers[irq];	ilock(&intrlock);	if (hp->handler != nil) {		/* occupied? */		/* add a new one at the end of the chain */		for (; hp->next != nil; hp = hp->next)			;		hp->next = smalloc(sizeof *hp);		hp = hp->next;		hp->next = nil;	}	hp->handler = h;	hp->arg = arg;	iunlock(&intrlock); 	if (irq == ILduart0) {		/* special apb sub-interrupt */		*Apbintrsts = 0;		*Apbintrmask = 1 << Apbintruart;  /* enable, actually */		coherence();	}	intron(1 << (ILshift + irq));	if (!resetclock) {		resetclock = 1;		addclock0link(resetcounts, 100);	}} voidintrshutdown(void){	introff(INTMASK);} static voidjabberoff(Ureg *ur, int irq, ulong bit){	introff(bit);			/* interrupt off now ... */	if (ur)		ur->status &= ~bit;	/* ... and upon return */	offintrs |= bit;	iprint("irq %d jabbering; shutting it down\n", irq);} ulongpollall(Ureg *ur, ulong cause)			/* must be called splhi */{	int i, intrs, sts;	ulong bit;	Handler *hp; 	/* exclude clock and sw intrs */	intrs = cause & (INTR6|INTR5|INTR4|INTR3|INTR2) & getstatus();	if(intrs == 0)		return cause; 	ilock(&intrlock);	for (i = ILmax; i >= ILmin; i--) {		bit = 1 << (ILshift + i);		if (!(intrs & bit))			continue;		intrcauses[i]++;		for (hp = &handlers[i]; hp != nil; hp = hp->next)			if (hp->handler) {				if (i == ILduart0) {					sts = *Apbintrsts;					if((sts & (1 << Apbintruart)) == 0)						continue;					/* don't need to ack apb sub-intr */					// *Apbintrsts &= ~(1 << Apbintruart);				}				(*hp->handler)(hp->arg);				splhi();				if (++hp->intrs > 25000) {					jabberoff(ur, i, bit);					intrs &= ~bit;					hp->intrs = 0;				}			} else if (ur)				iprint("no handler for interrupt %d\n", i);		cause &= ~bit;	}	iunlock(&intrlock);	return cause;} intintr(Ureg *ur){	int clockintr;

Lines 1–500 of 1084.