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

1990/0911/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); 
 
void	notify(Ureg*); 
void	noted(Ureg**); 
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]; 
 
	ecode = EXCCODE(ur->cause); 
	user = ur->status&KUP; 
	if(u) 
		u->p->pc = ur->pc;		/* BUG */ 
	switch(ecode){ 
	case CINT: 
		m->intrp = 0; 
		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; 
			} 
			m->intr = intr; 
			m->cause = ur->cause; 
1990/0731    
			m->pc = ur->pc; 
1990/0227    
			if(ur->cause & INTR2) 
				m->intrp = u->p; 
			sched(); 
		}else 
1990/0731    
			intr(ur->cause, ur->pc); 
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; 
		fault(ur, user, ecode); 
		u->p->insyscall = x; 
		break; 
 
	case CCPU: 
1990/0722    
		if(u && u->p && u->p->fpstate == FPinit) { 
1990/0227    
			restfpregs(&initfp); 
			u->p->fpstate = FPactive; 
			ur->status |= CU1; 
			break; 
		} 
1990/0722    
		if(u && u->p && u->p->fpstate == FPinactive) { 
1990/0227    
			restfpregs(&u->fpsave); 
			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: 
		/* 
		 * This isn't good enough; can still deadlock because we may hold print's locks 
		 * in this processor. 
		 */ 
		if(user){ 
			spllo(); 
			if(ecode == FPEXC) 
				sprint(buf, "fp: %s FCR31 %lux", fpexcname(x), x); 
			else 
1990/0427    
				sprint(buf, "trap: %s[%d]", excname[ecode], m->machno); 
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(); 
		} 
	} 
	if(user && u->nnote) 
		notify(ur); 
	splhi(); 
	if(user && u && u->p->fpstate == FPinactive) { 
		restfpregs(&u->fpsave); 
		u->p->fpstate = FPactive; 
		ur->status |= CU1; 
	} 
} 
 
void 
1990/0731    
intr(ulong cause, ulong pc) 
1990/0227    
{ 
	int i, pend; 
	long v; 
 
	cause &= INTR5|INTR4|INTR3|INTR2|INTR1; 
	if(cause & (INTR2|INTR4)){ 
1990/0731    
		clock(cause, pc); 
1990/0227    
		cause &= ~(INTR2|INTR4); 
	} 
	if(cause & INTR1){ 
		duartintr(); 
		cause &= ~INTR1; 
	} 
	if(cause & INTR5){ 
 
		if(!(*MPBERR1 & (1<<8))){ 
1990/0911    
			print("MP bus error %lux %lux\n", *MPBERR0, *MPBERR1); 
1990/0227    
			*MPBERR0 = 0; 
			i = *SBEADDR; 
		} 
 
		/* 
		 *  directions from IO2 manual 
		 *  1. clear all IO2 masks 
		 */ 
		*IO2CLRMASK = 0xff; 
 
		/* 
		 *  2. wait for interrupt in progress 
		 */ 
		while(!(*INTPENDREG & (1<<5))) 
			; 
 
		/* 
		 *  3. read pending interrupts 
		 */ 
		pend = SBCCREG->fintpending & 0xff; 
 
		/* 
		 *  4. clear pending register 
		 */ 
		i = SBCCREG->flevel; 
 
		/* 
		 *  5a. process lance, scsi 
		 */ 
1990/0907    
	loop: 
1990/0227    
		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; 
			} 
1990/0911    
			if(ioid < IO3R1){ 
1990/0907    
				if(!(v & (1<<2))) 
					lanceintr(); 
				if(!(v & (1<<1))) 
					lanceparity(); 
				if(!(v & (1<<0))) 
					print("SCSI interrupt\n"); 
1990/0911    
			} else { 
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 
		 *  i bet i can guess your level 
		 */ 
		pend >>= 1; 
		for(i=1; pend; i++) { 
			if(pend & 1) { 
				v = INTVECREG->i[i].vec; 
1990/0907    
				if(!(v & (1<<12))){ 
					print("io2 mp bus error %d %lux %lux\n", i, 
						*MPBERR0, *MPBERR1); 
					*MPBERR0 = 0; 
				} 
1990/0227    
				v &= 0xff; 
				(*vmevec[v])(v); 
			} 
			pend >>= 1; 
		} 
		/* 
		 *  6. re-enable interrupts 
		 */ 
1990/0907    
		*IO2SETMASK = 0xff; 
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]); 
	dumpstack(); 
} 
 
/* 
 * 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; 
	} 
	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; 
1990/0816    
		sp = ur->usp; 
1990/0227    
		sp -= sizeof(Ureg); 
		u->ureg = (void*)sp; 
		memcpy((Ureg*)sp, ur, sizeof(Ureg)); 
		sp -= ERRLEN; 
		memcpy((char*)sp, u->note[0].msg, ERRLEN); 
		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--; 
		memcpy(&u->note[0], &u->note[1], u->nnote*sizeof(Note)); 
	} 
	unlock(&u->p->debug); 
} 
 
/* 
 * Return user to state before notify() 
 */ 
void 
noted(Ureg **urp) 
{ 
	lock(&u->p->debug); 
1990/0619    
	if(!u->notified){ 
		unlock(&u->p->debug); 
		return; 
	} 
1990/0227    
	u->notified = 0; 
	memcpy(*urp, u->ureg, sizeof(Ureg)); 
	unlock(&u->p->debug); 
	splhi(); 
	rfnote(urp); 
} 
 
 
#undef	CHDIR	/* BUG */ 
#include "/sys/src/libc/mips9sys/sys.h" 
 
typedef long Syscall(ulong*); 
Syscall sysaccess, sysbind, sysbrk_, syschdir, sysclose, syscreate; 
Syscall	sysdup, syserrstr, sysexec, sysexits, sysfork, sysforkpgrp; 
Syscall	sysfstat, sysfwstat, sysgetpid, syslasterr, sysmount, sysnoted; 
Syscall	sysnotify, sysopen, syspipe, sysr1, sysread, sysremove, sysseek; 
Syscall syssleep, sysstat, sysuserstr, syswait, syswrite, syswstat; 
 
Syscall *systab[]={ 
	[SYSR1]		sysr1, 
1990/0826    
	[___ACCESS___]	sysaccess, 
1990/0227    
	[BIND]		sysbind, 
	[CHDIR]		syschdir, 
	[CLOSE]		sysclose, 
	[DUP]		sysdup, 
	[ERRSTR]	syserrstr, 
	[EXEC]		sysexec, 
	[EXITS]		sysexits, 
	[FORK]		sysfork, 
	[FORKPGRP]	sysforkpgrp, 
	[FSTAT]		sysfstat, 
	[LASTERR]	syslasterr, 
	[MOUNT]		sysmount, 
	[OPEN]		sysopen, 
	[READ]		sysread, 
	[SEEK]		sysseek, 
	[SLEEP]		syssleep, 
	[STAT]		sysstat, 
	[WAIT]		syswait, 
	[WRITE]		syswrite, 
	[PIPE]		syspipe, 
	[CREATE]	syscreate, 
	[USERSTR]	sysuserstr, 
	[BRK_]		sysbrk_, 
	[REMOVE]	sysremove, 
	[WSTAT]		syswstat, 
	[FWSTAT]	sysfwstat, 
	[NOTIFY]	sysnotify, 
	[NOTED]		sysnoted, 
}; 
 
long 
syscall(Ureg *aur) 
{ 
	long ret; 
	ulong sp; 
	ulong r1; 
	Ureg *ur; 
1990/0511    
	char *msg; 
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 
	 * guarantee anything about registers, 
	 */ 
	if(u->p->fpstate == FPactive) { 
1990/0722    
		u->p->fpstate = FPinit; 
1990/0227    
		ur->status &= ~CU1; 
	} 
	spllo(); 
	r1 = ur->r1; 
	sp = ur->sp; 
	u->nerrlab = 0; 
	ret = -1; 
1990/0511    
	if(!waserror()){ 
		if(r1 >= sizeof systab/BY2WD){ 
			pprint("bad sys call number %d pc %lux\n", r1, ((Ureg*)UREGADDR)->pc); 
			msg = "bad sys call"; 
	    Bad: 
			postnote(u->p, 1, msg, NDebug); 
			error(0, Ebadarg); 
		} 
		if(sp & (BY2WD-1)){ 
			pprint("odd sp in sys call pc %lux sp %lux\n", ((Ureg*)UREGADDR)->pc, ((Ureg*)UREGADDR)->sp); 
			msg = "odd stack"; 
			goto Bad; 
		} 
		if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-4*BY2WD)) 
1990/0515    
			validaddr(sp, 4*BY2WD, 0); 
1990/0227    
		ret = (*systab[r1])((ulong*)(sp+2*BY2WD)); 
1990/0511    
	} 
1990/0227    
	ur->pc += 4; 
	u->nerrlab = 0; 
	splhi(); 
1990/03091    
	u->p->insyscall = 0; 
1990/0227    
	if(r1 == NOTED)	/* ugly hack */ 
		noted(&aur);	/* doesn't return */ 
	if(u->nnote){ 
		ur->r1 = ret; 
		notify(ur); 
	} 
	return ret; 
} 
 
void 
error(Chan *c, int code) 
{ 
	if(c){ 
		u->error.type = c->type; 
		u->error.dev = c->dev; 
	}else{ 
		u->error.type = 0; 
		u->error.dev = 0; 
	} 
	u->error.code = code; 
	nexterror(); 
} 
 
void 
nexterror(void) 
{ 
	gotolabel(&u->errlab[--u->nerrlab]); 
} 
 
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)