~kris/9p

9hist

234f17944145ff676bb311ef4f0db5ea2774d95c — David du Colombier 33 years ago 9e304bc
Plan 9 from Bell Labs 1993-09-06
M carrera/dat.h => carrera/dat.h +2 -1
@@ 47,11 47,12 @@ struct Conf
	ulong	base0;		/* base of bank 0 */
	ulong	base1;		/* base of bank 1 */
	ulong	copymode;	/* 0 is copy on write, 1 is copy on reference */
	int	monitor;

	ulong	ipif;		/* Ip protocol interfaces */
	ulong	ip;		/* Ip conversations per interface */
	ulong	arp;		/* Arp table size */
	ulong	frag;		/* Ip fragment assemble queue size */
	ulong	debugger;	/* use processor 1 as a kernel debugger */
};

/*

M carrera/devether.c => carrera/devether.c +227 -156
@@ 16,8 16,18 @@
#define SONICADDR	((Sonic*)Sonicbase)

#define RD(rn)		(delay(1), *(ulong*)((ulong)&SONICADDR->rn^4))
#define WR(rn, v)	(delay(1), *(ulong*)((ulong)&SONICADDR->rn^4) = v)
#define ISquad(s)	if((ulong)s & 0x7) panic("sonoc: Quad alignment");
#define WR(rn, v)	(delay(1), *(ulong*)((ulong)&SONICADDR->rn^4) = (v))
#define ISquad(s)	if((ulong)s & 0x7) panic("sonic: Quad alignment");

typedef struct Pbuf Pbuf;
struct Pbuf
{
	uchar	d[6];
	uchar	s[6];
	uchar	type[2];
	uchar	data[1500];
	uchar	crc[4];
};

typedef struct
{


@@ 32,7 42,10 @@ typedef struct
	ulong	pad0x08[5];	/*  */
	ulong	urda;		/* upper receive descriptor address */
	ulong	crda;		/* current receive descriptor address */
	ulong	pad0x0F[4];	/*  */
	ulong	crba0;		/* DO NOT WRITE THESE */
	ulong	crba1;
	ulong	rbwc0;
	ulong	rbwc1;
	ulong	eobc;		/* end of buffer word count */
	ulong	urra;		/* upper receive resource address */
	ulong	rsa;		/* resource start address */


@@ 111,6 124,9 @@ enum
	Hbl	= 0x2000,	/* CD heartbeat lost */
	Br	= 0x4000,	/* bus retry occurred */
	AllIntr	= 0x7771,	/* all of the above */

	Rxbuf	= sizeof(Pbuf)+4,
	Txbuf	= sizeof(Pbuf),
};

/*


@@ 118,14 134,14 @@ enum
 */
typedef struct
{
	uchar	pad0[2];
	ushort	ptr0;		/* buffer pointer in the RRA */
	uchar	pad1[2];
	ushort	ptr1;
	uchar	pad2[2];
	ushort	wc0;		/* buffer word count in the RRA */
	uchar	pad3[2];
	ushort	wc1;
	ushort	pad1;
	ushort		ptr1;		/* buffer pointer in the RRA */
	ushort  pad2;
	ushort		ptr0;
	ushort  pad3;
	ushort		wc1;		/* buffer word count in the RRA */
	ushort  pad4;
	ushort		wc0;
} RXrsc;

/*


@@ 133,20 149,21 @@ typedef struct
 */
typedef struct
{
	uchar	pad0[2];
	ushort	status;		/* receive status */
	uchar	pad1[2];
	ushort	count;		/* packet byte count */
	uchar	pad2[2];
	ushort	ptr0;		/* buffer pointer */
	uchar	pad3[2];
	ushort	ptr1;
	uchar	pad4[2];
	ushort	seqno;		/*  */
	uchar	pad5[2];
	ushort	link;		/* descriptor link and EOL */
	uchar	pad6[2];
	ushort	owner;		/* in use */
	ushort	pad0;
		ushort	count;		/* packet byte count */
	ushort	pad1;
		ushort	status;		/* receive status */
	ushort	pad2;
		ushort	ptr1;		/* buffer pointer */
	ushort	pad3;
		ushort	ptr0;
	ushort  pad4;
		ushort	link;		/* descriptor link and EOL */
	ushort	pad5;
		ushort	seqno;		/*  */
	ulong	pad6;
	ushort  pad7;
		ushort	owner;		/* in use */
} RXpkt;

/*


@@ 154,22 171,22 @@ typedef struct
 */
typedef struct
{
	uchar	pad0[2];
	ushort	status;		/* transmit status */
	uchar	pad1[2];
	ushort	config;		/*  */
	uchar	pad2[2];
	ushort	size;		/* byte count of entire packet */
	uchar	pad3[2];
	ushort	count;		/* fragment count */
	uchar	pad4[2];
	ushort	ptr0;		/* packet pointer */
	uchar	pad5[2];
	ushort	ptr1;
	uchar	pad6[2];
	ushort	fsize;		/* fragment size */
	uchar	pad7[2];
	ushort	link;		/* descriptor link */
	ushort	pad1;
		ushort	config;		/*  */
	ushort	pad0;
		ushort	status;		/* transmit status */
	ushort	pad3;
		ushort	count;		/* fragment count */
	ushort	pad2;
		ushort	size;		/* byte count of entire packet */
	ushort	pad5;
		ushort	ptr1;
	ushort	pad4;
		ushort	ptr0;		/* packet pointer */
	ushort	pad7;
		ushort	link;		/* descriptor link */
	ushort	pad6;
		ushort	fsize;		/* fragment size */
} TXpkt;

enum{


@@ 186,16 203,17 @@ enum{
 */
typedef struct
{
	uchar	pad0[2];
	ushort	cep;		/* CAM entry pointer */
	uchar	pad1[2];
	ushort	cap0;		/* CAM address port 0 */
	uchar	pad2[2];
	ushort	cap1;		/* CAM address port 1 */
	uchar	pad3[2];
	ushort	cap2;		/* CAM address port 2 */
	uchar	pad4[2];
	ushort	ce;		/* CAM enable */
	ushort	pad0;
		ushort	cap0;		/* CAM address port 0 */
	ushort	pad1;
		ushort	cep;		/* CAM entry pointer */
	ushort	pad2;
		ushort	cap2;		/* CAM address port 2 */
	ushort	pad3;
		ushort	cap1;		/* CAM address port 1 */
	ulong	pad4;
	ushort	pad5;
		ushort	ce;		/* CAM enable */
} Cam;

typedef struct Ether Ether;


@@ 204,8 222,6 @@ struct Ether
	uchar	ea[6];
	uchar	ba[6];

	Sonic	*sonic;		/* SONIC registers */

	QLock	tlock;		/* lock for grabbing transmitter queue */
	Rendez	tr;		/* wait here for free xmit buffer */
	int	th;		/* first transmit buffer owned by host */	


@@ 214,12 230,13 @@ struct Ether
	int	rh;		/* first receive buffer owned by host */
	int	ri;		/* first receive buffer owned by interface */

	RXrsc	rra[Nrb];	/* receive resource area */
	RXpkt	rda[Nrb];	/* receive descriptor area */
	uchar	rb[Nrb][sizeof(Etherpkt)+4];	/* receive buffer area */
	TXpkt	tda[Ntb];	/* transmit descriptor area */
	uchar	tb[Ntb][sizeof(Etherpkt)];	/* transmit buffer area */
	Cam	cda;		/* CAM descriptor area */
	RXrsc	*rra;		/* receive resource area */
	RXpkt	*rda;		/* receive descriptor area */
	TXpkt	*tda;		/* transmit descriptor area */
	Cam	*cda;		/* CAM descriptor area */

	uchar	*rb[Nrb];	/* receive buffer area */
	uchar	*tb[Ntb];	/* transmit buffer area */

	Netif;
};


@@ 231,21 248,29 @@ Ether *ether[Nether];
#define LS16(addr)	(PADDR(addr) & 0xFFFF)
#define MS16(addr)	((PADDR(addr)>>16) & 0xFFFF)

void sonicswap(void*, int);

static void
wus(ushort *a, ushort v)
{
	a[0] = v;
	a[-1] = v;
}

static void
reset(Ether *ctlr)
{
	int i;
	ushort lolen, hilen, loadr, hiadr;

	/*
	 * Reset the SONIC, toggle the Rst bit.
	 * Set the data config register for synchronous termination
	 * and 32-bit data-path width.
	 * Clear the descriptor and buffer area.
	 * Setup the descriptor and buffer area.
	 */
	WR(cr, Rst);
	WR(dcr, 0x2423);	/* 5-19 Carrera manual */
iprint("eobc #%lux\n", RD(eobc));
	WR(cr, 0);

	/*
	 * Initialise the receive resource area (RRA) and


@@ 254,23 279,34 @@ iprint("eobc #%lux\n", RD(eobc));
	 * We use a simple scheme of one packet per descriptor.
	 * We achieve this by setting the EOBC register to be
	 * 2 (16-bit words) less than the buffer size;
	 * thus the size of the receive buffers must be sizeof(Etherpkt)+4.
	 * thus the size of the receive buffers must be sizeof(Pbuf)+4.
	 * Set up the receive descriptors as a ring.
	 */

	lolen = (Rxbuf/2) & 0xFFFF;
	hilen = ((Rxbuf/2)>>16) & 0xFFFF;

	for(i = 0; i < Nrb; i++) {
		ctlr->rra[i].wc0 = (sizeof(ctlr->rb[0])/2) & 0xFFFF;
		ctlr->rra[i].wc1 = ((sizeof(ctlr->rb[0])/2)>>16) & 0xFFFF;
		wus(&ctlr->rra[i].wc0, lolen);
		wus(&ctlr->rra[i].wc1, hilen);

		ctlr->rda[i].link = LS16(&ctlr->rda[NEXT(i, Nrb)]);
		ctlr->rda[i].link =  LS16(&ctlr->rda[NEXT(i, Nrb)]);
		ctlr->rda[i].owner = Interface;

		ctlr->rra[i].ptr0 = ctlr->rda[i].ptr0 = LS16(ctlr->rb[i]);
		ctlr->rra[i].ptr1 = ctlr->rda[i].ptr1 = MS16(ctlr->rb[i]);
		loadr = LS16(ctlr->rb[i]);
		wus(&ctlr->rra[i].ptr0, loadr);
		wus(&ctlr->rda[i].ptr0, loadr);

		hiadr = MS16(ctlr->rb[i]);
		wus(&ctlr->rra[i].ptr1, hiadr);
		wus(&ctlr->rda[i].ptr1, hiadr);
	}

	/*
	 * Check the important resources are QUAD aligned
	 */
	ISquad(ctlr->rra);
	ISquad(ctlr->rda);
	ISquad(ctlr->rb);

	/*
	 * Terminate the receive descriptor ring


@@ 280,8 316,7 @@ iprint("eobc #%lux\n", RD(eobc));

	WR(crda, LS16(ctlr->rda));
	WR(urda, MS16(ctlr->rda));
	WR(eobc, sizeof(ctlr->rb[0])/2 - 2);
iprint("eobc #%lux\n", RD(eobc));
	WR(eobc, Rxbuf/2 - 2);

	/*
	 * Load the SONIC registers to describe the RRA.


@@ 289,8 324,6 @@ iprint("eobc #%lux\n", RD(eobc));
	 * rea. This means that since we've already allocated all
	 * the buffers, we'll never get a 'receive buffer area
	 * exhausted' interrupt and the rrp will just wrap round.
	 * Tell the SONIC to load the RRA and wait for
	 * it to complete.
	 */
	WR(urra, MS16(&ctlr->rra[0]));
	WR(rsa, LS16(&ctlr->rra[0]));


@@ 298,10 331,6 @@ iprint("eobc #%lux\n", RD(eobc));
	WR(rea, LS16(&ctlr->rra[Nrb]));
	WR(rwp, LS16(&ctlr->rra[Nrb+1]));

	WR(cr, Rrra);
	while(RD(cr) & Rrra)
		;

	/*
	 * Initialise the transmit descriptor area (TDA).
	 * Each descriptor describes one packet, we make no use


@@ 339,18 368,26 @@ iprint("eobc #%lux\n", RD(eobc));
	 * broadcast is defined by the SONIC as all 1s.
	 *
	 * Load the SONIC registers to describe the CDA.
	 * Tell the SONIC to load the CDA and wait for it
	 * to complete.
	 */
	ctlr->cda.cep = 0;
	ctlr->cda.cap0 = (ctlr->ea[1]<<8)|ctlr->ea[0];
	ctlr->cda.cap1 = (ctlr->ea[3]<<8)|ctlr->ea[2];
	ctlr->cda.cap2 = (ctlr->ea[5]<<8)|ctlr->ea[4];
	ctlr->cda.ce = 1;
	ctlr->cda->cep = 0;
	ctlr->cda->cap0 = (ctlr->ea[1]<<8)|ctlr->ea[0];
	ctlr->cda->cap1 = (ctlr->ea[3]<<8)|ctlr->ea[2];
	ctlr->cda->cap2 = (ctlr->ea[5]<<8)|ctlr->ea[4];
	ctlr->cda->ce = 1;

	WR(cdp, LS16(&ctlr->cda));
	WR(cdp, LS16(ctlr->cda));
	WR(cdc, 1);

	/*
	 * End the reset
	 * Load the Resource Descriptors and Cam contents
	 */
	WR(cr, 0);

	WR(cr, Rrra);
	while(RD(cr) & Rrra)
		;

	WR(cr, Lcam);
	while(RD(cr) & Lcam)
		;


@@ 366,43 403,42 @@ iprint("eobc #%lux\n", RD(eobc));
}

void
pxp(RXpkt *rxpkt)
sonicpkt(Ether *ctlr, RXpkt *r, Pbuf *p)
{
	print("%lux %lux\n", rxpkt->pad0[0], rxpkt->pad0[1]);
	print("status %lux\n", rxpkt->status);		/* receive status */
	print("%lux %lux\n", rxpkt->pad1[0], rxpkt->pad1[1]);
	print("count %lux\n", rxpkt->count);		/* packet byte count */
	print("%lux %lux\n", rxpkt->pad2[0], rxpkt->pad2[1]);
	print("ptr0 %lux\n", rxpkt->ptr0);		/* buffer pointer */
	print("%lux %lux\n", rxpkt->pad3[0], rxpkt->pad3[1]);
	print("ptr1 %lux\n", rxpkt->ptr1);
	print("%lux %lux\n", rxpkt->pad4[0], rxpkt->pad4[1]);
	print("seqno %lux\n", rxpkt->seqno);		/*  */
	print("%lux %lux\n", rxpkt->pad5[0], rxpkt->pad5[1]);
	print("link %lux\n", rxpkt->link);		/* descriptor link and EOL */
	print("%lux %lux\n", rxpkt->pad6[0], rxpkt->pad6[1]);
	print("owner %lux\n", rxpkt->owner);		/* in use */
	int len;
	ushort type;
	Netfile *f, **fp, **ep;

	/*
	 * Sonic delivers CRC as part of the packet count
	 */
	len = (r->count & 0xFFFF)-4;

	sonicswap(p, len);

	type = (p->type[0]<<8) | p->type[1];
	ep = &ctlr->f[Ntypes];
	for(fp = ctlr->f; fp < ep; fp++) {
		f = *fp;
		if(f && (f->type == type || f->type < 0))
			qproduce(f->in, p->d, len);
	}
}

void
etherintr(void)
{
	int x;
	ushort t;
	Ether *ctlr;
	Ether *c;
	ulong status;
	TXpkt *txpkt;
	RXpkt *rxpkt;
	Etherpkt *p;
	Netfile *f, **fp;

	ctlr = ether[0];
	c = ether[0];

	for(;;) {
		status = RD(isr) & AllIntr;
		if(status == 0)
			break;
print("s %lux\n", status);	

		WR(isr, status);
	


@@ 410,7 446,7 @@ print("s %lux\n", status);
		 * Transmission complete, for good or bad.
		 */
		if(status & (Txdn|Txer)){
			txpkt = &ctlr->tda[ctlr->ti];
			txpkt = &c->tda[c->ti];
			while(txpkt->status != Host){
				if(txpkt->status == Interface){
					WR(ctda, LS16(txpkt));


@@ 419,11 455,11 @@ print("s %lux\n", status);
				}
	
				if((txpkt->status & Ptx) == 0)
					ctlr->oerrs++;
					c->oerrs++;
	
				txpkt->status = Host;
				ctlr->ti = NEXT(ctlr->ti, Ntb);
				txpkt = &ctlr->tda[ctlr->ti];
				c->ti = NEXT(c->ti, Ntb);
				txpkt = &c->tda[c->ti];
			}
			status &= ~(Txdn|Txer);
		}


@@ 434,38 470,24 @@ print("s %lux\n", status);
		/*
		 * A packet arrived or we ran out of descriptors.
		 */
		rxpkt = &ctlr->rda[ctlr->rh];
pxp(rxpkt);
		rxpkt = &c->rda[c->rh];
		while(rxpkt->owner == Host){
			ctlr->inpackets++;
			c->inpackets++;
	
			/*
			 * If the packet was received OK, pass it up,
			 * otherwise log the error.
			 * SONIC gives us the CRC in the packet, so
			 * remember to subtract it from the length.
			 */

			if(rxpkt->status & Prx) {
				x = (rxpkt->count & 0xFFFF)-4;
				p = (Etherpkt*)ctlr->rb[ctlr->rh];
				t = (p->type[0]<<8) | p->type[1];
				for(fp = ctlr->f; fp < &ctlr->f[Ntypes]; fp++){
					f = *fp;
					if(f == 0)
						continue;
					if(f->type == t || f->type < 0)
						qproduce(f->in, p->d, x);
				}
			}
			if(rxpkt->status & Prx)
				sonicpkt(c, rxpkt, (Pbuf*)c->rb[c->rh]);
			else
			if(rxpkt->status & Fae)
				ctlr->frames++;
				c->frames++;
			else
			if(rxpkt->status & Crc)
				ctlr->crcs++;
				c->crcs++;
			else
				ctlr->buffs++;
				c->buffs++;
	
			/*
			 * Finished with this packet, it becomes the


@@ 475,10 497,10 @@ pxp(rxpkt);
			 */
			rxpkt->link |= Eol;
			rxpkt->owner = Interface;
			ctlr->rda[PREV(ctlr->rh, Nrb)].link &= ~Eol;
			ctlr->rh = NEXT(ctlr->rh, Nrb);
			c->rda[PREV(c->rh, Nrb)].link &= ~Eol;
			c->rh = NEXT(c->rh, Nrb);
	
			rxpkt = &ctlr->rda[ctlr->rh];
			rxpkt = &c->rda[c->rh];
		}
		status &= ~(Pktrx|Rde);



@@ 494,16 516,16 @@ pxp(rxpkt);
		 * Warnings that something is afoot.
		 */
		if(status & Hbl){
			iprint("sonic: cd heartbeat lost\n");
			print("sonic: cd heartbeat lost\n");
			status &= ~Hbl;
		}
		if(status & Br){
			iprint("sonic: bus retry occurred\n");
			print("sonic: bus retry occurred\n");
			status &= ~Br;
		}
	
		if(status & AllIntr)
			iprint("sonic #%lux\n", status);
			print("sonic #%lux\n", status);
	}
}



@@ 524,6 546,47 @@ promiscuous(void *arg, int on)
		WR(rcr, reg&~Pro);
}

static void
initbufs(Ether *c)
{
	int i;
	uchar *mem;

	mem = xspanalloc(64*1024, BY2PG, 0);
	mem = CACHELINE(uchar, mem);

	/*
	 * Descriptors must be built in uncached space
	 */
	c->rra = UNCACHED(RXrsc, mem);
	mem = QUAD(uchar, mem+Nrb*sizeof(RXrsc));

	c->rda = UNCACHED(RXpkt, mem);
	mem = QUAD(uchar, mem+Nrb*sizeof(RXpkt));

	c->tda = UNCACHED(TXpkt, mem);
	mem = QUAD(uchar, mem+Ntb*sizeof(TXpkt));

	c->cda = UNCACHED(Cam, mem);

	/*
	 * DMA buffers are cache coherent - but we must not straddle
	 * a cache line
	 */
	mem = CACHELINE(uchar, mem+sizeof(Cam));

	for(i = 0; i < Nrb; i++) {
		c->rb[i] = UNCACHED(uchar, mem);
		mem += sizeof(Pbuf)+4;
		mem = QUAD(uchar, mem);
	}
	for(i = 0; i < Ntb; i++) {
		c->tb[i] = UNCACHED(uchar, mem);
		mem += sizeof(Pbuf);
		mem = QUAD(uchar, mem);
	}
}

void
etherreset(void)
{


@@ 535,12 598,11 @@ etherreset(void)
	 * Set the physical ethernet address and
	 * prime the interrupt handler.
	 */
	if(ether[0] == 0) {
		ether[0] = xspanalloc(sizeof(Ether), BY2PG, 64*1024);

		if(PADDR(ether[0])+sizeof(Ether) > Ntranslation*BY2PG)
			panic("sonic: 16M io map");

	if(ether[0] == 0) {
		ctlr = malloc(sizeof(Ether));
		ether[0] = ctlr;
		initbufs(ctlr);
		enetaddr(ether[0]->ea);
	}
	ctlr = ether[0];


@@ 559,12 621,6 @@ etherreset(void)
}

void
enab(void)
{
	WR(cr, Rxen);
}

void
etherinit(void)
{
}


@@ 578,7 634,6 @@ etherattach(char *spec)
		enable = 1;
		WR(cr, Rxen);
	}

	return devattach('l', spec);
}



@@ 629,14 684,12 @@ isoutbuf(void *arg)
long
etherwrite(Chan *c, void *buf, long n, ulong offset)
{
	Etherpkt *p;
	Pbuf *p;
	TXpkt *txpkt;
	Ether *ctlr = ether[0];

	USED(offset);

iprint("ether tx\n");

	if(n > ETHERMAXTU)
		error(Ebadarg);



@@ 651,13 704,14 @@ iprint("ether tx\n");
	if(!isoutbuf(ctlr))
		print("ether transmitter jammed\n");
	else {
		p =(Etherpkt*)ctlr->tb[ctlr->th];
		p =(Pbuf*)ctlr->tb[ctlr->th];
		memmove(p->d, buf, n);
		if(n < 60) {
			memset(p->d+n, 0, 60-n);
			n = 60;
		}
		memmove(p->s, ctlr->ea, sizeof(ctlr->ea));
		sonicswap(p, n);

		txpkt = &ctlr->tda[ctlr->th];
		txpkt->size = n;


@@ 671,8 725,6 @@ iprint("ether tx\n");
	}
	qunlock(&ctlr->tlock);

iprint("tx done %d\n", n);

	return n;
}



@@ 693,3 745,22 @@ etherwstat(Chan *c, char *dp)
{
	netifwstat(ether[0], c, dp);
}

#define swiz(s)	(s<<24)|((s>>8)&0xff00)|((s<<8)&0xff0000)|(s>>24)

void
sonicswap(void *a, int n)
{
	ulong *p, t0, t1;

	n = ((n+8)/8)*8;
	p = a;
	while(n) {
		t0 = p[0];
		t1 = p[1];
		p[0] = swiz(t1);
		p[1] = swiz(t0);
		p += 2;
		n -= 8;
	}
}

M carrera/fns.h => carrera/fns.h +1 -7
@@ 78,14 78,8 @@ void*	pxspanalloc(ulong, int, ulong);
ulong	rdcount(void);
int	readlog(ulong, char*, ulong);
void	restfpregs(FPsave*, ulong);
void	screeninit(int);
void	screeninit(void);
#define	screenputs 
void	sethandler(int, void(*)(void));
void	setled(int);
void	setleveldest(int, int, uvlong*);
void	sinit(void);
uchar*	smap(int, uchar*);
void	sunmap(int, uchar*);
void	syslog(char*, int);
void	sysloginit(void);
int	tas(ulong*);

M carrera/io.h => carrera/io.h +12 -2
@@ 4,6 4,7 @@
enum
{
	Devicephys	= 0x80000000,
	Eisaphys	= 0x90000000,
	Devicevirt	= 0xE0000000,
	Dmabase		= 0xE0000000,	
	Sonicbase	= 0xE0001000,    	


@@ 17,11 18,13 @@ enum
	Nvram		= 0xE0009000, 	
	NvramRW		= 0xE000A000,
	NvramRO		= 0xE000B000,
	 Enetoffset	= 0,
	KeyboardIO	= 0xE0005000,	
	MouseIO		= 0xE0005000,  	
	SoundIO		= 0xE000C000,
	EisaLatch	= 0xE000E000,
	Diag		= 0xE000F000,
	EisaControl	= 0xE0010000,	/* Second 64K Page from Devicevirt */
	VideoCTL	= 0x60000000,	
	VideoMEM	= 0x40000000, 	
	I386ack		= 0xE000023f,


@@ 46,11 49,18 @@ enum
	Ntranslation	= 4096,		/* Number of translation registers */
};

#define IO(type, reg)	(*(type*)reg)

typedef struct Tte Tte;
struct Tte
{
	ulong	hi;
	ulong	lo;
};

#define IO(type, reg)		(*(type*)reg)
#define QUAD(type, v)		(type*)(((ulong)(v)+7)&~7)
#define CACHELINE(type, v)	(type*)(((ulong)(v)+127)&~127)
#define UNCACHED(type, v)	(type*)((ulong)(v)|0xA0000000)

#define EISAUNCACHED(v)		(0xA0000000|0x10000000|(v))
#define EISAOUTB(port, v)	*(uchar*)((EisaControl+(port))^7) = v
#define EISAINB(port)		(*(uchar*)((EisaControl+(port))^7))

M carrera/main.c => carrera/main.c +25 -22
@@ 54,10 54,7 @@ main(void)
	rootfiles();
	swapinit();
	userinit();
enab();
spllo();
for(;;)
  ;
screeninit();
	schedinit();
}



@@ 166,31 163,44 @@ serialinit(void)
void
ioinit(void)
{
	ulong phys;
	ulong devphys, isaphys, intphys;

	/*
	 * Map devices
	 * Map devices and the Eisa control space
	 */
	phys = PPN(Devicephys)|PTEGLOBL|PTEVALID|PTEWRITE|PTEUNCACHED;
	puttlbx(1, Devicevirt, phys, PTEGLOBL, PGSZ64K);
	devphys = PPN(Devicephys)|PTEGLOBL|PTEVALID|PTEWRITE|PTEUNCACHED;
	isaphys = PPN(Eisaphys)|PTEGLOBL|PTEVALID|PTEWRITE|PTEUNCACHED;

	puttlbx(1, Devicevirt, devphys, isaphys, PGSZ64K);

	/*
	 * Map Interrupt control
	 */
	phys = PPN(Intctlphys)|PTEGLOBL|PTEVALID|PTEWRITE|PTEUNCACHED;
	puttlbx(2, Intctlvirt, phys, PTEGLOBL, PGSZ4K);
	intphys = PPN(Intctlphys)|PTEGLOBL|PTEVALID|PTEWRITE|PTEUNCACHED;
	puttlbx(2, Intctlvirt, intphys, PTEGLOBL, PGSZ4K);

	/* Enable all devce interrupt */
	IO(ushort, Intenareg) = 0xffff;
}

/*
 * Pull the ethernet address out of NVRAM
 */
void
enetaddr(uchar *ea)
{
	/** BUG get from PROM */
	static uchar tea[] = { 0x00, 0x00, 0x77, 0x01, 0xD2, 0xba };
	int i;
	uchar tbuf[8];

	for(i = 0; i < 8; i++)
		tbuf[i] = ((uchar*)(NvramRO+Enetoffset))[i];

	memmove(ea, tea, sizeof(tea));
	print("ether:");
	for(i = 0; i < 6; i++) {
		ea[i] = tbuf[7-i];
		print("%2.2ux", ea[i]);
	}
	print("\n");
}

/*


@@ 360,6 370,8 @@ confinit(void)
	conf.arp = 32;
	conf.frag = 32;

	conf.monitor = 1;

	conf.copymode = 0;		/* copy on write */
}



@@ 379,12 391,3 @@ buzz(int f, int d)
	USED(f);
	USED(d);
}

int
mouseputc(IOQ *q, int c)
{
	USED(q);
	USED(c);
	return 0;
}


M carrera/mem.h => carrera/mem.h +5 -10
@@ 78,9 78,8 @@
#define CU1		0x20000000

/*
 * Traps
 * Trap vectors
 */

#define	UTLBMISS	(KSEG0+0x000)
#define	XEXCEPTION	(KSEG0+0x80)
#define	CACHETRAP	(KSEG0+0x100)


@@ 89,7 88,6 @@
/*
 * Magic registers
 */

#define	USER		24		/* R24 is up-> */
#define	MACH		25		/* R25 is m-> */



@@ 97,17 95,12 @@
 * Fundamental addresses
 */
#define	MACHADDR	0x80005000	/* Mach structures */
/* Leave space below kmap for IO */
#define	KMAPADDR	0xE0040000
/* Sizeof(Ureg)+space for retpc & ur */
#define UREGSIZE	0xA0
#define UREGSIZE	0xA0		/* Sizeof(Ureg)+retpc & ur */
#define	MACHP(n)	((Mach *)(MACHADDR+(n)*BY2PG))


/*
 * MMU
 */

#define PGSZ4K		(0x00<<13)
#define PGSZ64K		(0x0F<<13)
#define PGSZ256K	(0x3F<<13)


@@ 121,9 114,11 @@

#define PIDXSHFT	12
#define PIDX		(0x7<<PIDXSHFT)
#define	KMAPADDR	0xE1000000
#define KMAPMASK	0xFF000000
#define KMAPSHIFT	15
#define NCOLOR		8
#define getcolor(a)	(((ulong)(a)>>PIDXSHFT)&7)
#define getpgcolor(a)	(((ulong)(a)>>PIDXSHFT)&7)

#define	PTEGLOBL	(1<<0)
#define	PTEVALID	(1<<1)

M carrera/mmu.c => carrera/mmu.c +5 -3
@@ 143,9 143,9 @@ void
kfault(ulong addr)
{
	KMap *k, *f;
	ulong x, index;
	ulong x, index, virt;

	index = (addr & ~KSEGM) >> KMAPSHIFT;
	index = (addr & ~KMAPADDR) >> KMAPSHIFT;
	if(index >= KPTESIZE)
		panic("kmapfault: %lux", addr);



@@ 163,7 163,9 @@ kfault(ulong addr)
	}

	x = m->ktlbnext;
	puttlbx(x, (k->virt & ~BY2PG)|TLBPID(tlbvirt()), k->phys0, k->phys1, PGSZ4K);
	virt = (k->virt&~BY2PG)|TLBPID(tlbvirt());
	puttlbx(x, virt, k->phys0, k->phys1, PGSZ4K);

	m->ktlbx[x] = 1;
	if(++x >= NTLB)
		m->ktlbnext = TLBROFF;

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

#include	<libg.h>
#include	<gnot.h>

#define	MINX	8

enum
{
	EMISCR=		0x3CC,		/* control sync polarity */
	EMISCW=		0x3C2,
	EFCW=		0x3DA,		/* feature control */
	EFCR=		0x3CA,
	GRX=		0x3CE,		/* index to graphics registers */
	GR=		0x3CF,		/* graphics registers */
	 Grms=		 0x04,		/*  read map select register */
	SRX=		0x3C4,		/* index to sequence registers */
	SR=		0x3C5,		/* sequence registers */
	 Smmask=	 0x02,		/*  map mask */
	CRX=		0x3D4,		/* index to crt registers */
	CR=		0x3D5,		/* crt registers */
	 Cvre=		 0x11,		/*  vertical retrace end */
	ARW=		0x3C0,		/* attribute registers (writing) */
	ARR=		0x3C1,		/* attribute registers (reading) */
	CMRX=		0x3C7,		/* color map read index */
	CMWX=		0x3C8,		/* color map write index */
	CM=		0x3C9,		/* color map data reg */
};

typedef struct VGAmode	VGAmode;
struct VGAmode
{
	uchar	general[2];
	uchar	sequencer[5];
	uchar	crt[0x19];
	uchar	graphics[9];
	uchar	attribute[0x15];
	uchar	special[12];
};

void	setmode(VGAmode*);

extern	struct GBitmap	gscreen;

VGAmode dfltmode = 
{
	/* general */
	0xef, 0x00, 
	/* sequence */
	0x03, 0x01, 0x0f, 0x00, 0x0e, 
	/* crt */
	0xa1, 0x7f, 0x7f, 0x85, 0x85, 0x96, 0x24, 0xf5, 
	0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x02, 0x88, 0xff, 0x80, 0x60, 0xff, 0x25, 0xab, 
	0xff, 
	/* graphics */
	0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f, 
	0xff, 
	/* attribute */
	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 
	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 
	0x01, 0x00, 0x0f, 0x00, 0x00,
	/* special */
	0x00, 0x00, 0xbc, 0x00, 0x00, 0x00, 0x28, 0x00, 
	0x0a, 0x00, 0x43, 0x1f, 
};

extern	GSubfont	defont0;
GSubfont		*defont;

static ulong rep(ulong, int);

struct{
	Point	pos;
	int	bwid;
}out;

Lock	screenlock;

GBitmap	gscreen =
{
	EISAUNCACHED(0xA0000),
	0,
	(1024*(1<<3))/32,
	3,
	{ 0, 0, 1024, 768 },
	{ 0, 0, 1024, 768 },
	0
};

static GBitmap hwcursor=
{
	0,		/* base filled in by malloc when needed */
	0,
	4,
	1,
	{0, 0, 64, 64},
	{0, 0, 64, 64}
};

uchar bdata[] =
{
	0xC0,
};

GBitmap bgrnd =
{
	(ulong*)bdata,
	0,
	4,
	3,
	{ 0, 0, 1, 1 },
	{ 0, 0, 1, 1 },
	0
};

/*
 *  a fatter than usual cursor for the safari
 */
Cursor fatarrow = {
	{ -1, -1 },
	{
		0xff, 0xff, 0x80, 0x01, 0x80, 0x02, 0x80, 0x0c, 
		0x80, 0x10, 0x80, 0x10, 0x80, 0x08, 0x80, 0x04, 
		0x80, 0x02, 0x80, 0x01, 0x80, 0x02, 0x8c, 0x04, 
		0x92, 0x08, 0x91, 0x10, 0xa0, 0xa0, 0xc0, 0x40, 
	},
	{
		0x00, 0x00, 0x7f, 0xfe, 0x7f, 0xfc, 0x7f, 0xf0, 
		0x7f, 0xe0, 0x7f, 0xe0, 0x7f, 0xf0, 0x7f, 0xf8, 
		0x7f, 0xfc, 0x7f, 0xfe, 0x7f, 0xfc, 0x73, 0xf8, 
		0x61, 0xf0, 0x60, 0xe0, 0x40, 0x40, 0x00, 0x00, 
	},
};

static Rectangle window;
static Point cursor;
static int h, w;
extern Cursor arrow;

void
gborder(GBitmap *l, Rectangle r, int i, Fcode c)
{
	if(i < 0){
		r = inset(r, i);
		i = -i;
	}
	gbitblt(l, r.min, l, Rect(r.min.x, r.min.y, r.max.x, r.min.y+i), c);
	gbitblt(l, Pt(r.min.x, r.max.y-i),
		l, Rect(r.min.x, r.max.y-i, r.max.x, r.max.y), c);
	gbitblt(l, Pt(r.min.x, r.min.y+i),
		l, Rect(r.min.x, r.min.y+i, r.min.x+i, r.max.y-i), c);
	gbitblt(l, Pt(r.max.x-i, r.min.y+i),
		l, Rect(r.max.x-i, r.min.y+i, r.max.x, r.max.y-i), c);
}

void
screenwin(void)
{
	gtexture(&gscreen, gscreen.r, &bgrnd, S);
	w = defont0.info[' '].width;
	h = defont0.height;

	window.min = Pt(100, 100);
	window.max = add(window.min, Pt(10+w*120, 10+h*60));

	gbitblt(&gscreen, window.min, &gscreen, window, Zero);
	window = inset(window, 5);
	cursor = window.min;
	window.max.y = window.min.y+((window.max.y-window.min.y)/h)*h;

	hwcurs = 0;
}

void
screeninit(void)
{
	setmode(&dfltmode);

	memmove(&arrow, &fatarrow, sizeof(fatarrow));

	/* save space; let bitblt do the conversion work */
	defont = &defont0;	
	gbitblt(&gscreen, Pt(0, 0), &gscreen, gscreen.r, 0);
	out.pos.x = MINX;
	out.pos.y = 0;
	out.bwid = defont0.info[' '].width;

	screenwin();
}

static void
scroll(void)
{
	int o;
	Rectangle r;

	o = 5*h;
	r = Rpt(Pt(window.min.x, window.min.y+o), window.max);
	gbitblt(&gscreen, window.min, &gscreen, r, S);
	r = Rpt(Pt(window.min.x, window.max.y-o), window.max);
	gbitblt(&gscreen, r.min, &gscreen, r, Zero);
	cursor.y -= o;
}

static void
screenputc(char *buf)
{
	int pos;

	switch(buf[0]) {
	case '\n':
		if(cursor.y+h >= window.max.y)
			scroll();
		cursor.y += h;
		screenputc("\r");
		break;
	case '\r':
		cursor.x = window.min.x;
		break;
	case '\t':
		pos = (cursor.x-window.min.x)/w;
		pos = 8-(pos%8);
		cursor.x += pos*w;
		break;
	case '\b':
		if(cursor.x-w >= 0)
			cursor.x -= w;
		break;
	default:
		if(cursor.x >= window.max.x-w)
			screenputc("\n");
		cursor = gsubfstring(&gscreen, cursor, &defont0, buf, S);
	}
}

#ifdef USEME
void
screenputs(char *s, int n)
{
	int i;
	Rune r;
	char buf[4];

	if((getstatus() & IEC) == 0) {
		/* don't deadlock trying to print in interrupt */
		if(!canlock(&screenlock))
			return;	
	}
	else
		lock(&screenlock);

	while(n > 0){
		i = chartorune(&r, s);
		if(i == 0){
			s++;
			--n;
			continue;
		}
		memmove(buf, s, i);
		buf[i] = 0;
		n -= i;
		s += i;
		screenputc(buf);
	}
	unlock(&screenlock);
}
#endif

/* replicate (from top) value in v (n bits) until it fills a ulong */
static ulong
rep(ulong v, int n)
{
	int o;
	ulong rv;

	rv = 0;
	for(o = 32 - n; o >= 0; o -= n)
		rv |= (v << o);
	return rv;
}

void
getcolor(ulong p, ulong *pr, ulong *pg, ulong *pb)
{
	ulong ans;

	/*
	 * The gnot says 0 is white (max intensity)
	 */
	if(gscreen.ldepth == 0){
		if(p == 0)
				ans = ~0;
		else
				ans = 0;
	}else{
		switch(p){
		case 0:		ans = ~0;		break;
		case 1:		ans = 0xAAAAAAAA;	break;
		case 2:		ans = 0x55555555;	break;
		default:	ans = 0;		break;
		}
	}
	*pr = *pg = *pb = ans;
}

int
setcolor(ulong p, ulong r, ulong g, ulong b)
{
	USED(p, r, g, b);
	return 0;	/* can't change mono screen colormap */
}

void
hwcursset(ulong *s, ulong *c, int ox, int oy)
{
	USED(s, c, ox, oy);
}

void
hwcursmove(int x, int y)
{
	USED(x, y);
}

/* only 1 flavor mouse */
void
mousectl(char *x)
{
	USED(x);
}

/* bits per pixel */
int
screenbits(void)
{
	return 1<<gscreen.ldepth;
}

void
mbbrect(Rectangle r)
{
	USED(r);
}

void
mbbpt(Point p)
{
	USED(p);
}

void
srout(int reg, int val)
{
	EISAOUTB(SRX, reg);
	EISAOUTB(SR, val);
}

void
grout(int reg, int val)
{
	EISAOUTB(GRX, reg);
	EISAOUTB(GR, val);
}

void
genout(int reg, int val)
{
	if(reg == 0)
		EISAOUTB(EMISCW, val);
	else if (reg == 1)
		EISAOUTB(EFCW, val);
}

void
arout(int reg, int val)
{
	uchar junk;

	junk = EISAINB(0x3DA);
	USED(junk);

	if (reg <= 0xf) {
		EISAOUTB(ARW, reg | 0x0);
		EISAOUTB(ARW, val);
		junk = EISAINB(0x3DA);
		USED(junk);
		EISAOUTB(ARW, reg | 0x20);
	} else {
		EISAOUTB(ARW, reg | 0x20);
		EISAOUTB(ARW, val);
	}
}

void
crout(int reg, int val)
{
	EISAOUTB(CRX, reg);
	EISAOUTB(CR, val);
}

void
setmode(VGAmode *v)
{
	int i;

	/* turn screen off (to avoid damage) */
	srout(1, 0x21);

	for(i = 0; i < sizeof(v->general); i++)
		genout(i, v->general[i]);

	for(i = 0; i < sizeof(v->sequencer); i++)
		if(i == 1)
			srout(i, v->sequencer[i]|0x20);
		else
			srout(i, v->sequencer[i]);

	crout(Cvre, 0);	/* allow writes to CRT registers 0-7 */
	for(i = 0; i < sizeof(v->crt); i++)
		crout(i, v->crt[i]);

	for(i = 0; i < sizeof(v->graphics); i++)
		grout(i, v->graphics[i]);

	for(i = 0; i < sizeof(v->attribute); i++)
		arout(i, v->attribute[i]);

	/* turn screen on */
	srout(1, v->sequencer[1]);
}

A carrera/screen.h => carrera/screen.h +8 -0
@@ 0,0 1,8 @@
extern void		mouseupdate(int);

#define	hwscreenwrite(a, b)

#define mbbpt(x)
#define mbbrect(x)
#define screenupdate()
#define mousescreenupdate()

M carrera/trap.c => carrera/trap.c +2 -3
@@ 204,8 204,7 @@ trap(Ureg *ur)
		if(up == 0)
			kernfault(ur, ecode);

		if(!user && (ur->badvaddr & KSEGM) == KSEG3) {
iprint("kf %lux %lux\n", ur->pc, ur->r31);
		if(!user && (ur->badvaddr & KMAPMASK) == KMAPADDR) {
			kfault(ur->badvaddr);
			break;
		}


@@ 392,7 391,7 @@ dumpregs(Ureg *ur)

	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]);
		print("%s\t0x%.8lux\t%s\t0x%.8lux\n", regname[i], l[0], regname[i+1], l[1]);
}

int

M port/devbit.c => port/devbit.c +94 -75
@@ 9,8 9,6 @@

#include	"devtab.h"

#include	"screen.h"

/*
 * Some monochrome screens are reversed from what we like:
 * We want 0's bright and 1's dark.


@@ 104,11 102,37 @@ void	bitstring(GBitmap*, Point, GFont*, uchar*, long, Fcode);
void	bitloadchar(GFont*, int, GSubfont*, int);
extern	GBitmap	gscreen;

typedef struct Mouseinfo	Mouseinfo;
typedef struct Cursorinfo	Cursorinfo;

struct Mouseinfo{
	/*
	 * First three fields are known in some l.s's
	 */
	int	dx;
	int	dy;
	int	track;		/* l.s has updated dx & dy */
	Mouse;
	int	redraw;		/* update cursor on screen */
	ulong	counter;	/* increments every update */
	ulong	lastcounter;	/* value when /dev/mouse read */
	Rendez	r;
};

struct Cursorinfo{
	Cursor;
	Lock;
	int	visible;	/* on screen */
	int	disable;	/* from being used */
	Rectangle r;		/* location */
};

Mouseinfo	mouse;
Cursorinfo	cursor;
int		mouseshifted;
int		mousetype;
int		islittle;
int		hwcurs;

Cursor	arrow =
{


@@ 269,6 293,7 @@ bitreset(void)

	if(!conf.monitor)
		return;

	memmove(&bdefont0, defont, sizeof(*defont));
	bdefont = &bdefont0;
	bit.map = smalloc(DMAP*sizeof(GBitmap*));


@@ 291,6 316,7 @@ bitreset(void)
	 * Somewhat of a heuristic: start with three screensful and
	 * allocate single screensful dynamically if needed.
	 */

	ws = BI2WD>>gscreen.ldepth;	/* pixels per word */
	a->nwords = 3*(HDR + gscreen.r.max.y*gscreen.r.max.x/ws);
	a->words = xalloc(a->nwords*sizeof(ulong));


@@ 524,21 550,16 @@ bitread(Chan *c, void *va, long n, ulong offset)
		 */
		if(n < 14)
			error(Ebadblt);
	    Again:
		while(mouse.changed == 0)
		while(mousechanged(0) == 0)
			sleep(&mouse.r, mousechanged, 0);
		lock(&cursor);
		if(mouse.changed == 0){
			unlock(&cursor);
			goto Again;
		}
		p = va;
		p[0] = 'm';
		p[1] = mouse.buttons;
		BPLONG(p+2, mouse.xy.x);
		BPLONG(p+6, mouse.xy.y);
		BPLONG(p+10, TK2MS(MACHP(0)->ticks));
		mouse.changed = 0;
		mouse.lastcounter = mouse.counter;
		unlock(&cursor);
		return 14;
	}


@@ 546,7 567,7 @@ bitread(Chan *c, void *va, long n, ulong offset)
		if(offset==0){
			if(n < 5*12)
				error(Eio);
			sprint(va, "%11d %11d %11d %11d %11d ",
			sprint(va, "%11d %11d %11d %11d %11d",
				gscreen.ldepth, gscreen.r.min.x,
				gscreen.r.min.y, gscreen.r.max.x,
				gscreen.r.max.y);


@@ 712,7 733,7 @@ bitread(Chan *c, void *va, long n, ulong offset)
			error(Ebadblt);
		for(j = 0; j < nw; j++){
			if(bit.mid == 0){
				getcolor(flipping? ~j : j, &rv, &gv, &bv);
				getcolor(flipping? nw-j-1 : j, &rv, &gv, &bv);
			}else{
				rv = j;
				for(off = 32-l; off > 0; off -= l)


@@ 1566,8 1587,6 @@ bitwrite(Chan *c, void *va, long n, ulong offset)
				p += l;
				m -= l;
			}
			if(v == 0)
				hwscreenwrite(miny, maxy);
			break;

		case 'x':


@@ 1583,6 1602,7 @@ bitwrite(Chan *c, void *va, long n, ulong offset)
			pt1.y = BGLONG(p+5);
			if(ptinrect(pt1, gscreen.r)){
				mouse.xy = pt1;
				mouse.redraw = 1;
				mouse.track = 1;
				mouseclock();
			}


@@ 1991,6 2011,8 @@ Cursortocursor(Cursor *c)
		*p = c->clr[2*i];
		*(p+1) = c->clr[2*i+1];
	}
	if(hwcurs)
		hwcursset(set.base, clr.base, cursor.offset.x, cursor.offset.y);
	unlock(&cursor);
}



@@ 2002,15 2024,19 @@ cursoron(int dolock)
	if(dolock)
		lock(&cursor);
	if(cursor.visible++ == 0){
		cursor.r.min = mouse.xy;
		cursor.r.max = add(mouse.xy, Pt(16, 16));
		cursor.r = raddp(cursor.r, cursor.offset);
		gbitblt(&cursorback, Pt(0, 0), &gscreen, cursor.r, S);
		gbitblt(&gscreen, cursor.r.min,
			&clr, Rect(0, 0, 16, 16), flipping? flipD[D&~S] : D&~S);
		gbitblt(&gscreen, cursor.r.min,
			&set, Rect(0, 0, 16, 16), flipping? flipD[S|D] : S|D);
		mbbrect(cursor.r);
		if(hwcurs)
			hwcursmove(mouse.xy.x, mouse.xy.y);
		else {
			cursor.r.min = mouse.xy;
			cursor.r.max = add(mouse.xy, Pt(16, 16));
			cursor.r = raddp(cursor.r, cursor.offset);
			gbitblt(&cursorback, Pt(0, 0), &gscreen, cursor.r, S);
			gbitblt(&gscreen, cursor.r.min,
				&clr, Rect(0, 0, 16, 16), flipping? flipD[D&~S] : D&~S);
			gbitblt(&gscreen, cursor.r.min,
				&set, Rect(0, 0, 16, 16), flipping? flipD[S|D] : S|D);
			mbbrect(cursor.r);
		}
	}
	if(dolock)
		unlock(&cursor);


@@ 2024,69 2050,61 @@ cursoroff(int dolock)
	if(dolock)
		lock(&cursor);
	if(--cursor.visible == 0) {
		gbitblt(&gscreen, cursor.r.min, &cursorback, Rect(0, 0, 16, 16), S);
		mbbrect(cursor.r);
		mousescreenupdate();
		if(!hwcurs) {
			gbitblt(&gscreen, cursor.r.min, &cursorback, Rect(0, 0, 16, 16), S);
			mbbrect(cursor.r);
			mousescreenupdate();
		}
	}
	if(dolock)
		unlock(&cursor);
}

/*
 *  called by the clock routine to redraw the cursor
 */
void
mousedelta(int b, int dx, int dy)	/* called at higher priority */
{
	mouse.dx += dx;
	mouse.dy += dy;
	mouse.newbuttons = b;
	mouse.track = 1;
}

void
mousebuttons(int b)	/* called at higher priority */
mouseclock(void)
{
	/*
	 * It is possible if you click very fast and get bad luck
	 * you could miss a button click (down up).  Doesn't seem
	 * likely or important enough to worry about.
	 */
	mouse.newbuttons = b;
	mouse.track = 1;		/* aggressive but o.k. */
	mouseclock();
	if(mouse.track){
		mousetrack(mouse.buttons, mouse.dx, mouse.dy);
		mouse.track = 0;
		mouse.dx = 0;
		mouse.dy = 0;
	}
	if(mouse.redraw && canlock(&cursor)){
		mouse.redraw = 0;
		cursoroff(0);
		cursoron(0);
		mousescreenupdate();
		unlock(&cursor);
	}
}

/*
 *  called at interrupt level to update the structure and
 *  awaken any waiting procs.
 */
void
mouseupdate(int dolock)
mousetrack(int b, int dx, int dy)
{
	int x, y;

	if(!mouse.track || (dolock && !canlock(&cursor)))
		return;

	x = mouse.xy.x + mouse.dx;
	x = mouse.xy.x + dx;
	if(x < gscreen.r.min.x)
		x = gscreen.r.min.x;
	if(x >= gscreen.r.max.x)
		x = gscreen.r.max.x;
	y = mouse.xy.y + mouse.dy;
	y = mouse.xy.y + dy;
	if(y < gscreen.r.min.y)
		y = gscreen.r.min.y;
	if(y >= gscreen.r.max.y)
		y = gscreen.r.max.y;
	cursoroff(0);
	mouse.counter++;
	mouse.xy = Pt(x, y);
	cursoron(0);
	mousescreenupdate();
	mouse.dx = 0;
	mouse.dy = 0;
	mouse.clock = 0;
	mouse.track = 0;
	mouse.buttons = mouse.newbuttons;
	mouse.changed = 1;

	if(dolock){
		unlock(&cursor);
		wakeup(&mouse.r);
	}
	mouse.buttons = b;
	mouse.redraw = 1;
	wakeup(&mouse.r);
}

/*


@@ 2107,6 2125,7 @@ m3mouseputc(IOQ *q, int c)
	static int middle;
	static uchar b[] = { 0, 4, 1, 5, 0, 2, 1, 5 };
	short x;
	int dx, dy, newbuttons;

	USED(q);
	/* 


@@ 2116,20 2135,20 @@ m3mouseputc(IOQ *q, int c)
		if((c&0x40) == 0){
			/* an extra byte gets sent for the middle button */
			middle = (c&0x20) ? 2 : 0;
			mousebuttons((mouse.buttons & ~2) | middle);
			newbuttons = (mouse.buttons & ~2) | middle;
			mousetrack(newbuttons, 0, 0);
			return 0;
		}
	}
	msg[nb] = c;
	if(++nb == 3){
		nb = 0;
		mouse.newbuttons = middle | b[(msg[0]>>4)&3 | (mouseshifted ? 4 : 0)];
		newbuttons = middle | b[(msg[0]>>4)&3 | (mouseshifted ? 4 : 0)];
		x = (msg[0]&0x3)<<14;
		mouse.dx = (x>>8) | msg[1];
		dx = (x>>8) | msg[1];
		x = (msg[0]&0xc)<<12;
		mouse.dy = (x>>8) | msg[2];
		mouse.track = 1;
		mouseclock();
		dy = (x>>8) | msg[2];
		mousetrack(newbuttons, dx, dy);
	}
	return 0;
}


@@ 2145,6 2164,7 @@ mouseputc(IOQ *q, int c)
	static short msg[5];
	static int nb;
	static uchar b[] = {0, 4, 2, 6, 1, 5, 3, 7, 0, 2, 2, 6, 1, 5, 3, 7};
	int dx, dy, newbuttons;

	USED(q);
	if((c&0xF0) == 0x80)


@@ 2153,11 2173,10 @@ mouseputc(IOQ *q, int c)
	if(c & 0x80)
		msg[nb] |= ~0xFF;	/* sign extend */
	if(++nb == 5){
		mouse.newbuttons = b[((msg[0]&7)^7) | (mouseshifted ? 8 : 0)];
		mouse.dx = msg[1]+msg[3];
		mouse.dy = -(msg[2]+msg[4]);
		mouse.track = 1;
		mouseclock();
		newbuttons = b[((msg[0]&7)^7) | (mouseshifted ? 8 : 0)];
		dx = msg[1]+msg[3];
		dy = -(msg[2]+msg[4]);
		mousetrack(newbuttons, dx, dy);
		nb = 0;
	}
	return 0;


@@ 2167,7 2186,7 @@ int
mousechanged(void *m)
{
	USED(m);
	return mouse.changed;
	return mouse.lastcounter != mouse.counter;
}

/*

M port/devcons.c => port/devcons.c +0 -1
@@ 122,7 122,6 @@ panic(char *fmt, ...)
	strcpy(buf, "panic: ");
	n = doprint(buf+strlen(buf), buf+sizeof(buf), fmt, (&fmt+1)) - buf;
	buf[n] = '\n';
iprint("%s\n", buf);
	putstrn(buf, n+1);
	prflush();
	dumpstack();

M port/page.c => port/page.c +2 -2
@@ 71,7 71,7 @@ newpage(int clear, Segment **s, ulong va)
retry:
	lock(&palloc);

	color = getcolor(va);
	color = getpgcolor(va);
	hw = swapalloc.highwater;
	for(;;) {
		if(palloc.freecol[color] > hw)


@@ 233,7 233,7 @@ duppage(Page *p)				/* Always call with p locked */
		return;
	}

	color = getcolor(p->va);
	color = getpgcolor(p->va);
	for(np = palloc.head; np; np = np->next)
		if(np->color == color)
			break;

M port/portdat.h => port/portdat.h +1 -0
@@ 623,6 623,7 @@ extern	Rune*	devchar;
extern	Dev	devtab[];
extern  char	eve[];
extern	char	hostdomain[];
extern	int	hwcurs;
extern	uchar	initcode[];
extern	FPsave	initfp;
extern  Queue	*kbdq;

M port/portfns.h => port/portfns.h +4 -2
@@ 81,13 81,14 @@ void		freechan(Chan*);
void		freepte(Segment*, Pte*);
void		freesegs(int);
void		freesession(Session*);
void		getcolor(ulong, ulong*, ulong*, ulong*);
int		getfields(char*, char**, int, char);
void		gotolabel(Label*);
int		haswaitq(void*);
long		hostdomainwrite(char*, int);
long		hostownerwrite(char*, int);
int		hwcursmove(int, int);
int		hwcursset(uchar*, uchar*, int, int);
void		hwcursset(ulong*, ulong*, int, int);
void		hwcursmove(int, int);
void		iallocinit(void);
long		ibrk(ulong, int);
int		incref(Ref*);


@@ 124,6 125,7 @@ void		mmurelease(Proc*);
void		mmuswitch(Proc*);
void		mntdump(void);
void		mntrepl(char*);
void		mousetrack(int, int, int);
int		mount(Chan*, Chan*, int, char*);
void		mountfree(Mount*);
void		mousebuttons(int);