~kris/9p

9hist

78a039249b0d7d691e995b3bfe6af86f3096ab4e — David du Colombier 24 years ago 0765327
Plan 9 from Bell Labs 2002-04-13
11 files changed, 46 insertions(+), 1243 deletions(-)

D bitsy/devsac.c
D bitsy/unsac.c
M pc/devarch.c
M pc/fns.h
M pc/l.s
M port/devloopback.c
M port/devtls.c
M port/nulledf.c
M port/portclock.c
M port/proc.c
M port/taslock.c
D bitsy/devsac.c => bitsy/devsac.c +0 -592
@@ 1,592 0,0 @@
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"
#include "../port/error.h"

/*
 *  definitions from the old 9P.  we need these because sac files
 *  are encoded using the old definitions.
 */
#define NAMELEN		28

#define CHDIR		0x80000000	/* mode bit for directories */
#define CHAPPEND	0x40000000	/* mode bit for append only files */
#define CHEXCL		0x20000000	/* mode bit for exclusive use files */
#define CHMOUNT		0x10000000	/* mode bit for mounted channel */
#define CHREAD		0x4		/* mode bit for read permission */
#define CHWRITE		0x2		/* mode bit for write permission */
#define CHEXEC		0x1		/* mode bit for execute permission */

enum
{
	OPERM	= 0x3,		/* mask of all permission types in open mode */
	Nram	= 512,
	CacheSize = 20,
	OffsetSize = 4,		/* size in bytes of an offset */
};

typedef struct SacPath SacPath;
typedef struct Sac Sac;
typedef struct SacHeader SacHeader;
typedef struct SacDir SacDir;
typedef struct Cache Cache;

enum {
	Magic = 0x5acf5,
};

struct SacDir
{
	char	name[NAMELEN];
	char	uid[NAMELEN];
	char	gid[NAMELEN];
	uchar	qid[4];
	uchar	mode[4];
	uchar	atime[4];
	uchar	mtime[4];
	uchar	length[8];
	uchar	blocks[8];
};

struct SacHeader
{
	uchar	magic[4];
	uchar	length[8];
	uchar	blocksize[4];
	uchar	md5[16];
};


struct Sac
{
	SacDir;
	SacPath *path;
};

struct SacPath
{
	Ref;
	SacPath *up;
	long blocks;
	int entry;
	int nentry;
};

struct Cache
{
	long block;
	ulong age;
	uchar *data;
};

enum
{
	Pexec =		1,
	Pwrite = 	2,
	Pread = 	4,
	Pother = 	1,
	Pgroup = 	8,
	Powner =	64,
};

static char *sacfs = "fs.sac";
static uchar *data;
static int blocksize;
static Sac root;
static Cache cache[CacheSize];
static ulong cacheage;

static int	sacdir(Chan *, SacDir*, uchar*, int);
static ulong	getl(void *p);
static Sac	*saccpy(Sac *s);
static Sac	*saclookup(Sac *s, char *name);
static int	sacdirread(Chan *, uchar *p, long off, long cnt);
static void	loadblock(void *buf, uchar *offset, int blocksize);
static void	sacfree(Sac*);

static void
pathtoqid(ulong path, Qid *q)
{
	if(path & CHDIR)
		q->type = QTDIR;
	else
		q->type = QTFILE;
	q->path = path & ~(CHDIR|CHAPPEND|CHEXCL|CHMOUNT);
	q->vers = 0;
}

static void
omodetomode(ulong om, ulong *m)
{
	ulong nm;

	nm = om & ~(CHDIR|CHAPPEND|CHEXCL|CHMOUNT);
	if(om & CHDIR)
		nm |= DMDIR;
	*m = nm;
}

static void
sacinit(void)
{
	SacHeader *hdr;
	uchar *p;
	int i;

	p = (uchar*)Flash_tar;
	data = tarlookup(p, sacfs, &i);
	if(data == 0) {
		p = (uchar*)Flash_tar+4;
		data = tarlookup(p, sacfs, &i);
		if(data == 0) {
			print("devsac: could not find file: %s\n", sacfs);
			return;
		}
	}
	hdr = (SacHeader*)data;
	if(getl(hdr->magic) != Magic) {
		print("devsac: bad magic\n");
		return;
	}
	blocksize = getl(hdr->blocksize);
	root.SacDir = *(SacDir*)(data + sizeof(SacHeader));
	p = malloc(CacheSize*blocksize);
	if(p == nil)
		error("allocating cache");
	for(i=0; i<CacheSize; i++) {
		cache[i].data = p;
		p += blocksize;
	}
}

static Chan*
sacattach(char* spec)
{
	Chan *c;
	int dev;

	dev = atoi(spec);
	if(dev != 0)
		error("bad specification");

	// check if init found sac file system in memory
	if(blocksize == 0)
		error("devsac: bad magic");

	c = devattach('C', spec);
	pathtoqid(getl(root.qid), &c->qid);
	c->dev = dev;
	c->aux = saccpy(&root);
	return c;
}

static void listprint(char **name, int nname, int j)
{
	int i;

	print("%d ", j);
	for(i = 0; i< nname; i++)
		print("%s/", name[i]);
	print("\n");
}

static Walkqid*
sacwalk(Chan *c, Chan *nc, char **name, int nname)
{
	Sac *sac;
	int j, alloc;
	Walkqid *wq;
	char *n;

	if(nname > 0)
		isdir(c);

	alloc = 0;
	wq = smalloc(sizeof(Walkqid)+(nname-1)*sizeof(Qid));
	if(waserror()){
		if(alloc && wq->clone!=nil)
			cclose(wq->clone);
		free(wq);
		return nil;
	}
	if(nc == nil){
		nc = devclone(c);
		nc->aux = saccpy(c->aux);
		alloc = 1;
	}
	wq->clone = nc;

	for(j=0; j<nname; j++){
		isdir(nc);
		n = name[j];
		if(strcmp(n, ".") == 0){
			wq->qid[wq->nqid++] = nc->qid;
			continue;
		}
		sac = nc->aux;
		sac = saclookup(sac, n);
		if(sac == nil) {
			if(j == 0)
				error(Enonexist);
			kstrcpy(up->errstr, Enonexist, ERRMAX);
			break;
		}
		pathtoqid(getl(sac->qid), &nc->qid);
		wq->qid[wq->nqid++] = nc->qid;
	}
	poperror();
	if(wq->nqid < nname){
//		listprint(name, wq->nqid, j);
		if(alloc)
			cclose(wq->clone);
		wq->clone = nil;
	}
	return wq;
}

static Chan*
sacopen(Chan *c, int omode)
{
	ulong t, mode;
	Sac *sac;
	static int access[] = { 0400, 0200, 0600, 0100 };

	sac = c->aux;
	mode = getl(sac->mode);
	if(strcmp(up->user, sac->uid) == 0)
		mode = mode;
	else if(strcmp(up->user, sac->gid) == 0)
		mode = mode<<3;
	else
		mode = mode<<6;

	t = access[omode&3];
	if((t & mode) != t)
			error(Eperm);
	c->offset = 0;
	c->mode = openmode(omode);
	c->flag |= COPEN;
	return c;
}


static long
sacread(Chan *c, void *a, long n, vlong voff)
{
	Sac *sac;
	char *buf, *buf2;
	int nn, cnt, i, j;
	uchar *blocks;
	long length;
	long off = voff;

	buf = a;
	cnt = n;
	if(c->qid.type & QTDIR)
		return sacdirread(c, a, off, cnt);
	sac = c->aux;
	length = getl(sac->length);
	if(off >= length)
		return 0;
	if(cnt > length-off)
		cnt = length-off;
	if(cnt == 0)
		return 0;
	n = cnt;
	blocks = data + getl(sac->blocks);
	buf2 = malloc(blocksize);
	while(cnt > 0) {
		i = off/blocksize;
		nn = blocksize;
		if(nn > length-i*blocksize)
			nn = length-i*blocksize;
		loadblock(buf2, blocks+i*OffsetSize, nn);
		j = off-i*blocksize;
		nn -= j;
		if(nn > cnt)
			nn = cnt;
		memmove(buf, buf2+j, nn);
		cnt -= nn;
		off += nn;
		buf += nn;
	}
	free(buf2);
	return n;
}

static long
sacwrite(Chan *, void *, long, vlong)
{
	error(Eperm);
	return 0;
}

static void
sacclose(Chan* c)
{
	Sac *sac = c->aux;

	c->aux = nil;
	sacfree(sac);
}

static int
sacstat(Chan *c, uchar *db, int n)
{
	n = sacdir(c, c->aux, db, n);
	if(n == 0)
		error(Ebadarg);
	return n;
}

static Sac*
saccpy(Sac *s)
{
	Sac *ss;
	
	ss = malloc(sizeof(Sac));
	*ss = *s;
	if(ss->path)
		incref(ss->path);
	return ss;
}

static SacPath *
sacpathalloc(SacPath *p, long blocks, int entry, int nentry)
{
	SacPath *pp = malloc(sizeof(SacPath));
	pp->ref = 1;
	pp->blocks = blocks;
	pp->entry = entry;
	pp->nentry = nentry;
	pp->up = p;
	return pp;
}

static void
sacpathfree(SacPath *p)
{
	if(p == nil)
		return;
	if(decref(p) > 0)
		return;
	sacpathfree(p->up);
	free(p);
}


static void
sacfree(Sac *s)
{
	sacpathfree(s->path);
	free(s);
}

static int
sacdir(Chan *c, SacDir *s, uchar *db, int n)
{
	Dir dir;

	dir.name = s->name;
	dir.uid = s->uid;
	dir.gid = s->gid;
	dir.muid = s->uid;
	pathtoqid(getl(s->qid), &dir.qid);
	omodetomode(getl(s->mode), &dir.mode);
	dir.length = getl(s->length);
	dir.atime = getl(s->atime);
	dir.mtime = getl(s->mtime);
	dir.type = devtab[c->type]->dc;
	dir.dev = c->dev;
	return convD2M(&dir, db, n);
}

static void
loadblock(void *buf, uchar *offset, int blocksize)
{
	long block, n;
	ulong age;
	int i, j;

	block = getl(offset);
	if(block < 0) {
		block = -block;
		cacheage++;
		// age has wraped
		if(cacheage == 0) {
			for(i=0; i<CacheSize; i++)
				cache[i].age = 0;
		}
		j = 0;
		age = cache[0].age;
		for(i=0; i<CacheSize; i++) {
			if(cache[i].age < age) {
				age = cache[i].age;
				j = i;
			}
			if(cache[i].block != block)
				continue;
			memmove(buf, cache[i].data, blocksize);
			cache[i].age = cacheage;
			return;
		}

		n = getl(offset+OffsetSize);
		if(n < 0)
			n = -n;
		n -= block;
		if(unsac(buf, data+block, blocksize, n)<0)
			panic("unsac failed!");
		memmove(cache[j].data, buf, blocksize);
		cache[j].age = cacheage;
		cache[j].block = block;
	} else {
		memmove(buf, data+block, blocksize);
	}
}

static Sac*
sacparent(Sac *s)
{
	uchar *blocks;
	SacDir *buf;
	int per, i, n;
	SacPath *p;

	p = s->path;
	if(p == nil || p->up == nil) {
		sacpathfree(p);
		*s = root;
		return s;
	}
	p = p->up;

	blocks = data + p->blocks;
	per = blocksize/sizeof(SacDir);
	i = p->entry/per;
	n = per;
	if(n > p->nentry-i*per)
		n = p->nentry-i*per;
	buf = malloc(per*sizeof(SacDir));
	loadblock(buf, blocks + i*OffsetSize, n*sizeof(SacDir));
	s->SacDir = buf[p->entry-i*per];
	free(buf);
	incref(p);
	sacpathfree(s->path);
	s->path = p;
	return s;
}

/* n**2 alg to read a directory */
static int
sacdirread(Chan *c, uchar *p, long off, long cnt)
{
	uchar *blocks;
	SacDir *buf;
	int per, i, j, n, ndir;
	long sofar;
	Sac *s;

	s = c->aux;
	blocks = data + getl(s->blocks);
	per = blocksize/sizeof(SacDir);
	ndir = getl(s->length);

	buf = malloc(blocksize);
	sofar = 0;
	for(j = 0; j < ndir; j++) {
		i = j%per;
		if(i == 0) {
			n = per;
			if(n > ndir-j*per)
				n = ndir-j*per;
			loadblock(buf, blocks + j*OffsetSize, n*sizeof(SacDir));
		}
		n = sacdir(c, buf+i, p, cnt - sofar);
		if(n == 0)
			break;
		if(off > 0)
			off -= n;
		else {
			p += n;
			sofar += n;
		}
	}
	free(buf);

	return sofar;
}

static Sac*
saclookup(Sac *s, char *name)
{
	int ndir;
	int i, j, k, n, per;
	uchar *blocks;
	SacDir *buf;
	int iblock;
	SacDir *sd;
	
	if(strcmp(name, "..") == 0)
		return sacparent(s);
	blocks = data + getl(s->blocks);
	per = blocksize/sizeof(SacDir);
	ndir = getl(s->length);
	buf = malloc(per*sizeof(SacDir));
	iblock = -1;

	// linear search
	for(i=0; i<ndir; i++) {
		j = i/per;
		if(j != iblock) {
			n = per;
			if(n > ndir-j*per)
				n = ndir-j*per;
			loadblock(buf, blocks + j*OffsetSize, n*sizeof(SacDir));
			iblock = j;
		}
		j *= per;
		sd = buf+i-j;
		k = strcmp(name, sd->name);
		if(k == 0) {
			s->path = sacpathalloc(s->path, getl(s->blocks), i, ndir);
			s->SacDir = *sd;
			free(buf);
			return s;
		}
	}
	free(buf);
	return 0;
}

static ulong
getl(void *p)
{
	uchar *a = p;

	return (a[0]<<24) | (a[1]<<16) | (a[2]<<8) | a[3];
}

Dev sacdevtab = {
	'C',
	"sac",

	devreset,
	sacinit,
	devshutdown,
	sacattach,
	sacwalk,
	sacstat,
	sacopen,
	devcreate,
	sacclose,
	sacread,
	devbread,
	sacwrite,
	devbwrite,
	devremove,
	devwstat,
};

D bitsy/unsac.c => bitsy/unsac.c +0 -627
@@ 1,627 0,0 @@
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"

typedef struct Huff	Huff;
typedef struct Mtf	Mtf;
typedef struct Decode	Decode;

enum
{
	ZBase		= 2,			/* base of code to encode 0 runs */
	LitBase		= ZBase-1,		/* base of literal values */
	MaxLit		= 256,

	MaxLeaf		= MaxLit+LitBase,
	MaxHuffBits	= 16,			/* max bits in a huffman code */
	MaxFlatbits	= 5,			/* max bits decoded in flat table */

	CombLog		= 4,
	CombSpace	= 1 << CombLog,		/* mtf speedup indices spacing */
	CombMask	= CombSpace - 1,
};

struct Mtf
{
	int	maxcomb;		/* index of last valid comb */
	uchar	prev[MaxLit];
	uchar	next[MaxLit];
	uchar	comb[MaxLit / CombSpace + 1];
};

struct Huff
{
	int	maxbits;
	int	flatbits;
	ulong	flat[1<<MaxFlatbits];
	ulong	maxcode[MaxHuffBits];
	ulong	last[MaxHuffBits];
	ulong	decode[MaxLeaf];
};

struct Decode{
	Huff	tab;
	Mtf	mtf;
	int	nbits;
	ulong	bits;
	int	nzero;
	int	base;
	ulong	maxblocksym;

	uchar	*src;				/* input buffer */
	uchar	*smax;				/* limit */
};

static	void	fatal(Decode *dec, char*);

static	int	hdec(Decode*);
static	void	recvtab(Decode*, Huff*, int, ushort*);
static	ulong	bitget(Decode*, int);
static	int	mtf(uchar*, int);

#define FORWARD 0

static void
mtflistinit(Mtf *m, uchar *front, int n)
{
	int last, me, f, i, comb;

	if(n == 0)
		return;

	/*
	 * add all entries to free list
	 */
	last = MaxLit - 1;
	for(i = 0; i < MaxLit; i++){
		m->prev[i] = last;
		m->next[i] = i + 1;
		last = i;
	}
	m->next[last] = 0;
	f = 0;

	/*
	 * pull valid entries off free list and enter into mtf list
	 */
	comb = 0;
	last = front[0];
	for(i = 0; i < n; i++){
		me = front[i];

		f = m->next[me];
		m->prev[f] = m->prev[me];
		m->next[m->prev[f]] = f;

		m->next[last] = me;
		m->prev[me] = last;
		last = me;
		if((i & CombMask) == 0)
			m->comb[comb++] = me;
	}

	/*
	 * pad out the list with dummies to the next comb,
	 * using free entries
	 */
	for(; i & CombMask; i++){
		me = f;

		f = m->next[me];
		m->prev[f] = m->prev[me];
		m->next[m->prev[f]] = f;

		m->next[last] = me;
		m->prev[me] = last;
		last = me;
	}
	me = front[0];
	m->next[last] = me;
	m->prev[me] = last;
	m->comb[comb] = me;
	m->maxcomb = comb;
}

static int
mtflist(Mtf *m, int pos)
{
	uchar *next, *prev, *mycomb;
	int c, c0, pc, nc, off;

	if(pos == 0)
		return m->comb[0];

	next = m->next;
	prev = m->prev;
	mycomb = &m->comb[pos >> CombLog];
	off = pos & CombMask;
	if(off >= CombSpace / 2){
		c = mycomb[1];
		for(; off < CombSpace; off++)
			c = prev[c];
	}else{
		c = *mycomb;
		for(; off; off--)
			c = next[c];
	}

	nc = next[c];
	pc = prev[c];
	prev[nc] = pc;
	next[pc] = nc;

	for(; mycomb > m->comb; mycomb--)
		*mycomb = prev[*mycomb];
	c0 = *mycomb;
	*mycomb = c;
	mycomb[m->maxcomb] = c;

	next[c] = c0;
	pc = prev[c0];
	prev[c] = pc;
	prev[c0] = c;
	next[pc] = c;
	return c;
}

static void
hdecblock(Decode *dec, ulong n, ulong I, uchar *buf, ulong *sums, ulong *prev)
{
	ulong i, nn, sum;
	int m, z, zz, c;

	nn = I;
	n--;
	i = 0;
again:
	for(; i < nn; i++){
		while((m = hdec(dec)) == 0 && i + dec->nzero < n)
			;
		if(z = dec->nzero){
			dec->nzero = 0;
			c = dec->mtf.comb[0];
			sum = sums[c];
			sums[c] = sum + z;

			z += i;
			zz = z;
			if(i < I && z > I){
				zz = I;
				z++;
			}

		zagain:
			for(; i < zz; i++){
				buf[i] = c;
				prev[i] = sum++;
			}
			if(i != z){
				zz = z;
				nn = ++n;
				i++;
				goto zagain;
			}
			if(i == nn){
				if(i == n)
					return;
				nn = ++n;
				i++;
			}
		}

		c = mtflist(&dec->mtf, m);

		buf[i] = c;
		sum = sums[c];
		prev[i] = sum++;
		sums[c] = sum;

	}
	if(i == n)
		return;
	nn = ++n;
	i++;
	goto again;
}

int
unsac(uchar *dst, uchar *src, int n, int nsrc)
{
	Decode *dec;
	uchar *buf, *front;
	ulong *prev, *sums;
	ulong sum, i, I;
	int m, j, c;

	dec = malloc(sizeof *dec);
	buf = malloc(n+2);
	prev = malloc((n+2) * sizeof *prev);
	front = malloc(MaxLit * sizeof *front);
	sums = malloc(MaxLit * sizeof *sums);

	if(waserror()){
		free(dec);
		free(buf);
		free(prev);
		free(front);
		free(sums);
		nexterror();
	}

	dec->src = src;
	dec->smax = src + nsrc;

	dec->nbits = 0;
	dec->bits = 0;
	dec->nzero = 0;
	for(i = 0; i < MaxLit; i++)
		front[i] = i;

	n++;
	I = bitget(dec, 16);
	if(I >= n)
		fatal(dec, "corrupted input");

	/*
	 * decode the character usage map
	 */
	for(i = 0; i < MaxLit; i++)
		sums[i] = 0;
	c = bitget(dec, 1);
	for(i = 0; i < MaxLit; ){
		m = bitget(dec, 8) + 1;
		while(m--){
			if(i >= MaxLit)
				fatal(dec, "corrupted char map");
			front[i++] = c;
		}
		c = c ^ 1;
	}

	/*
	 * initialize mtf state
	 */
	c = 0;
	for(i = 0; i < MaxLit; i++)
		if(front[i])
			front[c++] = i;
	mtflistinit(&dec->mtf, front, c);
	dec->maxblocksym = c + LitBase;

	/*
	 * huffman decoding, move to front decoding,
	 * along with character counting
	 */
	dec->base = 1;
	recvtab(dec, &dec->tab, MaxLeaf, nil);
	hdecblock(dec, n, I, buf, sums, prev);

	sum = 1;
	for(i = 0; i < MaxLit; i++){
		c = sums[i];
		sums[i] = sum;
		sum += c;
	}

	i = 0;
	for(j = n - 2; j >= 0; j--){
		if(i > n || i < 0 || i == I)
			fatal(dec, "corrupted data");
		c = buf[i];
		dst[j] = c;
		i = prev[i] + sums[c];
	}

	poperror();

	free(dec);
	free(buf);
	free(prev);
	free(front);
	free(sums);
	return n;
}

static ulong
bitget(Decode *dec, int nb)
{
	int c;

	while(dec->nbits < nb){
		if(dec->src >= dec->smax)
			fatal(dec, "premature eof 1");
		c = *dec->src++;
		dec->bits <<= 8;
		dec->bits |= c;
		dec->nbits += 8;
	}
	dec->nbits -= nb;
	return (dec->bits >> dec->nbits) & ((1 << nb) - 1);
}

static void
fillbits(Decode *dec)
{
	int c;

	while(dec->nbits < 24){
		if(dec->src >= dec->smax)
			fatal(dec, "premature eof 2");
		c = *dec->src++;
		dec->bits <<= 8;
		dec->bits |= c;
		dec->nbits += 8;
	}
}

/*
 * decode one symbol
 */
static int
hdecsym(Decode *dec, Huff *h, int b)
{
	long c;
	ulong bits;
	int nbits;

	bits = dec->bits;
	nbits = dec->nbits;
	for(; (c = bits >> (nbits - b)) > h->maxcode[b]; b++)
		;
	if(b > h->maxbits)
		fatal(dec, "too many bits consumed");
	dec->nbits = nbits - b;
	return h->decode[h->last[b] - c];
}

static int
hdec(Decode *dec)
{
	ulong c;
	int nbits, nb;

	if(dec->nbits < dec->tab.maxbits)
		fillbits(dec);
	nbits = dec->nbits;
	dec->bits &= (1 << nbits) - 1;
	c = dec->tab.flat[dec->bits >> (nbits - dec->tab.flatbits)];
	nb = c & 0xff;
	c >>= 8;
	if(nb == 0xff)
		c = hdecsym(dec, &dec->tab, c);
	else
		dec->nbits = nbits - nb;

	/*
	 * reverse funny run-length coding
	 */
	if(c < ZBase){
		dec->nzero += dec->base << c;
		dec->base <<= 1;
		return 0;
	}

	dec->base = 1;
	c -= LitBase;
	return c;
}

static void
hufftab(Decode *dec, Huff *h, char *hb, ulong *bitcount, int maxleaf, int maxbits, int flatbits)
{
	ulong c, mincode, code, nc[MaxHuffBits];
	int i, b, ec;

	h->maxbits = maxbits;
	if(maxbits < 0)
		return;

	code = 0;
	c = 0;
	for(b = 0; b <= maxbits; b++){
		h->last[b] = c;
		c += bitcount[b];
		mincode = code << 1;
		nc[b] = mincode;
		code = mincode + bitcount[b];
		if(code > (1 << b))
			fatal(dec, "corrupted huffman table");
		h->maxcode[b] = code - 1;
		h->last[b] += code - 1;
	}
	if(code != (1 << maxbits))
		fatal(dec, "huffman table not full");
	if(flatbits > maxbits)
		flatbits = maxbits;
	h->flatbits = flatbits;

	b = 1 << flatbits;
	for(i = 0; i < b; i++)
		h->flat[i] = ~0;

	/*
	 * initialize the flat table to include the minimum possible
	 * bit length for each code prefix
	 */
	for(b = maxbits; b > flatbits; b--){
		code = h->maxcode[b];
		if(code == -1)
			break;
		mincode = code + 1 - bitcount[b];
		mincode >>= b - flatbits;
		code >>= b - flatbits;
		for(; mincode <= code; mincode++)
			h->flat[mincode] = (b << 8) | 0xff;
	}

	for(i = 0; i < maxleaf; i++){
		b = hb[i];
		if(b == -1)
			continue;
		c = nc[b]++;
		if(b <= flatbits){
			code = (i << 8) | b;
			ec = (c + 1) << (flatbits - b);
			if(ec > (1<<flatbits))
				fatal(dec, "flat code too big");
			for(c <<= (flatbits - b); c < ec; c++)
				h->flat[c] = code;
		}else{
			c = h->last[b] - c;
			if(c >= maxleaf)
				fatal(dec, "corrupted huffman table");
			h->decode[c] = i;
		}
	}
}

static void
elimBit(int b, char *tmtf, int maxbits)
{
	int bb;

	for(bb = 0; bb < maxbits; bb++)
		if(tmtf[bb] == b)
			break;
	while(++bb <= maxbits)
		tmtf[bb - 1] = tmtf[bb];
}

static int
elimBits(int b, ulong *bused, char *tmtf, int maxbits)
{
	int bb, elim;

	if(b < 0)
		return 0;

	elim = 0;

	/*
	 * increase bits counts for all descendants
	 */
	for(bb = b + 1; bb < maxbits; bb++){
		bused[bb] += 1 << (bb - b);
		if(bused[bb] == (1 << bb)){
			elim++;
			elimBit(bb, tmtf, maxbits);
		}
	}

	/*
	 * steal bits from parent & check for fullness
	 */
	for(; b >= 0; b--){
		bused[b]++;
		if(bused[b] == (1 << b)){
			elim++;
			elimBit(b, tmtf, maxbits);
		}
		if((bused[b] & 1) == 0)
			break;
	}
	return elim;
}

static void
recvtab(Decode *dec, Huff *tab, int maxleaf, ushort *map)
{
	ulong bitcount[MaxHuffBits+1], bused[MaxHuffBits+1];
	char tmtf[MaxHuffBits+1], *hb;
	int i, b, ttb, m, maxbits, max, elim;

	hb = malloc(MaxLeaf * sizeof *hb);
	if(waserror()) {
		free(hb);
		nexterror();
	}

	/*
	 * read the tables for the tables
	 */
	max = 8;
	for(i = 0; i <= MaxHuffBits; i++){
		bitcount[i] = 0;
		tmtf[i] = i;
		bused[i] = 0;
	}
	tmtf[0] = -1;
	tmtf[max] = 0;
	elim = 0;
	maxbits = -1;
	for(i = 0; i <= MaxHuffBits && elim != max; i++){
		ttb = 4;
		while(max - elim < (1 << (ttb-1)))
			ttb--;
		b = bitget(dec, ttb);
		if(b > max - elim)
			fatal(dec, "corrupted huffman table table");
		b = tmtf[b];
		hb[i] = b;
		bitcount[b]++;
		if(b > maxbits)
			maxbits = b;

		elim += elimBits(b, bused, tmtf, max);
	}
	if(elim != max)
		fatal(dec, "incomplete huffman table table");
	hufftab(dec, tab, hb, bitcount, i, maxbits, MaxFlatbits);
	for(i = 0; i <= MaxHuffBits; i++){
		tmtf[i] = i;
		bitcount[i] = 0;
		bused[i] = 0;
	}
	tmtf[0] = -1;
	tmtf[MaxHuffBits] = 0;
	elim = 0;
	maxbits = -1;
	for(i = 0; i < maxleaf && elim != MaxHuffBits; i++){
		if(dec->nbits <= tab->maxbits)
			fillbits(dec);
		dec->bits &= (1 << dec->nbits) - 1;
		m = tab->flat[dec->bits >> (dec->nbits - tab->flatbits)];
		b = m & 0xff;
		m >>= 8;
		if(b == 0xff)
			m = hdecsym(dec, tab, m);
		else
			dec->nbits -= b;
		b = tmtf[m];
		for(; m > 0; m--)
			tmtf[m] = tmtf[m-1];
		tmtf[0] = b;

		if(b > MaxHuffBits)
			fatal(dec, "bit length too big");
		m = i;
		if(map != nil)
			m = map[m];
		hb[m] = b;
		bitcount[b]++;
		if(b > maxbits)
			maxbits = b;
		elim += elimBits(b, bused, tmtf, MaxHuffBits);
	}
	if(elim != MaxHuffBits && elim != 0)
		fatal(dec, "incomplete huffman table");
	if(map != nil)
		for(; i < maxleaf; i++)
			hb[map[i]] = -1;

	hufftab(dec, tab, hb, bitcount, i, maxbits, MaxFlatbits);

	poperror();
	free(hb);
}

static void
fatal(Decode *dec, char *msg)
{
	USED(dec);
print("unsac: %s\n", msg);
	error(msg);
}

M pc/devarch.c => pc/devarch.c +3 -0
@@ 791,6 791,9 @@ archinit(void)
	if(X86FAMILY(m->cpuidax) == 3)
		conf.copymode = 1;

//	if(X86FAMILY(m->cpuidax) >= 5 && conf.nmach > 1)
		coherence = wbflush;

	addarchfile("cputype", 0444, cputyperead, nil);
	addarchfile("pge", 0664, pgeread, pgewrite);
}

M pc/fns.h => pc/fns.h +2 -1
@@ 10,7 10,6 @@ int	cistrcmp(char*, char*);
int	cistrncmp(char*, char*, int);
#define	clearmmucache()				/* x86 doesn't have one */
void	clockintr(Ureg*, void*);
void	clockintrsched(void);
void	(*coherence)(void);
void	cpuid(char*, int*, int*);
int	cpuidentify(void);


@@ 126,6 125,7 @@ void	rdtsc(vlong*);
void	screeninit(void);
int	screenprint(char*, ...);			/* debugging */
void	(*screenputs)(char*, int);
void	sfence(void);
void	touser(void*);
void	trapenable(int, void (*)(Ureg*, void*), void*, char*);
void	trapinit(void);


@@ 140,6 140,7 @@ void	upafree(ulong, int);
void	vectortable(void);
void	wrmsr(int, vlong);
void	wbflush(void);
void	wbinvd(void);
int	xchgw(ushort*, int);
ulong	TK2MS(ulong);				/* ticks to milliseconds */


M pc/l.s => pc/l.s +15 -0
@@ 14,6 14,7 @@
#define RDTSC 		BYTE $0x0F; BYTE $0x31
#define WBINVD		BYTE $0x0F; BYTE $0x09
#define HLT		BYTE $0xF4
#define SFENCE		BYTE $0x0F; BYTE $0xAE; BYTE $0xF8

/*
 * Macros for calculating offsets within the page directory base


@@ 303,6 304,10 @@ TEXT wbinvd(SB), $0
	WBINVD
	RET

TEXT sfence(SB), $0
	SFENCE
	RET

/*
 * Try to determine the CPU type which requires fiddling with EFLAGS.
 * If the Id bit can be toggled then the CPUID instruciton can be used


@@ 498,6 503,16 @@ TEXT gotolabel(SB), $0
	MOVL	$1, AX				/* return 1 */
	RET

TEXT swaplabel(SB), $0
	MOVL	label+0(FP), AX
	MOVL	pc+4(FP), BX
	MOVL	0(AX), SP			/* restore sp */
	MOVL	4(AX), CX			/* put return pc on the stack */
	MOVL	CX, 0(SP)
	MOVL	BX, 4(AX)			/* put caller pc where return pc was */
	MOVL	$1, AX				/* return 1 */
	RET

TEXT setlabel(SB), $0
	MOVL	label+0(FP), AX
	MOVL	SP, 0(AX)			/* store sp */

M port/devloopback.c => port/devloopback.c +0 -1
@@ 597,7 597,6 @@ looper(Loop *lb)
	t = fastticks(nil);
	for(chan = 0; chan < 2; chan++)
		pushlink(&lb->link[chan], t);
	clockintrsched();
}

static void

M port/devtls.c => port/devtls.c +2 -2
@@ 760,8 760,8 @@ tlsrecread(TlsRec *tr)
		len = get16(header+3);
	}
	if(ver != tr->version && (tr->verset || ver < MinProtoVersion || ver > MaxProtoVersion))
		rcvError(tr, EProtocolVersion, "record layer saw ver %x, not %x/%d; %d %d",
			ver, tr->version, tr->verset, type, len);
		rcvError(tr, EProtocolVersion, "devtls expected ver=%x%s, saw (len=%d) type=%x ver=%x '%.12s'",
			tr->version, tr->verset?"/set":"", len, type, ver, (char*)header);
	if(len > MaxCipherRecLen || len < 0)
		rcvError(tr, ERecordOverflow, "record message too long %d", len);
	ensure(tr, &tr->unprocessed, len);

M port/nulledf.c => port/nulledf.c +5 -5
@@ 13,29 13,29 @@ isedf(Proc*)
}

void
edf_bury(Proc*)
edfbury(Proc*)
{
}

int
edf_anyready(void)
edfanyready(void)
{
	return 0;
}

void
edf_ready(Proc*)
edfready(Proc*)
{
}

Proc*
edf_runproc(void)
edfrunproc(void)
{
	return nil;
}

void
edf_block(Proc*)
edfblock(Proc*)
{
}


M port/portclock.c => port/portclock.c +9 -11
@@ 96,10 96,6 @@ hzclock(Ureg *ur)
	if(m->proc)
		m->proc->pc = ur->pc;

	if(m->inclockintr)
		return;		/* interrupted ourself */
	m->inclockintr = 1;

	if(m->flushmmu){
		if(up)
			flushmmu();


@@ 148,10 144,14 @@ timerintr(Ureg *u, uvlong)
	uvlong when, now;
	int callhzclock;

	if(m->inclockintr)
		return;
	m->inclockintr = 1;

	intrcount[m->machno]++;
	callhzclock = 0;
	tt = &timers[m->machno];
	now = (uvlong)fastticks(nil);
	now = fastticks(nil);
	ilock(tt);
	while(t = tt->head){
		when = t->when;


@@ 160,6 160,7 @@ timerintr(Ureg *u, uvlong)
			timerset(when);
			if(callhzclock)
				hzclock(u);
			m->inclockintr = 0;
			return;
		}
		tt->head = t->next;


@@ 179,6 180,7 @@ timerintr(Ureg *u, uvlong)
		}
	}
	iunlock(tt);
	m->inclockintr = 0;
}

uvlong hzperiod;


@@ 190,7 192,8 @@ timersinit(void)

	hzperiod = ms2fastticks(1000/HZ);

	t = smalloc(sizeof(*t));
	t = malloc(sizeof(*t));
	t->when = 0;
	t->period = hzperiod;
	t->f = nil;
	timeradd(t);


@@ 216,8 219,3 @@ addclock0link(void (*f)(void))
	 */
	iunlock(&timers[0]);
}

void
clockintrsched(void)
{
}

M port/proc.c => port/proc.c +1 -0
@@ 1146,6 1146,7 @@ error(char *err)
{
	spllo();
	kstrcpy(up->errstr, err, ERRMAX);
	setlabel(&up->errlab[NERR-1]);
	nexterror();
}


M port/taslock.c => port/taslock.c +9 -4
@@ 152,6 152,7 @@ canlock(Lock *l)
	return 1;
}

int buggeredsched;
void
unlock(Lock *l)
{


@@ 165,11 166,15 @@ unlock(Lock *l)
	coherence();

	/* give up the processor if ... */
	if(up && --up->nlocks == 0	/* we've closed the last nexted lock */
	if(up && --up->nlocks == 0	/* we've closed the last nested lock */
	&& up->delaysched		/* we delayed scheduling because of the lock */
	&& up->state == Running){	/* we're in running state */
		up->delaysched = 0;
		sched();
	&& up->state == Running){		/* we're in running state */
		if(!islo())
			buggeredsched++;
		else{
			up->delaysched = 0;
			sched();
		}
	}
}