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

1991/1102/power/trap.c (diff list | history)

power/trap.c on 1990/0227
1990/0227    
#include	"u.h" 
#include	"lib.h" 
#include	"mem.h" 
#include	"dat.h" 
#include	"fns.h" 
#include	"ureg.h" 
#include	"io.h" 
1990/0511    
#include	"errno.h" 
1990/0227    
 
/* 
 *  vme interrupt routines 
 */ 
void	(*vmevec[256])(int); 
 
1991/0717    
void	noted(Ureg**, ulong); 
1990/0227    
void	rfnote(Ureg**); 
 
#define	LSYS	0x01 
#define	LUSER	0x02 
/* 
 * CAUSE register 
 */ 
 
#define	EXCCODE(c)	((c>>2)&0x0F) 
#define	FPEXC		16 
 
char *excname[] = 
{ 
	"external interrupt", 
	"TLB modification", 
	"TLB miss (load or fetch)", 
	"TLB miss (store)", 
	"address error (load or fetch)", 
	"address error (store)", 
	"bus error (fetch)", 
	"bus error (data load or store)", 
	"system call", 
	"breakpoint", 
	"reserved instruction", 
	"coprocessor unusable", 
	"arithmetic overflow", 
	"undefined 13", 
	"undefined 14", 
1990/0901    
	"undefined 15",				/* used as sys call for debugger */ 
1990/0227    
	/* the following is made up */ 
	"floating point exception"		/* FPEXC */ 
}; 
char	*fpexcname(ulong); 
 
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", 
}; 
 
long	ticks; 
 
void 
trap(Ureg *ur) 
{ 
	int ecode; 
	int user; 
	ulong x; 
	char buf[ERRLEN]; 
 
1990/1214    
	SET(x); 
1990/0227    
	ecode = EXCCODE(ur->cause); 
	user = ur->status&KUP; 
	if(u) 
		u->p->pc = ur->pc;		/* BUG */ 
1991/0705    
 
1990/0227    
	switch(ecode){ 
	case CINT: 
		if(u && u->p->state==Running){ 
			if(u->p->fpstate == FPactive) { 
				if(ur->cause & INTR3){	/* FP trap */ 
					x = clrfpintr(); 
					ecode = FPEXC; 
				} 
				savefpregs(&u->fpsave); 
				u->p->fpstate = FPinactive; 
				ur->status &= ~CU1; 
				if(ecode == FPEXC) 
					goto Default; 
			} 
1991/0209    
		} 
		intr(ur); 
1990/0227    
		break; 
 
	case CTLBM: 
	case CTLBL: 
	case CTLBS: 
		if(u == 0) 
1990/0802    
			panic("fault u==0 pc %lux addr %lux", ur->pc, ur->badvaddr); 
1990/0227    
		if(u->p->fpstate == FPactive) { 
			savefpregs(&u->fpsave); 
			u->p->fpstate = FPinactive; 
			ur->status &= ~CU1; 
		} 
		spllo(); 
		x = u->p->insyscall; 
		u->p->insyscall = 1; 
1990/1212    
		faultmips(ur, user, ecode); 
1990/0227    
		u->p->insyscall = x; 
		break; 
 
	case CCPU: 
1990/0722    
		if(u && u->p && u->p->fpstate == FPinit) { 
1991/0314    
			restfpregs(&initfp, u->fpsave.fpstatus); 
1990/0227    
			u->p->fpstate = FPactive; 
			ur->status |= CU1; 
			break; 
		} 
1990/0722    
		if(u && u->p && u->p->fpstate == FPinactive) { 
1991/0314    
			restfpregs(&u->fpsave, u->fpsave.fpstatus); 
1990/0227    
			u->p->fpstate = FPactive; 
			ur->status |= CU1; 
			break; 
		} 
1990/0722    
		goto Default; 
1990/0227    
 
	default: 
1990/0722    
		if(u && u->p && u->p->fpstate == FPactive){ 
			savefpregs(&u->fpsave); 
			u->p->fpstate = FPinactive; 
			ur->status &= ~CU1; 
		} 
1990/0227    
	Default: 
		/* 
1991/0705    
		 * This isn't good enough; can still deadlock because we may  
		 * hold print's locks in this processor. 
1990/0227    
		 */ 
		if(user){ 
			spllo(); 
			if(ecode == FPEXC) 
1990/1110    
				sprint(buf, "sys: fp: %s FCR31 %lux", fpexcname(x), x); 
1990/0227    
			else 
1991/0705    
				sprint(buf, "sys: %s pc=0x%lux", excname[ecode], ur->pc); 
1991/0425    
 
1990/0227    
			postnote(u->p, 1, buf, NDebug); 
		}else{ 
			print("%s %s pc=%lux\n", user? "user": "kernel", excname[ecode], ur->pc); 
			if(ecode == FPEXC) 
				print("fp: %s FCR31 %lux\n", fpexcname(x), x); 
			dumpregs(ur); 
			if(m->machno == 0) 
				spllo(); 
			exit(); 
		} 
	} 
1991/0705    
 
	if(user) { 
		if(u->p->procctl) 
			procctl(u->p); 
		if(u->nnote) 
			notify(ur); 
	} 
 
1990/0227    
	splhi(); 
	if(user && u && u->p->fpstate == FPinactive) { 
1991/0314    
		restfpregs(&u->fpsave, u->fpsave.fpstatus); 
1990/0227    
		u->p->fpstate = FPactive; 
		ur->status |= CU1; 
	} 
} 
 
void 
1991/0209    
intr(Ureg *ur) 
1990/0227    
{ 
1991/0212    
	int i, any; 
1991/0316    
	uchar xxx; 
1991/0212    
	uchar pend, npend; 
1990/0227    
	long v; 
1991/0209    
	ulong cause; 
1991/0219    
	static int bogies; 
1990/0227    
 
1991/0425    
	m->intr++; 
1991/0209    
	cause = ur->cause&(INTR5|INTR4|INTR3|INTR2|INTR1); 
1990/0227    
	if(cause & (INTR2|INTR4)){ 
1991/0209    
		clock(ur); 
1990/0227    
		cause &= ~(INTR2|INTR4); 
	} 
	if(cause & INTR1){ 
		duartintr(); 
		cause &= ~INTR1; 
	} 
	if(cause & INTR5){ 
1991/0212    
		any = 0; 
1990/0227    
		if(!(*MPBERR1 & (1<<8))){ 
1990/0911    
			print("MP bus error %lux %lux\n", *MPBERR0, *MPBERR1); 
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; 
		npend = pend; 
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); 
			npend = pend |= 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))){ 
				print("io2 mp bus error %d %lux %lux\n", 0, 
					*MPBERR0, *MPBERR1); 
				*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)) 
					print("SCSI 1 interrupt\n"); 
				if(v & (1<<0)) 
					print("SCSI 0 interrupt\n"); 
			} 
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    
			} 
		} 
		/* 
1991/1031    
		 *  if nothing else, what the hell? 
1991/0212    
		 */ 
1991/1031    
		if(!any && bogies++<10){ 
1991/1102    
/*			print("bogus intr lvl 5 pend %lux on %d\n", npend, m->machno);/**/ 
1991/0212    
			delay(100); 
		} 
		/* 
1990/0227    
		 *  6. re-enable interrupts 
		 */ 
1991/0212    
		*IO2SETMASK = 0xff000000; 
1990/0227    
		cause &= ~INTR5; 
	} 
	if(cause) 
		panic("cause %lux %lux\n", u, cause); 
} 
 
char * 
fpexcname(ulong x) 
{ 
	static char *str[]={ 
		"inexact operation", 
		"underflow", 
		"overflow", 
		"division by zero", 
		"invalid operation", 
		"unimplemented operation", 
	}; 
	int i; 
 
	x >>= 12; 
	for(i=0; i<6; i++, x>>=1) 
		if(x & 1) 
			return str[i]; 
	return "no floating point exception"; 
} 
1990/03091    
 
1990/0227    
void 
dumpstack(void) 
{ 
	ulong l, v; 
	extern ulong etext; 
 
	if(u) 
		for(l=(ulong)&l; l<USERADDR+BY2PG; l+=4){ 
			v = *(ulong*)l; 
			if(KTZERO < v && v < (ulong)&etext) 
				print("%lux=%lux\n", l, v); 
		} 
} 
 
void 
dumpregs(Ureg *ur) 
{ 
	int i; 
	ulong *l; 
	int (*pr)(char*, ...); 
 
	if(u) 
		print("registers for %s %d\n", u->p->text, u->p->pid); 
	else 
		print("registers for kernel\n"); 
	l = &ur->status; 
	for(i=0; i<sizeof regname/sizeof(char*); i+=2, l+=2) 
		print("%s\t%.8lux\t%s\t%.8lux\n", regname[i], l[0], regname[i+1], l[1]); 
} 
 
/* 
 * Call user, if necessary, with note 
 */ 
void 
notify(Ureg *ur) 
{ 
	ulong sp; 
 
	lock(&u->p->debug); 
	if(u->nnote==0){ 
		unlock(&u->p->debug); 
		return; 
	} 
1991/0727    
	u->p->notepending = 0; 
1990/0227    
	if(u->note[0].flag!=NUser && (u->notified || u->notify==0)){ 
		if(u->note[0].flag == NDebug) 
			pprint("suicide: %s\n", u->note[0].msg); 
    Die: 
		unlock(&u->p->debug); 
		pexit(u->note[0].msg, u->note[0].flag!=NDebug); 
	} 
	if(!u->notified){ 
		if(!u->notify) 
			goto Die; 
1991/0503    
		u->svstatus = ur->status; 
1990/0816    
		sp = ur->usp; 
1990/0227    
		sp -= sizeof(Ureg); 
1991/0705    
		if(waserror()){ 
			pprint("suicide: trap in notify\n"); 
1991/0722    
			unlock(&u->p->debug); 
1991/0705    
			pexit("Suicide", 0); 
		} 
		validaddr((ulong)u->notify, 1, 0); 
		validaddr(sp-ERRLEN-3*BY2WD, sizeof(Ureg)+ERRLEN-3*BY2WD, 0); 
		poperror(); 
1990/0227    
		u->ureg = (void*)sp; 
1991/0318    
		memmove((Ureg*)sp, ur, sizeof(Ureg)); 
1990/0227    
		sp -= ERRLEN; 
1991/0318    
		memmove((char*)sp, u->note[0].msg, ERRLEN); 
1990/0227    
		sp -= 3*BY2WD; 
		*(ulong*)(sp+2*BY2WD) = sp+3*BY2WD;	/* arg 2 is string */ 
		*(ulong*)(sp+1*BY2WD) = (ulong)u->ureg;	/* arg 1 is ureg* */ 
		*(ulong*)(sp+0*BY2WD) = 0;		/* arg 0 is pc */ 
1990/0816    
		ur->usp = sp; 
1990/0227    
		ur->pc = (ulong)u->notify; 
		u->notified = 1; 
		u->nnote--; 
1991/0717    
		memmove(&u->lastnote, &u->note[0], sizeof(Note)); 
1991/0318    
		memmove(&u->note[0], &u->note[1], u->nnote*sizeof(Note)); 
1990/0227    
	} 
	unlock(&u->p->debug); 
} 
 
/* 
 * Return user to state before notify() 
 */ 
void 
1991/0717    
noted(Ureg **urp, ulong arg0) 
1990/0227    
{ 
1991/0503    
	Ureg *nur; 
 
	nur = u->ureg; 
	if(nur->status!=u->svstatus){ 
1991/0717    
		pprint("bad noted ureg status %lux\n", nur->status); 
1991/0814    
    Die: 
1991/0503    
		pexit("Suicide", 0); 
	} 
1990/0227    
	lock(&u->p->debug); 
1990/0619    
	if(!u->notified){ 
		unlock(&u->p->debug); 
1991/0814    
		pprint("call to noted() when not notified\n"); 
		goto Die; 
1990/0619    
	} 
1990/0227    
	u->notified = 0; 
1991/0318    
	memmove(*urp, u->ureg, sizeof(Ureg)); 
1991/0717    
	switch(arg0){ 
	case NCONT: 
1991/0814    
		if(waserror()){ 
			pprint("suicide: trap in noted\n"); 
			unlock(&u->p->debug); 
			goto Die; 
		} 
		validaddr(nur->pc, 1, 0); 
		validaddr(nur->usp, BY2WD, 0); 
		poperror(); 
1991/0717    
		splhi(); 
		unlock(&u->p->debug); 
		rfnote(urp); 
		break; 
		/* never returns */ 
 
	default: 
		pprint("unknown noted arg 0x%lux\n", arg0); 
		u->lastnote.flag = NDebug; 
		/* fall through */ 
		 
1991/0718    
	case NDFLT: 
1991/0717    
		if(u->lastnote.flag == NDebug) 
			pprint("suicide: %s\n", u->lastnote.msg); 
		unlock(&u->p->debug); 
		pexit(u->lastnote.msg, u->lastnote.flag!=NDebug); 
	} 
1990/0227    
} 
 
 
1991/0731    
#include "../port/systab.h" 
1990/0227    
 
long 
syscall(Ureg *aur) 
{ 
	long ret; 
	ulong sp; 
	ulong r1; 
	Ureg *ur; 
1990/0511    
	char *msg; 
1990/0227    
 
1991/0425    
	m->syscall++; 
1990/0227    
	u->p->insyscall = 1; 
	ur = aur; 
1990/0310    
	u->p->pc = ur->pc;		/* BUG */ 
1990/0901    
	ur->cause = 15<<2;		/* for debugging: system call is undef 15; 
1990/0227    
	/* 
	 * since the system call interface does not 
1991/0314    
	 * guarantee anything about registers, we can 
	 * smash them.  but we must save fpstatus. 
1990/0227    
	 */ 
	if(u->p->fpstate == FPactive) { 
1991/0314    
		u->fpsave.fpstatus = fcr31(); 
1990/0722    
		u->p->fpstate = FPinit; 
1990/0227    
		ur->status &= ~CU1; 
	} 
	spllo(); 
1991/0705    
 
	if(u->p->procctl) 
		procctl(u->p); 
 
1990/0227    
	r1 = ur->r1; 
	sp = ur->sp; 
	u->nerrlab = 0; 
	ret = -1; 
1990/0511    
	if(!waserror()){ 
1991/0731    
		if(r1 >= sizeof systab/sizeof systab[0]){ 
1990/0511    
			pprint("bad sys call number %d pc %lux\n", r1, ((Ureg*)UREGADDR)->pc); 
1990/1110    
			msg = "sys: bad sys call"; 
1990/0511    
	    Bad: 
			postnote(u->p, 1, msg, NDebug); 
1990/11211    
			error(Ebadarg); 
1990/0511    
		} 
		if(sp & (BY2WD-1)){ 
			pprint("odd sp in sys call pc %lux sp %lux\n", ((Ureg*)UREGADDR)->pc, ((Ureg*)UREGADDR)->sp); 
1990/1110    
			msg = "sys: odd stack"; 
1990/0511    
			goto Bad; 
		} 
1991/0710    
		if(((ulong*)ur->pc)[-2] == 0x23bdfffc){	/* old calling convention: look for ADD $-4, SP */ 
			pprint("old system call linkage; recompile\n"); 
			sp += BY2WD; 
		} 
1991/0711    
		if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-(1+MAXSYSARG)*BY2WD)) 
			validaddr(sp, (1+MAXSYSARG)*BY2WD, 0); 
1991/0926    
		u->p->psstate = sysctab[r1]; 
1991/0710    
		ret = (*systab[r1])((ulong*)(sp+BY2WD)); 
1990/0511    
	} 
1990/0227    
	ur->pc += 4; 
	u->nerrlab = 0; 
1991/0705    
	if(u->p->procctl) 
		procctl(u->p); 
 
1990/0227    
	splhi(); 
1991/0926    
	u->p->psstate = 0; 
1990/03091    
	u->p->insyscall = 0; 
1991/0926    
	if(r1 == NOTED)					/* ugly hack */ 
1991/0717    
		noted(&aur, *(ulong*)(sp+BY2WD));	/* doesn't return */ 
1991/0725    
	if(u->nnote && r1!=FORK){ 
1990/0227    
		ur->r1 = ret; 
		notify(ur); 
	} 
1991/0705    
 
1990/0227    
	return ret; 
} 
 
1990/1226    
void 
execpc(ulong entry) 
{ 
	((Ureg*)UREGADDR)->pc = entry - 4;		/* syscall advances it */ 
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]; 
	if(g && g != novme) 
		print("second setvmevec to 0x%.2x\n", v); 
	vmevec[v] = f; 
} 


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