plan 9 kernel history: overview | file list | diff list

1993/0501/power/trap.c (diff list | history)

power/trap.c on 1990/0227
1990/0227    
#include	"u.h" 
1992/0321    
#include	"../port/lib.h" 
1990/0227    
#include	"mem.h" 
#include	"dat.h" 
#include	"fns.h" 
#include	"ureg.h" 
#include	"io.h" 
1992/0111    
#include	"../port/error.h" 
1990/0227    
 
void	(*vmevec[256])(int); 
1991/0717    
void	noted(Ureg**, ulong); 
1990/0227    
void	rfnote(Ureg**); 
 
char *excname[] = 
{ 
1992/0102    
	"trap: external interrupt", 
	"trap: TLB modification", 
	"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", 
1990/0227    
	"breakpoint", 
1992/0102    
	"trap: reserved instruction", 
	"trap: coprocessor unusable", 
	"trap: arithmetic overflow", 
	"trap: undefined 13", 
	"trap: undefined 14", 
1993/0501    
	"trap: undefined 15",		/* used as sys call for debugger */ 
1990/0227    
}; 
1992/1129    
 
char *fpcause[] = 
{ 
	"inexact operation", 
	"underflow", 
	"overflow", 
	"division by zero", 
	"invalid operation", 
}; 
1992/0806    
char	*fpexcname(Ureg*, ulong, char*); 
1993/0501    
#define FPEXPMASK	(0x3f<<12)	/* Floating exception bits in fcr31 */ 
1990/0227    
 
1993/0501    
char* 
regname[]= 
{ 
	"STATUS", "PC",	"SP", "CAUSE", 
	"BADADDR", "TLBVIRT", "HI", "LO", 
	"R31",	"R30",	"R28",	"R27", 
	"R26",	"R25",	"R24",	"R23", 
	"R22",	"R21",	"R20",	"R19", 
	"R18",	"R17",	"R16",	"R15", 
	"R14",	"R13",	"R12",	"R11", 
	"R10",	"R9",	"R8",	"R7", 
	"R6",	"R5",	"R4",	"R3", 
	"R2",	"R1" 
1990/0227    
}; 
 
void 
trap(Ureg *ur) 
{ 
1992/0802    
	ulong fcr31; 
1993/0501    
	int user, cop, x, fpchk, ecode; 
1992/1128    
	char buf[2*ERRLEN], buf1[ERRLEN], *fpexcep; 
1992/1129    
 
1990/0227    
	user = ur->status&KUP; 
1993/0501    
	ecode = (ur->cause>>2)&0xf; 
 
1992/1129    
	fpchk = 0; 
1993/0106    
	if(user) { 
1993/0501    
		up->dbgreg = ur; 
		if(up->fpstate == FPactive) { 
1993/0106    
			if((ur->status&CU1) == 0)		/* Paranoid */ 
				panic("FPactive but no CU1"); 
1993/0501    
			up->fpstate = FPinactive; 
1993/0106    
			ur->status &= ~CU1; 
1993/0501    
			savefpregs(&up->fpsave); 
1993/0106    
			fptrap(ur); 
			fpchk = 1; 
		} 
1992/1128    
	} 
1990/0227    
	switch(ecode){ 
	case CINT: 
1992/1128    
		if(ur->cause&INTR3) {			/* FP trap */ 
1992/1129    
			clrfpintr(); 
1992/1128    
			ur->cause &= ~INTR3; 
1991/0209    
		} 
		intr(ur); 
1990/0227    
		break; 
 
	case CTLBM: 
	case CTLBL: 
	case CTLBS: 
1993/0501    
		if(up == 0) 
			panic("kfault pc %lux addr %lux", ur->pc, ur->badvaddr); 
1992/1129    
 
1993/0501    
		x = up->insyscall; 
		up->insyscall = 1; 
1992/1130    
 
		spllo(); 
1990/1212    
		faultmips(ur, user, ecode); 
1993/0501    
		up->insyscall = x; 
1990/0227    
		break; 
 
	case CCPU: 
1992/1128    
		cop = (ur->cause>>28)&3; 
1993/0106    
		if(user && cop == 1) { 
1993/0501    
			if(up->fpstate == FPinit) { 
				up->fpstate = FPinactive; 
				fcr31 = up->fpsave.fpstatus; 
				up->fpsave = initfp; 
				up->fpsave.fpstatus = fcr31; 
1992/1128    
				break; 
			} 
1993/0501    
			if(up->fpstate == FPinactive) 
1992/1128    
				break; 
1990/0227    
		} 
1992/1128    
		/* Fallthrough */ 
1990/0227    
 
	default: 
1992/1128    
		if(user) { 
1990/0227    
			spllo(); 
1992/1128    
			sprint(buf, "sys: %s", excname[ecode]); 
1993/0501    
			postnote(up, 1, buf, NDebug); 
1992/1128    
			break; 
1990/0227    
		} 
1992/1128    
		print("kernel %s pc=%lux\n", excname[ecode], ur->pc); 
		dumpregs(ur); 
		dumpstack(); 
		if(m->machno == 0) 
			spllo(); 
		exit(1); 
1990/0227    
	} 
1991/0705    
 
1992/1129    
	if(fpchk) { 
1993/0501    
		fcr31 = up->fpsave.fpstatus; 
1992/1129    
		if((fcr31>>12) & ((fcr31>>7)|0x20) & 0x3f) { 
			spllo(); 
			fpexcep	= fpexcname(ur, fcr31, buf1); 
			sprint(buf, "sys: fp: %s", fpexcep); 
1993/0501    
			postnote(up, 1, buf, NDebug); 
1991/1114    
		} 
1990/0227    
	} 
1992/1129    
 
	splhi(); 
	if(!user) 
		return; 
 
	notify(ur); 
1993/0501    
	if(up->fpstate == FPinactive) { 
		restfpregs(&up->fpsave, up->fpsave.fpstatus); 
		up->fpstate = FPactive; 
1992/1129    
		ur->status |= CU1; 
	} 
1990/0227    
} 
 
void 
1991/0209    
intr(Ureg *ur) 
1990/0227    
{ 
	long v; 
1993/0501    
	int i, any; 
1991/0209    
	ulong cause; 
1991/0219    
	static int bogies; 
1992/1217    
	uchar pend, xxx; 
1990/0227    
 
1991/0425    
	m->intr++; 
1991/0209    
	cause = ur->cause&(INTR5|INTR4|INTR3|INTR2|INTR1); 
1992/1128    
 
1990/0227    
	if(cause & INTR1){ 
		duartintr(); 
		cause &= ~INTR1; 
	} 
1992/1128    
 
1993/0501    
	while(cause & INTR5) { 
1991/0212    
		any = 0; 
1990/0227    
		if(!(*MPBERR1 & (1<<8))){ 
1990/0911    
			print("MP bus error %lux %lux\n", *MPBERR0, *MPBERR1); 
1992/1128    
			print("PC %lux R31 %lux\n", ur->pc, ur->r31); 
1990/0227    
			*MPBERR0 = 0; 
			i = *SBEADDR; 
1990/1214    
			USED(i); 
1991/0212    
			any = 1; 
1990/0227    
		} 
 
		/* 
		 *  directions from IO2 manual 
		 *  1. clear all IO2 masks 
		 */ 
1991/0212    
		*IO2CLRMASK = 0xff000000; 
1990/0227    
 
		/* 
		 *  2. wait for interrupt in progress 
		 */ 
		while(!(*INTPENDREG & (1<<5))) 
			; 
 
		/* 
		 *  3. read pending interrupts 
		 */ 
1991/0316    
		pend = SBCCREG->fintpending; 
1990/0227    
 
		/* 
		 *  4. clear pending register 
		 */ 
		i = SBCCREG->flevel; 
1990/1214    
		USED(i); 
1991/0316    
 
		/* 
		 *  4a. attempt to fix problem 
		 */ 
		if(!(*INTPENDREG & (1<<5))) 
			print("pause again\n"); 
		while(!(*INTPENDREG & (1<<5))) 
			; 
		xxx = SBCCREG->fintpending; 
		if(xxx){ 
			print("new pend %ux\n", xxx); 
			i = SBCCREG->flevel; 
1991/0425    
			USED(i); 
1991/0316    
		} 
1990/0227    
 
		/* 
		 *  5a. process lance, scsi 
		 */ 
		if(pend & 1) { 
			v = INTVECREG->i[0].vec; 
1990/0907    
			if(!(v & (1<<12))){ 
1992/1128    
				print("ioberr %lux %lux\n", *MPBERR0, *MPBERR1); 
				print("PC %lux R31 %lux\n", ur->pc, ur->r31); 
1990/0907    
				*MPBERR0 = 0; 
1991/0212    
				any = 1; 
1990/0907    
			} 
1990/0911    
			if(ioid < IO3R1){ 
1991/0212    
				if(!(v & 7)) 
					any = 1; 
1990/0907    
				if(!(v & (1<<2))) 
					lanceintr(); 
				if(!(v & (1<<1))) 
					lanceparity(); 
				if(!(v & (1<<0))) 
					print("SCSI interrupt\n"); 
1991/0212    
			}else{ 
				if(v & 7) 
					any = 1; 
1990/0907    
				if(v & (1<<2)) 
1990/0911    
					lanceintr(); 
1990/0907    
				if(v & (1<<1)) 
1992/1208    
					scsiintr(1); 
1990/0907    
				if(v & (1<<0)) 
1992/1208    
					scsiintr(0); 
1990/0907    
			} 
1990/0227    
		} 
		/* 
		 *  5b. process vme 
1991/0212    
		 *  i can guess your level 
1990/0227    
		 */ 
1991/0212    
		for(i=1; pend>>=1; i++){ 
1990/0227    
			if(pend & 1) { 
				v = INTVECREG->i[i].vec; 
1990/0907    
				if(!(v & (1<<12))){ 
1991/0212    
					print("io2 mp bus error %d %lux %lux\n", 
						i, *MPBERR0, *MPBERR1); 
1990/0907    
					*MPBERR0 = 0; 
				} 
1990/0227    
				v &= 0xff; 
				(*vmevec[v])(v); 
1991/0212    
				any = 1; 
1990/0227    
			} 
		} 
		/* 
		 *  6. re-enable interrupts 
		 */ 
1991/0212    
		*IO2SETMASK = 0xff000000; 
1992/1209    
		if(any == 0) 
			cause &= ~INTR5; 
1990/0227    
	} 
1992/1128    
 
1992/1129    
	if(cause & (INTR2|INTR4)) { 
1993/0501    
		LEDON(LEDclock); 
1992/1128    
		clock(ur); 
1993/0501    
		LEDOFF(LEDclock); 
1992/1128    
		cause &= ~(INTR2|INTR4); 
	} 
 
1990/0227    
	if(cause) 
1993/0501    
		panic("cause %lux %lux\n", up, cause); 
1990/0227    
} 
 
1992/0803    
char* 
1992/0806    
fpexcname(Ureg *ur, ulong fcr31, char *buf) 
1990/0227    
{ 
	int i; 
1992/0806    
	char *s; 
	ulong fppc; 
1990/0227    
 
1992/0806    
	fppc = ur->pc; 
	if(ur->cause & (1<<31))	/* branch delay */ 
		fppc += 4; 
	s = 0; 
1992/0803    
	if(fcr31 & (1<<17)) 
1992/0806    
		s = "unimplemented operation"; 
	else{ 
		fcr31 >>= 7;		/* trap enable bits */ 
		fcr31 &= (fcr31>>5);	/* anded with exceptions */ 
		for(i=0; i<5; i++) 
			if(fcr31 & (1<<i)) 
1992/1129    
				s = fpcause[i]; 
1992/0806    
	} 
	if(s == 0) 
		return "no floating point exception"; 
1992/1129    
 
1992/0806    
	sprint(buf, "%s fppc=0x%lux", s, fppc); 
	return buf; 
1990/0227    
} 
1990/03091    
 
1990/0227    
void 
dumpstack(void) 
{ 
1993/0501    
	ulong l, v, top; 
1990/0227    
	extern ulong etext; 
 
1993/0501    
	if(up == 0) 
1992/1129    
		return; 
 
1993/0501    
	top = (ulong)up->kstack + KSTACK; 
	for(l=(ulong)&l; l < top; l += BY2WD) { 
1992/1129    
		v = *(ulong*)l; 
1993/0501    
		if(KTZERO < v && v < (ulong)&etext) { 
1992/1129    
			print("%lux=%lux\n", l, v); 
			delay(100); 
1990/0227    
		} 
1992/1129    
	} 
1990/0227    
} 
 
void 
dumpregs(Ureg *ur) 
{ 
	int i; 
	ulong *l; 
 
1993/0501    
	if(up) 
		print("registers for %s %d\n", up->text, up->pid); 
1990/0227    
	else 
1992/1124    
		print("registers for kernel\n"); 
1992/1129    
 
1990/0227    
	l = &ur->status; 
1993/0501    
	for(i=0; i<sizeof regname/sizeof(char*); i+=2) { 
		print("%s\t%.8lux\t%s\t%.8lux\n", 
			regname[i], l[0], regname[i+1], l[1]); 
		l += 2; 
1992/1124    
		prflush(); 
1992/0319    
	} 
1990/0227    
} 
 
1992/0108    
int 
1990/0227    
notify(Ureg *ur) 
{ 
1992/1129    
	int l; 
	ulong sp; 
1991/1218    
	Note *n; 
1990/0227    
 
1993/0501    
	if(up->procctl) 
		procctl(up); 
	if(up->nnote == 0) 
1992/0108    
		return 0; 
1991/1114    
 
1992/1129    
	spllo(); 
1993/0501    
	qlock(&up->debug); 
	up->notepending = 0; 
	n = &up->note[0]; 
1992/1129    
	if(strncmp(n->msg, "sys:", 4) == 0) { 
1991/1218    
		l = strlen(n->msg); 
		if(l > ERRLEN-15)	/* " pc=0x12345678\0" */ 
			l = ERRLEN-15; 
1992/1128    
 
1992/0806    
		sprint(n->msg+l, " pc=0x%lux", ur->pc); 
1991/1218    
	} 
1992/1128    
 
1993/0501    
	if(n->flag != NUser && (up->notified || up->notify==0)) { 
1992/0714    
		if(n->flag == NDebug) 
1991/1218    
			pprint("suicide: %s\n", n->msg); 
1992/1128    
 
1993/0501    
		qunlock(&up->debug); 
1991/1218    
		pexit(n->msg, n->flag!=NDebug); 
1990/0227    
	} 
1992/1128    
 
1993/0501    
	if(up->notified) { 
		qunlock(&up->debug); 
1992/1129    
		splhi(); 
1992/1128    
		return 0; 
1990/0227    
	} 
1992/1128    
		 
1993/0501    
	if(!up->notify) { 
		qunlock(&up->debug); 
1992/1128    
		pexit(n->msg, n->flag!=NDebug); 
	} 
1993/0501    
	up->svstatus = ur->status; 
1992/1129    
	sp = ur->usp - sizeof(Ureg); 
1992/1128    
 
1993/0501    
	if(sp&0x3 || !okaddr((ulong)up->notify, BY2WD, 0) 
1992/1208    
	|| !okaddr(sp-ERRLEN-3*BY2WD, sizeof(Ureg)+ERRLEN+3*BY2WD, 1)) { 
1992/1128    
		pprint("suicide: bad address or sp in notify\n"); 
1993/0501    
		qunlock(&up->debug); 
1992/1128    
		pexit("Suicide", 0); 
	} 
1992/1129    
 
1993/0501    
	up->ureg = (void*)sp; 
1992/1128    
	memmove((Ureg*)sp, ur, sizeof(Ureg)); 
	sp -= ERRLEN; 
1993/0501    
	memmove((char*)sp, up->note[0].msg, ERRLEN); 
1992/1128    
	sp -= 3*BY2WD; 
	*(ulong*)(sp+2*BY2WD) = sp+3*BY2WD;	/* arg 2 is string */ 
1993/0501    
	up->svr1 = ur->r1;			/* save away r1 */ 
	ur->r1 = (ulong)up->ureg;		/* arg 1 is ureg* */ 
1992/1128    
	*(ulong*)(sp+0*BY2WD) = 0;		/* arg 0 is pc */ 
	ur->usp = sp; 
1993/0501    
	ur->pc = (ulong)up->notify; 
	up->notified = 1; 
	up->nnote--; 
	memmove(&up->lastnote, &up->note[0], sizeof(Note)); 
	memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note)); 
1992/1128    
 
1993/0501    
	qunlock(&up->debug); 
1992/1129    
	splhi(); 
1992/1128    
	return 1; 
1990/0227    
} 
 
/* 
 * Return user to state before notify() 
 */ 
void 
1991/0717    
noted(Ureg **urp, ulong arg0) 
1990/0227    
{ 
1991/0503    
	Ureg *nur; 
 
1993/0501    
	nur = up->ureg; 
	if(nur->status != up->svstatus) { 
1991/0717    
		pprint("bad noted ureg status %lux\n", nur->status); 
1991/0503    
		pexit("Suicide", 0); 
	} 
1993/0501    
	qlock(&up->debug); 
	if(!up->notified) { 
		qunlock(&up->debug); 
1991/0814    
		pprint("call to noted() when not notified\n"); 
1992/1129    
		pexit("Suicide", 0); 
1990/0619    
	} 
1993/0501    
	up->notified = 0; 
	memmove(*urp, up->ureg, sizeof(Ureg)); 
	(*urp)->r1 = up->svr1; 
1992/1129    
	switch(arg0) { 
1991/0717    
	case NCONT: 
1992/0616    
		if(!okaddr(nur->pc, 1, 0) || !okaddr(nur->usp, BY2WD, 0)){ 
1991/0814    
			pprint("suicide: trap in noted\n"); 
1993/0501    
			qunlock(&up->debug); 
1992/1129    
			pexit("Suicide", 0); 
1991/0814    
		} 
1991/0717    
		splhi(); 
1993/0501    
		qunlock(&up->debug); 
1991/0717    
		rfnote(urp); 
		break; 
 
	default: 
		pprint("unknown noted arg 0x%lux\n", arg0); 
1993/0501    
		up->lastnote.flag = NDebug; 
1991/0717    
		/* fall through */ 
		 
1991/0718    
	case NDFLT: 
1993/0501    
		if(up->lastnote.flag == NDebug) 
			pprint("suicide: %s\n", up->lastnote.msg); 
		qunlock(&up->debug); 
		pexit(up->lastnote.msg, up->lastnote.flag != NDebug); 
1991/0717    
	} 
1990/0227    
} 
 
 
1991/0731    
#include "../port/systab.h" 
1990/0227    
 
long 
syscall(Ureg *aur) 
{ 
	long ret; 
	ulong sp; 
	Ureg *ur; 
 
1991/0425    
	m->syscall++; 
1993/0501    
	up->insyscall = 1; 
1990/0227    
	ur = aur; 
1993/0501    
	up->pc = ur->pc; 
	up->dbgreg = aur; 
	ur->cause = 15<<2;	/* for debugging: system call is undef 15; */ 
1992/1130    
 
1993/0501    
	if(up->fpstate == FPactive) { 
1992/1129    
		if((ur->status&CU1) == 0) 
			panic("syscall: FPactive but no CU1"); 
1993/0501    
		up->fpsave.fpstatus = fcr31(); 
		up->fpstate = FPinit; 
1990/0227    
		ur->status &= ~CU1; 
	} 
1992/1129    
 
1990/0227    
	spllo(); 
1991/0705    
 
1993/0501    
	if(up->procctl) 
		procctl(up); 
1992/0803    
 
1993/0501    
	up->scallnr = ur->r1; 
	up->nerrlab = 0; 
1992/1130    
	sp = ur->sp; 
1990/0227    
	ret = -1; 
1990/0511    
	if(!waserror()){ 
1993/0501    
		if(up->scallnr >= sizeof systab/sizeof systab[0]) { 
			pprint("bad sys call number %d pc %lux\n", 
						up->scallnr, ur->pc); 
			postnote(up, 1, "sys: bad sys call", NDebug); 
1990/11211    
			error(Ebadarg); 
1990/0511    
		} 
1992/0625    
 
1990/0511    
		if(sp & (BY2WD-1)){ 
1992/0625    
			pprint("odd sp in sys call pc %lux sp %lux\n", ur->pc, ur->sp); 
1993/0501    
			postnote(up, 1, "sys: odd stack", NDebug); 
1992/0625    
			error(Ebadarg); 
1990/0511    
		} 
1992/0625    
 
1993/0501    
		if(sp < (USTKTOP-BY2PG) || sp > (USTKTOP-sizeof(Sargs))) 
1992/0625    
			validaddr(sp, sizeof(Sargs), 0); 
 
1993/0501    
		up->s = *((Sargs*)(sp+BY2WD)); 
		up->psstate = sysctab[up->scallnr]; 
1992/0625    
 
1993/0501    
		ret = (*systab[up->scallnr])(up->s.args); 
1992/0803    
		poperror(); 
1990/0511    
	} 
1990/0227    
	ur->pc += 4; 
1993/0501    
	up->nerrlab = 0; 
	up->psstate = 0; 
	up->insyscall = 0; 
	if(up->scallnr == NOTED)			/* ugly hack */ 
1991/0717    
		noted(&aur, *(ulong*)(sp+BY2WD));	/* doesn't return */ 
1992/1129    
 
1991/1114    
	splhi(); 
1993/0501    
	if(up->scallnr!=RFORK && (up->procctl || up->nnote)){ 
1992/1128    
		ur->r1 = ret;			/* load up for noted() */ 
1992/0108    
		if(notify(ur)) 
			return ur->r1; 
1990/0227    
	} 
1991/0705    
 
1990/0227    
	return ret; 
} 
 
1993/0501    
void 
forkchild(Proc *p, Ureg *ur) 
{ 
	Ureg *cur; 
 
	p->sched.sp = (ulong)p->kstack+KSTACK-(sizeof(Ureg)+2*BY2WD); 
	p->sched.pc = (ulong)forkret; 
 
	cur = (Ureg*)(p->sched.sp+2*BY2WD); 
	memmove(cur, ur, sizeof(Ureg)); 
 
	cur->pc += 4; 
 
	/* Things from bottom of syscall we never got to execute */ 
	p->psstate = 0; 
	p->insyscall = 0; 
} 
 
static 
void 
linkproc(void) 
{ 
	spllo(); 
	(*up->kpfun)(up->kparg); 
} 
 
void 
kprocchild(Proc *p, void (*func)(void*), void *arg) 
{ 
	p->sched.pc = (ulong)linkproc; 
	p->sched.sp = (ulong)p->kstack+KSTACK; 
 
	p->kpfun = func; 
	p->kparg = arg; 
} 
 
1991/1214    
long 
execregs(ulong entry, ulong ssize, ulong nargs) 
1990/1226    
{ 
1993/0501    
	Ureg *ur; 
1991/1214    
	ulong *sp; 
 
	sp = (ulong*)(USTKTOP - ssize); 
	*--sp = nargs; 
1993/0501    
 
	ur = (Ureg*)up->dbgreg; 
	ur->usp = (ulong)sp; 
	ur->pc = entry - 4;			/* syscall advances it */ 
	up->fpsave.fpstatus = initfp.fpstatus; 
1991/1214    
	return USTKTOP-BY2WD;			/* address of user-level clock */ 
1990/0227    
} 
 
1992/0120    
ulong 
userpc(void) 
{ 
1993/0501    
	Ureg *ur; 
 
	ur = (Ureg*)up->dbgreg; 
	return ur->pc; 
1992/0120    
} 
 
1990/0227    
void 
novme(int v) 
{ 
	static count = 0; 
 
	print("vme intr 0x%.2x\n", v); 
	count++; 
	if(count >= 10) 
		panic("too many vme intr"); 
} 
 
void 
setvmevec(int v, void (*f)(int)) 
{ 
	void (*g)(int); 
 
	v &= 0xff; 
	g = vmevec[v]; 
1992/0612    
	if(g && g != novme && g != f) 
1990/0227    
		print("second setvmevec to 0x%.2x\n", v); 
	vmevec[v] = f; 
1991/1110    
} 
 
1993/0501    
/* This routine must save the values of registers the user is not permitted to 
 * write from devproc and then restore the saved values before returning 
1991/1110    
 */ 
void 
setregisters(Ureg *xp, char *pureg, char *uva, int n) 
{ 
	ulong status; 
 
	status = xp->status; 
	memmove(pureg, uva, n); 
	xp->status = status; 
1990/0227    
} 


source code copyright © 1990-2005 Lucent Technologies; see license
Plan 9 distribution
comments to russ cox (rsc@swtch.com)