846 lines · 15.9 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. */ #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" static Lock vctllock;static Vctl *vctl[256]; voidhwintrinit(void){	i8259init();	mpicenable(0, nil);	/* 8259 interrupts are routed through MPIC intr 0 */} static inthwintrenable(Vctl *v){	int vec, irq; 	irq = v->irq;	if(BUSTYPE(v->tbdf) == BusPCI) {	/* MPIC? */		if(irq > 15) {			print("intrenable: pci irq %d out of range\n", v->irq);			return -1;		}		vec = irq;		mpicenable(vec, v);	}	else {		if(irq > MaxIrqPIC) {			print("intrenable: irq %d out of range\n", v->irq);			return -1;		}		vec = irq+VectorPIC;		if(i8259enable(v) == -1)			return -1;	}	return vec;} static inthwintrdisable(Vctl *v){	int vec, irq; 	irq = v->irq;	if(BUSTYPE(v->tbdf) == BusPCI) {	/* MPIC? */		if(irq > 15) {			print("intrdisable: pci irq %d out of range\n", v->irq);			return -1;		}		vec = irq;		mpicdisable(vec);	}	else {		if(irq > MaxIrqPIC) {			print("intrdisable: irq %d out of range\n", v->irq);			return -1;		}		vec = irq+VectorPIC;		if(i8259disable(irq) == -1)			return -1;	}	return vec;} static inthwvecno(int irq, int tbdf){	if(BUSTYPE(tbdf) == BusPCI) 	/* MPIC? */		return irq;	else		return irq+VectorPIC;} voidintrenable(int irq, void (*f)(Ureg*, void*), void* a, int tbdf, char *name){	int vno;	Vctl *v; 	if(f == nil){		print("intrenable: nil handler for %d, tbdf 0x%uX for %s\n",			irq, tbdf, name);		return;	} 	v = xalloc(sizeof(Vctl));	v->isintr = 1;	v->irq = irq;	v->tbdf = tbdf;	v->f = f;	v->a = a;	strncpy(v->name, name, KNAMELEN-1);	v->name[KNAMELEN-1] = 0; 	ilock(&vctllock);	vno = hwintrenable(v);	if(vno == -1){		iunlock(&vctllock);		print("intrenable: couldn't enable irq %d, tbdf 0x%uX for %s\n",			irq, tbdf, v->name);		xfree(v);		return;	}	if(vctl[vno]){		if(vctl[vno]->isr != v->isr || vctl[vno]->eoi != v->eoi)			panic("intrenable: handler: %s %s %#p %#p %#p %#p",				vctl[vno]->name, v->name,				vctl[vno]->isr, v->isr, vctl[vno]->eoi, v->eoi);		v->next = vctl[vno];	}	vctl[vno] = v;	iunlock(&vctllock);} voidintrdisable(int irq, void (*f)(Ureg *, void *), void *a, int tbdf, char *name){	Vctl **pv, *v;	int vno; 	vno = hwvecno(irq, tbdf);	ilock(&vctllock);	pv = &vctl[vno];	while (*pv && 		  ((*pv)->irq != irq || (*pv)->tbdf != tbdf || (*pv)->f != f || (*pv)->a != a ||		   strcmp((*pv)->name, name)))		pv = &((*pv)->next);	assert(*pv); 	v = *pv;	*pv = (*pv)->next;	/* Link out the entry */		if(vctl[vno] == nil)		hwintrdisable(v);	iunlock(&vctllock);	xfree(v);} void	syscall(Ureg*);void	noted(Ureg*, ulong);static void _dumpstack(Ureg*); char *excname[] ={	"reserved 0",	"system reset",	"machine check",	"data access",	"instruction access",	"external interrupt",	"alignment",	"program exception",	"floating-point unavailable",	"decrementer",	"reserved A",	"reserved B",	"system call",	"trace trap",	"floating point assist",	"reserved F",	"reserved 10",	"reserved 11",	"reserved 12",	"instruction address breakpoint",	"system management interrupt",}; char *fpcause[] ={	"inexact operation",	"division by zero",	"underflow",	"overflow",	"invalid operation",};char	*fpexcname(Ureg*, ulong, char*);#define FPEXPMASK	0xfff80300		/* Floating exception bits in fpscr */  char *regname[]={	"CAUSE",	"SRR1",	"PC",		"GOK",	"LR",		"CR",	"XER",	"CTR",	"R0",		"R1",	"R2",		"R3",	"R4",		"R5",	"R6",		"R7",	"R8",		"R9",	"R10",	"R11",	"R12",	"R13",	"R14",	"R15",	"R16",	"R17",	"R18",	"R19",	"R20",	"R21",	"R22",	"R23",	"R24",	"R25",	"R26",	"R27",	"R28",	"R29",	"R30",	"R31",}; voidtrap(Ureg *ureg){	ulong dsisr;	int ecode, user;	char buf[ERRMAX], *s; 	ecode = (ureg->cause >> 8) & 0xff;	user = (ureg->srr1 & MSR_PR) != 0;	if(user)		up->dbgreg = ureg; 	if(ureg->status & MSR_RI == 0)		print("double fault?: ecode = %d\n", ecode); 	switch(ecode) {	case CEI:		intr(ureg);		break;	case CDEC:		clockintr(ureg);		break;	case CSYSCALL:		if(!user)			panic("syscall in kernel: srr1 0x%4.4luX", ureg->srr1);		syscall(ureg);		return;		/* syscall() calls notify itself, don't do it again */	case CFPU:		if(!user || up == nil) {			dumpregs(ureg);			panic("floating point in kernel");		}		switch(up->fpstate){		case FPinit:			fprestore(&initfp);			up->fpstate = FPactive;			break;		case FPinactive:			fprestore(&up->fpsave);			up->fpstate = FPactive;			break;		default:			panic("fpstate");		}		ureg->srr1 |= MSR_FP;		break;	case CISI:		faultpower(ureg, ureg->pc, 1);		break;	case CDSI:		dsisr = getdsisr();		if(dsisr & BIT(6))			faultpower(ureg, getdar(), 0);		else			faultpower(ureg, getdar(), 1);		break;	case CPROG:		if(ureg->status & (1<<19))			s = "floating point exception";		else if(ureg->status & (1<<18))			s = "illegal instruction";		else if(ureg->status & (1<<17))			s = "privileged instruction";		else			s = "undefined program exception";		if(user){			spllo();			sprint(buf, "sys: trap: %s", s);			postnote(up, 1, buf, NDebug);			break;		}		dumpregs(ureg);		panic(s);		break;	default:		if(ecode < nelem(excname) && user){			spllo();			sprint(buf, "sys: trap: %s", excname[ecode]);			postnote(up, 1, buf, NDebug);			break;		}		dumpregs(ureg);		if(ecode < nelem(excname))			panic("%s", excname[ecode]);		panic("unknown trap/intr: %d", ecode);	} 	/* restoreureg must execute at high IPL */	splhi(); 	/* delaysched set because we held a lock or because our quantum ended */	if(up && up->delaysched && ecode == CDEC){		sched();		splhi();	} 	if(user) {		notify(ureg);		if(up->fpstate == FPinactive)			ureg->srr1 &= ~MSR_FP;		kexit(ureg);	}} voidfaultpower(Ureg *ureg, ulong addr, int read){	int user, insyscall, n;	char buf[ERRMAX]; 	user = (ureg->srr1 & MSR_PR) != 0;	insyscall = up->insyscall;	up->insyscall = 1;	n = fault(addr, read);	if(n < 0){		if(!user){			dumpregs(ureg);			panic("fault: 0x%lux", addr);		}		sprint(buf, "sys: trap: fault %s addr=0x%lux", read? "read" : "write", addr);		postnote(up, 1, buf, NDebug);	}	up->insyscall = insyscall;} voidsethvec(int v, void (*r)(void)){	ulong *vp, pa, o; 	vp = KADDR(v);	vp[0] = 0x7c1043a6;	/* MOVW R0, SPR(SPRG0) */	vp[1] = 0x7c0802a6;	/* MOVW LR, R0 */	vp[2] = 0x7c1243a6;	/* MOVW R0, SPR(SPRG2) */	pa = PADDR(r);	o = pa >> 25;	if(o != 0 && o != 0x7F){		/* a branch too far */		vp[3] = (15<<26)|(pa>>16);	/* MOVW $r&~0xFFFF, R0 */		vp[4] = (24<<26)|(pa&0xFFFF);	/* OR $r&0xFFFF, R0 */		vp[5] = 0x7c0803a6;	/* MOVW	R0, LR */		vp[6] = 0x4e800021;	/* BL (LR) */	}else		vp[3] = (18<<26)|(pa&0x3FFFFFC)|3;	/* bla */	dcflush(vp, 8*sizeof(ulong));} voidtrapinit(void){	int i; 	/*	 * set all exceptions to trap	 */	for(i = 0; i < 0x2000; i += 0x100)		sethvec(i, trapvec); 	putmsr(getmsr() & ~MSR_IP);} voidintr(Ureg *ureg){	int vno;	Vctl *ctl, *v; 	vno = mpicintack();	if(vno == 0) {			/* 8259, wired through MPIC vec 0 */		vno = i8259intack();		mpiceoi(0);	} 	if(vno > nelem(vctl) || (ctl = vctl[vno]) == 0) {		panic("spurious intr %d", vno);		return;	} 	if(ctl->isr)		ctl->isr(vno);	for(v = ctl; v != nil; v = v->next){		if(v->f)			v->f(ureg, v->a);	}	if(ctl->eoi)		ctl->eoi(vno); 	if(up)		preempted();} char*fpexcname(Ureg *ur, ulong fpscr, char *buf){	int i;	char *s;	ulong fppc; 	fppc = ur->pc;	s = 0;	fpscr >>= 3;		/* trap enable bits */	fpscr &= (fpscr>>22);	/* anded with exceptions */	for(i=0; i<5; i++)		if(fpscr & (1<<i))			s = fpcause[i];	if(s == 0)		return "no floating point exception";	sprint(buf, "%s fppc=0x%lux", s, fppc);	return buf;} /* * Fill in enough of Ureg to get a stack trace, and call a function. * Used by debugging interface rdb. */ static voidgetpcsp(ulong *pc, ulong *sp){	*pc = getcallerpc(&pc);	*sp = (ulong)&pc-4;} voidcallwithureg(void (*fn)(Ureg*)){	Ureg ureg; 	getpcsp((ulong*)&ureg.pc, (ulong*)&ureg.sp);	ureg.lr = getcallerpc(&fn);	fn(&ureg);} static void_dumpstack(Ureg *ureg){	ulong l, sl, el, v;	int i; 	l = (ulong)&l;	if(up == 0){		el = (ulong)m+BY2PG;		sl = el-KSTACK;	}	else{		sl = (ulong)up->kstack;		el = sl + KSTACK;	}	if(l > el || l < sl){		el = (ulong)m+BY2PG;		sl = el-KSTACK;	}	if(l > el || l < sl)		return;	print("ktrace /kernel/path %.8lux %.8lux %.8lux\n", ureg->pc, ureg->sp, ureg->lr);	i = 0;	for(; l < el; l += 4){		v = *(ulong*)l;		if(KTZERO < v && v < (ulong)etext){			print("%.8lux=%.8lux ", l, v);			if(i++ == 4){				print("\n");				i = 0;			}		}	}} voiddumpstack(void){	callwithureg(_dumpstack);} voiddumpregs(Ureg *ur){	int i;	ulong *l; 	if(up) {

Lines 1–500 of 846.