~kris/9p

9hist

ca597059f8c66dc96f5830b11f0619dffbb3eacc — David du Colombier 34 years ago c11e90f
Plan 9 from Bell Labs 1992-07-26
10 files changed, 303 insertions(+), 23 deletions(-)

M gnot/mem.h
M pc/mem.h
M port/alloc.c
M port/portdat.h
M power/mem.h
M ss/dat.h
M ss/fns.h
A ss/fptrap.c
M ss/l.s
M ss/trap.c
M gnot/mem.h => gnot/mem.h +0 -1
@@ 15,7 15,6 @@
#define PGROUND(s)	(((s)+(BY2PG-1))&~(BY2PG-1))
#define ICACHESIZE	0
#define MB4		(4*1024*1024)		/* Lots of things are 4Mb in size */
#define MB		(1024*1024)

#define	MAXMACH		1			/* max # cpus system can run */


M pc/mem.h => pc/mem.h +0 -1
@@ 12,7 12,6 @@
#define	WD2PG		(BY2PG/BY2WD)		/* words per page */
#define	PGSHIFT		12			/* log(BY2PG) */
#define PGROUND(s)	(((s)+(BY2PG-1))&~(BY2PG-1))
#define MB		(1024*1024)

#define	MAXMACH		1			/* max # cpus system can run */


M port/alloc.c => port/alloc.c +1 -1
@@ 113,7 113,7 @@ xinit(void)

	palloc.np0 = np0;
	palloc.np1 = np1;
	/* Save the bounds of kernel alloc memory for kernel mmu mapping (NeXT) */
	/* Save the bounds of kernel alloc memory for kernel mmu mapping */
	conf.base0 = (ulong)KADDR(conf.base0);
	conf.base1 = (ulong)KADDR(conf.base1);
	conf.npage0 = (ulong)KADDR(conf.npage0);

M port/portdat.h => port/portdat.h +1 -0
@@ 676,6 676,7 @@ struct Network

#define	PRINTSIZE	256
#define	NUMSIZE		12		/* size of formatted number */
#define MB		(1024*1024)

extern	Conf	conf;
extern	char*	conffile;

M power/mem.h => power/mem.h +0 -1
@@ 14,7 14,6 @@
#define	PGSHIFT		12			/* log(BY2PG) */
#define PGROUND(s)	(((s)+(BY2PG-1))&~(BY2PG-1))
#define ICACHESIZE	(64*1024)		/* Power series */
#define MB		(1024*1024)

#define	MAXMACH		4			/* max # cpus system can run */


M ss/dat.h => ss/dat.h +6 -1
@@ 48,11 48,16 @@ enum
	FPinactive,
};

#define	NFPQ	4	/* just a guess */

struct	FPsave
{
	long	fsr;
	long	fpreg[32];
	long	pad;		/* so fsr can be guaranteed at 4 mod 8 */
	struct{
		ulong	a;	/* address */
		ulong	i;	/* instruction */
	}q[NFPQ];
};

struct Conf

M ss/fns.h => ss/fns.h +6 -1
@@ 1,9 1,11 @@
#include "../port/portfns.h"

void	cacheinit(void);
void	clearfpintr(void);
void	clearftt(ulong);
#define	clearmmucache()
void	clockinit(void);
void	disabfp(void);
void	enabfp(void);
void	evenaddr(ulong);
char*	excname(ulong);
void	faultasync(Ureg*);


@@ 15,7 17,10 @@ void	fpregrestore(char*);
void	fpregsave(char*);
void	fprestore(FPsave*);
void	fpsave(FPsave*);
int	fptrap(void);
int	getb2(ulong);
int	getfpq(ulong*);
ulong	getfsr(void);
int	getw2(ulong);
void	intrinit(void);
void	ioinit(void);

A ss/fptrap.c => ss/fptrap.c +223 -0
@@ 0,0 1,223 @@
#include	"u.h"
#include	"../port/lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"ureg.h"
#include	"io.h"
#include	"../port/error.h"

static	int	unfinished(FPsave*);
static	int	fixq(FPsave*, int);
extern	void*	bbmalloc(int);

int
fptrap(void)
{
	int n, ret;
	ulong fsr;

	n = getfpq(&u->fpsave.q[0].a);
	if(n > NFPQ)
		panic("FPQ %d\n", n);
    again:
	fsr = getfsr();
	savefpregs(&u->fpsave);
	u->fpsave.fsr = fsr;
	ret = 0;
	switch((fsr>>14) & 7){
	case 2:
		ret = unfinished(&u->fpsave);
		break;
	}
	if(ret){
		enabfp();	/* savefpregs disables it */
		clearftt(fsr & ~0x1F);	/* clear ftt and cexc */
		restfpregs(&u->fpsave);
		enabfp();	/* restfpregs disables it */
		n = fixq(&u->fpsave, n);
		if(n > 0)
			goto again;
	}
	return ret;
}

static void
unpack(FPsave *f, int size, int reg, int *sign, int *exp)
{
	*sign = 1;
	if(f->fpreg[reg] & 0x80000000)
		*sign = -1;
	switch(size){
	case 1:
		*exp = ((f->fpreg[reg]>>23)&0xFF) - ((1<<7)-2);
		break;
	case 2:
		if(reg & 1){
			pprint("unaligned double fp register\n");
			reg &= ~1;
		}
		*exp = ((f->fpreg[reg]>>20)&0x7FF) - ((1<<10)-2);
		break;
	case 3:
		if(reg & 3){
			pprint("unaligned quad fp register\n");
			reg &= ~3;
		}
		*exp = ((f->fpreg[reg]>>16)&0x7FFF) - ((1<<14)-2);
		break;
	}
}

static void
zeroreg(FPsave *f, int size, int reg, int sign)
{
	switch(size){
	case 1:
		size = 4;
		break;
	case 2:
		if(reg & 1)
			reg &= ~1;
		size = 8;
		break;
	case 3:
		if(reg & 3)
			reg &= ~3;
		size = 16;
		break;
	}
	memset(&f->fpreg[reg], 0, size);
	if(sign < 0)
		f->fpreg[reg] |= 0x80000000;
}

static int
unfinished(FPsave *f)
{
	ulong instr;
	int size, maxe, maxm, op, rd, rs1, rs2;
	int sd, ss1, ss2;
	int ed, es1, es2;

	instr = f->q[0].i;
	if((instr&0xC1F80000) != 0x81A00000){
    bad:
		pprint("unknown unfinished instruction %lux\n", instr);
		return 0;
	}
	size = (instr>>5) & 0x3;
	if(size == 0)
		goto bad;
	maxe = 0;
	maxm = 0;
	switch(size){
	case 1:
		maxe = 1<<7;
		maxm = 24;
		break;
	case 2:
		maxe = 1<<10;
		maxm = 53;
		break;
	case 3:
		maxe = 1<<14;
		maxm = 113;
		break;
	}
	rd = (instr>>25) & 0x1F;
	rs1 = (instr>>14) & 0x1F;
	rs2 = (instr>>0) & 0x1F;
	unpack(f, size, rs1, &ss1, &es1);
	unpack(f, size, rs2, &ss2, &es2);
	op = (instr>>7) & 0x7F;
	ed = 0;
	switch(op){
	case 0x11:	/* FSUB */
		ss2 = -ss2;
	case 0x10:	/* FADD */
		if(es1<-(maxe-maxm) && es2<-(maxe-maxm))
			ed = -maxe;
		if(es1 > es2)
			sd = es1;
		else
			sd = es2;
		break;

	case 0x13:	/* FDIV */
		es2 = -es2;
	case 0x12:	/* FMUL */
		sd = 1;
		if(ss1 != ss2)
			sd = -1;
		ed = es1 + es2;
		break;

	case 0x31:	/* F?TOS */
	case 0x32:	/* F?TOD */
	case 0x33:	/* F?TOQ */
		if(es2 == maxe)		/* NaN or Inf */
			return 0;
		sd = ss2;
		ed = es2;	/* if underflow, this will do the trick */
		break;

	default:
		goto bad;
	}
	if(ed <= -(maxe-4)){	/* guess: underflow */
		zeroreg(f, size, rd, sd);
		return 1;
	}
	return 0;
}

static int
fixq(FPsave *f, int n)
{
	ulong instr, fsr;
	ulong *ip;

	while(n > 1){
		memmove(&f->q[0], &f->q[1], (n-1)*sizeof f->q[0]);
		instr = f->q[0].i;
		ip = bbmalloc(3*sizeof(ulong));
		ip[0] = instr;
		ip[1] = 0x81c3e008;	/* JMPL #8(R15), R0 [RETURN] */
		ip[2] = 0x01000000;	/* SETHI #0, R0 [NOP] */
		(*(void(*)(void))ip)();
		/*
		 * WARNING: This code is wrong (and I don't know how
		 * to fix it without emulating the entire FPU in
		 * software--please let me knw) if the queued
		 * instruction gets an exception: the getfsr() generates
		 * a trap and the staggeringly inept SPARC design
		 * translates that to a reset, as you can't have
		 * nested exceptions.  So here's the fairly solid but
		 * not fail-safe solution: jump out NOW if there's
		 * nothing else pending.  If this last instruction
		 * causes an exception, it will fire when the *user*
		 * executes the next FP instruction.  The system
		 * avoids executing any FP on the way out.  The
		 * user will trap and we'll be back but will have
		 * made progress.  The FQ will point to kernel space
		 * but the trap will happen in user space, and that's
		 * what matters.
		 *
		 * This same botch may cause the system to reset
		 * if a trap is pending when we call savefpregs() in
		 * trap.c.  I don't know; the documentation is unclear.
		 */
		if(n == 1)
			return 0;
		for(;;){
			fsr = getfsr();
			if((fsr & (1<<13)) == 0)	/* qne */
				break;
			if(fsr & 0x1F)			/* cexc */
				return n;
		}
		--n;
	}
	return 0;
}

M ss/l.s => ss/l.s +33 -9
@@ 500,6 500,20 @@ TEXT	savefpregs(SB), $0
	MOVW	R8, PSR
	RETURN

TEXT	enabfp(SB), $0

	MOVW	PSR, R8
	OR	$PSREF, R8
	MOVW	R8, PSR
	RETURN

TEXT	disabfp(SB), $0

	MOVW	PSR, R8
	ANDN	$PSREF, R8
	MOVW	R8, PSR
	RETURN

TEXT	restfpregs(SB), $0

	MOVW	PSR, R8


@@ 533,17 547,21 @@ TEXT	restfpregs(SB), $0
	MOVW	R8, PSR
	RETURN

TEXT	clearfpintr(SB), $0
TEXT	getfpq(SB), $0

	MOVW	$fpq+BY2WD(SB), R7
	ANDN	$0x7, R7		/* must be D aligned */
	MOVW	R7, R8	/* must be D aligned */
	MOVW	$fsr+0(SB), R9
clrq:
	MOVD	FQ, (R7)
	MOVW	$0, R7
getfpq1:
	MOVW	FSR, (R9)
	MOVW	(R9), R8
	AND	$(1<<13), R8		/* queue not empty? */
	BNE	clrq
	MOVW	(R9), R10
	ANDCC	$(1<<13), R10		/* queue not empty? */
	BE	getfpq2
	MOVD	FQ, (R8)
	ADD	$1, R7
	ADD	$8, R8
	BA	getfpq1
getfpq2:
	RETURN

TEXT	getfsr(SB), $0


@@ 552,6 570,12 @@ TEXT	getfsr(SB), $0
	MOVW	(R7), R7
	RETURN

TEXT	clearftt(SB), $0
	MOVW	R7, fsr+0(SB)
	MOVW	$fsr+0(SB), R7
	MOVW	(R7), FSR
	FMOVF	F0, F0
	RETURN

GLOBL	mach0+0(SB), $MACHSIZE
GLOBL	fpq+0(SB), $(3*BY2WD)
GLOBL	fsr+0(SB), $BY2WD

M ss/trap.c => ss/trap.c +33 -8
@@ 14,7 14,8 @@ int	domuldiv(ulong, Ureg*);
extern	void traplink(void);
extern	void syslink(void);

long	ticks;
	long	ticks;
static	char	excbuf[64];	/* BUG: not reentrant! */

char *trapname[]={
	"reset",


@@ 31,14 32,37 @@ char *trapname[]={
	"watchpoint detected",
};

char *fptrapname[]={
	"none",
	"IEEE 754 exception",
	"unfinished FP op",
	"unimplemented FP op",
	"sequence error",
	"hardware error",
	"invalid FP register",
	"reserved",
};

char*
excname(ulong tbr)
{
	static char buf[64];	/* BUG: not reentrant! */
	char xx[64];
	char *t;
	ulong fsr;

	switch(tbr){
	case 8:
		if(u == 0){
			fsr = getfsr();
			sprint(excbuf, "fp: %s FSR %lux",
				fptrapname[(fsr>>14)&7], fsr);
		}else{
			fsr = u->fpsave.fsr;
			sprint(excbuf, "fp: %s FQpc=0x%lux",
				fptrapname[(fsr>>14)&7],
				u->fpsave.q[0].a, fsr);
		}
		return excbuf;
	case 36:
		return "trap: cp disabled";
	case 37:


@@ 65,10 89,10 @@ excname(ulong tbr)
		t = xx;
	}
	if(strncmp(t, "fp: ", 4) == 0)
		strcpy(buf, t);
		strcpy(excbuf, t);
	else
		sprint(buf, "trap: %s", t);
	return buf;
		sprint(excbuf, "trap: %s", t);
	return excbuf;
}

void


@@ 148,7 172,10 @@ trap(Ureg *ur)
			}
			break;
		case 8:				/* floating point exception */
			clearfpintr();
			if(fptrap()){
				/* do NOT talk to the FPU: see fptrap.c */
				return;
			}
			break;
		default:
			break;


@@ 157,8 184,6 @@ trap(Ureg *ur)
		if(user){
			spllo();
			sprint(buf, "sys: %s", excname(tbr));
			if(tbr == 8)
				sprint(buf+strlen(buf), " FSR %lux", u->fpsave.fsr);
			postnote(u->p, 1, buf, NDebug);
		}else{
			print("kernel trap: %s pc=0x%lux\n", excname(tbr), ur->pc);