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

1992/0711/power/trap.c (diff list | history)

1992/0711/sys/src/9/power/trap.c:1,6131992/0714/sys/src/9/power/trap.c:1,613 (short | long | prev | next)
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    
 
/* 
 *  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[] = 
{ 
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", 
	"trap: undefined 15",				/* used as sys call for debugger */ 
1990/0227    
	/* the following is made up */ 
1992/0102    
	"trap: floating point exception"		/* FPEXC */ 
1990/0227    
}; 
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); 
1992/0527    
	LEDON(ecode); 
1990/0227    
	user = ur->status&KUP; 
1991/1110    
	if(u) { 
1990/0227    
		u->p->pc = ur->pc;		/* BUG */ 
1991/1110    
		u->dbgreg = ur; 
	} 
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 
1992/0102    
				sprint(buf, "sys: %s", excname[ecode]); 
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    
 
1990/0227    
	splhi(); 
1991/1114    
	if(user) { 
		notify(ur); 
		if(u->p->fpstate == FPinactive) { 
			restfpregs(&u->fpsave, u->fpsave.fpstatus); 
			u->p->fpstate = FPactive; 
			ur->status |= CU1; 
		} 
1990/0227    
	} 
1992/0527    
	LEDOFF(ecode); 
1990/0227    
} 
 
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)){ 
1992/0508    
		LEDON(LEDclock); 
1991/0209    
		clock(ur); 
1992/0508    
		LEDOFF(LEDclock); 
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){ 
1992/0325    
			if(0) 
			print("bogus intr lvl 5 pend %lux on %d\n", npend, m->machno); 
			USED(npend); 
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; 
1992/0319    
			if(KTZERO < v && v < (ulong)&etext){ 
1990/0227    
				print("%lux=%lux\n", l, v); 
1992/0320    
				delay(100); 
1992/0319    
			} 
1990/0227    
		} 
} 
 
void 
dumpregs(Ureg *ur) 
{ 
	int i; 
	ulong *l; 
 
	if(u) 
		print("registers for %s %d\n", u->p->text, u->p->pid); 
	else 
		print("registers for kernel\n"); 
	l = &ur->status; 
1992/0319    
	for(i=0; i<sizeof regname/sizeof(char*); i+=2, l+=2){ 
1990/0227    
		print("%s\t%.8lux\t%s\t%.8lux\n", regname[i], l[0], regname[i+1], l[1]); 
1992/0319    
		prflush(); 
	} 
1990/0227    
} 
 
/* 
 * Call user, if necessary, with note 
 */ 
1992/0108    
int 
1990/0227    
notify(Ureg *ur) 
{ 
1992/0124    
	int l, sent; 
1991/1114    
	ulong s, sp; 
1991/1218    
	Note *n; 
1990/0227    
 
1991/1110    
	if(u->p->procctl) 
		procctl(u->p); 
1991/1230    
	if(u->nnote == 0) 
1992/0108    
		return 0; 
1991/1114    
 
	s = spllo(); 
1991/1216    
	qlock(&u->p->debug); 
1991/0727    
	u->p->notepending = 0; 
1991/1218    
	n = &u->note[0]; 
	if(strncmp(n->msg, "sys:", 4) == 0){ 
		l = strlen(n->msg); 
		if(l > ERRLEN-15)	/* " pc=0x12345678\0" */ 
			l = ERRLEN-15; 
		sprint(n->msg+l, " pc=0x%.8lux", ur->pc); 
	} 
	if(n->flag!=NUser && (u->notified || u->notify==0)){ 
1990/0227    
		if(u->note[0].flag == NDebug) 
1992/0714    
		if(n->flag == NDebug) 
1991/1218    
			pprint("suicide: %s\n", n->msg); 
1990/0227    
    Die: 
1991/1216    
		qunlock(&u->p->debug); 
1991/1218    
		pexit(n->msg, n->flag!=NDebug); 
1990/0227    
	} 
1992/0124    
	sent = 0; 
1990/0227    
	if(!u->notified){ 
		if(!u->notify) 
			goto Die; 
1992/0124    
		sent = 1; 
1991/0503    
		u->svstatus = ur->status; 
1990/0816    
		sp = ur->usp; 
1990/0227    
		sp -= sizeof(Ureg); 
1992/0616    
		if(!okaddr((ulong)u->notify, 1, 0) 
		|| !okaddr(sp-ERRLEN-3*BY2WD, sizeof(Ureg)+ERRLEN-3*BY2WD, 0)){ 
			pprint("suicide: bad address in notify\n"); 
1991/1216    
			qunlock(&u->p->debug); 
1991/0705    
			pexit("Suicide", 0); 
		} 
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 */ 
1992/0409    
		u->svr1 = ur->r1;			/* save away r1 */ 
1992/0102    
		ur->r1 = (ulong)u->ureg;		/* arg 1 is ureg* */ 
1990/0227    
		*(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    
	} 
1991/1216    
	qunlock(&u->p->debug); 
1991/1114    
	splx(s); 
1992/0124    
	return sent; 
1990/0227    
} 
 
/* 
 * 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); 
	} 
1991/1216    
	qlock(&u->p->debug); 
1990/0619    
	if(!u->notified){ 
1991/1216    
		qunlock(&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)); 
1992/0102    
	(*urp)->r1 = u->svr1; 
1991/0717    
	switch(arg0){ 
	case NCONT: 
1992/0616    
		if(!okaddr(nur->pc, 1, 0) || !okaddr(nur->usp, BY2WD, 0)){ 
1991/0814    
			pprint("suicide: trap in noted\n"); 
1991/1216    
			qunlock(&u->p->debug); 
1991/0814    
			goto Die; 
		} 
1991/0717    
		splhi(); 
1991/1216    
		qunlock(&u->p->debug); 
1991/0717    
		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); 
1991/1216    
		qunlock(&u->p->debug); 
1991/0717    
		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; 
	Ureg *ur; 
1992/0407    
	Proc *p; 
1990/0227    
 
1991/0425    
	m->syscall++; 
1992/0407    
	p = u->p; 
	p->insyscall = 1; 
1990/0227    
	ur = aur; 
1992/0407    
	p->pc = ur->pc;		/* BUG */ 
1991/1110    
	u->dbgreg = aur; 
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    
	 */ 
1992/0407    
	if(p->fpstate == FPactive) { 
1991/0314    
		u->fpsave.fpstatus = fcr31(); 
1992/0407    
		p->fpstate = FPinit; 
1990/0227    
		ur->status &= ~CU1; 
	} 
	spllo(); 
1991/0705    
 
1992/06271    
	u->scallnr = ur->r1; 
1990/0227    
	sp = ur->sp; 
	u->nerrlab = 0; 
	ret = -1; 
1990/0511    
	if(!waserror()){ 
1992/06271    
		if(u->scallnr >= sizeof systab/sizeof systab[0]) { 
			pprint("bad sys call number %d pc %lux\n", u->scallnr, ur->pc); 
1992/0625    
			postnote(p, 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); 
			postnote(p, 1, "sys: odd stack", NDebug); 
			error(Ebadarg); 
1990/0511    
		} 
1992/0625    
 
		if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs))) 
			validaddr(sp, sizeof(Sargs), 0); 
 
		u->s = *((Sargs*)(sp+BY2WD)); 
1992/06271    
		p->psstate = sysctab[u->scallnr]; 
1992/0625    
 
1992/06271    
		ret = (*systab[u->scallnr])(u->s.args); 
1990/0511    
	} 
1990/0227    
	ur->pc += 4; 
	u->nerrlab = 0; 
1991/0705    
 
1992/0407    
	p->psstate = 0; 
	p->insyscall = 0; 
1992/06271    
	if(u->scallnr == NOTED)					/* ugly hack */ 
1991/0717    
		noted(&aur, *(ulong*)(sp+BY2WD));	/* doesn't return */ 
1991/1114    
	splhi(); 
1992/06271    
	if(u->scallnr!=RFORK && (p->procctl || u->nnote)){ 
1992/0409    
		ur->r1 = ret;				/* load up for noted() */ 
1992/0108    
		if(notify(ur)) 
			return ur->r1; 
1990/0227    
	} 
1991/0705    
 
1990/0227    
	return ret; 
} 
 
1991/1214    
long 
execregs(ulong entry, ulong ssize, ulong nargs) 
1990/1226    
{ 
1991/1214    
	ulong *sp; 
 
	sp = (ulong*)(USTKTOP - ssize); 
	*--sp = nargs; 
	((Ureg*)UREGADDR)->usp = (ulong)sp; 
	((Ureg*)UREGADDR)->pc = entry - 4;	/* syscall advances it */ 
	return USTKTOP-BY2WD;			/* address of user-level clock */ 
1990/0227    
} 
 
1992/0120    
ulong 
userpc(void) 
{ 
	return ((Ureg*)UREGADDR)->pc; 
} 
 
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    
} 
 
1991/1111    
/* This routine must save the values of registers the user is not permitted to write 
 * from devproc and the 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)