~kris/9p

9hist

d94140b5c6daf32bfac211d9ed602ce06d1c13b7 — David du Colombier 34 years ago 56d6000
Plan 9 from Bell Labs 1992-06-22
M gnot/dat.h => gnot/dat.h +0 -4
@@ 83,10 83,6 @@ struct Conf
	int	nstream;	/* streams */
	int	nqueue;		/* stream queues */
	int	nsrv;		/* public servers (devsrv.c) */
	int	nbitmap;	/* bitmap structs (devbit.c) */
	int	nbitbyte;	/* bytes of bitmap data (devbit.c) */
	int	nfont;		/* GFont structs (devbit.c) */
	int	nsubfont;	/* Gsubfont structs (devbit.c) */
	int	nurp;		/* max urp conversations */
	int	nasync;		/* number of async protocol modules */
	int	nfsyschan;	/* number of filsys open channels */

M gnot/main.c => gnot/main.c +9 -18
@@ 52,8 52,6 @@ main(void)
	chaninit();
	chandevreset();
	streaminit();
/*	serviceinit(); /**/
/*	filsysinit(); /**/
	swapinit();
	pageinit();
	kmapinit();


@@ 278,19 276,19 @@ banksize(int base)
	if(end > (char *)((KZERO|1024L*1024L)-BY2PG))
		return 0;
	va = UZERO;	/* user page 1 is free to play with */
	putmmu(va, PTEVALID|(base+0)*1024L*1024L/BY2PG, 0);
	putmmu(va, PTEVALID|(base+0)*MB/BY2PG, 0);
	*(ulong*)va = 0;	/* 0 at 0M */
	putmmu(va, PTEVALID|(base+1)*1024L*1024L/BY2PG, 0);
	putmmu(va, PTEVALID|(base+1)*MB/BY2PG, 0);
	*(ulong*)va = 1;	/* 1 at 1M */
	putmmu(va, PTEVALID|(base+4)*1024L*1024L/BY2PG, 0);
	putmmu(va, PTEVALID|(base+4)*MB/BY2PG, 0);
	*(ulong*)va = 4;	/* 4 at 4M */
	putmmu(va, PTEVALID|(base+0)*1024L*1024L/BY2PG, 0);
	putmmu(va, PTEVALID|(base+0)*MB/BY2PG, 0);
	if(*(ulong*)va == 0)
		return 16;
	putmmu(va, PTEVALID|(base+1)*1024L*1024L/BY2PG, 0);
	putmmu(va, PTEVALID|(base+1)*MB/BY2PG, 0);
	if(*(ulong*)va == 1)
		return 4;
	putmmu(va, PTEVALID|(base+0)*1024L*1024L/BY2PG, 0);
	putmmu(va, PTEVALID|(base+0)*MB/BY2PG, 0);
	if(*(ulong*)va == 4)
		return 1;
	return 0;


@@ 307,10 305,10 @@ confinit(void)
		panic("confinit");
	bank[0] = banksize(0);
	bank[1] = banksize(16);
	conf.npage0 = (bank[0]*1024*1024)/BY2PG;
	conf.npage0 = (bank[0]*MB)/BY2PG;
	conf.base0 = 0;
	conf.npage1 = (bank[1]*1024*1024)/BY2PG;
	conf.base1 = 16*1024*1024;
	conf.npage1 = (bank[1]*MB)/BY2PG;
	conf.base1 = 16*MB;
	conf.npage = conf.npage0+conf.npage1;
	conf.upages = (conf.npage*70)/100;



@@ 323,14 321,7 @@ confinit(void)
	conf.npgenv = 200*mul;
	conf.nstream = 40 + 32*mul;
	conf.nqueue = 5 * conf.nstream;
	conf.nsrv = 16*mul;			/* was 32 */
	conf.nbitmap = 300*mul;
	conf.nbitbyte = 300*1024*mul;
	conf.nmux = 10;
	if(*(uchar*)MOUSE & (1<<4))
		conf.nbitbyte *= 2;	/* ldepth 1 */
	conf.nsubfont = 30*mul;
	conf.nfont = 10*mul;
	conf.nurp = 32;
	conf.nasync = 1;
	conf.copymode = 0;		/* copy on write */

M gnot/mem.h => gnot/mem.h +1 -0
@@ 15,6 15,7 @@
#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 gnot/mmu.c => gnot/mmu.c +2 -2
@@ 99,9 99,9 @@ kmapinit(void)
	print("%lud free map registers\n", e-i);

	kmapalloc.free = 0;
	for(k=&kmapalloc.arena[i]; i<e; i++,k++){
	for(k=&kmapalloc.arena[i]; i < e; i++){
		k->va = i*BY2PG|KZERO;
		kunmap(k);
		kunmap(k++);
	}
}


M pc/dat.h => pc/dat.h +0 -4
@@ 74,10 74,6 @@ struct Conf
	ulong	nqueue;		/* stream queues */
	ulong	nblock;		/* stream blocks */
	ulong	nsrv;		/* public servers (devsrv.c) */
	ulong	nbitmap;	/* bitmap structs (devbit.c) */
	ulong	nbitbyte;	/* bytes of bitmap data (devbit.c) */
	int	nfont;		/* GFont structs (devbit.c) */
	ulong	nsubfont;	/* Gsubfont structs (devbit.c) */
	ulong	nurp;		/* max urp conversations */
	ulong	nasync;		/* number of async protocol modules */
	ulong	npipe;		/* number of pipes */

M pc/main.c => pc/main.c +0 -4
@@ 259,10 259,6 @@ confinit(void)
	conf.nmntbuf = conf.nmntdev+3;
	conf.nmnthdr = 2*conf.nmntdev;
	conf.nsrv = 16*mul;			/* was 32 */
	conf.nbitmap = 512*mul;
	conf.nbitbyte = conf.nbitmap*1024*screenbits();
	conf.nfont = 10*mul;
	conf.nsubfont = 30*mul;
	conf.nurp = 32;
	conf.nasync = 1;
	conf.nstream = (conf.nproc*3)/2;

M port/alloc.c => port/alloc.c +4 -16
@@ 73,21 73,6 @@ struct Arena
static Arena	arena;
static Xalloc	xlists;

void*
ialloc(ulong size, int align)
{
	ulong p;

	if(align) {
		size += BY2PG;
		p = (ulong)xalloc(size);
		p += BY2PG;
		p &= ~(BY2PG-1);
		return (void*)p;
	}
	return xalloc(size);;
}

void
xinit(void)
{


@@ 305,8 290,11 @@ smalloc(ulong size)
	void *p;

	p = malloc(size);
	if(p == nil)
	if(p == nil) {
		print("asking for %d\n", size);
		xsummary();
		panic("smalloc should sleep");
	}
	return p;
}


M port/devbit.c => port/devbit.c +323 -259
@@ 37,26 37,36 @@ int flipping;	/* are flip tables being used to transform Fcodes? */
 */

/*
 * Arena is a word containing N, followed by a pointer to its bitmap,
 * followed by N blocks.  The bitmap pointer is zero if block is free.
 * Arena is a word containing N, followed by a pointer to the Arena,
 * followed by a pointer to the Bitmap, followed by N words.
 * The bitmap pointer is zero if block is free.
 * bit.map is an array of pointers to GBitmaps.  The GBitmaps are
 * freed individually and their corresponding entries in bit.map are zeroed.
 * The index into bit.map is the Bitmap id as seen in libg.  Subfonts and
 * fonts are handled similarly.
 */

typedef struct	Arena	Arena;
struct Arena
{
	ulong	*words;		/* storage */
	ulong	*wfree;		/* pointer to next free word */
	ulong	nwords;		/* total in arena */
	int	nbusy;		/* number of busy blocks */
};

struct
{
	Ref;
	QLock;
	GBitmap	**map;		/* indexed array */
	int	nmap;		/* number allocated */
	ulong	*words;		/* storage */
	ulong	nwords;		/* total in arena */
	ulong	*wfree;		/* pointer to next free word */
	GFont	**font;		/* indexed array */
	int	nfont;		/* number allocated */
	GSubfont**subfont;	/* indexed array */
	int	nsubfont;	/* number allocated */
	Arena	*arena;		/* array */
	int	narena;		/* number allocated */
	int	lastid;		/* last allocated bitmap id */
	int	lastsubfid;	/* last allocated subfont id */
	int	lastfid;	/* last allocated font id */


@@ 67,13 77,15 @@ struct
	int	mid;		/* colormap read bitmap id */
}bit;

#define	DMAP	32		/* delta increase in size of arrays */
#define	DMAP	16		/* delta increase in size of arrays */
#define	FREE	0x80000000

void	bitcompact(void);
int	bitalloc(Rectangle, int);
void	bitfree(GBitmap*);
void	fontfree(GFont*);
void	subfontfree(GSubfont*);
void	arenafree(Arena*);
void	bitstring(GBitmap*, Point, GFont*, uchar*, long, Fcode);
void	bitloadchar(GFont*, int, GSubfont*, int);
extern	GBitmap	gscreen;


@@ 149,6 161,7 @@ Dirtab bitdir[]={

#define	NBIT	(sizeof bitdir/sizeof(Dirtab))
#define	NINFO	8192
#define	HDR	3

void
bitreset(void)


@@ 156,6 169,7 @@ bitreset(void)
	int i;
	GBitmap *bp;
	ulong r;
	Arena *a;

	bit.map = smalloc(DMAP*sizeof(GBitmap*));
	bit.nmap = DMAP;


@@ 165,14 179,23 @@ bitreset(void)
	bit.lastid = -1;
	bit.lastsubfid = -1;
	bit.lastfid = -1;
	bit.words = ialloc(conf.nbitbyte, 0);
print("bitreset %lux\n", bit.words);
	bit.nwords = conf.nbitbyte/sizeof(ulong);
	bit.wfree = bit.words;
	bit.font = smalloc(DMAP*sizeof(GFont*));
	bit.nfont = DMAP;
	bit.subfont = smalloc(DMAP*sizeof(GSubfont*));
	bit.nsubfont = DMAP;
	bit.arena = smalloc(DMAP*sizeof(Arena));
	bit.narena = DMAP;
	a = &bit.arena[0];
	/*
	 * Somewhat of a heuristic: start with three screensful and
	 * allocate single screensful dynamically if needed.
	 */
	a->nwords = 3*(gscreen.width*gscreen.r.max.y+HDR);
	a->words = xalloc(a->nwords*sizeof(ulong));
	if(a->words == 0)
		panic("bitreset");
	a->wfree = a->words;
	a->nbusy = 1;	/* keep 0th arena from being freed */
	Cursortocursor(&arrow);
}



@@ 336,8 359,7 @@ bitread(Chan *c, void *va, long n, ulong offset)
	if(c->qid.path & CHDIR)
		return devdirread(c, va, n, bitdir, NBIT, devgen);

	switch(c->qid.path){
	case Qmouse:
	if(c->qid.path == Qmouse){
		/*
		 * mouse:
		 *	'm'		1


@@ 361,179 383,9 @@ bitread(Chan *c, void *va, long n, ulong offset)
		PLONG(p+6, mouse.xy.y);
		mouse.changed = 0;
		unlock(&cursor);
		n = 10;
		break;

	case Qbitblt:
		p = va;
		/*
		 * Fuss about and figure out what to say.
		 */
		if(bit.init){
			/*
			 * init:
			 *	'I'		1
			 *	ldepth		1
			 * 	rectangle	16
			 * if count great enough, also
			 *	font info	3*12
			 *	fontchars	6*(defont->n+1)
			 */
			if(n < 18)
				error(Ebadblt);
			p[0] = 'I';
			p[1] = gscreen.ldepth;
			PLONG(p+2, gscreen.r.min.x);
			PLONG(p+6, gscreen.r.min.y);
			PLONG(p+10, gscreen.r.max.x);
			PLONG(p+14, gscreen.r.max.y);
			dn = 18;
			if(bit.init=='j' && n>=18+16){
				PLONG(p+18, gscreen.clipr.min.x);
				PLONG(p+22, gscreen.clipr.min.y);
				PLONG(p+26, gscreen.clipr.max.x);
				PLONG(p+30, gscreen.clipr.max.y);
				dn += 16;
			}
			if(n >= dn+3*12+6*(defont->n+1)){
				p += dn;
				sprint((char*)p, "%11d %11d %11d ", defont->n,
					defont->height, defont->ascent);
				p += 3*12;
				for(i=defont->info,j=0; j<=defont->n; j++,i++,p+=6){
					PSHORT(p, i->x);
					p[2] = i->top;
					p[3] = i->bottom;
					p[4] = i->left;
					p[5] = i->width;
				}
				n = dn+3*12+6*(defont->n+1);
			}else
				n = dn;
			bit.init = 0;
			break;
		}
		if(bit.lastid > 0){
			/*
			 * allocate:
			 *	'A'		1
			 *	bitmap id	2
			 */
			if(n < 3)
				error(Ebadblt);
			p[0] = 'A';
			PSHORT(p+1, bit.lastid);
			bit.lastid = -1;
			n = 3;
			break;
		}
		if(bit.lastsubfid > 0){
			/*
			 * allocate subfont:
			 *	'K'		1
			 *	subfont id	2
			 */
			if(n < 3)
				error(Ebadblt);
			p[0] = 'K';
			PSHORT(p+1, bit.lastsubfid);
			bit.lastsubfid = -1;
			n = 3;
			break;
		}
		if(bit.lastfid >= 0){
			/*
			 * allocate font:
			 *	'N'		1
			 *	font id		2
			 */
			if(n < 3)
				error(Ebadblt);
			p[0] = 'N';
			PSHORT(p+1, bit.lastfid);
			bit.lastfid = -1;
			n = 3;
			break;
		}
		if(bit.mid >= 0){
			/*
			 * read colormap:
			 *	data		12*(2**bitmapdepth)
			 */
			src = bit.map[bit.mid];
			if(src == 0)
				error(Ebadbitmap);
			l = (1<<src->ldepth);
			nw = 1 << l;
			if(n < 12*nw)
				error(Ebadblt);
			for(j = 0; j < nw; j++){
				if(bit.mid == 0){
					getcolor(flipping? ~j : j, &rv, &gv, &bv);
				}else{
					rv = j;
					for(off = 32-l; off > 0; off -= l)
						rv = (rv << l) | j;
					gv = bv = rv;
				}
				PLONG(p, rv);
				PLONG(p+4, gv);
				PLONG(p+8, bv);
				p += 12;
			}
			bit.mid = -1;
			n = 12*nw;
			break;
		}
		if(bit.rid >= 0){
			/*
			 * read bitmap:
			 *	data		bytewidth*(maxy-miny)
			 */
			src = bit.map[bit.rid];
			if(src == 0)
				error(Ebadbitmap);
			off = 0;
			if(bit.rid == 0)
				off = 1;
			miny = bit.rminy;
			maxy = bit.rmaxy;
			if(miny>maxy || miny<src->r.min.y || maxy>src->r.max.y)
				error(Ebadblt);
			ws = 1<<(3-src->ldepth);	/* pixels per byte */
			/* set l to number of bytes of incoming data per scan line */
			if(src->r.min.x >= 0)
				l = (src->r.max.x+ws-1)/ws - src->r.min.x/ws;
			else{	/* make positive before divide */
				t = (-src->r.min.x)+ws-1;
				t = (t/ws)*ws;
				l = (t+src->r.max.x+ws-1)/ws;
			}
			if(n < l*(maxy-miny))
				error(Ebadblt);
			if(off)
				cursoroff(1);
			n = 0;
			p = va;
			for(y=miny; y<maxy; y++){
				q = (uchar*)gaddr(src, Pt(src->r.min.x, y));
				q += (src->r.min.x&((sizeof(ulong))*ws-1))/ws;
				if(bit.rid == 0 && flipping)	/* flip bits */
					for(x=0; x<l; x++)
						*p++ = ~(*q++);
				else
					for(x=0; x<l; x++)
						*p++ = *q++;
				n += l;
			}
			if(off)
				cursoron(1);
			bit.rid = -1;
			break;
		}
		error(Ebadblt);

	case Qscreen:
		return 10;
	}
	if(c->qid.path == Qscreen){
		if(offset==0){
			if(n < 5*12)
				error(Eio);


@@ 541,8 393,7 @@ bitread(Chan *c, void *va, long n, ulong offset)
				gscreen.ldepth, gscreen.r.min.x,
				gscreen.r.min.y, gscreen.r.max.x,
				gscreen.r.max.y);
			n = 5*12;
			break;
			return 5*12;
		}
		ws = 1<<(3-gscreen.ldepth);	/* pixels per byte */
		l = (gscreen.r.max.x+ws-1)/ws - gscreen.r.min.x/ws;


@@ 565,12 416,174 @@ bitread(Chan *c, void *va, long n, ulong offset)
					*p++ = *q++;
			n += l;
		}
		break;

	default:
		return n;
	}
	if(c->qid.path != Qbitblt)
		error(Egreg);

	qlock(&bit);
	if(waserror()){
		qunlock(&bit);
		nexterror();
	}
	p = va;
	/*
	 * Fuss about and figure out what to say.
	 */
	if(bit.init){
		/*
		 * init:
		 *	'I'		1
		 *	ldepth		1
		 * 	rectangle	16
		 * if count great enough, also
		 *	font info	3*12
		 *	fontchars	6*(defont->n+1)
		 */
		if(n < 18)
			error(Ebadblt);
		p[0] = 'I';
		p[1] = gscreen.ldepth;
		PLONG(p+2, gscreen.r.min.x);
		PLONG(p+6, gscreen.r.min.y);
		PLONG(p+10, gscreen.r.max.x);
		PLONG(p+14, gscreen.r.max.y);
		dn = 18;
		if(bit.init=='j' && n>=18+16){
			PLONG(p+18, gscreen.clipr.min.x);
			PLONG(p+22, gscreen.clipr.min.y);
			PLONG(p+26, gscreen.clipr.max.x);
			PLONG(p+30, gscreen.clipr.max.y);
			dn += 16;
		}
		if(n >= dn+3*12+6*(defont->n+1)){
			p += dn;
			sprint((char*)p, "%11d %11d %11d ", defont->n,
				defont->height, defont->ascent);
			p += 3*12;
			for(i=defont->info,j=0; j<=defont->n; j++,i++,p+=6){
				PSHORT(p, i->x);
				p[2] = i->top;
				p[3] = i->bottom;
				p[4] = i->left;
				p[5] = i->width;
			}
			n = dn+3*12+6*(defont->n+1);
		}else
			n = dn;
		bit.init = 0;
	}else if(bit.lastid > 0){
		/*
		 * allocate:
		 *	'A'		1
		 *	bitmap id	2
		 */
		if(n < 3)
			error(Ebadblt);
		p[0] = 'A';
		PSHORT(p+1, bit.lastid);
		bit.lastid = -1;
		n = 3;
	}else if(bit.lastsubfid > 0){
		/*
		 * allocate subfont:
		 *	'K'		1
		 *	subfont id	2
		 */
		if(n < 3)
			error(Ebadblt);
		p[0] = 'K';
		PSHORT(p+1, bit.lastsubfid);
		bit.lastsubfid = -1;
		n = 3;
	}else if(bit.lastfid >= 0){
		/*
		 * allocate font:
		 *	'N'		1
		 *	font id		2
		 */
		if(n < 3)
			error(Ebadblt);
		p[0] = 'N';
		PSHORT(p+1, bit.lastfid);
		bit.lastfid = -1;
		n = 3;
	}else if(bit.mid >= 0){
		/*
		 * read colormap:
		 *	data		12*(2**bitmapdepth)
		 */
		src = bit.map[bit.mid];
		if(src == 0)
			error(Ebadbitmap);
		l = (1<<src->ldepth);
		nw = 1 << l;
		if(n < 12*nw)
			error(Ebadblt);
		for(j = 0; j < nw; j++){
			if(bit.mid == 0){
				getcolor(flipping? ~j : j, &rv, &gv, &bv);
			}else{
				rv = j;
				for(off = 32-l; off > 0; off -= l)
					rv = (rv << l) | j;
				gv = bv = rv;
			}
			PLONG(p, rv);
			PLONG(p+4, gv);
			PLONG(p+8, bv);
			p += 12;
		}
		bit.mid = -1;
		n = 12*nw;
	}else if(bit.rid >= 0){
		/*
		 * read bitmap:
		 *	data		bytewidth*(maxy-miny)
		 */
		src = bit.map[bit.rid];
		if(src == 0)
			error(Ebadbitmap);
		off = 0;
		if(bit.rid == 0)
			off = 1;
		miny = bit.rminy;
		maxy = bit.rmaxy;
		if(miny>maxy || miny<src->r.min.y || maxy>src->r.max.y)
			error(Ebadblt);
		ws = 1<<(3-src->ldepth);	/* pixels per byte */
		/* set l to number of bytes of incoming data per scan line */
		if(src->r.min.x >= 0)
			l = (src->r.max.x+ws-1)/ws - src->r.min.x/ws;
		else{	/* make positive before divide */
			t = (-src->r.min.x)+ws-1;
			t = (t/ws)*ws;
			l = (t+src->r.max.x+ws-1)/ws;
		}
		if(n < l*(maxy-miny))
			error(Ebadblt);
		if(off)
			cursoroff(1);
		n = 0;
		p = va;
		for(y=miny; y<maxy; y++){
			q = (uchar*)gaddr(src, Pt(src->r.min.x, y));
			q += (src->r.min.x&((sizeof(ulong))*ws-1))/ws;
			if(bit.rid == 0 && flipping)	/* flip bits */
				for(x=0; x<l; x++)
					*p++ = ~(*q++);
			else
				for(x=0; x<l; x++)
					*p++ = *q++;
			n += l;
		}
		if(off)
			cursoron(1);
		bit.rid = -1;
	}

	poperror();
	qunlock(&bit);
	return n;
}



@@ 598,7 611,9 @@ bitwrite(Chan *c, void *va, long n, ulong offset)
		error(Egreg);

	isoff = 0;
	qlock(&bit);
	if(waserror()){
		qunlock(&bit);
		if(isoff)
			cursoron(1);
		nexterror();


@@ 1001,48 1016,6 @@ bitwrite(Chan *c, void *va, long n, ulong offset)
			m -= 11;
			break;

		case 's':
			/*
			 * subfstring
			 *	's'		1
			 *	id		2
			 *	pt		8
			 *	subfont id	2
			 *	code		2
			 * 	string		n (null terminated)
			 */
			if(m < 16)
				error(Ebadblt);
			v = GSHORT(p+1);
			if(v<0 || v>=bit.nmap || (dst=bit.map[v])==0)
				error(Ebadbitmap);
			off = 0;
			fc = GSHORT(p+13) & 0xF;
			if(v == 0){
				if(flipping)
					fc = flipD[fc];
				off = 1;
			}
			pt.x = GLONG(p+3);
			pt.y = GLONG(p+7);
			v = GSHORT(p+11);
			if(v<0 || v>=bit.nsubfont || (f=bit.subfont[v])==0)
				error(Ebadblt);
			p += 15;
			m -= 15;
			q = memchr(p, 0, m);
			if(q == 0)
				error(Ebadblt);
			if(off && !isoff){
				cursoroff(1);
				isoff = 1;
			}
			gsubfstring(dst, pt, f, (char*)p, fc);
			q++;
			m -= q-p;
			p = q;
			break;

		case 't':
			/*
			 * texture


@@ 1234,13 1207,13 @@ bitwrite(Chan *c, void *va, long n, ulong offset)
			if(m < 9)
				error(Ebadblt);
			v = GSHORT(p+1);
			if(v<0 || v>=conf.nfont || (ff=bit.font[v])==0)
			if(v<0 || v>=bit.nfont || (ff=bit.font[v])==0)
				error(Ebadblt);
			l = GSHORT(p+3);
			if(l >= NFCACHE+NFLOOK)
				error(Ebadblt);
			v = GSHORT(p+5);
			if(v<0 || v>=conf.nsubfont || (f=bit.subfont[v])==0)
			if(v<0 || v>=bit.nsubfont || (f=bit.subfont[v])==0)
				error(Ebadblt);
			nw = GSHORT(p+7);
			if(nw >= f->n)


@@ 1286,18 1259,19 @@ bitwrite(Chan *c, void *va, long n, ulong offset)
	poperror();
	if(isoff)
		cursoron(1);
	qunlock(&bit);
	return n;
}

int
bitalloc(Rectangle rect, int ld)
{
	Arena *a, *ea, *na, *aa;
	GBitmap *b, **bp, **ep;
	ulong l, ws, nw;
	long t;
	int i;
	int i, try;

print("bitalloc %lux\n", bit.wfree);
	ws = 1<<(5-ld);	/* pixels per word */
	if(rect.min.x >= 0){
		l = (rect.max.x+ws-1)/ws;


@@ 1308,17 1282,58 @@ print("bitalloc %lux\n", bit.wfree);
		l = (t+rect.max.x+ws-1)/ws;
	}
	nw = l*Dy(rect);
	if(bit.wfree+2+nw > bit.words+bit.nwords){
		bitcompact();
		if(bit.wfree+2+nw > bit.words+bit.nwords)
			error(Enobitstore);
	ea = &bit.arena[bit.narena];

	/* first try easy fit */
	for(a=bit.arena; a<ea; a++){
		if(a->words == 0)
			continue;
		if(a->wfree+HDR+nw <= a->words+a->nwords)
			goto found;
	}

	/* compact and try again */
	bitcompact();
	aa = 0;
	for(a=bit.arena; a<ea; a++){
		if(a->words == 0){
			if(aa == 0)
				aa = a;
			continue;
		}
		if(a->wfree+HDR+nw <= a->words+a->nwords)
			goto found;
	}

	/* need new arena */
	if(aa)
		a = aa;
	else{
		na = bit.arena;
		bit.arena = smalloc((bit.narena+DMAP)*sizeof(Arena));
		memmove(bit.arena, na, bit.narena*sizeof(Arena));
		free(na);
		a = bit.arena+bit.narena;
		bit.narena += DMAP;
	}
	a->nwords = gscreen.width*gscreen.r.max.y+HDR;
	if(a->nwords < HDR+nw)
		a->nwords = HDR+nw;
	a->words = xalloc(a->nwords*sizeof(ulong));
	if(a->words == 0)
		error(Enobitstore);
	a->wfree = a->words;
	a->nbusy = 0;
	
    found:
	b = smalloc(sizeof(GBitmap));
	*bit.wfree++ = nw;
	*bit.wfree++ = (ulong)b;
	b->base = bit.wfree;
	*a->wfree++ = nw;
	*a->wfree++ = (ulong)a;
	*a->wfree++ = (ulong)b;
	b->base = a->wfree;
	memset(b->base, 0, nw*sizeof(ulong));
	bit.wfree += nw;
	a->wfree += nw;
	a->nbusy++;
	b->zero = l*rect.min.y;
	if(rect.min.x >= 0)
		b->zero += rect.min.x/ws;


@@ 1350,6 1365,12 @@ print("bitalloc %lux\n", bit.wfree);
void
bitfree(GBitmap *b)
{
	Arena *a;

	a = (Arena*)(b->base[-2]);
	a->nbusy--;
	if(a->nbusy == 0)
		arenafree(a);
	b->base[-1] = 0;
	free(b);
}


@@ 1370,6 1391,13 @@ subfontfree(GSubfont *s)
}

void
arenafree(Arena *a)
{
	xfree(a->words);
	a->words = 0;
}

void
bitstring(GBitmap *bp, Point pt, GFont *f, uchar *p, long l, Fcode fc)
{
	int full;


@@ 1435,29 1463,65 @@ bitloadchar(GFont *f, int ci, GSubfont *subf, int si)
	gbitblt(f->b, Pt(c->x, f->ascent-subf->ascent), subf->bits, rect, S);
}

QLock	bitlock;

void
bitcompact(void)
{
	ulong *p1, *p2;
	Arena *a, *b, *ea, *na;
	ulong *p1, *p2, n;

	qlock(&bitlock);
	p1 = p2 = bit.words;
	while(p2 < bit.wfree){
		if(p2[1] == 0){
			p2 += 2 + p2[0];
	ea = &bit.arena[bit.narena];
	for(a=bit.arena; a<ea; a++){
		if(a->words == 0)
			continue;
		/* first compact what's here */
		p1 = p2 = a->words;
		while(p2 < a->wfree){
			n = HDR+p2[0];
			if(p2[2] == 0){
				p2 += n;
				continue;
			}
			if(p1 != p2){
				memmove(p1, p2, n*sizeof(ulong));
				((GBitmap*)p1[2])->base = p1+HDR;
			}
			p2 += n;
			p1 += n;
		}
		if(p1 != p2){
			memmove(p1, p2, (2+p2[0])*sizeof(ulong));
			((GBitmap*)p1[1])->base = p1+2;
		/* now pull stuff from later arena to fill this one */
		na = a+1;
		while(na<ea && p1<a->words+a->nwords){
			p2 = na->words;
			if(p2 == 0){
				na++;
				continue;
			}
			while(p2 < na->wfree){
				n = HDR+p2[0];
				if(p2[2] == 0){
					p2 += n;
					continue;
				}
				if(p1+n < a->words+a->nwords){
					memmove(p1, p2, n*sizeof(ulong));
					((GBitmap*)p1[2])->base = p1+HDR;
					/* block now in new arena... */
					p1[1] = (ulong)a;
					a->nbusy++;
					/* ... not in old arena */
					na->nbusy--;
					p2[2] = 0;
					p1 += n;
				}
				p2 += n;
			}
			na++;
		}
		p2 += 2 + p1[0];
		p1 += 2 + p1[0];
		a->wfree = p1;
	}
	bit.wfree = p1;
	qunlock(&bitlock);
	for(a=bit.arena; a<ea && a->words; a++)
		if(a->nbusy == 0)
			arenafree(a);
}

void

M port/devconc.c => port/devconc.c +1 -1
@@ 333,7 333,7 @@ concdevstoput(Queue *q, Block *bp)
void
concreset(void)
{
	concs = ialloc(conf.nconc*sizeof(Conc), 0);
	concs = xalloc(conf.nconc*sizeof(Conc));
	newqinfo(&concinfo);
}


M port/devdk.c => port/devdk.c +19 -33
@@ 159,14 159,14 @@ enum {
	DKreject,
};
char* dkerr[]={
	[DKok]"",
	[DKbusy]"devdk: destination busy",
	[DKnetotl]"devdk: network not answering",
	[DKdestotl]"devdk: destination not answering",
	[DKbadnet]"devdk: unknown address",
	[DKnetbusy]"devdk: network busy",
	[DKinuse]"devdk: service in use",
	[DKreject]"devdk: connection refused", 
	[DKok]		"",
	[DKbusy]	"devdk: destination busy",
	[DKnetotl]	"devdk: network not answering",
	[DKdestotl]	"devdk: destination not answering",
	[DKbadnet]	"devdk: unknown address",
	[DKnetbusy]	"devdk: network busy",
	[DKinuse]	"devdk: service in use",
	[DKreject]	"devdk: connection refused", 
};
#define DKERRS sizeof(dkerr)/sizeof(char*)



@@ 229,7 229,6 @@ dkalloc(char *name, int ncsc, int lines)
{
	Dk *dp;
	Dk *freep;
	Block *bp;
	int i, n;
	Line *lp;



@@ 261,28 260,15 @@ dkalloc(char *name, int ncsc, int lines)
	/*
	 *  allocate memory for line structures
	 */
	n = sizeof(Line*)*(dp->lines);
	bp = allocb(n);
	if(bp->lim - bp->base < n){
		unlock(&dklock);
		error(Ebadarg);
	}
	memset(bp->base, 0, bp->lim-bp->base);
	dp->linep = (Line **)bp->base;
	bp->wptr += n;
	dp->alloc = bp;
	n = sizeof(Line)*(dp->lines);
	for(i = 0; i < dp->lines; i++){
		if(bp->lim - bp->wptr < sizeof(Line)){
			bp = allocb(sizeof(Line)*n);
			memset(bp->base, 0, bp->lim-bp->base);
			bp->next = dp->alloc;
			dp->alloc = bp;
		}
		dp->linep[i] = (Line*)bp->wptr;
		dp->linep[i]->lineno = i;
		bp->wptr += sizeof(Line);
		n -= sizeof(Line);
	dp->linep = (Line **)xalloc(sizeof(Line*) * dp->lines);
	if(dp->linep == 0)
		error(Enomem);
	lp = xalloc(dp->lines*sizeof(Line));
	if(lp == 0)
		error(Enomem);
	for(i = 0; i < dp->lines; i++) {
		lp->lineno = i;
		dp->linep[i] = lp++;
	}

	/*


@@ 720,9 706,9 @@ void
dkreset(void)
{
	int i;
	dk = (Dk*)ialloc(conf.dkif*sizeof(Dk), 0);
	dk = (Dk*)xalloc(conf.dkif*sizeof(Dk));
	for(i = 0; i < conf.dkif; i++)
		dk[i].prot = (Netprot*)ialloc(conf.nurp*sizeof(Netprot), 0);
		dk[i].prot = (Netprot*)xalloc(conf.nurp*sizeof(Netprot));
	newqinfo(&dkmuxinfo);
}


M port/devenv.c => port/devenv.c +1 -1
@@ 42,7 42,7 @@ void	evfree(Envval*);
void
envreset(void)
{
	evscratch = ialloc(BY2PG, 0);
	evscratch = xalloc(BY2PG);
}

void

M port/devip.c => port/devip.c +4 -4
@@ 68,7 68,7 @@ ipinitnet(Network *np, Qinfo *stproto, Ipconv *cp)
	if(stproto != &udpinfo)
		np->listen = iplisten;
	np->clone = ipclonecon;
	np->prot = (Netprot *)ialloc(sizeof(Netprot) * conf.ip, 0);
	np->prot = (Netprot *)xalloc(sizeof(Netprot) * conf.ip);
	np->ninfo = 3;
	np->info[0].name = "remote";
	np->info[0].fill = ipremotefill;


@@ 83,11 83,11 @@ ipreset(void)
{
	int i, j;

	ipifc = (Ipifc *)ialloc(sizeof(Ipifc) * conf.ip, 0);
	ipifc = (Ipifc *)xalloc(sizeof(Ipifc) * conf.ip);

	for(i = 0; protocols[i]; i++) {
		ipconv[i] = (Ipconv *)ialloc(sizeof(Ipconv) * conf.ip, 0);
		ipnet[i] = (Network *)ialloc(sizeof(Network), 0);
		ipconv[i] = (Ipconv *)xalloc(sizeof(Ipconv) * conf.ip);
		ipnet[i] = (Network *)xalloc(sizeof(Network));
		ipinitnet(ipnet[i], protocols[i], ipconv[i]);
		newqinfo(protocols[i]);
	}

M port/devmux.c => port/devmux.c +1 -1
@@ 127,7 127,7 @@ muxinit(void)
void
muxreset(void)
{
	muxes = ialloc(conf.nmux*sizeof(Mux), 0);
	muxes = xalloc(conf.nmux*sizeof(Mux));
}

Chan *

M port/devscc.c => port/devscc.c +2 -2
@@ 665,9 665,9 @@ sccreset(void)
		sp = scc[i];
		if(sp->nostream)
			continue;
		sp->iq = ialloc(sizeof(IOQ), 0);
		sp->iq = xalloc(sizeof(IOQ));
		initq(sp->iq);
		sp->oq = ialloc(sizeof(IOQ), 0);
		sp->oq = xalloc(sizeof(IOQ));
		initq(sp->oq);
		sccenable(sp);
	}

M port/devsrv.c => port/devsrv.c +84 -59
@@ 8,49 8,56 @@
#include	"devtab.h"

typedef struct Srv Srv;
struct Srv{
struct Srv
{
	char	name[NAMELEN];
	char	owner[NAMELEN];
	ulong	perm;
	Chan	*chan;
	Srv	*link;
	ulong	path;
};

Lock	srvlk;
Srv	*srv;
static QLock	srvlk;
static Srv	*srv;
static int	path;

int
srvgen(Chan *c, Dirtab *tab, int ntab, int s, Dir *dp)
{
	Srv *sp;

	if(s >= conf.nsrv)
		return -1;
	qlock(&srvlk);
	for(sp = srv; sp && s; sp = sp->link)
		s--;

	sp = &srv[s];
	if(sp->chan == 0)
		return 0;
	devdir(c, (Qid){s, 0}, sp->name, 0, sp->owner, sp->perm, dp);
	if(sp == 0) {
		qunlock(&srvlk);
		return -1;
	}
	devdir(c, (Qid){sp->path, 0}, sp->name, 0, sp->owner, sp->perm, dp);
	qunlock(&srvlk);
	return 1;
}

void
srvinit(void)
{
	path = 1;
}

void
srvreset(void)
{
	srv = ialloc(conf.nsrv*sizeof(Srv), 0);
}

Chan *
Chan*
srvattach(char *spec)
{
	return devattach('s', spec);
}

Chan *
Chan*
srvclone(Chan *c, Chan *nc)
{
	return devclone(c, nc);


@@ 68,10 75,10 @@ srvstat(Chan *c, char *db)
	devstat(c, db, 0, 0, srvgen);
}

Chan *
Chan*
srvopen(Chan *c, int omode)
{
	Chan *f;
	Srv *sp;

	if(c->qid.path == CHDIR){
		if(omode != OREAD)


@@ 81,60 88,59 @@ srvopen(Chan *c, int omode)
		c->offset = 0;
		return c;
	}
	lock(&srvlk);
	qlock(&srvlk);
	if(waserror()){
		unlock(&srvlk);
		qunlock(&srvlk);
		nexterror();
	}
	f = srv[c->qid.path].chan;
	if(f == 0)

	for(sp = srv; sp; sp = sp->link)
		if(sp->path == c->qid.path)
			break;

	if(sp == 0 || sp->chan == 0)
		error(Eshutdown);

	if(omode&OTRUNC)
		error(Eperm);
	if(omode!=f->mode && f->mode!=ORDWR)
	if(omode!=sp->chan->mode && sp->chan->mode!=ORDWR)
		error(Eperm);

	close(c);
	incref(f);
	unlock(&srvlk);
	incref(sp->chan);
	qunlock(&srvlk);
	poperror();
	return f;
	return sp->chan;
}

void
srvcreate(Chan *c, char *name, int omode, ulong perm)
{
	int j, i;
	Srv *sp;

	if(omode != OWRITE)
		error(Eperm);

	lock(&srvlk);
	sp = malloc(sizeof(Srv));
	if(sp == 0)
		error(Enomem);

	qlock(&srvlk);
	if(waserror()){
		unlock(&srvlk);
		qunlock(&srvlk);
		nexterror();
	}
	j = -1;
	for(i=0; i<conf.nsrv; i++){
		if(srv[i].chan == 0){
			if(j == -1)
				j = i;
		}
		else if(strcmp(name, srv[i].name) == 0)
			error(Einuse);
	}
	if(j == -1)
		exhausted("server slots");
	sp = &srv[j];
	sp->chan = c;
	incref(c);
	unlock(&srvlk);
	sp->path = path++;
	sp->link = srv;
	c->qid.path = sp->path;
	srv = sp;
	qunlock(&srvlk);
	poperror();

	strncpy(sp->name, name, NAMELEN);
	strncpy(sp->owner, u->p->user, NAMELEN);
	sp->perm = perm&0777;

	c->qid.path = j;
	c->flag |= COPEN;
	c->mode = OWRITE;
}


@@ 143,24 149,36 @@ void
srvremove(Chan *c)
{
	Chan *f;
	Srv *sp, **l;

	if(c->qid.path == CHDIR)
		error(Eperm);

	lock(&srvlk);
	qlock(&srvlk);
	if(waserror()){
		unlock(&srvlk);
		qunlock(&srvlk);
		nexterror();
	}
	f = srv[c->qid.path].chan;
	if(f == 0)
		error(Eshutdown);
	if(strcmp(srv[c->qid.path].name, "boot") == 0)
	l = &srv;
	for(sp = *l; sp; sp = sp->link) {
		if(sp->path == c->qid.path)
			break;

		l = &srv->link;
	}
	if(sp == 0)
		error(Enonexist);

	if(strcmp(sp->name, "boot") == 0)
		error(Eperm);
	srv[c->qid.path].chan = 0;
	unlock(&srvlk);

	*l = sp->link;
	qunlock(&srvlk);
	poperror();
	close(f);

	if(sp->chan)
		close(sp->chan);
	free(sp);
}

void


@@ 186,10 204,11 @@ srvread(Chan *c, void *va, long n, ulong offset)
long
srvwrite(Chan *c, void *va, long n, ulong offset)
{
	Srv *sp;
	Fgrp *f;
	Chan *c1;
	int i, fd;
	char buf[32];
	Chan *c1;

	if(n >= sizeof buf)
		error(Egreg);


@@ 209,18 228,24 @@ srvwrite(Chan *c, void *va, long n, ulong offset)
	unlock(f);
	poperror();

	lock(&srvlk);
	if (waserror()) {
		unlock(&srvlk);
	qlock(&srvlk);
	if(waserror()) {
		qunlock(&srvlk);
		close(c1);
		nexterror();
	}
	i = c->qid.path;
	if(srv[i].chan != c)	/* already been written to */
		error(Egreg);
	for(sp = srv; sp; sp = sp->link)
		if(sp->path == c->qid.path)
			break;

	if(sp == 0)
		error(Enonexist);

	if(sp->chan)
		panic("srvwrite");

	srv[i].chan = c1;
	unlock(&srvlk);
	sp->chan = c1;
	qunlock(&srvlk);
	poperror();
	return n;
}

M port/error.h => port/error.h +1 -1
@@ 23,7 23,6 @@ extern char Ebadbitmap[];	/* unallocated bitmap */
extern char Enobitmap[];	/* out of bitmap descriptors */
extern char Enobitstore[];	/* out of bitmap storage */
extern char Ebadfont[];		/* unallocated font */
extern char Enofont[];		/* no free font descriptors */
extern char Enetaddr[];		/* bad network address */
extern char Emsgsize[];		/* message is too big for protocol */
extern char Enetbusy[];		/* network device is busy or allocated */


@@ 51,4 50,5 @@ extern char Econrefused[];	/* connection refused */
extern char Enetunreach[];	/* network unreachable */
extern char Eintr[];		/* interrupted */
extern char Eneedservice[];	/* service required for tcp/udp/il calls */
extern char Enomem[];		/* kernel allocate failed */
extern char Egreg[];		/* it's a thermal problem */

M port/page.c => port/page.c +1 -1
@@ 21,7 21,7 @@ pageinit(void)
	palloc.head = xalloc(np*sizeof(Page));
	if(palloc.head == 0)
		panic("pageinit");
print("page: %lux %d %lux %d\n", palloc.p0, palloc.np0, palloc.p1, palloc.np1);

	p = palloc.head;
	while(palloc.np0 > 0) {
		p->prev = p-1;

M port/portfns.h => port/portfns.h +249 -251
@@ 1,253 1,251 @@
void	alarmkproc(void*);
Block*	allocb(ulong);
int	anyready(void);
Image*	attachimage(int, Chan*, ulong, ulong);
int	blen(Block *);
int	bround(Block *, int);
void	buzz(int, int);
void	cachepage(Page*, Image*);
int	cangetc(void*);
int	canlock(Lock*);
int	canpage(Proc*);
int	canputc(void*);
int	canqlock(QLock*);
void	chandevinit(void);
void	chandevreset(void);
void	chanfree(Chan*);
void	checkalarms(void);
void	clock(Ureg*);
Chan*	clone(Chan*, Chan*);
void	close(Chan*);
void	closeegrp(Egrp*);
void	closefgrp(Fgrp*);
void	closemount(Mount*);
void	closepgrp(Pgrp*);
long	clrfpintr(void);
void	confinit(void);
void	confinit1(int);
int	consactive(void);
void	consdebug(void);
Block	*copyb(Block*, int);
Env*	copyenv(Env*, int);
void	copypage(Page*, Page*);
int	decref(Ref*);
int	decrypt(void*, void*, int);
void	delay(int);
Chan*	devattach(int, char*);
Chan*	devclone(Chan*, Chan*);
void	devdir(Chan*, Qid, char*, long, char*, long, Dir*);
long	devdirread(Chan*, char*, long, Dirtab*, int, Devgen*);
Devgen	devgen;
int	devno(int, int);
Chan*	devopen(Chan*, int, Dirtab*, int, Devgen*);
void	devstat(Chan*, char*, Dirtab*, int, Devgen*);
int	devwalk(Chan*, char*, Dirtab*, int, Devgen*);
void	dumpqueues(void);
void	dumpregs(Ureg*);
void	dumpstack(void);
Fgrp*	dupfgrp(Fgrp*);
void	duppage(Page*);
Segment*	dupseg(Segment*, int);
void	dupswap(Page*);
int	encrypt(void*, void*, int);
void	envcpy(Egrp*, Egrp*);
void	envpgclose(Env*);
void	envpgcopy(Env*, Env*);
int	eqchan(Chan*, Chan*, long);
int	eqqid(Qid, Qid);
void	error(char*);
long	execregs(ulong, ulong, ulong);
void	exhausted(char*);
void	exit(void);
Block*	expandb(Block*, int);
int	fault(ulong, int);
void	fdclose(int, int);
Chan*	fdtochan(int, int, int);
int	fixfault(Segment*, ulong, int, int);
void	flowctl(Queue*, Block*);
void	flushmmu(void);
void	freeb(Block*);
int	freebroken(void);
void	freechan(Chan*);
void	freepte(Segment*, Pte*);
void	freesegs(int);
Block*	getb(Blist*);
int	getc(IOQ*);
void	getcolor(ulong, ulong*, ulong*, ulong*);
int	getfields(char*, char**, int, char);
Block*	getq(Queue*);
int	gets(IOQ*, void*, int);
void	gotolabel(Label*);
Block*	grabq(Queue*);
int	hwcursmove(int, int);
int	hwcursset(uchar*, uchar*, int, int);
void*	ialloc(ulong, int);
void*	iallocspan(ulong, int, ulong);
long	ibrk(ulong, int);
int	incref(Ref*);
void	initq(IOQ*);
void	initseg(void);
void	invalidateu(void);
void	isdir(Chan*);
int	ispages(void*);
void	kbdclock(void);
int	kbdcr2nl(IOQ*, int);
int	kbdputc(IOQ*, int);
void	kbdrepeat(int);
void	kickpager(void);
int	kprint(char*, ...);
void	kproc(char*, void(*)(void*), void*);
void	kproftimer(ulong);
void	ksetenv(char*, char*);
void	ksetterm(char*);
long	latin1(uchar*);
void	lights(int);
void	lock(Lock*);
void	lockinit(void);
void	lockpage(Page*);
Page*	lookpage(Image*, ulong);
void	machinit(void);
void	mapstack(Proc*);
void	mfreeseg(Segment*, ulong, int);
void	mmurelease(Proc*);
void	mntdump(void);
int	mount(Chan*, Chan*, int);
void	mouseclock(void);
int	mouseputc(IOQ*, int);
Chan*	namec(char*, int, int, ulong);
void	nameok(char*);
void	netdisown(Network*, int);
int	netgen(Chan*, void*, int, int, Dir*);
Chan*	netopen(Chan*, int, Network*);
int	netown(Network*, int, char*, int);
long	netread(Chan*, void*, long, ulong, Network*);
void	netstat(Chan*, char*, Network*);
int	netwalk(Chan*, char*, Network*);
void	netwstat(Chan*, char*, Network*);
Chan*	newchan(void);
Egrp*	newegrp(void);
Fgrp*	newfgrp(void);
Mount*	newmount(Mhead*, Chan*);
Page*	newpage(int, Segment **, ulong);
Pgrp*	newpgrp(void);
Proc*	newproc(void);
void	newqinfo(Qinfo*);
void		alarmkproc(void*);
Block*		allocb(ulong);
int		anyready(void);
Image*		attachimage(int, Chan*, ulong, ulong);
int		blen(Block *);
int		bround(Block *, int);
void		buzz(int, int);
void		cachepage(Page*, Image*);
int		cangetc(void*);
int		canlock(Lock*);
int		canpage(Proc*);
int		canputc(void*);
int		canqlock(QLock*);
void		chandevinit(void);
void		chandevreset(void);
void		chanfree(Chan*);
void		checkalarms(void);
void		clock(Ureg*);
Chan*		clone(Chan*, Chan*);
void		close(Chan*);
void		closeegrp(Egrp*);
void		closefgrp(Fgrp*);
void		closemount(Mount*);
void		closepgrp(Pgrp*);
long		clrfpintr(void);
void		confinit(void);
void		confinit1(int);
int		consactive(void);
void		consdebug(void);
Block*		copyb(Block*, int);
Env*		copyenv(Env*, int);
void		copypage(Page*, Page*);
int		decref(Ref*);
int		decrypt(void*, void*, int);
void		delay(int);
Chan*		devattach(int, char*);
Chan*		devclone(Chan*, Chan*);
void		devdir(Chan*, Qid, char*, long, char*, long, Dir*);
long		devdirread(Chan*, char*, long, Dirtab*, int, Devgen*);
Devgen		devgen;
int		devno(int, int);
Chan*		devopen(Chan*, int, Dirtab*, int, Devgen*);
void		devstat(Chan*, char*, Dirtab*, int, Devgen*);
int		devwalk(Chan*, char*, Dirtab*, int, Devgen*);
void		dumpqueues(void);
void		dumpregs(Ureg*);
void		dumpstack(void);
Fgrp*		dupfgrp(Fgrp*);
void		duppage(Page*);
void		dupswap(Page*);
int		encrypt(void*, void*, int);
void		envcpy(Egrp*, Egrp*);
void		envpgclose(Env*);
void		envpgcopy(Env*, Env*);
int		eqchan(Chan*, Chan*, long);
int		eqqid(Qid, Qid);
void		error(char*);
long		execregs(ulong, ulong, ulong);
void		exhausted(char*);
void		exit(void);
Block*		expandb(Block*, int);
int		fault(ulong, int);
void		fdclose(int, int);
Chan*		fdtochan(int, int, int);
int		fixfault(Segment*, ulong, int, int);
void		flowctl(Queue*, Block*);
void		flushmmu(void);
void		free(void*);
void		freeb(Block*);
int		freebroken(void);
void		freechan(Chan*);
void		freepte(Segment*, Pte*);
void		freesegs(int);
Block*		getb(Blist*);
int		getc(IOQ*);
void		getcolor(ulong, ulong*, ulong*, ulong*);
int		getfields(char*, char**, int, char);
Block*		getq(Queue*);
int		gets(IOQ*, void*, int);
void		gotolabel(Label*);
Block*		grabq(Queue*);
int		hwcursmove(int, int);
int		hwcursset(uchar*, uchar*, int, int);
long		ibrk(ulong, int);
int		incref(Ref*);
void		initq(IOQ*);
void		initseg(void);
void		invalidateu(void);
void		isdir(Chan*);
int		ispages(void*);
void		kbdclock(void);
int		kbdcr2nl(IOQ*, int);
int		kbdputc(IOQ*, int);
void		kbdrepeat(int);
void		kickpager(void);
int		kprint(char*, ...);
void		kproc(char*, void(*)(void*), void*);
void		kproftimer(ulong);
void		ksetenv(char*, char*);
void		ksetterm(char*);
long		latin1(uchar*);
void		lights(int);
void		lock(Lock*);
void		lockinit(void);
void		lockpage(Page*);
Page*		lookpage(Image*, ulong);
void		machinit(void);
void*		malloc(ulong);
void		mapstack(Proc*);
void		mfreeseg(Segment*, ulong, int);
void		mmurelease(Proc*);
void		mntdump(void);
int		mount(Chan*, Chan*, int);
void		mountfree(Mount*);
void		mouseclock(void);
int		mouseputc(IOQ*, int);
Chan*		namec(char*, int, int, ulong);
void		nameok(char*);
void		netdisown(Network*, int);
int		netgen(Chan*, void*, int, int, Dir*);
Chan*		netopen(Chan*, int, Network*);
int		netown(Network*, int, char*, int);
long		netread(Chan*, void*, long, ulong, Network*);
void		netstat(Chan*, char*, Network*);
int		netwalk(Chan*, char*, Network*);
void		netwstat(Chan*, char*, Network*);
Chan*		newchan(void);
Egrp*		newegrp(void);
Fgrp*		newfgrp(void);
Mount*		newmount(Mhead*, Chan*);
Page*		newpage(int, Segment **, ulong);
Pgrp*		newpgrp(void);
Proc*		newproc(void);
void		newqinfo(Qinfo*);
Segment*	newseg(int, ulong, ulong);
char*	nextelem(char*, char*);
void	nexterror(void);
int	nodelims(Stream*);
int	notify(Ureg*);
int	nrand(int);
void	nullput(Queue*, Block*);
int	okaddr(ulong, ulong, int);
int	openmode(ulong);
Block*	padb(Block*, int);
void	pageinit(void);
void	panic(char*, ...);
void	pexit(char*, int);
void	pgrpcpy(Pgrp*, Pgrp*);
void	pgrpnote(ulong, char*, long, int);
Pgrp*	pgrptab(int);
void	pio(Segment *, ulong, ulong, Page **);
#define	poperror()	u->nerrlab--
int	postnote(Proc*, int, char*, int);
int	pprint(char*, ...);
void	printinit(void);
ulong	procalarm(ulong);
void	procctl(Proc*);
void	procdump(void);
void	procinit0(void);
Proc*	proctab(int);
Pte*	ptealloc(void);
Pte*	ptecpy(Pte*);
Block*	pullup(Block *, int);
Queue*	pushq(Stream*, Qinfo*);
int	putb(Blist*, Block*);
void	putbq(Blist*, Block*);
int	putc(IOQ*, int);
void	putimage(Image*);
void	putmmu(ulong, ulong, Page*);
void	putpage(Page*);
int	putq(Queue*, Block*);
void	puts(IOQ*, void*, int);
void	putseg(Segment*);
void	putstr(char*);
void	putstr(char*);
void	putstrn(char*, long);
void	putswap(Page*);
ulong	pwait(Waitmsg*);
Qinfo*	qinfofind(char*);
void	qlock(QLock*);
void	qunlock(QLock*);
int	readnum(ulong, char*, ulong, ulong, int);
void	ready(Proc*);
void	relocateseg(Segment*, ulong);
void	resched(char*);
void	resrcwait(char*);
int	return0(void*);
Proc*	runproc(void);
void	savefpregs(FPsave*);
void	sccclock(void);
void	sccintr(void);
void	sccsetup(void*, ulong);
void	sccspecial(int, IOQ*, IOQ*, int);
void	sched(void);
void	schedinit(void);
int	screenbits(void);
long	seconds(void);
char*		nextelem(char*, char*);
void		nexterror(void);
int		nodelims(Stream*);
int		notify(Ureg*);
int		nrand(int);
void		nullput(Queue*, Block*);
int		okaddr(ulong, ulong, int);
int		openmode(ulong);
Block*		padb(Block*, int);
void		pageinit(void);
void		panic(char*, ...);
void		pexit(char*, int);
void		pgrpcpy(Pgrp*, Pgrp*);
void		pgrpnote(ulong, char*, long, int);
Pgrp*		pgrptab(int);
void		pio(Segment *, ulong, ulong, Page **);
#define		poperror()		u->nerrlab--
int		postnote(Proc*, int, char*, int);
int		pprint(char*, ...);
void		printinit(void);
ulong		procalarm(ulong);
void		procctl(Proc*);
void		procdump(void);
void		procinit0(void);
Proc*		proctab(int);
Pte*		ptealloc(void);
Pte*		ptecpy(Pte*);
Block*		pullup(Block *, int);
Queue*		pushq(Stream*, Qinfo*);
int		putb(Blist*, Block*);
void		putbq(Blist*, Block*);
int		putc(IOQ*, int);
void		putimage(Image*);
void		putmmu(ulong, ulong, Page*);
void		putpage(Page*);
int		putq(Queue*, Block*);
void		puts(IOQ*, void*, int);
void		putseg(Segment*);
void		putstr(char*);
void		putstr(char*);
void		putstrn(char*, long);
void		putswap(Page*);
ulong		pwait(Waitmsg*);
Qinfo*		qinfofind(char*);
void		qlock(QLock*);
void		qunlock(QLock*);
int		readnum(ulong, char*, ulong, ulong, int);
void		ready(Proc*);
void		relocateseg(Segment*, ulong);
void		resched(char*);
void		resrcwait(char*);
int		return0(void*);
void		rlock(RWlock*);
void		runlock(RWlock*);
Proc*		runproc(void);
void		savefpregs(FPsave*);
void		sccclock(void);
void		sccintr(void);
void		sccsetup(void*, ulong);
void		sccspecial(int, IOQ*, IOQ*, int);
void		sched(void);
void		schedinit(void);
int		screenbits(void);
long		seconds(void);
ulong		segattach(Proc*, ulong, char *, ulong, ulong);
void		segpage(Segment*, Page*);
int		setcolor(ulong, ulong, ulong, ulong);
int		setlabel(Label*);
void		setregisters(Ureg*, char*, char*, int);
void		setswapchan(Chan*);
void		simpleputpage(Page*);
char*		skipslash(char*);
void		sleep(Rendez*, int(*)(void*), void*);
void*		smalloc(ulong);
int		splhi(void);
int		spllo(void);
void		splx(int);
int		streamclose(Chan*);
int		streamclose1(Stream*);
int		streamenter(Stream*);
int		streamexit(Stream*, int);
Devgen		streamgen;
void		streaminit(void);
void		streaminit0(void);
Stream*		streamnew(ushort, ushort, ushort, Qinfo*, int);
void		streamopen(Chan*, Qinfo*);
int		streamparse(char*, Block*);
long		streamread(Chan*, void*, long);
void		streamstat(Chan*, char*, char*);
long		streamwrite(Chan*, void*, long, int);
long		stringread(void*, long, char*, ulong);
void		swapinit(void);
long		syscall(Ureg*);
void		tsleep(Rendez*, int (*)(void*), void*, int);
void		uncachepage(Page*);
long		unicode(uchar*);
long		unionread(Chan*, void*, long);
void		unlock(Lock*);
void		unlockpage(Page*);
void		unmount(Chan*, Chan*);
void		urpfillstats(Chan*, char*, int);
void		userinit(void);
ulong		userpc(void);
void		validaddr(ulong, ulong, int);
void*		vmemchr(void*, int, int);
void		wakeup(Rendez*);
void		wlock(RWlock*);
void		wunlock(RWlock*);
void*		xalloc(ulong);
void		xfree(void*);
void		xhole(ulong, ulong);
void		xinit(void);
void*		xspanalloc(ulong, int, ulong);
void		xsummary(void);
Segment*	dupseg(Segment*, int);
Segment*	seg(Proc*, ulong, int);
ulong	segattach(Proc*, ulong, char *, ulong, ulong);
void	segpage(Segment*, Page*);
int	setcolor(ulong, ulong, ulong, ulong);
int	setlabel(Label*);
void	setregisters(Ureg*, char*, char*, int);
void	setswapchan(Chan*);
void	simpleputpage(Page*);
char*	skipslash(char*);
void	sleep(Rendez*, int(*)(void*), void*);
int	splhi(void);
int	spllo(void);
void	splx(int);
int	streamclose(Chan*);
int	streamclose1(Stream*);
int	streamenter(Stream*);
int	streamexit(Stream*, int);
Devgen	streamgen;
void	streaminit(void);
void	streaminit0(void);
Stream*	streamnew(ushort, ushort, ushort, Qinfo*, int);
void	streamopen(Chan*, Qinfo*);
int	streamparse(char*, Block*);
long	streamread(Chan*, void*, long);
void	streamstat(Chan*, char*, char*);
long	streamwrite(Chan*, void*, long, int);
long	stringread(void*, long, char*, ulong);
void	swapinit(void);
long	syscall(Ureg*);
void	tsleep(Rendez*, int (*)(void*), void*, int);
void	uncachepage(Page*);
long	unionread(Chan*, void*, long);
void	unlock(Lock*);
void	unlockpage(Page*);
long	unicode(uchar*);
void	userinit(void);
ulong	userpc(void);
void	validaddr(ulong, ulong, int);
void*	vmemchr(void*, int, int);
void	wakeup(Rendez*);
void	rlock(RWlock*);
void	runlock(RWlock*);
void	wlock(RWlock*);
void	wunlock(RWlock*);
void	mountfree(Mount*);
void	unmount(Chan*, Chan*);
void	urpfillstats(Chan*, char*, int);
void	xinit(void);
void	*xalloc(ulong);
void	*xspanalloc(ulong, int, ulong);
void	xfree(void*);
void	xhole(ulong, ulong);
void	xsummary(void);
void	*malloc(ulong);
void	*smalloc(ulong);
void	free(void*);

M port/proc.c => port/proc.c +2 -2
@@ 157,9 157,9 @@ runproc(void)
loop:
	spllo();
	while(runhiq.head==0 && runloq.head==0)
		for(i=0; i<10; i++)	/* keep out of shared memory for a while */
			;
		;
	splhi();

	lock(&runhiq);
	if(runhiq.head)
		rq = &runhiq;

M port/stasync.c => port/stasync.c +9 -5
@@ 15,7 15,14 @@ enum {
};

/* input states */
enum { Hunt=0, Framing, Framed, Data, Escape };
enum
{
	Hunt,
	Framing,
	Framed,
	Data,
	Escape
};

typedef struct Async {
	QLock;


@@ 24,7 31,6 @@ typedef struct Async {
	Queue	*wq;

	/* output state */

	QLock	xmit;		/* transmit lock */
	int	chan;		/* current urp channel */
	Block	*bp;		/* current output buffer */


@@ 32,14 38,12 @@ typedef struct Async {
	ushort	crc;

	/* input state */

	int	state;		/* input state */
	uchar	buf[MAXFRAME];	/* current input buffer */
	int	icount;
	ushort	icrc;

	/* statistics */

	ulong	chan0;
	ulong	toolong;
	ulong	tooshort;


@@ 93,7 97,7 @@ static ushort crc_table[256] = {
static void
asyncreset(void)
{
	async = (Async *)ialloc(conf.nasync*sizeof(Async), 0);
	async = (Async *)xalloc(conf.nasync*sizeof(Async));
}

/*

M port/stip.c => port/stip.c +1 -1
@@ 55,7 55,7 @@ initfrag(int size)
{
	Fragq *fq, *eq;

	fragfree = (Fragq*)ialloc(sizeof(Fragq) * size, 0);
	fragfree = (Fragq*)xalloc(sizeof(Fragq) * size);

	eq = &fragfree[size];
	for(fq = fragfree; fq < eq; fq++)

M port/stlapd.c => port/stlapd.c +33 -30
@@ 10,35 10,36 @@

typedef struct Lapd	Lapd;

#define NOW	TK2MS(MACHP(0)->ticks)
#define	T200	(NOW+2500)

	/* C/R bits */

#define	UCmd	0	/* command, user to network */
#define	UResp	2	/* response, user to network */
#define	NCmd	2	/* command, network to user */
#define	NResp	0	/* response, network to user */

#define NOW		TK2MS(MACHP(0)->ticks)
#define	T200		(NOW+2500)
#define	SAPI(s, cr)	(((s)<<2)|cr)
#define	TEI(t)		(((t)<<1)|1)

/*
 *  Commands and responses
 */
enum
{
	RR	= 0x01,	/* Receiver Ready */
	RNR	= 0x05,	/* Receiver Not Ready */
	REJ	= 0x09,	/* Reject */
	SABME	= 0x6f,	/* Set Asynchronous Balanced Mode Extended */
	DM	= 0x0f,	/* Disconnect Mode */
	UI	= 0x03,	/* Unnumbered Information */
	DISC	= 0x43,	/* Disconnect */
	UA	= 0x63,	/* Unnumbered Acknowledgement */
	FRMR	= 0x87,	/* Frame Reject */
	XID	= 0xaf,	/* Exchange Identification */

#define	RR	0x01	/* Receiver Ready */
#define	RNR	0x05	/* Receiver Not Ready */
#define	REJ	0x09	/* Reject */
#define	SABME	0x6f	/* Set Asynchronous Balanced Mode Extended */
#define	DM	0x0f	/* Disconnect Mode */
#define	UI	0x03	/* Unnumbered Information */
#define	DISC	0x43	/* Disconnect */
#define	UA	0x63	/* Unnumbered Acknowledgement */
#define	FRMR	0x87	/* Frame Reject */
#define	XID	0xaf	/* Exchange Identification */

enum States {
	/* C/R bits */
	UCmd	= 0,	/* command, user to network */
	UResp	= 2,	/* response, user to network */
	NCmd	= 2,	/* command, network to user */
	NResp	= 0	/* response, network to user */
};

enum States
{
	Unused = 0,
	NoTEI,
	WaitTEI,


@@ 48,12 49,13 @@ enum States {
	WaitRel,
};

enum Flags {
	Ownbusy = 0x01,
	Peerbusy = 0x02,
	Rejecting = 0x04,
	Timeout = 0x08,
	Hungup = 0x80
enum Flags
{
	Ownbusy 	= 0x01,
	Peerbusy 	= 0x02,
	Rejecting	= 0x04,
	Timeout		= 0x08,
	Hungup		= 0x80
};

#define	SMASK		127


@@ 69,7 71,8 @@ enum Flags {
#define	RSTATE(lp)	((lp->flags&Ownbusy) ? RNR : \
			(lp->flags&Rejecting) ? REJ : RR)

struct Lapd {
struct Lapd
{
	QLock;		/* access, state change */
	Rendez;		/* waiting for state change */
	int	state;


@@ 158,7 161,7 @@ lapderror(Lapd *lp, int code)
static void
lapdreset(void)
{
	lapd = ialloc(conf.nlapd*sizeof(Lapd), 0);
	lapd = xalloc(conf.nlapd*sizeof(Lapd));
}

static void

M port/sturp.c => port/sturp.c +1 -1
@@ 135,7 135,7 @@ Qinfo urpinfo =
static void
urpreset(void)
{
	urp = (Urp *)ialloc(conf.nurp*sizeof(Urp), 0);
	urp = (Urp *)xalloc(conf.nurp*sizeof(Urp));
}

static void

M port/sysproc.c => port/sysproc.c +5 -106
@@ 8,7 8,6 @@
#include	<a.out.h>

int	shargs(char*, int, char**);
long	rfork(ulong);

long
sysr1(ulong *arg)


@@ 17,52 16,24 @@ sysr1(ulong *arg)
	return 0;
}

enum					/* Argument to forkpgrp call */
{
	FPall 	  = 0,			/* Concession to back portablility */
	FPnote 	  = 1,
	FPnamespc = 2,
	FPenv	  = 4,
	FPclear	  = 8,
};

long
sys__fork__(ulong *arg)
{
	USED(arg);
	return rfork(RFFDG|RFPROC);
}

long
sys__rfork__(ulong *arg)
{
	return rfork(arg[0]|RFPROC);
}

/* This call will obsolete fork */
long
sysrfork(ulong *arg)
{
	return rfork(arg[0]);
}

long
rfork(ulong flag)
{
	Proc *p, *parent;
	Segment *s;
	ulong usp, upa, pid;
	int n, on, i;
	Chan *c;
	KMap *k;
	Pgrp *opg;
	Egrp *oeg;
	Fgrp *ofg;
	Segment *s;
	int n, on, i;
	Proc *p, *parent;
	ulong usp, upa, pid, flag;
	/*
	 * used to compute last valid system stack address for copy
	 */
	int lastvar;	

	flag = arg[0];
	p = u->p;
	if((flag&RFPROC) == 0) {
		if(flag & (RFNAMEG|RFCNAMEG)) {


@@ 522,36 493,6 @@ syswait(ulong *arg)
}

long
sys__wait__(ulong *arg)			/* binary compatibility: BUG */
{
	int i;

	struct oldWaitmsg
	{
		int	pid;		/* of loved one */
		int	status;		/* unused; a vestige */
		long	time[3];	/* of loved one & descendants */
		char	msg[ERRLEN];
	} *wp;
	Waitmsg w;

	if(arg[0]){
		validaddr(arg[0], sizeof(struct oldWaitmsg), 1);
		evenaddr(arg[0]);
		i = pwait(&w);
		wp = (struct oldWaitmsg*)arg[0];
		wp->pid = atoi(w.pid);
		wp->status = 0;
		wp->time[TUser] = atoi(w.time+TUser*NUMSIZE);
		wp->time[TSys] = atoi(w.time+TSys*NUMSIZE);
		wp->time[TReal] = atoi(w.time+TReal*NUMSIZE);
		memmove(wp->msg, w.msg, ERRLEN);
		return i;
	}
	return pwait(0);
}

long
sysdeath(ulong *arg)
{
	USED(arg);


@@ 572,48 513,6 @@ syserrstr(ulong *arg)
}

long
sys__forkpgrp__(ulong *arg)
{
	int mask;
	Pgrp *pg;
	Egrp *eg;

	pg = newpgrp();
	eg = newegrp();
	if(waserror()){
		closepgrp(pg);
		closeegrp(eg);
		nexterror();
	}

	mask = arg[0];
	if(mask == FPall)
		mask = FPnote|FPenv|FPnamespc;

	if(mask & FPnamespc)
		pgrpcpy(pg, u->p->pgrp);
	else
		*pg->crypt = *u->p->pgrp->crypt;

	if(mask & FPenv)
		envcpy(eg, u->p->egrp);

	if((mask & FPnote) == 0) {
		u->nnote = 0;
		u->notified = 0;
		memset(u->note, 0, sizeof(u->note));
	}
	u->p->noteid = incref(&noteidalloc);

	poperror();
	closepgrp(u->p->pgrp);
	closeegrp(u->p->egrp);
	u->p->pgrp = pg;
	u->p->egrp = eg;
	return pg->pgrpid;
}

long
sysnotify(ulong *arg)
{
	USED(arg);

M port/systab.h => port/systab.h +6 -6
@@ 12,8 12,8 @@ Syscall sysdup;
Syscall sysalarm;
Syscall sysexec;
Syscall sysexits;
Syscall sys__fork__;
Syscall sys__forkpgrp__;
Syscall sysdeath;
Syscall sysdeath;
Syscall sysfstat;
Syscall syssegbrk;
Syscall sysmount;


@@ 26,7 26,7 @@ Syscall sysrfork;
Syscall syswrite;
Syscall syspipe;
Syscall syscreate;
Syscall sys__rfork__;
Syscall sysdeath;
Syscall sysbrk_;
Syscall sysremove;
Syscall syswstat;


@@ 51,8 51,8 @@ Syscall *systab[]={
	[ALARM]		sysalarm,
	[EXEC]		sysexec,
	[EXITS]		sysexits,
	[__FORK__]	sys__fork__,
	[__FORKPGRP__]	sys__forkpgrp__,
	[__FORK__]	sysdeath,
	[__FORKPGRP__]	sysdeath,
	[FSTAT]		sysfstat,
	[SEGBRK]	syssegbrk,
	[MOUNT]		sysmount,


@@ 65,7 65,7 @@ Syscall *systab[]={
	[WRITE]		syswrite,
	[PIPE]		syspipe,
	[CREATE]	syscreate,
	[__RFORK__]	sys__rfork__,
	[__RFORK__]	sysdeath,
	[BRK_]		sysbrk_,
	[REMOVE]	sysremove,
	[WSTAT]		syswstat,

M power/conf.h => power/conf.h +0 -13
@@ 1,32 1,19 @@
Conftab conftab[] = {
	{"nmach", &conf.nmach },
	{"nproc", &conf.nproc },
	{"npgrp", &conf.npgrp },
	{"npage0", &conf.npage0 },
	{"npage1", &conf.npage1 },
	{"npage", &conf.npage },
	{"nseg", &conf.nseg },
	{"nimage", &conf.nimage },
	{"npagetab", &conf.npagetab },
	{"nswap", &conf.nswap },
	{"nalarm", &conf.nalarm },
	{"nchan", &conf.nchan },
	{"nenv", &conf.nenv },
	{"nenvchar", &conf.nenvchar },
	{"npgenv", &conf.npgenv },
	{"nmtab", &conf.nmtab },
	{"nmount", &conf.nmount },
	{"nmntdev", &conf.nmntdev },
	{"nmntbuf", &conf.nmntbuf },
	{"nmnthdr", &conf.nmnthdr },
	{"nstream", &conf.nstream },
	{"nqueue", &conf.nqueue },
	{"nblock", &conf.nblock },
	{"nsrv", &conf.nsrv },
	{"nurp", &conf.nurp },
	{"nasync", &conf.nasync },
	{"npipe", &conf.npipe },
	{"maxialloc", &conf.maxialloc },
	{"base0", &conf.base0 },
	{"base1", &conf.base1 },
	{"copymode", &conf.copymode },

M power/dat.h => power/dat.h +2 -14
@@ 23,7 23,7 @@ typedef struct User	User;

struct Lock
{
	ulong	*sbsem;			/* addr of sync bus semaphore */
	int	val;
	ulong	pc;
};



@@ 37,32 37,20 @@ struct Conf
{
	ulong	nmach;		/* processors */
	ulong	nproc;		/* processes */
	ulong	npgrp;		/* process groups */
	ulong	npage0;		/* total physical pages of memory */
	ulong	npage1;		/* total physical pages of memory */
	ulong	npage;		/* total physical pages of memory */
	ulong	nseg;		/* number of segments */
	ulong	upages;		/* user page pool */
	ulong	nimage;		/* number of page cache image headers */
	ulong 	npagetab;	/* number of pte tables */
	ulong	nswap;		/* number of swap pages */
	ulong	nalarm;		/* alarms */
	ulong	nchan;		/* channels */
	ulong	nenv;		/* distinct environment values */
	ulong	nenvchar;	/* environment text storage */
	ulong	npgenv;		/* environment files per process group */
	ulong	nmtab;		/* mounted-upon channels per process group */
	ulong	nmount;		/* mounts */
	ulong	nmntdev;	/* mounted devices (devmnt.c) */
	ulong	nmntbuf;	/* buffers for devmnt.c messages */
	ulong	nmnthdr;	/* headers for devmnt.c messages */
	ulong	nstream;	/* streams */
	ulong	nqueue;		/* stream queues */
	ulong	nblock;		/* stream blocks */
	ulong	nsrv;		/* public servers (devsrv.c) */
	ulong	nurp;		/* max urp conversations */
	ulong	nasync;		/* number of async protocol modules */
	ulong	npipe;		/* number of pipes */
	ulong	maxialloc;	/* maximum bytes used by ialloc */
	ulong	base0;		/* base of bank 0 */
	ulong	base1;		/* base of bank 1 */
	ulong	copymode;	/* 0 is copy on write, 1 is copy on reference */

M power/devcyc.c => power/devcyc.c +0 -1
@@ 5,7 5,6 @@
#include	"fns.h"
#include	"../port/error.h"
#include	"devtab.h"
#include	"fcall.h"

#include	"io.h"
#include	"../../fs/cyc/comm.h"

M power/devduart.c => power/devduart.c +3 -3
@@ 695,7 695,7 @@ duartreset(void)
 	 *  allocate the directory and fill it in
	 */
	nduartport = 2*conf.nmach;
	duartdir = ialloc(nduartport*2*sizeof(Dirtab), 0);
	duartdir = xalloc(nduartport*2*sizeof(Dirtab));
	for(i = 0; i < nduartport; i++){
		sprint(duartdir[2*i].name, "eia%d", i+1);
		sprint(duartdir[2*i+1].name, "eia%dctl", i+1);


@@ 714,11 714,11 @@ duartreset(void)
		if(p->nostream)
			continue;

		p->iq = ialloc(sizeof(IOQ), 0);
		p->iq = xalloc(sizeof(IOQ));
		initq(p->iq);
		p->iq->ptr = p;

		p->oq = ialloc(sizeof(IOQ), 0);
		p->oq = xalloc(sizeof(IOQ));
		initq(p->oq);
		p->oq->ptr = p;
		p->oq->puts = duartputs;

M power/fns.h => power/fns.h +2 -0
@@ 71,3 71,5 @@ void	vmereset(void);
void	wbflush(void);
#define	waserror()	setlabel(&u->errlab[u->nerrlab++])
#define	kmapperm(x)	kmap(x)
#define KADDR(a)	((void*)((ulong)(a)|KZERO))
#define PADDR(a)	((ulong)(a)&~KZERO)

M power/lock.c => power/lock.c +54 -84
@@ 13,51 13,35 @@
 * Writing a semaphore sets the value, so writing 0 resets (clears) the semaphore.
 */

#define	SEMPERPG	64		/* hardware semaphores per page */
#define NSEMPG		1024
#define ULOCKPG		512
enum
{
	SEMPERPG	= 64,		/* hardware semaphores per page */
	NSEMPG		= 1024,
	ULOCKPG		= 512,
};

struct
{
	Lock	lock;			/* lock to allocate */
	ulong	*nextsem;		/* next one to allocate */
	int	nsem;			/* at SEMPERPG, jump to next page */
	uchar	bmap[NSEMPG];		/* allocation map */
	int	ulockpg;		/* count of user lock available */
}semalloc;

Page lkpgheader[NSEMPG];
#define lhash(laddr)	((int)laddr>>2)&(((NSEMPG-ULOCKPG)*(BY2PG>>2))-1)

void
lockinit(void)
{
	memset(semalloc.bmap, 0, sizeof(semalloc.bmap));
	semalloc.bmap[0] = 1;

	/*
	 * Initialise the system semaphore hardware
	 */
	memset(SBSEM, 0, (NSEMPG-ULOCKPG)*BY2PG);
	semalloc.ulockpg = ULOCKPG;
	semalloc.lock.sbsem = SBSEM;
	semalloc.nextsem = SBSEM+1;
	semalloc.nsem = 1;
	unlock(&semalloc.lock);
}

/* return the address of the next free page of locks */
ulong*
lkpgalloc(void)
{
	uchar *p, *top;

	top = &semalloc.bmap[NSEMPG];
	for(p = semalloc.bmap; *p && p < top; p++)
		;
	if(p == top)
		panic("lkpgalloc");

	*p = 1;
	return (p-semalloc.bmap)*WD2PG + SBSEM;
}

/* Moral equivalent of newpage for pages of hardware lock */
/* Moral equivalent of newpage for pages of hardware locks */
Page*
lkpage(ulong va)
{


@@ 103,78 87,64 @@ lkpgfree(Page *pg)
	unlock(&semalloc.lock);
}

/*
 * If l->sbsem is zero, allocate a hardware semaphore first.
 */
void
lock(Lock *l)
lock(Lock *lk)
{
	int i;
	ulong *sbsem;

	sbsem = l->sbsem;
	if(sbsem == 0){
		lock(&semalloc.lock);
		if(l->sbsem == 0){
			if(semalloc.nsem == SEMPERPG){
				semalloc.nsem = 0;
				semalloc.nextsem = lkpgalloc();
	int *hwsem;
	int i, hash;

	hash = lhash(lk);
	hwsem = (int*)SBSEM+hash;

	i = 1000000;
	for(;;) {
		if((*hwsem & 1) == 0) {
			if(lk->val)
				*hwsem = 0;
			else {
				lk->val = 1;
				*hwsem = 0;
				lk->pc = getcallerpc(lk);
				return;
			}
			l->sbsem = semalloc.nextsem;
			semalloc.nextsem++;
			semalloc.nsem++;
			unlock(l);		/* put sem in known state */
		}
		unlock(&semalloc.lock);
		sbsem = l->sbsem;
		while(lk->val && i)
			i--;
		if(i <= 0)
			break;
	}
	/*
	 * Try the fast grab first
	 */
	if((*sbsem&1) == 0){
		l->pc = getcallerpc(l);
		return;
	}
	for(i=0; i<10000000; i++)
    		if((*sbsem&1) == 0){
			l->pc = getcallerpc(l);
			return;
	}
	*sbsem = 0;
	print("lock loop %lux pc %lux held by pc %lux\n", l, getcallerpc(l), l->pc);
	print("lock loop %lux pc %lux held by pc %lux\n", lk, getcallerpc(lk), lk->pc);
	dumpstack();
}
}	

int
canlock(Lock *l)
canlock(Lock *lk)
{
	ulong *sbsem;

	sbsem = l->sbsem;
	if(sbsem == 0){
		lock(&semalloc.lock);
		if(l->sbsem == 0){
			if(semalloc.nsem == SEMPERPG){
				semalloc.nsem = 0;
				semalloc.nextsem = lkpgalloc();
	int *hwsem;
	int i, hash;

	hash = lhash(lk);
	hwsem = (int*)SBSEM+hash;

	for(;;) {
		if((*hwsem & 1) == 0) {
			if(lk->val)
				*hwsem = 0;
			else {
				lk->val = 1;
				*hwsem = 0;
				lk->pc = getcallerpc(lk);
				return 1;
			}
			l->sbsem = semalloc.nextsem;
			semalloc.nextsem++;
			semalloc.nsem++;
			unlock(l);		/* put sem in known state */
		}
		unlock(&semalloc.lock);
		sbsem = l->sbsem;
		if(lk->val)
			return 0;
	}
	if(*sbsem & 1)
		return 0;
	l->pc = getcallerpc(l);
	return 1;
}

void
unlock(Lock *l)
{
	l->pc = 0;
	*l->sbsem = 0;
	l->val = 0;
}

M power/main.c => power/main.c +23 -53
@@ 6,37 6,16 @@
#include	"io.h"
#include	"init.h"

/*
 * software tlb simulation
 */
Softtlb stlb[4][STLBSIZE];

/*
 *  args passed by boot process
 */
int _argc; char **_argv; char **_env;

/*
 *  arguments passed to initcode
 */
char argbuf[128];
int argsize;

/*
 *  environment variables extracted from NVRAM
 */
char consname[NAMELEN];
char diskless[NAMELEN];

/*
 *  configuration file read by boot program
 */
char confbuf[4*1024];

/*
 *  IO board type
 */
int ioid;
Softtlb stlb[MAXMACH][STLBSIZE];		/* software tlb simulation */
int	_argc;					/* args passed by boot process */
char 	**_argv;
char	**_env;
char 	argbuf[128];				/* arguments passed to initcode */
int	argsize;
char	consname[NAMELEN];			/* environment vars from NVRAM */
char	diskless[NAMELEN];
char	confbuf[4*1024];			/* config file read by boot program */
int	ioid;					/* IO board type */

void
main(void)


@@ 47,20 26,20 @@ main(void)
	arginit();
	confinit();
	lockinit();
	xinit();
	printinit();
	duartspecial(0, &printq, &kbdq, 9600);
	pageinit();
xsummary();
	tlbinit();
	vecinit();
	procinit0();
	initseg();
	grpinit();
	chaninit();
	clockinit();
	ioboardinit();
	chandevreset();
	streaminit();
	swapinit();
	pageinit();
	userinit();
	launchinit();
	schedinit();


@@ 521,14 500,14 @@ confinit(void)
	/*
	 *  copy configuration down from high memory
	 */
	strcpy(confbuf, (char *)(0x80000000 + 4*1024*1024 - 4*1024));
	strcpy(confbuf, (char *)(0x80000000 + (4*MB) - BY2PG));

	/*
	 *  size memory
	 */
	x = 0x12345678;
	for(i=4; i<128; i+=4){
		l = (long*)(KSEG1|(i*1024L*1024L));
		l = (long*)(KSEG1|(i*MB));
		*l = x;
		wbflush();
		*(ulong*)KSEG1 = *(ulong*)KSEG1;	/* clear latches */


@@ 541,8 520,11 @@ confinit(void)
	conf.npage = conf.npage0;
	conf.npage1 = 0;
	conf.base1 = 0;
	conf.maxialloc = 16*1024*1024;

	conf.upages = (conf.npage*70)/100;
	i = conf.npage-conf.upages;
	if(i > (12*MB)/BY2PG)
		conf.upages +=  i - ((12*MB)/BY2PG);
	/*
 	 *  clear MP bus error caused by sizing memory
	 */


@@ 554,27 536,15 @@ confinit(void)
	 */
	conf.nmach = 1;
	conf.nproc = 100;
	conf.npgrp = conf.nproc / 4;
	conf.npgenv = 4 * conf.npgrp;
	conf.npgenv = 4 * conf.nproc;
	conf.nenv = 4 * conf.nproc;
	conf.nenvchar = 20 * conf.nenv;
	conf.nmtab = conf.nproc;
	conf.nseg = 4 * conf.nproc;
	conf.npagetab = conf.nseg*3;
	conf.nswap = 262144;
	conf.nimage = 200;
	conf.nchan = 20 * conf.nproc;
	conf.nmntdev = conf.nproc;
	conf.nmntbuf = conf.nproc;
	conf.nmnthdr = conf.nproc;
	conf.nstream = 2 * conf.nproc;
	conf.nalarm = 2500;
	conf.nmount = 500;
	conf.nsrv = 20;
	conf.nurp = 25;
	conf.dkif = 1;
	conf.nqueue = 5 * conf.nstream;
	conf.nblock = 10 * conf.nstream;
	conf.ipif = 8;
	conf.ip = 64;
	conf.arp = 32;


@@ 582,7 552,6 @@ confinit(void)

	confread();

	conf.npipe = conf.nstream/2;	/* must be after confread */
	if(conf.nmach > MAXMACH)
		panic("confinit");



@@ 597,7 566,8 @@ confinit(void)
 *
 *  also grab any environment variables that might be useful
 */
struct{
struct
{
	char	*name;
	char	*val;
}bootenv[] = {


@@ 718,7 688,7 @@ lanceIO3setup(Lance *lp)
	 *  space
	 */
	len = (lp->nrrb + lp->ntrb)*sizeof(Etherpkt);
	lp->rp = (Etherpkt*)ialloc(len , 1);
	lp->rp = (Etherpkt*)xspanalloc(len , BY2PG, 0);
	lp->tp = lp->rp + lp->nrrb;
	x = (ulong)lp->rp;
	lp->lrp = (Etherpkt*)(x & 0xFFF);

M power/mem.h => power/mem.h +1 -0
@@ 14,6 14,7 @@
#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/main.c => ss/main.c +1 -6
@@ 215,11 215,6 @@ confinit(void)
	conf.npgenv = 200*mul;
	conf.nstream = 40 + 32*mul;
	conf.nqueue = 5 * conf.nstream;
	conf.nsrv = 16*mul;			/* was 32 */
	conf.nbitmap = 300*mul;
	conf.nbitbyte = 300*1024*mul;
	conf.nfont = 10*mul;
	conf.nsubfont = 10*mul;
	conf.nurp = 32;
	conf.nasync = 1;
	conf.copymode = 0;		/* copy on write */


@@ 276,7 271,7 @@ lancesetup(Lance *lp)
	 */
	i = (lp->nrrb+lp->ntrb)*sizeof(Etherpkt);
	i = (i+(BY2PG-1))/BY2PG;
	pa = (ulong)ialloc(i*BY2PG, 1)&~KZERO;
	pa = (ulong)xspanalloc(i*BY2PG, BY2PG, 0)&~KZERO;
	va = 0;
	for(j=i-1; j>=0; j--){
		k = kmappa(pa+j*BY2PG, PTEMAINMEM|PTENOCACHE);