~kris/9p

9hist

723e986e12255a7ce91be3f3cb66b35ff97023ea — David du Colombier 35 years ago 6a8b27b
Plan 9 from Bell Labs 1991-01-10
M gnot/dat.h => gnot/dat.h +1 -0
@@ 154,6 154,7 @@ struct Conf
	int	nfsyschan;	/* number of filsys open channels */
	ulong	maxialloc;	/* maximum bytes used by ialloc */
	int	copymode;	/* 0 is copy on write, 1 is copy on reference */
	int	portispaged;	/* ??? */
};

struct Dev

A gnot/devport.c => gnot/devport.c +222 -0
@@ 0,0 1,222 @@
#include	"u.h"
#include	"lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"io.h"
#include	"errno.h"

#include	"devtab.h"

#include	"port.h"

enum {
	Qdir,
	Qdata,
};

Dirtab portdir[]={
	"data",		{Qdata},	0,	0600,
};

#define	NPORT	(sizeof portdir/sizeof(Dirtab))

int
portprobe(char *what, int select, int addr, int rw, long val)
{
	int time;
	if (!conf.portispaged)
		return 0;
	P_qlock(select);
	switch (rw) {
	case -1:
		val = *(uchar *)(PORT+addr); break;
	case -2:
		val = *(ushort *)(PORT+addr); break;
	case -4:
		val = *(long *)(PORT+addr); break;
	case 1:
		*(uchar *)(PORT+addr) = val; break;
	case 2:
		*(ushort *)(PORT+addr) = val; break;
	case 4:
		*(long *)(PORT+addr) = val; break;
	default:
		panic("portprobe");
	}
	time = PORTSELECT & 0x1f;
	P_qunlock(select);
	if (what) {
		print("%s at %d, %d", what, select, addr);
		print("%s", time & 0x10 ? " -- NOT FOUND\n" : "\n");
	}
	if (time & 0x10)
		return -1;
	return val;
}

void
portreset(void)
{
	portpage.select = -1;
	lock(&portpage);
	unlock(&portpage);
}

void
portinit(void)
{}

Chan *
portattach(char *param)
{
	return devattach('x', param);
}

Chan *
portclone(Chan *c, Chan *nc)
{
	return devclone(c, nc);
}

int
portwalk(Chan *c, char *name)
{
	return devwalk(c, name, portdir, NPORT, devgen);
}

void
portstat(Chan *c, char *db)
{
	devstat(c, db, portdir, NPORT, devgen);
}

Chan *
portopen(Chan *c, int omode)
{
	return devopen(c, omode, portdir, NPORT, devgen);
}

void
portcreate(Chan *c, char *name, int omode, ulong perm)
{
	error(Eperm);
}

void
portclose(Chan *c)
{}

long
portread(Chan *c, char *a, long n)
{
	long s, k;
	if (n == 0)
		return 0;
	switch ((int)(c->qid.path & ~CHDIR)) {
	case Qdir:
		return devdirread(c, a, n, portdir, NPORT, devgen);
	case Qdata:
		if (!conf.portispaged || (s = c->offset >> PORTSHIFT) > 0xff)
			s = -1;
		k = c->offset % PORTSIZE;
		P_qlock(s);
		switch ((int)n) {
		case 1:
			*a = PORT[k]; break;
		case 2:
			*(short *)a = *(short *)(PORT+k); break;
		case 4:
			*(long *)a = *(long *)(PORT+k); break;
		default:
			P_qunlock(s);
			error(Ebadarg);
		}
		P_qunlock(s);
		break;
	default:
		panic("portread");
	}
	return n;
}

long
portwrite(Chan *c, char *a, long n)
{
	long s, k;
	if (n == 0)
		return 0;
	switch ((int)c->qid.path) {
	case Qdata:
		if (!conf.portispaged || (s = c->offset >> PORTSHIFT) > 0xff)
			s = -1;
		k = c->offset % PORTSIZE;
		P_qlock(s);
		switch ((int)n) {
		case 1:
			PORT[k] = *a; break;
		case 2:
			*(short *)(PORT+k) = *(short *)a; break;
		case 4:
			*(long *)(PORT+k) = *(long *)a; break;
		default:
			P_qunlock(s);
			error(Ebadarg);
		}
		P_qunlock(s);
		break;
	default:
		panic("portwrite");
	}
	return n;
}

void
portremove(Chan *c)
{
	error(Eperm);
}

void
portwstat(Chan *c, char *dp)
{
	error(Eperm);
}

#define	Nportservice	8
int	(*portservice[Nportservice])(void);

Portpage portpage;

Lock	intrlock;

void
addportintr(int (*f)(void))
{
	int s = splhi();
	int (**p)(void);
	lock(&intrlock);
	for (p=portservice; *p; p++)
		if (*p == f)
			goto out;
	if (p >= &portservice[Nportservice-1])
		panic("addportintr");
	*p = f;
out:
	unlock(&intrlock);
	splx(s);
}

void
devportintr(void)
{
	int (**p)(void); int i = 0;
	for (p=portservice; *p; p++)
		i |= (**p)();
	if (!i)
		/*putstring("spurious portintr\n");*/
		panic("portintr");
	if (portpage.select >= 0)
		PORTSELECT = portpage.select;

}

M gnot/main.c => gnot/main.c +1 -0
@@ 340,6 340,7 @@ confinit(void)
	conf.nservice = 3*mul;			/* was conf.nproc/5 */
	conf.nfsyschan = 31 + conf.nchan/20;
	conf.copymode = 0;		/* copy on write */
	conf.portispaged = 0;
}

/*

A gnot/scsisubs.s => gnot/scsisubs.s +67 -0
@@ 0,0 1,67 @@
#include "mem.h"

TEXT	spl1(SB), $0

	MOVL	$0, R0
	MOVW	SR, R0
	MOVW	$(SUPER|SPL(1)), SR
	RTS

TEXT	spl2(SB), $0

	MOVL	$0, R0
	MOVW	SR, R0
	MOVW	$(SUPER|SPL(2)), SR
	RTS

TEXT	scsirecv(SB), $0
	MOVL	$0x40300033, A0	/* data		*/
	MOVL	$0x40300032, A1	/* status	*/
	MOVL	p+0(FP), A2
	BTST	$1, (A1)
	BEQ	rout
rloop:
	MOVB	(A0), (A2)+
	BTST	$1, (A1)
	BEQ	rout

	MOVB	(A0), (A2)+
	BTST	$1, (A1)
	BEQ	rout

	MOVB	(A0), (A2)+
	BTST	$1, (A1)
	BEQ	rout

	MOVB	(A0), (A2)+
	BTST	$1, (A1)
	BNE	rloop
rout:
	MOVL	A2, R0
	RTS

TEXT	scsixmit(SB), $0
	MOVL	$0x40300033, A0	/* data		*/
	MOVL	$0x40300032, A1	/* status	*/
	MOVL	p+0(FP), A2
	BTST	$1, (A1)
	BEQ	xout
xloop:
	MOVB	(A2)+, (A0)
	BTST	$1, (A1)
	BEQ	xout

	MOVB	(A2)+, (A0)
	BTST	$1, (A1)
	BEQ	xout

	MOVB	(A2)+, (A0)
	BTST	$1, (A1)
	BEQ	xout

	MOVB	(A2)+, (A0)
	BTST	$1, (A1)
	BNE	xloop
xout:
	MOVL	A2, R0
	RTS

M port/devroot.c => port/devroot.c +2 -0
@@ 94,7 94,9 @@ rootread(Chan *c, void *buf, long n)
			return 0;
		if(c->offset+n > sizeof bootcode)
			n = sizeof bootcode - c->offset;
ck("1");
		memcpy(buf, ((char*)bootcode)+c->offset, n);
ck("2");
		return n;

	case Qdev:

A port/devscsi.c => port/devscsi.c +548 -0
@@ 0,0 1,548 @@
#include	"u.h"
#include	"lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"errno.h"
#include	"devtab.h"
#include	"io.h"

#include	"port.h"
#include	"scsi.h"

int	scsiintr(void);

#define	DPRINT	if(debug)kprint

enum {
	Qdir, Qcmd, Qdata, Qdebug,
};

static Dirtab scsidir[]={
	"cmd",		{Qcmd},		0,	0600,
	"data",		{Qdata},	0,	0600,
	"debug",	{Qdebug},	1,	0600,
};

#define	NSCSI	(sizeof scsidir/sizeof(Dirtab))

static Scsi	staticcmd;	/* BUG */
static uchar	datablk[8192];	/* BUG */

static int	debugs[8];
static int	isscsi;
static int	ownid = 0x08|7; /* enable advanced features */

static int
scsigen1(Chan *c, long qid, Dir *dp)
{
	if (qid == CHDIR)
		devdir(c, (Qid){qid,0}, ".", 0, 0500, dp);
	else if (qid == 1)
		devdir(c, (Qid){qid,0}, "id", 1, 0600, dp);
	else if (qid&CHDIR) {
		char name[2];
		name[0] = '0'+((qid>>4)&7), name[1] = 0;
		devdir(c, (Qid){qid,0}, name, 0, 0500, dp);
	} else {
		Dirtab *tab = &scsidir[(qid&7)-1];
		devdir(c, (Qid){qid,0}, tab->name, tab->length, tab->perm, dp);
	}
	return 1;
}

static int
scsigeno(Chan *c, Dirtab *tab, long ntab, long s, Dir *dp)
{
	return scsigen1(c, c->qid.path, dp);
}

static int
scsigen(Chan *c, Dirtab *tab, long ntab, long s, Dir *dp)
{
	if (c->qid.path == CHDIR) {
		if (0<=s && s<=7)
			return scsigen1(c, CHDIR|0x100|(s<<4), dp);
		else if (s == 8)
			return scsigen1(c, 1, dp);
		else
			return -1;
	}
	if (s >= NSCSI)
		return -1;
	return scsigen1(c, (c->qid.path&~CHDIR)+s+1, dp);
}

void
scsireset(void)
{
	addportintr(scsiintr);
}

Chan *
scsiattach(char *param)
{
	return devattach('S', param);
}

Chan *
scsiclone(Chan *c, Chan *nc)
{
	return devclone(c, nc);
}

int
scsiwalk(Chan *c, char *name)
{
	return devwalk(c, name, 0, 0, scsigen);
}

void
scsistat(Chan *c, char *db)
{
	devstat(c, db, 0, 0, scsigen);
}

Chan *
scsiopen(Chan *c, int omode)
{
	return devopen(c, omode, 0, 0, scsigeno);
}

void
scsicreate(Chan *c, char *name, int omode, ulong perm)
{
	error(Eperm);
}

void
scsiclose(Chan *c)
{}

long
scsiread(Chan *c, char *a, long n)
{
	Scsi *cmd = &staticcmd;
	if (n == 0)
		return 0;
	if(c->qid.path & CHDIR)
		return devdirread(c, a, n, 0, 0, scsigen);
	if(c->qid.path==1){
		if(c->offset == 0){
			*a = ownid;
			n = 1;
		}else
			n = 0;
	}else switch((int)(c->qid.path & 0xf)){
	case Qcmd:
		if (n < 4)
			error(Ebadarg);
		/*if(canqlock(cmd)){
			qunlock(cmd);
			error(Egreg);
		}*/
		n = 4;
		*a++ = cmd->state>>8; *a++ = cmd->state;
		*a++ = cmd->status>>8; *a = cmd->status;
		/*qunlock(cmd);*/
		break;
	case Qdata:
		if (n > sizeof datablk)
			error(Ebadarg);
		cmd->data.base = datablk;
		cmd->data.lim = cmd->data.base + n;
		cmd->data.ptr = cmd->data.base;
		cmd->save = cmd->data.base;
		scsiexec(cmd, 1);
		n = cmd->data.ptr - cmd->data.base;
		memcpy(a, cmd->data.base, n);
		break;
	case Qdebug:
		if (c->offset == 0) {
			n=1;
			*a="01"[debugs[(c->qid.path>>4)&7]!=0];
		} else
			n = 0;
		break;
	default:
		panic("scsiread");
	}
	return n;
}

long
scsiwrite(Chan *c, char *a, long n)
{
	Scsi *cmd = &staticcmd;
	if(c->qid.path==1 && n>0){
		if(c->offset == 0){
			n = 1;
			ownid=*a;
			scsiinit();
		}else
			n = 0;
	}else switch ((int)c->qid.path & 0xf){
	case Qcmd:
		if (n < 6 || n > sizeof cmd->cmdblk)
			error(Ebadarg);
		/*qlock(cmd);*/
		cmd->cmd.base = cmd->cmdblk;
		memcpy(cmd->cmd.base, a, n);
		cmd->cmd.lim = cmd->cmd.base + n;
		cmd->cmd.ptr = cmd->cmd.base;
		cmd->target = (c->qid.path>>4)&7;
		cmd->lun = (a[1]>>5)&7;
		cmd->state = 0;
		cmd->status = 0xFFFF;
		break;
	case Qdata:
		if (n > sizeof datablk)
			error(Ebadarg);
		cmd->data.base = datablk;
		cmd->data.lim = cmd->data.base + n;
		cmd->data.ptr = cmd->data.base;
		cmd->save = cmd->data.base;
		memcpy(cmd->data.base, a, n);
		scsiexec(cmd, 0);
		n = cmd->data.ptr - cmd->data.base;
		break;
	case Qdebug:
		if (c->offset == 0) {
			debugs[(c->qid.path>>4)&7] = (*a=='1');
			n = 1;
		} else
			n = 0;
		break;
	default:
		panic("scsiwrite");
	}
	return n;
}

void
scsiremove(Chan *c)
{
	error(Eperm);
}

void
scsiwstat(Chan *c, char *dp)
{
	error(Eperm);
}

void
scsicmd(Scsi *cmd, int dev, int cmdbyte, uchar *buf, long size)
{
	qlock(cmd);
	cmd->target = dev>>3;
	cmd->lun = dev&7;
	cmd->cmd.base = cmd->cmdblk;
	cmd->data.base = buf;
	cmd->cmd.ptr = cmd->cmd.base;
	memset(cmd->cmdblk, 0, sizeof cmd->cmdblk);
	cmd->cmdblk[0] = cmdbyte;
	switch (cmdbyte>>5) {
	case 0:
		cmd->cmd.lim = &cmd->cmdblk[6]; break;
	case 1:
		cmd->cmd.lim = &cmd->cmdblk[10]; break;
	default:
		cmd->cmd.lim = &cmd->cmdblk[12]; break;
	}
	switch (cmdbyte) {
	case 0x00:	/* test unit ready */
		break;
	case 0x03:	/* read sense data */
		cmd->cmdblk[4] = size;
		break;
	case 0x25:	/* read capacity */
		break;
	}
	cmd->data.lim = cmd->data.base + size;
	cmd->data.ptr = cmd->data.base;
	cmd->save = cmd->data.base;
}

int
scsiready(int dev)
{
	static Scsi cmd;
	int status;
	scsicmd(&cmd, dev, 0x00, 0, 0);
	status = scsiexec(&cmd, 0);
	qunlock(&cmd);
	if ((status&0xff00) != 0x6000)
		error(Eio);
	return status&0xff;
}

int
scsisense(int dev, uchar *p)
{
	static Scsi cmd;
	static uchar buf[18];
	int status;
	scsicmd(&cmd, dev, 0x03, buf, sizeof buf);
	status = scsiexec(&cmd, 1);
	memcpy(p, buf, sizeof buf);
	qunlock(&cmd);
	if ((status&0xff00) != 0x6000)
		error(Eio);
	return status&0xff;
}

int
scsicap(int dev, uchar *p)
{
	static Scsi cmd;
	static uchar buf[8];
	int status;
	scsicmd(&cmd, dev, 0x25, buf, sizeof buf);
	status = scsiexec(&cmd, 1);
	memcpy(p, buf, sizeof buf);
	qunlock(&cmd);
	if ((status&0xff00) != 0x6000)
		error(Eio);
	return status&0xff;
}

typedef struct Scsictl {
	uchar	asr;
	uchar	data;
	uchar	stat;
	uchar	dma;
} Scsictl;

#define	Scsiaddr	48
#define	DEV	((Scsictl *)&PORT[Scsiaddr])

static long	poot;
#define	WAIT	(poot=0, (poot==0?0:poot))

#define	PUT(a,d)	(DEV->asr=(a), WAIT, DEV->data=(d))
#define	GET(a)		(DEV->asr=(a), WAIT, DEV->data)

enum Int_status {
	Inten = 0x01, Scsirst = 0x02,
	INTRQ = 0x01, DMA = 0x02,
};

enum SBIC_regs {
	Own_id=0x00, Control=0x01, CDB=0x03, Target_LUN=0x0f,
	Cmd_phase=0x10, Tc_hi=0x12,
	Dest_id=0x15, Src_id=0x16, SCSI_Status=0x17,
	Cmd=0x18, Data=0x19,
};

enum Commands {
	Reset = 0x00,
	Assert_ATN = 0x02,
	Negate_ACK = 0x03,
	Select_with_ATN = 0x06,
	Select_with_ATN_and_Xfr = 0x08,
	Select_and_Xfr = 0x09,
	Transfer_Info = 0x20,
	SBT = 0x80,		/* modifier for single-byte transfer */
};

enum Aux_status {
	INT=0x80, LCI=0x40, BSY=0x20, CIP=0x10,
	PE=0x02, DBR=0x01,
};

static QLock	scsilock;
static Rendez	scsirendez;
static uchar	*datap;
static long	debug, scsirflag, scsibusy, scsiinservice;

static void
nop(void)
{}

static int
scsidone(void *arg)
{
	return (scsibusy == 0);
}

int
scsiexec(Scsi *p, int rflag)
{
	long n;
	debug = debugs[p->target&7];
	DPRINT("scsi %d.%d ", p->target, p->lun);
	qlock(&scsilock);
	if(waserror()){
		qunlock(&scsilock);
		nexterror();
	}
	scsirflag = rflag;
	datap = p->data.base;
	if ((ownid & 0x08) && rflag)
		PUT(Dest_id, 0x40|p->target);
	else
		PUT(Dest_id, p->target);
	PUT(Target_LUN, p->lun);
	n = p->data.lim - p->data.base;
	PUT(Tc_hi, n>>16);
	DEV->data = n>>8;
	DEV->data = n;
	if (ownid & 0x08) {
		n = p->cmd.lim - p->cmd.ptr;
		DPRINT("len=%d ", n);
		PUT(Own_id, n);
	}
	PUT(CDB, *(p->cmd.ptr)++);
	while (p->cmd.ptr < p->cmd.lim)
		DEV->data = *(p->cmd.ptr)++;
	scsibusy = 1;
	PUT(Cmd, Select_and_Xfr);
	DPRINT("S<");
	sleep(&scsirendez, scsidone, 0);
	DPRINT(">");
	p->data.ptr = datap;
	p->status = GET(Target_LUN);
	p->status |= DEV->data<<8;
	poperror();
	qunlock(&scsilock);
	debug = 0;
	return p->status;
}

void
scsirun(void)
{
	wakeup(&scsirendez);
	scsibusy = 0;
}

void
scsiinit(void)
{
	isscsi = portprobe("scsi", -1, Scsiaddr, -1, 0L);
	if (isscsi >= 0) {
		DEV->stat = Scsirst;
		WAIT; nop(); WAIT;
		DEV->stat = Inten;
		while (DEV->stat & (INTRQ|DMA))
			nop();
		ownid &= 0x0f; /* possibly advanced features */
		ownid |= 0x80; /* 16MHz */
		PUT(Own_id, ownid);
		PUT(Cmd, Reset);
	}
}

void
scsireset0(void)
{
	PUT(Control, 0x29);	/* burst DMA, halt on parity error */
	PUT(Control+1, 0xff);	/* timeout */
	PUT(Src_id, 0x80);	/* enable reselection */
	scsirun();
	/*qunlock(&scsilock);*/
}

int
scsiintr(void)
{
	int status, s;
	if (isscsi < 0 || scsiinservice
		|| !((status = DEV->stat) & (DMA|INTRQ)))
			return 0;
	DEV->stat = 0;
	scsiinservice = 1;
	s = spl1();
	DPRINT("i%x ", status);
	do {
		if (status & DMA)
			scsidmaintr();
		if (status & INTRQ)
			scsictrlintr();
	} while ((status = DEV->stat) & (DMA|INTRQ));
	splx(s);
	scsiinservice = 0;
	DEV->stat = Inten;
	return 1;
}

void
scsidmaintr(void)
{
	uchar *p=0;
/*
 *	if (scsirflag) {
 *		unsigned char *p;
 *		DPRINT("R", p=datap);
 *		do
 *			*datap++ = DEV->dma;
 *		while (DEV->stat & DMA);
 *		DPRINT("%d ", datap-p);
 *	} else {
 *		unsigned char *p;
 *		DPRINT("W", p=datap);
 *		do
 *			DEV->dma = *datap++;
 *		while (DEV->stat & DMA);
 *		DPRINT("%d ", datap-p);
 *	}
 */
	if (scsirflag) {
		DPRINT("R", p=datap);
		datap = scsirecv(datap);
		DPRINT("%d ", datap-p);
	} else {
		DPRINT("X", p=datap);
		datap = scsixmit(datap);
		DPRINT("%d ", datap-p);
	}
}

void
scsictrlintr(void)
{
	int status;
	status = GET(SCSI_Status);
	DPRINT("I%2.2x ", status);
	switch(status){
	case 0x00:			/* reset by command or power-up */
	case 0x01:			/* reset by command or power-up */
		scsireset0();
		break;
	case 0x21:			/* Save Data Pointers message received */
		break;
	case 0x16:			/* select-and-transfer completed */
	case 0x42:			/* timeout during select */
		scsirun();
		break;
	case 0x4b:			/* unexpected status phase */
		PUT(Tc_hi, 0);
		DEV->data = 0;
		DEV->data = 0;
		PUT(Cmd_phase, 0x46);
		PUT(Cmd, Select_and_Xfr);
		break;
	default:
		kprint("scsintr 0x%ux\n", status);
		DEV->asr = Target_LUN;
		kprint("lun/status 0x%ux\n", DEV->data);
		kprint("phase 0x%ux\n", DEV->data);
		switch (status&0xf0) {
		case 0x00:
		case 0x10:
		case 0x20:
		case 0x40:
		case 0x80:
			if (status & 0x08) {
				kprint("count 0x%ux", GET(Tc_hi));
				kprint(" 0x%ux", DEV->data);
				kprint(" 0x%ux\n", DEV->data);
			}
			scsirun();
			break;
		default:
			panic("scsi status 0x%2.2ux", status);
		}
	}
}

A port/devwren.c => port/devwren.c +254 -0
@@ 0,0 1,254 @@
#include	"u.h"
#include	"lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"errno.h"
#include	"devtab.h"
#include	"io.h"

#include	"scsi.h"

enum {
	Qdir, Qdata, Qstruct,
};

static Dirtab wrendir[]={
	"data",		{Qdata},	0,	0600,
	"struct",	{Qstruct},	8,	0400,
};

#define	NWREN	(sizeof wrendir/sizeof(Dirtab))

static long	maxblock[64];
static long	blocksize[64];

static Scsi	staticcmd;		/* BUG */
static uchar	datablk[4*512];		/* BUG */

/*
 *  accepts [0-7].[0-7], or abbreviation
 */
static int
wrendev(char *p)
{
	int dev = 0;
	if (p==0 || p[0]==0)
		goto out;
	if (p[0]<'0' || p[0]>'7')
		goto cant;
	dev = (p[0]-'0')<<3;
	if (p[1]==0)
		goto out;
	if (p[1]!='.')
		goto cant;
	if (p[2]==0)
		goto out;
	if (p[2]<'0' || p[2]>'7')
		goto cant;
	dev |= p[2]-'0';
	if (p[3]!=0)
		goto cant;
out:
	return dev;
cant:
	error(Ebadarg);
}

static int
wrengen(Chan *c, Dirtab *tab, long ntab, long s, Dir *dp)
{
	long l;
	if(tab==0 || s>=ntab)
		return -1;
	tab+=s;
	if (tab->qid.path==Qdata && 0<=c->dev && c->dev<64)
		l = maxblock[c->dev]*blocksize[c->dev];
	else
		l = tab->length;
	devdir(c, tab->qid, tab->name, l, tab->perm, dp);
	return 1;
}

void
wrenreset(void)
{}

void
wreninit(void)
{
	Scsi *cmd = &staticcmd;
	cmd->cmd.base = cmd->cmdblk;
	cmd->data.base = datablk;
}

/*
 *  param is #r<target>.<lun>
 */
Chan *
wrenattach(char *param)
{
	uchar buf[32];
	int dev;
	Chan *c;
	dev = wrendev(param);
	scsiready(dev);
	scsisense(dev, buf);
	scsicap(dev, buf);
	c = devattach('r', param);
	c->dev = dev;
	maxblock[dev] = BGLONG(&buf[0]);
	blocksize[dev] = BGLONG(&buf[4]);
	return c;
}

Chan *
wrenclone(Chan *c, Chan *nc)
{
	return devclone(c, nc);
}

int
wrenwalk(Chan *c, char *name)
{
	return devwalk(c, name, wrendir, NWREN, wrengen);
}

void
wrenstat(Chan *c, char *db)
{
	devstat(c, db, wrendir, NWREN, wrengen);
}

Chan *
wrenopen(Chan *c, int omode)
{
	if (c->qid.path == Qdata && scsiready(c->dev) != 0)
		error(Eio);
	return devopen(c, omode, wrendir, NWREN, wrengen);
}

void
wrencreate(Chan *c, char *name, int omode, ulong perm)
{
	error(Eperm);
}

void
wrenclose(Chan *c)
{}

#define	PSHORT(p, v)		((p)[0]=(v), (p)[1]=((v)>>8))
#define	PLONG(p, v)		(PSHORT(p, (v)), PSHORT(p+2, (v)>>16))
long
wrenread(Chan *c, char *a, long n)
{
	Scsi *cmd = &staticcmd;
	unsigned long lbn;
	if (n == 0)
		return 0;
	switch ((int)(c->qid.path & ~CHDIR)) {
	case Qdir:
		return devdirread(c, a, n, wrendir, NWREN, wrengen);
	case Qdata:
		if (n % blocksize[c->dev] || c->offset % blocksize[c->dev])
			error(Ebadarg);
		lbn = c->offset/blocksize[c->dev];
		if (lbn >= maxblock[c->dev])
			error(Ebadarg);
		if (n > sizeof datablk)
			n = sizeof datablk;
		qlock(cmd);
		if (waserror()) {
			qunlock(cmd);
			nexterror();
		}
		cmd->target = c->dev>>3;
		cmd->lun = c->dev&7;
		cmd->cmd.ptr = cmd->cmd.base;
		cmd->cmdblk[0] = 0x08;
		cmd->cmdblk[1] = lbn>>16;
		cmd->cmdblk[2] = lbn>>8;
		cmd->cmdblk[3] = lbn;
		cmd->cmdblk[4] = n/blocksize[c->dev];
		cmd->cmdblk[5] = 0x00;
		cmd->cmd.lim = &cmd->cmdblk[6];
		cmd->data.lim = cmd->data.base + n;
		cmd->data.ptr = cmd->data.base;
		cmd->save = cmd->data.base;
		scsiexec(cmd, 1);
		n = cmd->data.ptr - cmd->data.base;
		memcpy(a, cmd->data.base, n);
		qunlock(cmd);
		break;
	case Qstruct:
		if (n < 8)
			error(Ebadarg);
		if (c->offset >= 8)
			return 0;
		n = 8;
		PLONG((uchar *)&a[0], maxblock[c->dev]);
		PLONG((uchar *)&a[4], blocksize[c->dev]);
		break;
	default:
		panic("wrenread");
	}
	return n;
}

long
wrenwrite(Chan *c, char *a, long n)
{
	Scsi *cmd = &staticcmd;
	unsigned long lbn;
	if (n == 0)
		return 0;
	switch ((int)(c->qid.path & ~CHDIR)) {
	case Qdata:
		if (n % blocksize[c->dev] || c->offset % blocksize[c->dev])
			error(Ebadarg);
		lbn = c->offset/blocksize[c->dev];
		if (lbn >= maxblock[c->dev])
			error(Ebadarg);
		if (n > sizeof datablk)
			n = sizeof datablk;
		qlock(cmd);
		if (waserror()) {
			qunlock(cmd);
			nexterror();
		}
		cmd->target = c->dev>>3;
		cmd->lun = c->dev&7;
		cmd->cmd.ptr = cmd->cmd.base;
		cmd->cmdblk[0] = 0x0a;
		cmd->cmdblk[1] = lbn>>16;
		cmd->cmdblk[2] = lbn>>8;
		cmd->cmdblk[3] = lbn;
		cmd->cmdblk[4] = n/blocksize[c->dev];
		cmd->cmdblk[5] = 0x00;
		cmd->cmd.lim = &cmd->cmdblk[6];
		cmd->data.lim = cmd->data.base + n;
		cmd->data.ptr = cmd->data.base;
		cmd->save = cmd->data.base;
		memcpy(cmd->data.base, a, n);
		scsiexec(cmd, 0);
		n = cmd->data.ptr - cmd->data.base;
		qunlock(cmd);
		break;
	default:
		panic("wrenwrite");
	}
	return n;
}

void
wrenremove(Chan *c)
{
	error(Eperm);
}

void
wrenwstat(Chan *c, char *dp)
{
	error(Eperm);
}

M port/fault.c => port/fault.c +1 -1
@@ 21,7 21,7 @@ fault(ulong addr, int read)

	s = seg(u->p, addr);
	if(s == 0){
		if(addr>USTKTOP)
		if(addr > USTKTOP)
			return -1;
		s = &u->p->seg[SSEG];
		if(s->o==0 || addr<s->maxva-USTACKSIZE || addr>=s->maxva)

M port/page.c => port/page.c +2 -2
@@ 85,7 85,7 @@ audit(char *s)
	do;while(here);
	here=1;
	p = palloc.head;
	nf=nb=0;
	nf = nb = 0;
	while(p){
		print("%lux %lux %d\n", p->pa, p->va, p->ref);
		if(p->o){


@@ 208,7 208,7 @@ loop:
	goto loop;
    out:
	if(p->o){
		print("page in use %lux %lux %lux\n", p->va, p->o, origalloc.arena);
		print("page in use %lux %lux %lux %lux\n", p, p->va, p->o, origalloc.arena);
		print("%c %lux %lux, %d %d %d\n", devchar[p->o->type], p->o->va, p->o->qid, p->o->flag, p->o->nproc, p->o->npte);
		panic("shit");
	}

M port/proc.c => port/proc.c +6 -4
@@ 412,8 412,13 @@ pexit(char *s, int freemem)
	Proc *p, *c, *k, *l;
	int n;
	Chan *ch;
	char msg[ERRLEN];
	ulong *up, *ucp, *wp;

	if(s)	/* squirrel away; we'll lose our address space */
		strcpy(msg, s);
	else
		msg[0] = 0;
	c = u->p;
	mypid = c->pid;
	if(freemem){


@@ 450,10 455,7 @@ pexit(char *s, int freemem)
	qlock(&p->wait);
	lock(&p->wait.queue);
	if(p->pid==c->parentpid && !p->exiting){
		if(s)
			strcpy(p->waitmsg.msg, s);
		else
			p->waitmsg.msg[0] = 0;
		memcpy(p->waitmsg.msg, msg, ERRLEN);
		p->waitmsg.pid = mypid;
		wp = &p->waitmsg.time[TUser];
		up = &c->time[TUser];

M ss/dat.h => ss/dat.h +3 -2
@@ 228,9 228,9 @@ struct Mach
	void	(*intr)(ulong, ulong);	/* !!Compatibility with mips!! */
	ulong	cause;			/*	... */
	ulong	pc;			/*	... */
	char	pidhere[NCONTEXT];	/* is this tlbpid possibly in this mmu? */
	char	pidhere[NTLBPID];	/* is this tlbpid possibly in this mmu? */
	int	lastpid;		/* last pid allocated on this machine */
	Proc	*pidproc[NCONTEXT];	/* process that owns this pid on this mach */
	Proc	*pidproc[NTLBPID];	/* process that owns this pid on this mach */
	int	stack[1];
};



@@ 773,6 773,7 @@ extern	FPsave	initfp;
extern	Mach	mach0;
extern	char	user[NAMELEN];
extern	char	*errstrtab[];
extern	uchar	*intrreg;

extern  void	(*kprofp)(ulong);


M ss/faultsparc.c => ss/faultsparc.c +32 -1
@@ 6,6 6,12 @@
#include	"ureg.h"
#include	"errno.h"

ck(char *s)
{
	if(u->p->seg[SSEG].o->flag == 0)
		panic(s);
}

void
faultsparc(Ureg *ur)
{


@@ 28,7 34,8 @@ faultsparc(Ureg *ur)
		return;
	}
	spllo();
/* print("fault: %s pc=0x%lux addr %lux %d\n", excname(tbr), ur->pc, addr, read); /**/
print("fault: %s pc=0x%lux addr %lux %d\n", excname(tbr), ur->pc, addr, read); /**/
ck("faultsparc");
	if(u == 0){
		dumpregs(ur);
		panic("fault u==0 pc=%lux", ur->pc);


@@ 41,6 48,11 @@ faultsparc(Ureg *ur)
	user = !(ur->psr&PSRPSUPER);

	if(fault(addr, read) < 0){
print("death read %lux %d sizes %lux-%lux %lux-%lux, %lux-%lux %lux-%lux\n", addr, read,
u->p->seg[SSEG].minva, u->p->seg[SSEG].maxva, 
u->p->seg[TSEG].minva, u->p->seg[TSEG].maxva, 
u->p->seg[DSEG].minva, u->p->seg[DSEG].maxva, 
u->p->seg[BSEG].minva, u->p->seg[BSEG].maxva); 
		if(user){
			pprint("user %s error addr=0x%lux\n", read? "read" : "write", badvaddr);
			pprint("psr=0x%lux pc=0x%lux sp=0x%lux\n", ur->psr, ur->pc, ur->sp);


@@ 52,6 64,25 @@ faultsparc(Ureg *ur)
		exit();
	}
	u->p->insyscall = insyscall;
ck("faultsparc return");
}

void
faultasync(Ureg *ur)
{
	int user;

	print("interrupt 15 ASER %lux ASEVAR %lux SER %lux\n", getw2(ASER), getw2(ASEVAR), getw2(SER));
	dumpregs(ur);
	/*
	 * Clear interrupt by toggling low bit of interrupt register
	 */
	*intrreg &= ~1;
	*intrreg |= 1;
	user = !(ur->psr&PSRPSUPER);
	if(user)
		pexit("Suicide", 0);
	panic("interrupt 15");
}

/*

M ss/fns.h => ss/fns.h +4 -1
@@ 58,7 58,7 @@ char	*excname(ulong);
void	execpc(ulong);
void	exit(void);
int	fault(ulong, int);
void	fault68020(Ureg*, FFrame*);
void	faultasync(Ureg*);
void	fdclose(int);
Chan	*fdtochan(int, int);
void	filsys(Chan*, char*, long);


@@ 91,6 91,7 @@ void	growpte(Orig*, ulong);
void	*ialloc(ulong, int);
int	incref(Ref*);
void	insert(List**, List*, List*);
void	intrinit(void);
void	invalidateu(void);
void	isdir(Chan*);
void	kbdchar(int);


@@ 168,7 169,9 @@ void	putw2(ulong, ulong);
void	putw4(ulong, ulong);
void	putwC(ulong, ulong);
void	putwD(ulong, ulong);
void	putwD16(ulong, ulong);
void	putwE(ulong, ulong);
void	putwE16(ulong, ulong);
ulong	pwait(Waitmsg*);
int	readnum(ulong, char*, ulong, ulong, int);
void	ready(Proc*);

M ss/io.h => ss/io.h +1 -0
@@ 7,6 7,7 @@ typedef struct	Duart	Duart;
#define	KMDUART		0xF0000000	/* keyboard A, mouse B */
#define	ETHER		0xF8C00000	/* RDP, RAP */
#define	EEPROM		0xF2000000
#define	INTRREG		0xF5000000	/* interrupt register, IO space */

#define	ENAB		0x40000000	/* ASI 2, System Enable Register */
#define	ENABCACHE	0x10

M ss/l.s => ss/l.s +79 -7
@@ 1,6 1,6 @@
#include "mem.h"

#define	SYSPSR	(PSREF|SPL(0x0)|PSRSUPER)
#define	SYSPSR	(SPL(0xF)|PSRSUPER)

TEXT	start(SB), $-4



@@ 33,13 33,11 @@ TEXT	getpsr(SB), $0
	MOVW	PSR, R7
	RETURN

/*
TEXT	swap1_please(SB), $0
TEXT	swap1(SB), $0

	MOVW	keyaddr+0(FP), R8
	LDSTUB	(R8), R7
	TAS	(R8), R7
	RETURN
*/

TEXT	swap1_should_work(SB), $0



@@ 48,7 46,7 @@ TEXT	swap1_should_work(SB), $0
	SWAP	(R8), R7
	RETURN

TEXT	swap1(SB), $0
TEXT	swap1x(SB), $0

	MOVW	keyaddr+0(FP), R8
	MOVW	PSR, R9


@@ 100,7 98,7 @@ TEXT	splx(SB), $0

TEXT	touser(SB), $-4

	MOVW	$SYSPSR, R7	/* BUG SPL(0xF) for now */
	MOVW	$SYSPSR, R7
	MOVW	R7, PSR

	OR	R0, R0


@@ 400,6 398,43 @@ TEXT	putwD(SB), $0
	MOVW	R8, (R7, 0xD)
	RETURN

TEXT	putwD16(SB), $0

	MOVW	0(FP), R7
	MOVW	4(FP), R8
	MOVW	R8, (R7, 0xD)
	ADD	$(1<<4), R7
	MOVW	R8, (R7, 0xD)
	ADD	$(1<<4), R7
	MOVW	R8, (R7, 0xD)
	ADD	$(1<<4), R7
	MOVW	R8, (R7, 0xD)
	ADD	$(1<<4), R7
	MOVW	R8, (R7, 0xD)
	ADD	$(1<<4), R7
	MOVW	R8, (R7, 0xD)
	ADD	$(1<<4), R7
	MOVW	R8, (R7, 0xD)
	ADD	$(1<<4), R7
	MOVW	R8, (R7, 0xD)
	ADD	$(1<<4), R7
	MOVW	R8, (R7, 0xD)
	ADD	$(1<<4), R7
	MOVW	R8, (R7, 0xD)
	ADD	$(1<<4), R7
	MOVW	R8, (R7, 0xD)
	ADD	$(1<<4), R7
	MOVW	R8, (R7, 0xD)
	ADD	$(1<<4), R7
	MOVW	R8, (R7, 0xD)
	ADD	$(1<<4), R7
	MOVW	R8, (R7, 0xD)
	ADD	$(1<<4), R7
	MOVW	R8, (R7, 0xD)
	ADD	$(1<<4), R7
	MOVW	R8, (R7, 0xD)
	RETURN

TEXT	putwE(SB), $0

	MOVW	0(FP), R7


@@ 407,6 442,43 @@ TEXT	putwE(SB), $0
	MOVW	R8, (R7, 0xE)
	RETURN

TEXT	putwE16(SB), $0

	MOVW	0(FP), R7
	MOVW	4(FP), R8
	MOVW	R8, (R7, 0xE)
	ADD	$(1<<4), R7
	MOVW	R8, (R7, 0xE)
	ADD	$(1<<4), R7
	MOVW	R8, (R7, 0xE)
	ADD	$(1<<4), R7
	MOVW	R8, (R7, 0xE)
	ADD	$(1<<4), R7
	MOVW	R8, (R7, 0xE)
	ADD	$(1<<4), R7
	MOVW	R8, (R7, 0xE)
	ADD	$(1<<4), R7
	MOVW	R8, (R7, 0xE)
	ADD	$(1<<4), R7
	MOVW	R8, (R7, 0xE)
	ADD	$(1<<4), R7
	MOVW	R8, (R7, 0xE)
	ADD	$(1<<4), R7
	MOVW	R8, (R7, 0xE)
	ADD	$(1<<4), R7
	MOVW	R8, (R7, 0xE)
	ADD	$(1<<4), R7
	MOVW	R8, (R7, 0xE)
	ADD	$(1<<4), R7
	MOVW	R8, (R7, 0xE)
	ADD	$(1<<4), R7
	MOVW	R8, (R7, 0xE)
	ADD	$(1<<4), R7
	MOVW	R8, (R7, 0xE)
	ADD	$(1<<4), R7
	MOVW	R8, (R7, 0xE)
	RETURN

TEXT	putsegm(SB), $0

	MOVW	0(FP), R7

M ss/main.c => ss/main.c +16 -4
@@ 15,6 15,8 @@ char bootline[64];
char bootserver[64];
char bootdevice[64];

uchar *intrreg;

void unloadboot(void);

#ifdef asdf


@@ 68,6 70,7 @@ main(void)
	trapinit();
	kmapinit();
	cacheinit();
	intrinit();
	procinit0();
	pgrpinit();
	chaninit();


@@ 83,6 86,15 @@ main(void)
}

void
intrinit(void)
{
	KMap *k;

	k = kmappa(INTRREG, PTEIO);
	intrreg = (uchar*)k->va;
}

void
reset(void)
{
	delay(100);


@@ 162,7 174,7 @@ userinit(void)
	/*
	 * Kernel Stack
	 */
	p->sched.pc = (ulong)init0;
	p->sched.pc = (((ulong)init0) - 8);	/* 8 because of RETURN in gotolabel */
	p->sched.sp = USERADDR+BY2PG-20;	/* BUG */
	p->upage = newpage(0, 0, USERADDR|(p->pid&0xFFFF));



@@ 289,7 301,7 @@ confinit(void)
	conf.nmach = 1;
	if(conf.nmach > MAXMACH)
		panic("confinit");
	conf.npage0 = (8*1024*1024)/BY2PG;	/* BUG */
	conf.npage0 = (6*1024*1024)/BY2PG;	/* BUG */
	conf.npage = conf.npage0;
	conf.base0 = 0;
	conf.npage = conf.npage0+conf.npage1;


@@ 297,8 309,8 @@ confinit(void)
	mul = 2;
	conf.nproc = 50*mul;
	conf.npgrp = 12*mul;
	conf.npte = 700*mul;
	conf.nmod = 400*mul;
	conf.npte = 1400*mul;
	conf.nmod = 800*mul;
	conf.nalarm = 1000;
	conf.norig = 150*mul;
	conf.nchan = 200*mul;

M ss/mem.h => ss/mem.h +4 -7
@@ 58,7 58,7 @@
#define	NPMEG		(1<<12)
#define	BY2SEGM		(1<<18)
#define	PG2SEGM		(1<<6)
#define	NTLBPID		(NCONTEXT+1)
#define	NTLBPID		(1+NCONTEXT)	/* TLBPID 0 is unallocated */
#define	NCONTEXT	8
#define	CONTEXT		0x30000000	/* in ASI 2 */



@@ 77,9 77,7 @@
#define	IOPMEG0		(SCREENPMEG-NIOSEGM)
#define	IOSEGM		ROMEND
#define	IOEND		SCREENSEGM
#define	LANCESEGM	(16*1024*1024-BY2SEGM)
#define	LANCEPMEG	(IOSEGM0-1)
#define	TOPPMEG		LANCEPMEG
#define	TOPPMEG		IOPMEG0

/*
 * MMU entries


@@ 97,15 95,14 @@
#define	INVALIDPTE	0
#define	PPN(pa)		((pa>>12)&0xFFFF)

#define	KMAP	((unsigned long *)0xD0000000)
#define	UMAP	((unsigned long *)0x50000000)

/*
 * Weird addresses in various ASI's
 */
#define	CACHETAGS	0x80000000		/* ASI 2 */
#define	SER		0x60000000		/* ASI 2 */
#define	SEVAR		0x60000004		/* ASI 2 */
#define	ASER		0x60000008		/* ASI 2 */
#define	ASEVAR		0x6000000C		/* ASI 2 */

/*
 * Virtual addresses

M ss/mmu.c => ss/mmu.c +79 -36
@@ 14,12 14,15 @@ struct
	KMap	arena[(IOEND-IOSEGM)/BY2PG];
}kmapalloc;

#define	NKLUDGE	8

/*
 * On SPARC, tlbpid i == context i-1 so that 0 means unallocated
 */

int	newpid(Proc*);
void	purgepid(int);
int	pidtime[NTLBPID];	/* should be per m */

/*
 * Called splhi, not in Running state


@@ 36,14 39,12 @@ mapstack(Proc *p)
		p->pidonmach[m->machno] = tp;
	}
	if(p->upage->va != (USERADDR|(p->pid&0xFFFF)))
		panic("mapstack %d 0x%lux 0x%lux", p->pid, p->upage->pa, p->upage->va);
	/* don't set m->pidhere[*tp] because we're only writing U entry */
		panic("mapstack %s %d %lux 0x%lux 0x%lux", p->text, p->pid, p->upage, p->upage->pa, p->upage->va);
	tlbphys = PPN(p->upage->pa)|PTEVALID|PTEWRITE|PTEKERNEL|PTEMAINMEM;
	putcontext(tp-1);
	/*
	 * putw4(USERADDR, tlbphys) might be good enough but
	 * there is that fuss in pexit/pwait() copying between
	 * u areas and that might surprise any cache entries
	 * shouldn't need putpmeg because nothing has been mapped at
	 * USERADDR in this context except this page.  however, it crashes.
	 */
	putpmeg(USERADDR, tlbphys);
	u = (User*)USERADDR;


@@ 56,28 57,34 @@ int
newpid(Proc *p)
{
	int i, j, k;
	ulong t;
	Proc *sp;

	i = m->lastpid+1;
	if(i >= NCONTEXT+1)
		i = 1;
	t = ~0;
	i = 1+((m->ticks)&(NCONTEXT-1));	/* random guess */
	for(j=1; j<NTLBPID; j++)
		if(pidtime[j] < t){
			i = j;
			t = pidtime[j];
		}
	
	sp = m->pidproc[i];
	if(sp){
		sp->pidonmach[m->machno] = 0;
		purgepid(i);
	}
	pidtime[i] = m->ticks;
	m->pidproc[i] = p;
	m->lastpid = i;
	putcontext(i-1);
/* print("new pid %d\n", i); /**/
	/*
	 * kludge: each context is allowed 5 pmegs, four for text & data and one for stack
	 * kludge: each context is allowed NKLUDGE pmegs, NKLUDGE-1 for text & data and 1 for stack
	 */
	for(j=0; j<4; j++)
		putsegm(UZERO, kmapalloc.lowpmeg+(2*i)+j);
	putsegm(TSTKTOP-BY2SEGM, kmapalloc.lowpmeg+(2*i)+4);
	for(j=0; j<NKLUDGE-1; j++)
		putsegm(UZERO+j*BY2SEGM, kmapalloc.lowpmeg+(NKLUDGE*(i-1))+j);
	putsegm(TSTKTOP-BY2SEGM, kmapalloc.lowpmeg+(NKLUDGE*(i-1))+(NKLUDGE-1));
	for(j=0; j<PG2SEGM; j++){
		for(k=0; k<4; k++)
		for(k=0; k<NKLUDGE-1; k++)
			putpmeg(UZERO+k*BY2SEGM+j*BY2PG, INVALIDPTE);
		putpmeg((TSTKTOP-BY2SEGM)+j*BY2PG, INVALIDPTE);
	}


@@ 87,26 94,30 @@ newpid(Proc *p)
void
putcontext(int c)
{
	m->pidhere[c] = 1;
	m->pidhere[c+1] = 1;
	putcxreg(c);
}

void
purgepid(int pid)
flushcontext(void)
{
	int i, rpid;
	int i;

	/*
	 * Clear context from cache
	 */
	for(i=0; i<0x1000; i+=16)
		putwE16((i<<4), 0);
}

void
purgepid(int pid)
{
	if(m->pidhere[pid] == 0)
		return;
/* print("purge pid %d\n", pid);/**/
	memset(m->pidhere, 0, sizeof m->pidhere);
	putcontext(pid-1);
	/*
	 * Clear context from cache
	 */
	for(i=0; i<0x1000; i++)
		putwE((i<<4), 0);
/* print("purge done\n");/**/
	flushcontext();
}




@@ 129,7 140,6 @@ mmuinit(void)
	pte = PTEVALID|PTEWRITE|PTEKERNEL|PTEMAINMEM;
	for(i=0; i<conf.maxialloc/BY2PG; i++)
		putpmeg(KZERO+i*BY2PG, pte+i);
		

	/*
	 * Create invalid pmeg; use highest segment


@@ 178,10 188,6 @@ mmuinit(void)
				for(i=0; i<PG2SEGM; i++)
					putpmeg(IOSEGM0+j*BY2SEGM+i*BY2PG, INVALIDPTE);
		}
		/*
		 * Lance
		 */
		putsegm(LANCESEGM, LANCEPMEG);
	}
	putcontext(0);
}


@@ 202,8 208,10 @@ putmmu(ulong tlbvirt, ulong tlbphys)
	/*
	 * kludge part 2: make sure we've got a valid segment
	 */
	if(tlbvirt>=TSTKTOP || (UZERO+4*BY2SEGM<=tlbvirt && tlbvirt<(TSTKTOP-BY2SEGM)))
		panic("putmmu %lux", tlbvirt);
	if(tlbvirt>=TSTKTOP || (UZERO+(NKLUDGE-1)*BY2SEGM<=tlbvirt && tlbvirt<(TSTKTOP-BY2SEGM))){
		pprint("putmmu %lux", tlbvirt);
		pexit("Suicide", 0);
	}
	putpmeg(tlbvirt, tlbphys);
	spllo();
}


@@ 219,8 227,8 @@ putpmeg(ulong virt, ulong phys)
	/*
	 * Flush old entries from cache
	 */
	for(i=0; i<0x100; i++)
		putwD(virt+(i<<4), 0);
	for(i=0; i<0x100; i+=16)
		putwD16(virt+(i<<4), 0);
	if(u && u->p)
		m->pidhere[u->p->pidonmach[m->machno]] = 1;	/* UGH! */
	putw4(virt, phys);


@@ 229,7 237,13 @@ putpmeg(ulong virt, ulong phys)
void
flushmmu(void)
{
	int tp;

	splhi();
	flushcontext();
	tp = u->p->pidonmach[m->machno];
	if(tp)
		pidtime[tp] = 0;
	/* easiest is to forget what pid we had.... */
	memset(u->p->pidonmach, 0, sizeof u->p->pidonmach);
	/* ....then get a new one by trying to map our stack */


@@ 240,14 254,19 @@ flushmmu(void)
void
cacheinit(void)
{
	int i;
	int c, i;

	/*
	 * Initialize cache by clearing the valid bit
	 * (along with the others) in all cache entries
	 */
	for(i=0; i<0x1000; i++)
		putw2(CACHETAGS+(i<<4), 0);
	for(c=0; c<NCONTEXT; c++){	/* necessary? */
		putcontext(c);
		for(i=0; i<0x1000; i++)
			putw2(CACHETAGS+(i<<4), 0);
	}
	putcontext(0);

	/*
	 * Turn cache on
	 */


@@ 260,6 279,7 @@ kmapinit(void)
	KMap *k;
	int i;

print("low pmeg %d high pmeg %d\n", kmapalloc.lowpmeg, TOPPMEG);
	kmapalloc.free = 0;
	k = kmapalloc.arena;
	for(i=0; i<(IOEND-IOSEGM)/BY2PG; i++,k++){


@@ 272,6 292,7 @@ KMap*
kmappa(ulong pa, ulong flag)
{
	KMap *k;
	ulong s;

	lock(&kmapalloc);
	k = kmapalloc.free;


@@ 287,7 308,29 @@ kmappa(ulong pa, ulong flag)
	 * Must avoid having the same entry in the cache twice, so
	 * must use NOCACHE or else extreme cleverness elsewhere.
	 */
	s = splhi();
#ifdef stupid
{
	int i, c, d;

	c = u->p->pidonmach[m->machno];
	/*
	 * Flush old entries from cache
	 */
	for(d=0; d<NCONTEXT; d++){
		putcontext(d);
		for(i=0; i<0x100; i+=16)
			putwD16(k->va+(i<<4), 0);
	}
	putcontext(c-1);
	if(u && u->p)
		m->pidhere[c] = 1;	/* UGH! */
	putw4(k->va, PPN(pa)|PTEVALID|PTEKERNEL|PTEWRITE|PTENOCACHE|flag);
}
#else
	putpmeg(k->va, PPN(pa)|PTEVALID|PTEKERNEL|PTEWRITE|PTENOCACHE|flag);
#endif
	splx(s);
	return k;
}


M ss/screen.c => ss/screen.c +2 -0
@@ 266,6 266,7 @@ duartintr(void)
	Duart *dp;

	cause = duartrdreg(&duart[0], 3);

	/*
	 * Keyboard
	 */


@@ 290,6 291,7 @@ duartintr(void)
	}
	if(cause & TxPendB)
		duartwrreg(dp, 0, ResTxPend);
	cause = duartrdreg(&duart[0], 3);
}

/*

M ss/trap.c => ss/trap.c +4 -4
@@ 58,6 58,10 @@ trap(Ureg *ur)
	ulong tbr;

	tbr = (ur->tbr&0xFFF)>>4;
	if(tbr == 16+15){			/* interrupt 14: counter 1 */
		faultasync(ur);
		return;
	}
	if(tbr == 16+14){			/* interrupt 14: counter 1 */
		clock(ur);
		return;


@@ 77,11 81,8 @@ trap(Ureg *ur)
		u->p->pc = ur->pc;		/* BUG */
	if(user){
		print("user trap: %s pc=0x%lux\n", excname(tbr), ur->pc);
dumpregs(ur);
		sprint(buf, "sys: trap: pc=0x%lux %s", ur->pc, excname(tbr));
print("call postnote\n");
		postnote(u->p, 1, buf, NDebug);
print("return from postnote\n");
	}else{
		print("kernel trap: %s pc=0x%lux\n", excname(tbr), ur->pc);
		dumpregs(ur);


@@ 169,7 170,6 @@ notify(Ureg *ur)
		if(u->note[0].flag == NDebug)
			pprint("suicide: %s\n", u->note[0].msg);
    Die:
print("suicide: %s\n", u->note[0].msg);
		unlock(&u->p->debug);
		pexit(u->note[0].msg, u->note[0].flag!=NDebug);
	}