~kris/9p

9hist

38e1a3ef0538f0308a8830de9cec92f0aa029fde — David du Colombier 34 years ago 6e1a0b8
Plan 9 from Bell Labs 1992-06-25
M boot/aux.c => boot/aux.c +2 -2
@@ 148,7 148,7 @@ outin(char *prompt, char *def, int len)

/*
 *  get second word of the terminal environment variable.   If it
 *  ends in "boot", get work of that part.
 *  ends in "boot", get rid of that part.
 */
void
getconffile(char *conffile, char *terminal)


@@ 169,7 169,7 @@ getconffile(char *conffile, char *terminal)
		*conffile++ = *p++;
	*conffile = 0;

	/* dump a trailig boot */
	/* dump a trailing boot */
	n = strlen(s);
	if(n > 4 && strcmp(s + n - 4, "boot") == 0)
		*(s+n-4) = 0;

M gnot/dat.h => gnot/dat.h +1 -13
@@ 76,22 76,12 @@ struct Conf
	ulong	upages;		/* user page pool */
	ulong	nimage;		/* number of page cache image headers */
	ulong	nswap;		/* number of swap blocks */
	int	nenv;		/* distinct environment values */
	int	nenvchar;	/* environment text storage */
	int	npgenv;		/* environment files per process group */
	int	nmux;		/* number of mux devices */
	int	nstream;	/* streams */
	int	nqueue;		/* stream queues */
	int	nsrv;		/* public servers (devsrv.c) */
	int	nurp;		/* max urp conversations */
	int	nasync;		/* number of async protocol modules */
	int	nfsyschan;	/* number of filsys open channels */
	int	nisdn;		/* number of isdn interfaces */
	int	nlapd;		/* number of dragnet protocol modules */
	int	copymode;	/* 0 is copy on write, 1 is copy on reference */
	int	portispaged;	/* ??? */
	int	cntrlp;		/* panic on ^P */
	int	dkif;		/* number of datakit interfaces */
	int	nconc;		/* number of datakit concentrators */
};



@@ 147,15 137,12 @@ struct Portpage
	int	 select;
};

extern Portpage portpage;
extern int	portispaged;
extern int	(*portservice[])(void);

struct Scsibuf
{
	void	*virt;
	void	*phys;
	Scsibuf	*next;
};

#define	NERR	25


@@ 171,6 158,7 @@ struct User
	char	elem[NAMELEN];		/* last name element from namec */
	Chan	*slash;
	Chan	*dot;
	Sargs	s;
	/*
	 * Rest of structure controlled by devproc.c and friends.
	 * lock(&p->debug) to modify.

M gnot/devduart.c => gnot/devduart.c +2 -2
@@ 645,9 645,9 @@ duartreset(void)

	if(dp->nostream)
		return;
	dp->iq = ialloc(sizeof(IOQ), 0);
	dp->iq = xalloc(sizeof(IOQ));
	initq(dp->iq);
	dp->oq = ialloc(sizeof(IOQ), 0);
	dp->oq = xalloc(sizeof(IOQ));
	initq(dp->oq);
	duartenable(dp);
}

M gnot/main.c => gnot/main.c +2 -12
@@ 40,20 40,19 @@ main(void)
	active.machs = 1;
	mmuinit();
	confinit();
	xinit();
	kmapinit();
	duartinit();
	screeninit();
	printinit();
	print("bank 0: %dM  bank 1: %dM\n", bank[0], bank[1]);
	flushmmu();
	pageinit();
	procinit0();
	initseg();
	grpinit();
	chaninit();
	chandevreset();
	streaminit();
	swapinit();
	pageinit();
	kmapinit();
	userinit();
	schedinit();


@@ 318,18 317,9 @@ confinit(void)
	conf.nproc = 50*mul;
	conf.nswap = 4096;
	conf.nimage = 50;
	conf.nenv = 100*mul;
	conf.nenvchar = 8000*mul;
	conf.npgenv = 200*mul;
	conf.nstream = 40 + 32*mul;
	conf.nqueue = 5 * conf.nstream;
	conf.nmux = 10;
	conf.nurp = 32;
	conf.nasync = 1;
	conf.copymode = 0;		/* copy on write */
	conf.portispaged = 0;
	conf.cntrlp = 0;
	conf.dkif = 2;

	confinit1(mul);
}

M gnot/mmu.c => gnot/mmu.c +12 -10
@@ 81,8 81,9 @@ flushmmu(void)
void
kmapinit(void)
{
	int i;
	Page *p;
	KMap *k;
	int i, e;

	if(kmapalloc.init == 0){
		k = &kmapalloc.arena[0];


@@ 93,16 94,17 @@ kmapinit(void)
		return;
	}

	e = (MB4 - 256*1024)/BY2PG;	/* screen lives at top 256K */
	i = PGROUND(palloc.addr0)/BY2PG;

	print("%lud free map registers\n", e-i);

	kmapalloc.free = 0;
	for(k=&kmapalloc.arena[i]; i < e; i++){
		k->va = i*BY2PG|KZERO;
		kunmap(k++);
	i = 0;
	/* Reclaim map register for pages in bank0 */
	for(p = palloc.head; p; p = p->next) {
		if(p->pa < MB4) {
			k = &kmapalloc.arena[p->pa/BY2PG];
			k->va = p->pa|KZERO;
			kunmap(k);
			i++;
		}
	}
	print("%lud free map registers\n", i);
}

KMap*

M gnot/trap.c => gnot/trap.c +13 -12
@@ 278,7 278,6 @@ syscall(Ureg *aur)
	ulong sp;
	ulong r0;
	Ureg *ur;
	char *msg;

	u->p->insyscall = 1;
	ur = aur;


@@ 310,22 309,24 @@ syscall(Ureg *aur)
	ret = -1;
	if(!waserror()){
		if(r0 >= sizeof systab/sizeof systab[0]){
			pprint("bad sys call number %d pc %lux\n", r0, ((Ureg*)UREGADDR)->pc);
			msg = "sys: bad sys call";
	    Bad:
			postnote(u->p, 1, msg, NDebug);
			pprint("bad sys call number %d pc %lux\n", r0, ur->pc);
			postnote(u->p, 1, "sys: bad sys call", NDebug);
			error(Ebadarg);
		}

		if(sp & (BY2WD-1)){
			pprint("odd sp in sys call pc %lux sp %lux\n",
				((Ureg*)UREGADDR)->pc, ((Ureg*)UREGADDR)->sp);
			msg = "sys: odd stack";
			goto Bad;
			pprint("odd sp in sys call pc %lux sp %lux\n", ur->pc, ur->sp);
			postnote(u->p, 1, "sys: odd stack", NDebug);
			error(Ebadarg);
		}
		if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-(1+MAXSYSARG)*BY2WD))
			validaddr(sp, (1+MAXSYSARG)*BY2WD, 0);

		if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)))
			validaddr(sp, sizeof(Sargs), 0);

		u->s = *((Sargs*)(sp+BY2WD));
		u->p->psstate = sysctab[r0];
		ret = (*systab[r0])((ulong*)(sp+BY2WD));

		ret = (*systab[r0])(u->s.args);
		poperror();
	}


M pc/dat.h => pc/dat.h +5 -24
@@ 52,32 52,13 @@ struct Conf
{
	ulong	nmach;		/* processors */
	ulong	nproc;		/* processes */
	ulong	npgrp;		/* process groups */
	ulong	npage0;		/* total physical pages in bank0 */
	ulong	npage1;		/* total physical pages in bank1 */
	ulong	npage0;		/* total physical pages of memory */
	ulong	npage1;		/* total physical pages of memory */
	ulong	topofmem;	/* highest physical address + 1 */
	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 */


@@ 88,7 69,6 @@ struct Conf
	ulong	cntrlp;		/* panic on ^P */
	ulong	nfloppy;	/* number of floppy drives */
	ulong	nhard;		/* number of hard drives */
	int	dkif;		/* number of datakit interfaces */
};

/*


@@ 151,6 131,7 @@ struct User
	char	elem[NAMELEN];		/* last name element from namec */
	Chan	*slash;
	Chan	*dot;
	Sargs	s;
	/*
	 * Rest of structure controlled by devproc.c and friends.
	 * lock(&p->debug) to modify.

M pc/devether.c => pc/devether.c +10 -7
@@ 59,6 59,7 @@ enum {
 */
struct Type {
	QLock;
	Netprot;			/* stat info */
	int	type;			/* ethernet type */
	int	prom;			/* promiscuous mode */
	Queue	*q;


@@ 96,7 97,6 @@ struct Ctlr {
	uchar	kproc;		/* true if kproc started */
	char	name[NAMELEN];	/* name of kproc */
	Network	net;
	Netprot	prot[NType];

	Queue	lbq;		/* software loopback packet queue */



@@ 331,7 331,7 @@ etherstclose(Queue *q)
	tp->q = 0;
	tp->prom = 0;
	tp->inuse = 0;
	netdisown(&tp->ctlr->net, tp - tp->ctlr->type);
	netdisown(tp);
	tp->ctlr = 0;
	qunlock(tp);
}


@@ 357,7 357,7 @@ clonecon(Chan *c)
			continue;
		}
		tp->inuse = 1;
		netown(&cp->net, tp - cp->type, u->p->user, 0);
		netown(tp, u->p->user, 0);
		qunlock(tp);
		return tp - cp->type;
	}


@@ 483,8 483,10 @@ etherkproc(void *arg)
void
etherreset(void)
{
	Ctlr *cp = &ctlr[0];
	int i;
	Ctlr *cp;

	cp = &ctlr[0];
	cp->hw = &wd8013;
	(*cp->hw->reset)(cp);



@@ 497,11 499,12 @@ etherreset(void)
	cp->net.listen = 0;
	cp->net.clone = clonecon;
	cp->net.ninfo = 2;
	cp->net.prot = cp->prot;
	cp->net.info[0].name = "stats";
	cp->net.info[0].fill = statsfill;
	cp->net.info[1].name = "type";
	cp->net.info[1].fill = typefill;
	for(i = 0; i < NType; i++)
		netadd(&cp->net, &cp->type[i], i);
}

void


@@ 611,9 614,9 @@ wd8013reset(Ctlr *cp)
	int i;
	uchar msr;

	cp->rb = ialloc(sizeof(Buffer)*Nrb, 1);
	cp->rb = xspanalloc(sizeof(Buffer)*Nrb, BY2PG, 0);
	cp->nrb = Nrb;
	cp->tb = ialloc(sizeof(Buffer)*Ntb, 1);
	cp->tb = xspanalloc(sizeof(Buffer)*Ntb, BY2PG, 0);
	cp->ntb = Ntb;

	msr = IN(hw, msr);

M pc/devfloppy.c => pc/devfloppy.c +2 -2
@@ 212,7 212,7 @@ floppyreset(void)
	/*
	 *  allocate the drive storage
	 */
	fl.d = ialloc(conf.nfloppy*sizeof(Drive), 0);
	fl.d = xalloc(conf.nfloppy*sizeof(Drive));
	fl.selected = fl.d;

	/*


@@ 231,7 231,7 @@ floppyreset(void)
		dp->t = &floppytype[0];		/* default type */
		floppydir[NFDIR*dp->dev].length = dp->t->cap;
		dp->cyl = -1;		/* because we don't know */
		dp->cache = (uchar*)ialloc(dp->t->tsize, 1);
		dp->cache = (uchar*)xspanalloc(dp->t->tsize, BY2PG, 0);
		dp->ccyl = -1;
		dp->vers = 1;
	}

M pc/devhard.c => pc/devhard.c +3 -3
@@ 201,8 201,8 @@ hardreset(void)
	Controller *cp;
	int drive;

	hard = ialloc(conf.nhard * sizeof(Drive), 0);
	hardc = ialloc(((conf.nhard+1)/2 + 1) * sizeof(Controller), 0);
	hard = xalloc(conf.nhard * sizeof(Drive));
	hardc = xalloc(((conf.nhard+1)/2 + 1) * sizeof(Controller));
	
	for(drive = 0; drive < conf.nhard; drive++){
		dp = &hard[drive];


@@ 211,7 211,7 @@ hardreset(void)
		dp->online = 0;
		dp->cp = cp;
		if((drive&1) == 0){
			cp->buf = ialloc(Maxxfer, 0);
			cp->buf = xalloc(Maxxfer);
			cp->lastcmd = cp->cmd;
			cp->cmd = 0;
			cp->pbase = Pbase + (cp-hardc)*8;	/* BUG!! guessing */

M pc/devincon.c => pc/devincon.c +1 -1
@@ 579,7 579,7 @@ inconread(Chan *c, void *buf, long n, ulong offset)
		sprint(b, "%d\n", incondebug);
		break;
	}
	return stringread(buf, n, b, offset);
	return readstr(offset, buf, n, b);
}

long	 

M pc/devuart.c => pc/devuart.c +2 -2
@@ 578,9 578,9 @@ uartreset(void)
	for(up = uart; up < &uart[2]; up++){
		if(up->nostream)
			continue;
		up->iq = ialloc(sizeof(IOQ), 0);
		up->iq = xalloc(sizeof(IOQ));
		initq(up->iq);
		up->oq = ialloc(sizeof(IOQ), 0);
		up->oq = xalloc(sizeof(IOQ));
		initq(up->oq);
	}
}

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

M pc/main.c => pc/main.c +16 -33
@@ 19,10 19,11 @@ main(void)
	active.exiting = 0;
	active.machs = 1;
	confinit();
	xinit();
	screeninit();
	printinit();
	print("%ludK bytes of physical memory\n", (conf.base1 + conf.npage1*BY2PG)/1024);
	mmuinit();
	pageinit();
	trapinit();
	mathinit();
	clockinit();


@@ 30,12 31,9 @@ main(void)
	kbdinit();
	procinit0();
	initseg();
	grpinit();
	chaninit();
	chandevreset();
	streaminit();
	swapinit();
	pageinit();
	userinit();

	schedinit();


@@ 107,8 105,10 @@ userinit(void)

	p = newproc();
	p->pgrp = newpgrp();
	p->egrp = newegrp();
	p->fgrp = newfgrp();
	p->egrp = smalloc(sizeof(Egrp));
	p->egrp->ref = 1;
	p->fgrp = smalloc(sizeof(Fgrp));
	p->fgrp->ref = 1;
	p->procmode = 0640;

	strcpy(p->text, "*init*");


@@ 219,52 219,35 @@ confinit(void)
		/*
		 *  write the word
		 */
		l = (long*)(KZERO|(i*1024L*1024L));
		l = (long*)(KZERO|(i*MB));
		*l = x;
		/*
		 *  take care of wraps
		 */
		for(j = 0; j < i; j++){
			l = (long*)(KZERO|(j*1024L*1024L));
			l = (long*)(KZERO|(j*MB));
			*l = 0;
		}
		/*
		 *  check
		 */
		l = (long*)(KZERO|(i*1024L*1024L));
		l = (long*)(KZERO|(i*MB));
		if(*l != x)
			break;
		x += 0x3141526;
	}
	conf.base1 = 0x100000;
	conf.npage1 = ((i-1)*1024*1024 - conf.base1)/BY2PG;

	conf.base1 = 1*MB;
	conf.npage1 = ((i-1)*MB - conf.base1)/BY2PG;
	conf.npage = conf.npage0 + conf.npage1;
	conf.upages = (conf.npage*70)/100;

	/* for meminit() */
	conf.topofmem = i*MB;

	mul = 1;
	conf.nproc = 30 + i*5;
	conf.npgrp = conf.nproc/2;
	conf.nseg = conf.nproc*3;
	conf.npagetab = (conf.nseg*14)/10;
	conf.nswap = conf.nproc*80;
	conf.nimage = 50;
	conf.nalarm = 1000;
	conf.nchan = 6*conf.nproc;
	conf.nenv = 4*conf.nproc;
	conf.nenvchar = 8000*mul;
	conf.npgenv = 200*mul;
	conf.nmtab = 50*mul;
	conf.nmount = 80*mul;
	conf.nmntdev = 15*mul;
	conf.nmntbuf = conf.nmntdev+3;
	conf.nmnthdr = 2*conf.nmntdev;
	conf.nsrv = 16*mul;			/* was 32 */
	conf.nurp = 32;
	conf.nasync = 1;
	conf.nstream = (conf.nproc*3)/2;
	conf.nqueue = 5 * conf.nstream;
	conf.nblock = 24 * conf.nstream;
	conf.npipe = conf.nstream/2;
	conf.copymode = 0;			/* copy on write */
	conf.ipif = 8;
	conf.ip = 64;


@@ 273,7 256,7 @@ confinit(void)
	conf.cntrlp = 0;
	conf.nfloppy = 2;
	conf.nhard = 1;
	conf.dkif = 1;

	confinit1(mul);
}


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

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


M pc/mmu.c => pc/mmu.c +4 -4
@@ 117,15 117,15 @@ mmuinit(void)
	 */

	/*  allocate top level table */
	top = ialloc(BY2PG, 1);
	top = xspanalloc(BY2PG, BY2PG, 0);
	ktoppg.va = (ulong)top;
	ktoppg.pa = ktoppg.va & ~KZERO;

	/*  map all memory to KZERO */
	npage = conf.base1/BY2PG + conf.npage1;
	npage = conf.topofmem/BY2PG;
	nbytes = PGROUND(npage*BY2WD);		/* words of page map */
	nkpt = nbytes/BY2PG;			/* pages of page map */
	kpt = ialloc(nbytes, 1);
	kpt = xspanalloc(nbytes, BY2PG, 0);
	for(i = 0; i < npage; i++)
		kpt[i] = (0+i*BY2PG) | PTEVALID | PTEKERNEL | PTEWRITE;
	x = TOPOFF(KZERO);


@@ 134,7 134,7 @@ mmuinit(void)
		top[x+i] = (y+i*BY2PG) | PTEVALID | PTEKERNEL | PTEWRITE;

	/*  page table for u-> */
	upt = ialloc(BY2PG, 1);
	upt = xspanalloc(BY2PG, BY2PG, 0);
	x = TOPOFF(USERADDR);
	y = ((ulong)upt)&~KZERO;
	top[x] = y | PTEVALID | PTEKERNEL | PTEWRITE;

M pc/trap.c => pc/trap.c +5 -1
@@ 328,10 328,14 @@ syscall(Ureg *ur)
			postnote(u->p, 1, "sys: bad sys call", NDebug);
			error(Ebadarg);
		}

		if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-(1+MAXSYSARG)*BY2WD))
			validaddr(sp, (1+MAXSYSARG)*BY2WD, 0);

		u->s = *((Sargs*)(sp+1*BY2WD));
		u->p->psstate = sysctab[ax];
		ret = (*systab[ax])((ulong*)(sp+BY2WD));

		ret = (*systab[ax])(u->s.args);
		poperror();
	}
	if(u->nerrlab){

M port/alloc.c => port/alloc.c +25 -5
@@ 68,6 68,8 @@ struct Arena
	Lock;
	Bucket	*btab[Maxpow];
	int	nbuck[Maxpow];
	QLock	rq;
	Rendez	r;
};

static Arena	arena;


@@ 100,6 102,7 @@ xinit(void)
	conf.base1 += np1*BY2PG;
	conf.npage1 -= np1;
	xhole(conf.base1, conf.npage1*BY2PG);
	conf.npage1 = conf.base1+(conf.npage1*BY2PG);
	up -= np1;

	np0 = up;


@@ 110,9 113,15 @@ xinit(void)
	conf.base0 += np0*BY2PG;
	conf.npage0 -= np0;
	xhole(conf.base0, conf.npage0*BY2PG);
	conf.npage0 = conf.base0+(conf.npage0*BY2PG);

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

/*


@@ 287,13 296,22 @@ good:
void*
smalloc(ulong size)
{
	char *s;
	void *p;

	p = malloc(size);
	if(p == nil) {
		print("asking for %d\n", size);
		xsummary();
		panic("smalloc should sleep");
	for(;;) {
		p = malloc(size);
		if(p != nil)
			return p;
		s = u->p->psstate;
		u->p->psstate = "Malloc";
		qlock(&arena.rq);
		while(waserror())
			;
		sleep(&arena.r, return0, nil);
		poperror();
		qunlock(&arena.rq);
		u->p->psstate = s;
	}
	return p;
}


@@ 324,6 342,8 @@ free(void *ptr)
	bp->next = *l;
	*l = bp;
	unlock(&arena);
	if(arena.r.p)
		wakeup(&arena.r);
}

void

M port/devboot.c => port/devboot.c +11 -3
@@ 76,8 76,19 @@ long
bootread(Chan *c, void *buf, long n, ulong offset)
{
	switch(c->qid.path & ~CHDIR){

	case Qdir:
		return devdirread(c, buf, n, bootdir, NBOOT, devgen);

	case Qmem:
		/* kernel memory */
		if(offset>=KZERO && offset<KZERO+conf.npage*BY2PG){
			if(offset+n > KZERO+conf.npage*BY2PG)
				n = KZERO+conf.npage*BY2PG - offset;
			memmove(buf, (char*)offset, n);
			return n;
		}
		error(Ebadarg);
	}

	error(Egreg);


@@ 93,13 104,11 @@ bootwrite(Chan *c, void *buf, long n, ulong offset)
	case Qmem:
		/* kernel memory */
		if(offset>=KZERO && offset<KZERO+conf.npage*BY2PG){
/* print("%ux, %d\n", c->offset, n);/**/
			if(offset+n > KZERO+conf.npage*BY2PG)
				n = KZERO+conf.npage*BY2PG - offset;
			memmove((char*)offset, buf, n);
			return n;
		}
		print("bootwrite: bad addr %lux\n", offset);
		error(Ebadarg);

	case Qboot:


@@ 107,7 116,6 @@ bootwrite(Chan *c, void *buf, long n, ulong offset)
		splhi();
		gotopc(pc);
	}
	print("bootwrite: bad path %d\n", c->qid.path);
	error(Ebadarg);
	return 0;	/* not reached */
}

M port/devdk.c => port/devdk.c +89 -127
@@ 104,30 104,27 @@ struct Line {
 *  a dkmux dk.  one exists for every stream that a 
 *  dkmux line discipline is pushed onto.
 */
struct Dk {
struct Dk
{
	QLock	netlock;
	Network	net;
	Network	net;		/* stat info */
	Line	**linep;	/* array of line structures */

	QLock	csclock;
	Chan	*csc;

	Lock;
	int	opened;

	char	name[64];	/* dk name */
	Queue	*wq;		/* dk output queue */
	Stream	*s;
	int	ncsc;		/* csc line number */
	int	lines;		/* number of lines */
	Line	**linep;
	int	restart;
	int	urpwindow;
	Rendez	timer;
	int	closeall;	/* set when we receive a closeall message */
	Rendez	closeallr;	/* wait here for a closeall */
};
static Dk *dk;
static Lock dklock;
Lock	dklock;
Dk	*dk[Maxdk];

/*
 *  conversation states (for Line.state)


@@ 207,9 204,9 @@ extern Qinfo dkinfo;
/*
 *  the datakit multiplexor stream module definition
 */
static void dkmuxopen(Queue *, Stream *);
static void dkmuxoput(Queue *, Block *);
static void dkmuxiput(Queue *, Block *);
static Streamopen dkmuxopen;
static Streamput dkmuxoput;
static Streamput dkmuxiput;
Qinfo dkmuxinfo =
{
	dkmuxiput,


@@ 220,70 217,6 @@ Qinfo dkmuxinfo =
};

/*
 *  Look for a dk struct with a name.  If none exists,  create one.
 */ 
static Dk*
dkalloc(char *name, int ncsc, int lines)
{
	Dk *dp;
	Dk *freep;
	int i, n;
	Line *lp;

	lock(&dklock);
	freep = 0;
	for(dp = dk; dp < &dk[Maxdk]; dp++){
		if(strcmp(name, dp->name) == 0){
			unlock(&dklock);
			return dp;
		}
		if(dp->name[0] == 0)
			freep = dp;
	}
	if(freep == 0 || lines == 0){
		unlock(&dklock);
		error(Enoifc);
	}

	dp = freep;
	dp->opened = 0;
	dp->s = 0;
	dp->ncsc = ncsc;
	dp->lines = lines;
	strncpy(dp->name, name, sizeof(freep->name));

	/*
	 *  allocate memory for array of pointers to lines.
	 *  line structures are allocated as needed.
	 */
	dp->linep = smalloc(sizeof(Line*) * dp->lines);

	/*
	 *  fill in the network structure
	 */
	dp->net.name = dp->name;
	dp->net.nconv = dp->lines;
	dp->net.devp = &dkinfo;
	dp->net.protop = &urpinfo;
	dp->net.listen = dklisten;
	dp->net.clone = dkcloneline;
	dp->net.ninfo = 5;
	dp->net.info[0].name = "addr";
	dp->net.info[0].fill = dkfilladdr;
	dp->net.info[1].name = "raddr";
	dp->net.info[1].fill = dkfillraddr;
	dp->net.info[2].name = "ruser";
	dp->net.info[2].fill = dkfillruser;
	dp->net.info[3].name = "stats";
	dp->net.info[3].fill = urpfillstats;
	dp->net.info[4].name = "other";
	dp->net.info[4].fill = dkfillother;

	unlock(&dklock);
	return dp;
}

/*
 *  allocate a line if it doesn't exist
 */
static Line*


@@ 291,8 224,6 @@ linealloc(Dk *dp, int lineno, int dolock)
{
	Line *lp;

	if(dp->opened == 0)
		error(Enoifc);
	if(dolock)
		qlock(&dp->netlock);
	if(lineno > dp->lines)


@@ 315,11 246,10 @@ linealloc(Dk *dp, int lineno, int dolock)
static void
dkmuxopen(Queue *q, Stream *s)
{
	RD(q)->ptr = s;
	RD(q)->ptr = 0;
	WR(q)->ptr = 0;

	s->opens++;		/* Hold this queue in place */
	s->inuse++;
	naildownstream(s);
}

/*


@@ 395,10 325,9 @@ dkmuxiput(Queue *q, Block *bp)
/*
 *  the datakit line stream module definition
 */
static void dkstopen(Queue *, Stream *);
static void dkstclose(Queue *);
static void dkoput(Queue *, Block *);
static void dkiput(Queue *, Block *);
static Streamopen dkstopen;
static Streamclose dkstclose;
static Streamput dkoput, dkiput;
Qinfo dkinfo =
{
	dkiput,


@@ 417,7 346,7 @@ dkstopen(Queue *q, Stream *s)
	Dk *dp;
	Line *lp;

	dp = &dk[s->dev];
	dp = dk[s->dev];
	q->other->ptr = q->ptr = lp = dp->linep[s->id];
	lp->dp = dp;
	lp->rq = q;


@@ 498,8 427,6 @@ out:
	lp->rq = 0;
	qunlock(lp);

	if(lp->lineno == dp->ncsc)
		dp->csc = 0;
	netdisown(lp);
	lp->window = 0;
}


@@ 598,6 525,7 @@ dkmuxconfig(Queue *q, Block *bp)
		window = strtoul(fields[4], 0, 0);
	case 4:
		strncpy(name, fields[3], sizeof(name));
		name[sizeof(name)-1] = 0;
	case 3:
		if(strcmp(fields[2], "restart")!=0)
			restart = 0;


@@ 615,27 543,62 @@ dkmuxconfig(Queue *q, Block *bp)
		error(Ebadarg);

	/*
	 *  set up
	 *  find a free dk slot.  it name is already configured
	 *  or no slots are left, error.
	 */
	dp = dkalloc(name, ncsc, lines);
	lock(dp);
	if(dp->opened){
		unlock(dp);
		error(Ebadarg);
	lock(&dklock);
	if(waserror()){
		unlock(&dklock);
		nexterror();
	}
	for(n = 0; n < Maxdk; n++){
		dp = dk[n];
		if(dp == 0)
			break;
		if(strcmp(name, dp->name) == 0)
			error(Einuse);
	}
	if(n == Maxdk)
		error(Enoifc);

	/*
	 *  allocate both a dk structure and an array of pointers to line
	 *  structures
	 */
	dp = smalloc(sizeof(Dk));
	dp->ncsc = ncsc;
	dp->lines = lines;
	dp->linep = smalloc(sizeof(Line*) * dp->lines);
	strcpy(dp->name, name);
	dp->net.name = dp->name;
	dp->net.nconv = dp->lines;
	dp->net.devp = &dkinfo;
	dp->net.protop = &urpinfo;
	dp->net.listen = dklisten;
	dp->net.clone = dkcloneline;
	dp->net.ninfo = 5;
	dp->net.info[0].name = "addr";
	dp->net.info[0].fill = dkfilladdr;
	dp->net.info[1].name = "raddr";
	dp->net.info[1].fill = dkfillraddr;
	dp->net.info[2].name = "ruser";
	dp->net.info[2].fill = dkfillruser;
	dp->net.info[3].name = "stats";
	dp->net.info[3].fill = urpfillstats;
	dp->net.info[4].name = "other";
	dp->net.info[4].fill = dkfillother;
	dp->restart = restart;
	dp->urpwindow = window;
	dp->s = RD(q)->ptr;
	q->ptr = q->other->ptr = dp;
	dp->opened = 1;
	dp->wq = WR(q);
	unlock(dp);
	q->ptr = q->other->ptr = dp;
	dk[n] = dp;
	unlock(&dklock);
	poperror();

	/*
	 *  open csc here so that boot, dktimer, and dkcsckproc aren't
	 *  all fighting for it at once.
	 */
	dp->closeall = 0;
	dkopencsc(dp);

	/*


@@ 643,7 606,6 @@ dkmuxconfig(Queue *q, Block *bp)
	 */
	sprint(buf, "csc.%s.%d", dp->name, dp->ncsc);
	kproc(buf, dkcsckproc, dp);
	tsleep(&dp->closeallr, haveca, dp, 5000);	/* wait for initial closeall */

	/*
	 *  tell datakit we've rebooted. It should close all channels.


@@ 653,8 615,8 @@ dkmuxconfig(Queue *q, Block *bp)
		DPRINT("dktimer: restart %s\n", dp->name);
		dp->closeall = 0;
		dkmesg(dp->csc, T_ALIVE, D_RESTART, 0, 0);
		tsleep(&dp->closeallr, haveca, dp, 5000); /* wait for restart closeall */
	}
	tsleep(&dp->closeallr, haveca, dp, 15000);

	/*
	 *  start a keepalive process


@@ 666,9 628,6 @@ dkmuxconfig(Queue *q, Block *bp)
void
dkreset(void)
{
	int i;

	dk = (Dk*)xalloc(Maxdk*sizeof(Dk));
	newqinfo(&dkmuxinfo);
}



@@ 682,19 641,26 @@ dkattach(char *spec)
{
	Chan *c;
	Dk *dp;
	int dev;

	/*
	 *  find a multiplexor with the same name (default dk)
	 */
	if(*spec == 0)
		spec = "dk";
	dp = dkalloc(spec, 0, 0);
	for(dev = 0; dev < Maxdk; dev++){
		dp = dk[dev];
		if(dp && strcmp(dp->name, spec) == 0)
			break;
	}
	if(dev == Maxdk)
		error(Enoifc);

	/*
	 *  return the new channel
	 */
	c = devattach('k', spec);
	c->dev = dp - dk;
	c->dev = dev;
	return c;
}



@@ 707,13 673,13 @@ dkclone(Chan *c, Chan *nc)
int	 
dkwalk(Chan *c, char *name)
{
	return netwalk(c, name, &dk[c->dev].net);
	return netwalk(c, name, &dk[c->dev]->net);
}

void	 
dkstat(Chan *c, char *dp)
{
	netstat(c, dp, &dk[c->dev].net);
	netstat(c, dp, &dk[c->dev]->net);
}

Chan*


@@ 721,7 687,7 @@ dkopen(Chan *c, int omode)
{
	Dk *dp;

	dp = &dk[c->dev];
	dp = dk[c->dev];
	linealloc(dp, STREAMID(c->qid.path), 1);
	return netopen(c, omode, &dp->net);
}


@@ 743,7 709,7 @@ dkclose(Chan *c)
long	 
dkread(Chan *c, void *a, long n, ulong offset)
{
	return netread(c, a, n, offset,  &dk[c->dev].net);
	return netread(c, a, n, offset, &dk[c->dev]->net);
}

long	 


@@ 813,7 779,7 @@ dkremove(Chan *c)
void	 
dkwstat(Chan *c, char *dp)
{
	netwstat(c, dp, &dk[c->dev].net);
	netwstat(c, dp, &dk[c->dev]->net);
}

/*


@@ 826,7 792,7 @@ dkcloneline(Chan *c)
	Dk *dp;
	int line;

	dp = &dk[c->dev];
	dp = dk[c->dev];
	/*
	 *  get an unused device and open its control file
	 */


@@ 869,7 835,7 @@ dkopenline(Dk *dp, int line)
}

/*
 *  open the common signalling channel
 *  open the common signalling channel (dp->csc's reference count never goes below 1)
 */
static Chan*
dkopencsc(Dk *dp)


@@ 879,8 845,7 @@ dkopencsc(Dk *dp)
	qlock(&dp->csclock);
	if(dp->csc == 0)
		dp->csc = dkopenline(dp, dp->ncsc);
	else
		incref(dp->csc);
	incref(dp->csc);
	qunlock(&dp->csclock);
	return dp->csc;
}


@@ 891,22 856,22 @@ dkopencsc(Dk *dp)
void
dkfilladdr(Chan *c, char *buf, int len)
{
	strncpy(buf, dk[c->dev].linep[STREAMID(c->qid.path)]->addr, len);
	strncpy(buf, dk[c->dev]->linep[STREAMID(c->qid.path)]->addr, len);
}
void
dkfillraddr(Chan *c, char *buf, int len)
{
	strncpy(buf, dk[c->dev].linep[STREAMID(c->qid.path)]->raddr, len);
	strncpy(buf, dk[c->dev]->linep[STREAMID(c->qid.path)]->raddr, len);
}
void
dkfillruser(Chan *c, char *buf, int len)
{
	strncpy(buf, dk[c->dev].linep[STREAMID(c->qid.path)]->ruser, len);
	strncpy(buf, dk[c->dev]->linep[STREAMID(c->qid.path)]->ruser, len);
}
void
dkfillother(Chan *c, char *buf, int len)
{
	strncpy(buf, dk[c->dev].linep[STREAMID(c->qid.path)]->other, len);
	strncpy(buf, dk[c->dev]->linep[STREAMID(c->qid.path)]->other, len);
}

/*


@@ 963,7 928,7 @@ dkcall(int type, Chan *c, char *addr, char *nuser, char *machine)
	char *bang, *dot;
	
	line = STREAMID(c->qid.path);
	dp = &dk[c->dev];
	dp = dk[c->dev];
	lp = linealloc(dp, line, 1);

	/*


@@ 1139,7 1104,7 @@ dklisten(Chan *c)
	Chan *dc;
	static int dts;

	dp = &dk[c->dev];
	dp = dk[c->dev];
	from = STREAMID(c->qid.path);

	/*


@@ 1309,7 1274,7 @@ dkanswer(Chan *c, int line, int code)
	Line *lp;
	Dk *dp;

	dp = &dk[c->dev];
	dp = dk[c->dev];
	lp = linealloc(dp, line, 1);

	/*


@@ 1359,7 1324,7 @@ dkwindow(Chan *c)
	long wins;
	Line *lp;

	lp = linealloc(&dk[c->dev], STREAMID(c->qid.path), 1);
	lp = linealloc(dk[c->dev], STREAMID(c->qid.path), 1);
	if(lp->window == 0)
		lp->window = 64;
	sprint(buf, "init %d %d", lp->window, Streamhi);


@@ 1488,11 1453,8 @@ dkchgmesg(Chan *c, Dk *dp, Dkmsg *dialp, int line)
		break;
	
	case D_ISCLOSED:	/* acknowledging a local shutdown */
		if (line <= 0 || line >= dp->lines || (lp = dp->linep[line]) == 0) {
			/* tell controller this line is not in use */
			dkmesg(c, T_CHG, D_CLOSE, line, 0);
		if (line <= 0 || line >= dp->lines || (lp = dp->linep[line]) == 0)
			return;
		}
		switch (lp->state) {
		case Llclose:
		case Lclosed:

M port/devenv.c => port/devenv.c +41 -1
@@ 76,7 76,7 @@ envopen(Chan *c, int omode)
	Evalue *e;
	
	eg = u->p->egrp;
	if(c->qid.path & CHDIR){
	if(c->qid.path & CHDIR) {
		if(omode != OREAD)
			error(Eperm);
	}


@@ 256,6 256,46 @@ envwrite(Chan *c, void *a, long n, ulong offset)
	return n;
}

void
envcpy(Egrp *to, Egrp *from)
{
	Evalue **l, *ne, *e;

	l = &to->entries;
	qlock(from);
	for(e = from->entries; e; e = e->link) {
		ne = smalloc(sizeof(Evalue));
		ne->name = smalloc(strlen(e->name)+1);
		strcpy(ne->name, e->name);
		if(e->value) {
			ne->value = smalloc(e->len);
			memmove(ne->value, e->value, e->len);
			ne->len = e->len;
		}
		ne->path = ++to->path;
		*l = ne;
		l = &ne->link;
	}
	qunlock(from);
}

void
closeegrp(Egrp *eg)
{
	Evalue *e, *next;

	if(decref(eg) == 0) {
		for(e = eg->entries; e; e = next) {
			next = e->link;
			free(e->name);
			if(e->value)
				free(e->value);
			free(e);
		}
		free(eg);
	}
}

/*
 *  to let the kernel set environment variables
 */

M port/devip.c => port/devip.c +3 -20
@@ 23,26 23,9 @@ Network	*ipnet[Nrprotocol];		/* User level interface for protocol */
QLock	ipalloc;			/* Protocol port allocation lock */
Ipconv	*tcpbase;			/* Base tcp connection */

/* ARPA User Datagram Protocol */
void	udpstiput(Queue *, Block *);
void	udpstoput(Queue *, Block *);
void	udpstopen(Queue *, Stream *);
void	udpstclose(Queue *);
/* ARPA Transmission Control Protocol */
void	tcpstiput(Queue *, Block *);
void	tcpstoput(Queue *, Block *);
void	tcpstopen(Queue *, Stream *);
void	tcpstclose(Queue *);
/* Plan9 Reliable Datagram Protocol */
void	iliput(Queue *, Block *);
void	iloput(Queue *, Block *);
void	ilopen(Queue *, Stream *);
void	ilclose(Queue *);
/* BSD authentication Protocol checker */
void	bsdiput(Queue *, Block *);
void	bsdoput(Queue *, Block *);
void	bsdopen(Queue *, Stream *);
void	bsdclose(Queue *);
Streamput   udpstiput, udpstoput, tcpstiput, tcpstoput, iliput, iloput, bsdiput, bsdoput;
Streamopen  udpstopen, tcpstopen, ilopen, bsdopen;
Streamclose udpstclose, tcpstclose, ilclose, bsdclose;

Qinfo tcpinfo = { tcpstiput, tcpstoput, tcpstopen, tcpstclose, "tcp", 0, 1 };
Qinfo udpinfo = { udpstiput, udpstoput, udpstopen, udpstclose, "udp" };

M port/devpipe.c => port/devpipe.c +3 -3
@@ 229,7 229,7 @@ pipeclose(Chan *c)
				*l = p->next;
				break;
			}
			l = &p->next;
			l = &f->next;
		}
		unlock(&pipealloc);
		free(p);


@@ 319,6 319,6 @@ getpipe(ulong path)
		}
	}
	unlock(&pipealloc);
	error(Enonexist);
	return 0;
	panic("getpipe");
	return 0;		/* not reached */
}

M port/devscsi.c => port/devscsi.c +5 -44
@@ 51,11 51,6 @@ struct Scsi
	uchar	cmdblk[16];
};

struct{
	Lock;
	Scsibuf	*free;
}scsibufalloc;

static Scsi	staticcmd;	/* BUG: should be one per scsi device */

enum


@@ 465,22 460,6 @@ scsibwrite(int dev, Scsibuf *b, long n, long blocksize, long blockno)
}

/*
 * allocate a scsi buf of any length
 * must be called at ialloc time and never freed
 */
Scsibuf *
scsialloc(ulong n)
{
	Scsibuf *b;
	uchar *x;
	long m;

	b = ialloc(sizeof *b, 0);
	b->virt = b->phys = ialloc(n, 0);
	return b;
}

/*
 * get a scsi io buffer of DATASIZE size
 */
Scsibuf *


@@ 488,26 467,16 @@ scsibuf(void)
{
	Scsibuf *b;

	for(;;) {
		lock(&scsibufalloc);
		if(b = scsibufalloc.free) {
			scsibufalloc.free = b->next;
			unlock(&scsibufalloc);
			return b;
		}

		unlock(&scsibufalloc);
		resrcwait("no scsi buffers");
	}
	b = smalloc(sizeof(Scsibuf)+DATASIZE);
	b->phys = (void*)(b + 1);
	b->virt = b->phys;
	return b;
}

void
scsifree(Scsibuf *b)
{
	lock(&scsibufalloc);
	b->next = scsibufalloc.free;
	scsibufalloc.free = b;
	unlock(&scsibufalloc);
	free(b);
}

typedef struct Scsictl {


@@ 567,15 536,7 @@ nop(void)
void
scsireset(void)
{
	static int alloced = 0;
	int i;

	addportintr(scsiintr);
	if(!alloced){
		for(i = 0; i < Nbuf; i++)
			scsifree(scsialloc(DATASIZE));
		alloced = 1;
	}
}

void

M port/fault.c => port/fault.c +3 -3
@@ 112,9 112,9 @@ fixfault(Segment *s, ulong addr, int read, int doputmmu)
		}

		lkp = *pg;
		lockpage(lkp);
		lock(lkp);
		if(lkp->ref > 1) {
			unlockpage(lkp);
			unlock(lkp);
			if(new == 0)
			if(new = newpage(0, &s, addr))
			if(s == 0)


@@ 129,7 129,7 @@ fixfault(Segment *s, ulong addr, int read, int doputmmu)
			if(lkp->image)     
				duppage(lkp);	
		
			unlockpage(lkp);
			unlock(lkp);
		}
	done:
		mmuphys = PPN((*pg)->pa) | PTEWRITE|PTEVALID;

M port/ipdat.h => port/ipdat.h +197 -210
@@ 1,18 1,18 @@
typedef struct Ipconv	Ipconv;
typedef struct Ipifc	Ipifc;
typedef struct Etherhdr	Etherhdr;
typedef struct Fragq	Fragq;
typedef struct Ipfrag	Ipfrag;
typedef struct Ilcb	Ilcb;
typedef struct Ilhdr	Ilhdr;
typedef ulong		Ipaddr;
typedef struct Ipconv	Ipconv;
typedef struct Ipfrag	Ipfrag;
typedef struct Ipifc	Ipifc;
typedef ushort		Port;
typedef struct Udphdr	Udphdr;
typedef struct Etherhdr	Etherhdr;
typedef struct Reseq	Reseq;
typedef struct Tcp	Tcp;
typedef struct Tcpctl	Tcpctl;
typedef struct Tcphdr	Tcphdr;
typedef struct Timer	Timer;
typedef struct Ilhdr	Ilhdr;
typedef struct Ilcb	Ilcb;
typedef struct Udphdr	Udphdr;

struct Etherhdr
{


@@ 94,40 94,40 @@ struct Ilhdr
	uchar	ilack[4];	/* Acked sequence */
};

struct Ilcb				/* Control block */
struct Ilcb			/* Control block */
{
	int	state;			/* Connection state */
	int	state;		/* Connection state */

	Rendez	syncer;			/* where syncer waits for a connect */
	Rendez	syncer;		/* where syncer waits for a connect */

	QLock	ackq;			/* Unacknowledged queue */
	QLock	ackq;		/* Unacknowledged queue */
	Block	*unacked;
	Block	*unackedtail;

	QLock	outo;			/* Out of order packet queue */
	QLock	outo;		/* Out of order packet queue */
	Block	*outoforder;

	Lock	nxl;
	ulong	next;			/* Id of next to send */
	ulong	recvd;			/* Last packet received */
	ulong	start;			/* Local start id */
	ulong	rstart;			/* Remote start id */

	int	timeout;		/* Time out counter */
	int	slowtime;		/* Slow time counter */
	int	fasttime;		/* Retransmission timer */
	int	acktime;		/* Acknowledge timer */
	int	querytime;		/* Query timer */
	int	deathtime;		/* Time to kill connection */

	int	rtt;			/* Average round trip time */
	ulong	rttack;			/* The ack we are waiting for */
	ulong	ackms;			/* Time we issued */

	int	window;			/* Maximum receive window */
	ulong	next;		/* Id of next to send */
	ulong	recvd;		/* Last packet received */
	ulong	start;		/* Local start id */
	ulong	rstart;		/* Remote start id */

	int	timeout;	/* Time out counter */
	int	slowtime;	/* Slow time counter */
	int	fasttime;	/* Retransmission timer */
	int	acktime;	/* Acknowledge timer */
	int	querytime;	/* Query timer */
	int	deathtime;	/* Time to kill connection */

	int	rtt;		/* Average round trip time */
	ulong	rttack;		/* The ack we are waiting for */
	ulong	ackms;		/* Time we issued */

	int	window;		/* Maximum receive window */
};

enum					/* Packet types */
enum				/* Packet types */
{
	Ilsync,
	Ildata,


@@ 138,7 138,7 @@ enum					/* Packet types */
	Ilclose,
};

enum					/* Connection state */
enum				/* Connection state */
{
	Ilclosed,
	Ilsyncer,


@@ 204,46 204,46 @@ struct Tctl
	uchar	type;		/* Listening or active connection */
	uchar	code;		/* Icmp code */		
	struct {
		int una;	/* Unacked data pointer */
		int nxt;	/* Next sequence expected */
		int ptr;	/* Data pointer */
		ushort wnd;	/* Tcp send window */
		int up;		/* Urgent data pointer */
		int wl1;
		int wl2;
		int	una;	/* Unacked data pointer */
		int	nxt;	/* Next sequence expected */
		int	ptr;	/* Data pointer */
		ushort	wnd;	/* Tcp send window */
		int	up;	/* Urgent data pointer */
		int	wl1;
		int	wl2;
	} snd;
	struct {
		int	nxt;
		ushort	wnd;
		int	up;
	} rcv;
	int	iss;
	ushort	cwind;
	ushort	ssthresh;
	int	resent;
	struct {
		int nxt;
		ushort wnd;
		int up;
	} rcv;
	int	irs;
	ushort	mss;
	int	rerecv;
	ushort	window;
	int	max_snd;
	int	last_ack;
	int	last_ack;	/* Last acknowledege received */
	char	backoff;
	char	flags;
	char	tos;
	char	flags;		/* State flags */
	char	tos;		/* Type of service */

	Blist	rcvq;
	Blist	rcvq;		/* Received data */
	ulong	rcvcnt;

	Block	*sndq;			/* List of data going out */
	ulong	sndcnt;			/* Amount of data in send queue */
	Block	*sndq;		/* List of data going out */
	ulong	sndcnt;		/* Amount of data in send queue */

	Reseq	*reseq;			/* Resequencing queue */
	Reseq	*reseq;		/* Resequencing queue */
	Timer	timer;			 
	Timer	acktimer;		/* Acknoledge timer */
	Timer	rtt_timer;		/* Round trip timer */
	int	rttseq;			/* Round trip sequence */
	int	srtt;			/* Shortened round trip */
	int	mdev;			/* Mean deviation of round trip */
	Timer	acktimer;	/* Acknoledge timer */
	Timer	rtt_timer;	/* Round trip timer */
	int	rttseq;		/* Round trip sequence */
	int	srtt;		/* Shortened round trip */
	int	mdev;		/* Mean deviation of round trip */
};

struct Tcpctl


@@ 277,77 277,77 @@ struct Reseq
/* An ip interface used for UDP/TCP/IL */
struct Ipconv
{
	QLock;				/* Ref count lock */
	Netprot;			/* stat info */
	QLock;			/* Ref count lock */
	Netprot;		/* stat info */
	int 	ref;
	Qinfo	*stproto;		/* Stream protocol for this device */
	Network	*net;			/* user level network interface */
	Ipaddr	dst;			/* Destination from connect */
	Port	psrc;			/* Source port */
	Port	pdst;			/* Destination port */

	Ipifc	*ipinterface;		/* Ip protocol interface */
	Queue	*readq;			/* Pointer to upstream read q */
	QLock	listenq;		/* List of people waiting incoming cons */
	Rendez	listenr;		/* Some where to sleep while waiting */
	Qinfo	*stproto;	/* Stream protocol for this device */
	Network	*net;		/* user level network interface */
	Ipaddr	dst;		/* Destination from connect */
	Port	psrc;		/* Source port */
	Port	pdst;		/* Destination port */

	Ipifc	*ipinterface;	/* Ip protocol interface */
	Queue	*readq;		/* Pointer to upstream read q */
	QLock	listenq;	/* List of people waiting incoming cons */
	Rendez	listenr;	/* Some where to sleep while waiting */
		
	char	*err;			/* Async protocol error */
	int	backlog;		/* Maximum number of waiting connections */
	int	curlog;			/* Number of waiting connections */
	Ipconv 	*newcon;		/* Flags that this is the start of a connection */
	char	*err;		/* Async protocol error */
	int	backlog;	/* Maximum number of waiting connections */
	int	curlog;		/* Number of waiting connections */
	Ipconv 	*newcon;	/* This is the start of a connection */

	union {
		Tcpctl	tcpctl;			/* Tcp control block */
		Ilcb	ilctl;			/* Il control block */
		Tcpctl	tcpctl;	/* Tcp control block */
		Ilcb	ilctl;	/* Il control block */
	};
};

#define	MAX_TIME	100000000	/* Forever */
#define TCP_ACK		200		/* Timed ack sequence every 200ms */

#define URG	0x20
#define ACK	0x10
#define PSH	0x08
#define RST	0x04
#define SYN	0x02
#define FIN	0x01

#define EOL_KIND	0
#define NOOP_KIND	1
#define MSS_KIND	2

#define MSS_LENGTH	4
#define MSL2		10
#define MSPTICK		100
#define DEF_MSS		1024
#define DEF_RTT		1000

#define TCP_PASSIVE	0
#define TCP_ACTIVE	1
#define IL_PASSIVE	0
#define IL_ACTIVE	1

#define MAXBACKOFF	5
#define FORCE		1
#define	CLONE		2
#define RETRAN		4
#define ACTIVE		8
#define SYNACK		16
#define AGAIN		8
#define DGAIN		4

#define TIMER_STOP	0
#define TIMER_RUN	1
#define TIMER_EXPIRE	2

#define Nreseq		128
enum {
	MAX_TIME 	= (1<<20),/* Forever */
	TCP_ACK		= 200,	/* Timed ack sequence every 200ms */

	URG		= 0x20,	/* Data marked urgent */
	ACK		= 0x10,	/* Aknowledge is valid */
	PSH		= 0x08,	/* Whole data pipe is pushed */
	RST		= 0x04,	/* Reset connection */
	SYN		= 0x02,	/* Pkt. is synchronise */
	FIN		= 0x01,	/* Start close down */

	EOL_KIND	= 0,
	NOOP_KIND	= 1,
	MSS_KIND	= 2,

	MSS_LENGTH	= 4,	/* Mean segment size */
	MSL2		= 10,
	MSPTICK		= 100,	/* Milliseconds per timer tick */
	DEF_MSS		= 1024,	/* Default mean segment */
	DEF_RTT		= 1000,	/* Default round trip */

	TCP_PASSIVE	= 0,	/* Listen connection */
	TCP_ACTIVE	= 1,	/* Outgoing connection */
	IL_PASSIVE	= 0,
	IL_ACTIVE	= 1,

	MAXBACKOFF	= 5,
	FORCE		= 1,
	CLONE		= 2,
	RETRAN		= 4,
	ACTIVE		= 8,
	SYNACK		= 16,
	AGAIN		= 8,
	DGAIN		= 4,

	TIMER_STOP	= 0,
	TIMER_RUN	= 1,
	TIMER_EXPIRE	= 2,
};

#define	set_timer(t,x)	(((t)->start) = (x)/MSPTICK)
#define	run_timer(t)	((t)->state == TIMER_RUN)

enum					/* Tcp connection states */
enum				/* Tcp connection states */
{
	Closed = 0,
	Closed		= 0,
	Listen,
	Syn_sent,
	Syn_received,


@@ 395,111 395,100 @@ struct Ipfrag
	ushort	flen;
};

#define IP_VER	0x40			/* Using IP version 4 */
#define IP_HLEN 0x05			/* Header length in characters */
#define IP_DF	0x4000			/* Don't fragment */
#define IP_MF	0x2000			/* More fragments */

#define	ICMP_ECHOREPLY		0	/* Echo Reply */
#define	ICMP_UNREACH		3	/* Destination Unreachable */
#define	ICMP_SOURCEQUENCH	4	/* Source Quench */
#define	ICMP_REDIRECT		5	/* Redirect */
#define	ICMP_ECHO		8	/* Echo Request */
#define	ICMP_TIMXCEED		11	/* Time-to-live Exceeded */
#define	ICMP_PARAMPROB		12	/* Parameter Problem */
#define	ICMP_TSTAMP		13	/* Timestamp */
#define	ICMP_TSTAMPREPLY	14	/* Timestamp Reply */
#define	ICMP_IREQ		15	/* Information Request */
#define	ICMP_IREQREPLY		16	/* Information Reply */

/* Sizes */
#define IP_MAX		(32*1024)		/* Maximum Internet packet size */
#define UDP_MAX		(IP_MAX-ETHER_IPHDR)	/* Maximum UDP datagram size */
#define UDP_DATMAX	(UDP_MAX-UDP_HDRSIZE)	/* Maximum amount of udp data */
#define IL_DATMAX	(IP_MAX-IL_HDRSIZE)	/* Maximum IL data in one ip packet */

/* Protocol numbers */
#define IP_UDPPROTO	17
#define IP_TCPPROTO	6
#define	IP_ILPROTO	40

/* Protocol port numbers */
#define PORTALLOC	5000		/* First automatic allocated port */
#define PRIVPORTALLOC	600		/* First priveleged port allocated */
#define PORTMAX		30000		/* Last port to allocte */

/* IP function declarations */
Ipifc   *newipifc(uchar, void (*)(Ipconv *, Block*), Ipconv *, int, int, int, char*);
enum {
	IP_VER		= 0x40,			/* Using IP version 4 */
	IP_HLEN		= 0x05,			/* Header length in characters */
	IP_DF		= 0x4000,		/* Don't fragment */
	IP_MF		= 0x2000,		/* More fragments */

	/* Sizes */
	IP_MAX		= (32*1024),		/* Maximum Internet packet size */
	UDP_MAX		= (IP_MAX-ETHER_IPHDR),	/* Maximum UDP datagram size */
	UDP_DATMAX	= (UDP_MAX-UDP_HDRSIZE),/* Maximum amount of udp data */
	IL_DATMAX	= (IP_MAX-IL_HDRSIZE),	/* Maximum IL data in one ip packet */

	/* Protocol numbers */
	IP_UDPPROTO	= 17,
	IP_TCPPROTO	= 6,
	IP_ILPROTO	= 40,

	/* Protocol port numbers */
	PORTALLOC	= 5000,			/* First automatic allocated port */
	PRIVPORTALLOC	= 600,			/* First priveleged port allocated */
	PORTMAX		= 30000,		/* Last port to allocte */
};

void	add_reseq(Tcpctl *, char, Tcp *, Block *, ushort);
int	arp_lookup(uchar*, uchar*);
int	backoff(int);
Block*	btrim(Block*, int, int);
void	close_self(Ipconv *, char []);
void	closeipifc(Ipifc*);
int	dupb(Block **, Block *, int, int);
void	extract_oob(Block **, Block **, Tcp *);
void	get_reseq(Tcpctl *, char *, Tcp *, Block **, ushort *);
void	hnputl(uchar*, ulong);
void	hnputs(uchar*, ushort);
Block*	htontcp(Tcp *, Block *, Tcphdr *);
Block*	htontcp(Tcp *, Block *, Tcphdr *);
void	iloutoforder(Ipconv*, Ilhdr*, Block*);
void	ilstart(Ipconv *, int, int);
int	inb_window(Tcpctl *, int);
void	init_tcpctl(Ipconv *);
void	initfrag(int);
Ipconv*	ip_conn(Ipconv *, Port, Port, Ipaddr dest, char proto);
ushort	ip_csum(uchar*);
int	arp_lookup(uchar*, uchar*);
Block*	ip_reassemble(int, Block*, Etherhdr*);
int	ipclonecon(Chan *);
int	ipconbusy(Ipconv*);
int	ipforme(uchar*);
Fragq*	ipfragallo(void);
void	ipfragfree(Fragq*, int);
Ipconv*	ipincoming(Ipconv*, Ipconv*);
int	iplisten(Chan *);
void	iplocalfill(Chan*, char*, int);
void	ipmkdir(Qinfo *, Dirtab *, Ipconv *);
Ipaddr	ipparse(char*);
void	hnputs(uchar*, ushort);
void	hnputl(uchar*, ulong);
void	ipremotefill(Chan*, char*, int);
void	iproute(uchar*, uchar*);
void	ipsetaddrs(void);
void	ipstatusfill(Chan*, char*, int);
Ipifc*	newipifc(uchar, void (*)(Ipconv *, Block*), Ipconv *, int, int, int, char*);
Port	nextport(Ipconv *, int);
ulong	nhgetl(uchar*);
ushort	nhgets(uchar*);
ushort	ptcl_csum(Block*bp, int, int);
void	ppkt(Block*);
void	udprcvmsg(Ipconv *, Block*);
Block	*btrim(Block*, int, int);
Block	*ip_reassemble(int, Block*, Etherhdr*);
Ipconv	*portused(Ipconv *, Port);
Port	nextport(Ipconv *, int);
Fragq   *ipfragallo(void);
void	ipfragfree(Fragq*, int);
void	iproute(uchar*, uchar*);
void	initfrag(int);
int	ntohtcp(Tcp *, Block **);
int	ntohtcp(Tcp*, Block**);
void	reset(Ipaddr, Ipaddr, char, ushort, Tcp*);
Ipconv*	portused(Ipconv *, Port);
void	ppkt(Block*);
void	proc_syn(Ipconv*, char, Tcp*);
ushort	ptcl_csum(Block*bp, int, int);
int	pullb(Block **, int);
void	reset(Ipaddr, Ipaddr, char, ushort, Tcp*);
void	send_syn(Tcpctl*);
void	tcp_output(Ipconv*);
int	seq_within(int, int, int);
void	update(Ipconv *, Tcp *);
int	trim(Tcpctl *, Tcp *, Block **, ushort *);
void	add_reseq(Tcpctl *, char, Tcp *, Block *, ushort);
void	close_self(Ipconv *, char []);
int	seq_ge(int, int);
int	seq_gt(int, int);
Ipconv	*ip_conn(Ipconv *, Port, Port, Ipaddr dest, char proto);
void	ipmkdir(Qinfo *, Dirtab *, Ipconv *);
Ipconv	*ipincoming(Ipconv*, Ipconv*);
int	inb_window(Tcpctl *, int);
Block	*htontcp(Tcp *, Block *, Tcphdr *);
void	start_timer(Timer *);
void	stop_timer(Timer *);
int	pullb(Block **, int);
void	init_tcpctl(Ipconv *);
int	seq_within(int, int, int);
int	seq_lt(int, int);
int	seq_le(int, int);
int	seq_gt(int, int);
int	seq_ge(int, int);
int	seq_le(int, int);
int	seq_lt(int, int);
int	seq_within(int, int, int);
int	seq_within(int, int, int);
void	setstate(Ipconv *, char);
void	tcpackproc(void*);
Block 	*htontcp(Tcp *, Block *, Tcphdr *);
int	ntohtcp(Tcp *, Block **);
void	extract_oob(Block **, Block **, Tcp *);
void	get_reseq(Tcpctl *, char *, Tcp *, Block **, ushort *);
void	start_timer(Timer *);
void	state_upcall(Ipconv*, char oldstate, char newstate);
int	backoff(int);
int	dupb(Block **, Block *, int, int);
void	stop_timer(Timer *);
void	tcp_acktimer(void *);
void	tcp_input(Ipconv *, Block *);
void 	tcprcvwin(Ipconv *);
void	tcpstart(Ipconv *, int, ushort, char);
void	ilstart(Ipconv *, int, int);
void	tcp_output(Ipconv*);
void	tcp_timeout(void *);
void	tcpackproc(void*);
void	tcpflow(void*);
void 	tcp_timeout(void *);
void	tcp_acktimer(void *);
int	ipclonecon(Chan *);
int	iplisten(Chan *);
void	iloutoforder(Ipconv*, Ilhdr*, Block*);
void	iplocalfill(Chan*, char*, int);
void	ipremotefill(Chan*, char*, int);
void	ipstatusfill(Chan*, char*, int);
int	ipforme(uchar*);
void	ipsetaddrs(void);
int	ipconbusy(Ipconv*);
void	tcpflushincoming(Ipconv*);
void	tcprcvwin(Ipconv *);
void	tcpstart(Ipconv *, int, ushort, char);
int	trim(Tcpctl *, Tcp *, Block **, ushort *);
void	udprcvmsg(Ipconv *, Block*);
void	update(Ipconv *, Tcp *);

#define	fmtaddr(xx)	(xx>>24)&0xff,(xx>>16)&0xff,(xx>>8)&0xff,xx&0xff
#define	MIN(a, b)	((a) < (b) ? (a) : (b))


@@ 508,8 497,6 @@ void	tcpflushincoming(Ipconv*);
#define BLKFRAG(xp)	((Ipfrag *)((xp)->base))
#define PREC(x)		((x)>>5 & 7)

#define WORKBUF		64

extern Ipaddr Myip[7];
extern Ipaddr Mymask;
extern Ipaddr Mynetmask;


@@ 528,8 515,8 @@ extern Queue *Ipoutput;
/* offsets into Myip */
enum
{
	Myself=		0,
	Mybcast=	1,
	Mynet=		3,
	Mysubnet=	5,
	Myself		= 0,
	Mybcast		= 1,
	Mynet		= 3,
	Mysubnet	= 5,
};

M port/net.c => port/net.c +5 -2
@@ 65,6 65,8 @@ netgen(Chan *c, void *vp, int ntab, int i, Dir *dp)
			q.path = Qclone;
			devdir(c, q, "clone", 0, eve, 0666, dp);
		}else if(i <= np->nconv){
			if(findprot(np, i-1) == 0)
				return 0;
			q.path = CHDIR|STREAMQID(i-1, Q3rd);
			sprint(buf, "%d", i-1);
			devdir(c, q, buf, 0, eve, 0555, dp);


@@ 75,7 77,9 @@ netgen(Chan *c, void *vp, int ntab, int i, Dir *dp)

	/* third level depends on the number of info files */
	p = findprot(np, STREAMID(c->qid.path));
	if(p && *p->owner){
	if(p == 0)
		return 0;
	if(*p->owner){
		o = p->owner;
		perm = p->mode;
	} else {


@@ 215,7 219,6 @@ netopen(Chan *c, int omode, Network *np)
			if(np->protop && c->stream->devq->next->info != np->protop)
				pushq(c->stream, np->protop);
			p = findprot(np, id);
if(p == 0) print("netopen: can't find %d\n", id);
			if(netown(p, u->p->user, omode&7) < 0)
				error(Eperm);
			break;

M port/page.c => port/page.c +32 -61
@@ 101,7 101,7 @@ newpage(int clear, Segment **s, ulong va)
	palloc.freecount--;
	unlock(&palloc);

	lockpage(p);
	lock(p);

	if(p->ref != 0)
		panic("newpage");


@@ 112,7 112,7 @@ newpage(int clear, Segment **s, ulong va)
	p->modref = 0;
	for(i = 0; i < MAXMACH; i++)
		p->cachectl[i] = PG_NOFLUSH;
	unlockpage(p);
	unlock(p);

	if(clear){
		k = kmap(p);


@@ 138,7 138,7 @@ putpage(Page *p)
		return;
	}

	lockpage(p);
	lock(p);
	if(--p->ref == 0) {
		lock(&palloc);
		if(p->image && p->image != &swapimage) {


@@ 169,7 169,7 @@ putpage(Page *p)
		palloc.freecount++;		/* Release people waiting for memory */
		unlock(&palloc);
	}
	unlockpage(p);
	unlock(p);
}

void


@@ 177,16 177,15 @@ simpleputpage(Page *pg)			/* Always call with palloc locked */
{
	pg->ref = 0;
	palloc.freecount++;
	if(palloc.head) {
		pg->next = palloc.head;
		palloc.head->prev = pg;
		pg->prev = 0;
		palloc.head = pg;
	}
	else {
	if(palloc.head == 0) {
		palloc.head = palloc.tail = pg;
		pg->prev = pg->next = 0;
		return;
	}
	pg->next = palloc.head;
	palloc.head->prev = pg;
	pg->prev = 0;
	palloc.head = pg;
}

void


@@ 223,10 222,10 @@ duppage(Page *p)				/* Always call with p locked */

	unlock(&palloc);

	lockpage(np);				/* Cache the new version */
	lock(np);				/* Cache the new version */
	if(np->ref != 0) {			/* Stolen by new page */
		uncachepage(p);
		unlockpage(np);
		unlock(np);
		return;
	}
	


@@ 235,7 234,7 @@ duppage(Page *p)				/* Always call with p locked */
	np->daddr = p->daddr;
	copypage(p, np);
	cachepage(np, p->image);
	unlockpage(np);
	unlock(np);
	uncachepage(p);
}



@@ 256,20 255,21 @@ uncachepage(Page *p)				/* Always called with a locked page */
{
	Page **l, *f;

	if(p->image) {
		lock(&palloc.hashlock);
		l = &pghash(p);
		for(f = *l; f; f = f->hash) {
			if(f == p) {
				*l = p->hash;
				break;
			}
			l = &f->hash;
	if(p->image == 0)
		return;

	lock(&palloc.hashlock);
	l = &pghash(p);
	for(f = *l; f; f = f->hash) {
		if(f == p) {
			*l = p->hash;
			break;
		}
		unlock(&palloc.hashlock);
		putimage(p->image);
		p->image = 0;
		l = &f->hash;
	}
	unlock(&palloc.hashlock);
	putimage(p->image);
	p->image = 0;
}

void


@@ 296,9 296,9 @@ lookpage(Image *i, ulong daddr)
		if(f->image == i && f->daddr == daddr) {
			unlock(&palloc.hashlock);

			lockpage(f);
			lock(f);
			if(f->image != i || f->daddr != daddr) {
				unlockpage(f);
				unlock(f);
				return 0;
			}



@@ 317,7 317,7 @@ lookpage(Image *i, ulong daddr)
			}
			unlock(&palloc);

			unlockpage(f);
			unlock(f);
			return f;	
		}
	}


@@ 328,8 328,8 @@ lookpage(Image *i, ulong daddr)
Pte*
ptecpy(Pte *old)
{
	Page **src, **dst, **end;
	Pte *new;
	Page **src, **dst, **end;

	new = ptealloc();
	dst = &new->pages[old->first-old->pages];


@@ 339,9 339,9 @@ ptecpy(Pte *old)
			if(onswap(*src))
				dupswap(*src);
			else {
				lockpage(*src);
				lock(*src);
				(*src)->ref++;
				unlockpage(*src);
				unlock(*src);
			}
			new->last = dst;
			*dst = *src;


@@ 384,32 384,3 @@ freepte(Segment *s, Pte *p)
	}
	free(p);
}

/* Multiplex a hardware lock for per page manipulations */
void
lockpage(Page *p)
{	
	int s;

	for(;;) {
		if(p->lock == 0) {
			s = splhi();
			lock(&pglock);
			if(p->lock == 0) {
				p->lock = 1;
				unlock(&pglock);
				splx(s);
				return;
			}
			unlock(&pglock);
			splx(s);
		}
		sched();
	}
}

void
unlockpage(Page *p)
{
	p->lock = 0;
}

M port/pgrp.c => port/pgrp.c +0 -40
@@ 115,23 115,6 @@ closepgrp(Pgrp *p)
}

void
closeegrp(Egrp *eg)
{
	Evalue *e, *next;

	if(decref(eg) == 0) {
		for(e = eg->entries; e; e = next) {
			next = e->link;
			free(e->name);
			if(e->value)
				free(e->value);
			free(e);
		}
		free(eg);
	}
}

void
closefgrp(Fgrp *f)
{
	int i;


@@ 161,29 144,6 @@ newmount(Mhead *mh, Chan *to)
}

void
envcpy(Egrp *to, Egrp *from)
{
	Evalue **l, *ne, *e;

	l = &to->entries;
	qlock(from);
	for(e = from->entries; e; e = e->link) {
		ne = smalloc(sizeof(Evalue));
		ne->name = smalloc(strlen(e->name)+1);
		strcpy(ne->name, e->name);
		if(e->value) {
			ne->value = smalloc(e->len);
			memmove(ne->value, e->value, e->len);
			ne->len = e->len;
		}
		ne->path = ++to->path;
		*l = ne;
		l = &ne->link;
	}
	qunlock(from);
}

void
pgrpcpy(Pgrp *to, Pgrp *from)
{
	Mhead **h, **e, *f, **tom, **l, *mh;

M port/portdat.h => port/portdat.h +64 -67
@@ 32,11 32,16 @@ typedef struct Queue	Queue;
typedef struct Ref	Ref;
typedef struct Rendez	Rendez;
typedef struct RWlock	RWlock;
typedef struct Sargs	Sargs;
typedef struct Segment	Segment;
typedef struct Stream	Stream;
typedef struct Talarm	Talarm;
typedef struct Waitq	Waitq;
typedef int    Devgen(Chan*, Dirtab*, int, int, Dir*);
typedef	void   Streamput(Queue*, Block*);
typedef	void   Streamopen(Queue*, Stream*);
typedef	void   Streamclose(Queue*);
typedef	void   Streamreset(void);

#include "fcall.h"



@@ 80,6 85,12 @@ struct Alarms
	Proc	*head;
};

#define MAXSYSARG	5		/* for mount(fd, mpt, flag, arg, srv) */
struct Sargs
{
	ulong	args[MAXSYSARG];
};

/* Block.flags */
#define S_DELIM 0x80
#define S_CLASS 0x07


@@ 238,11 249,6 @@ struct KIOQ
	int	count;
};

extern IOQ	lineq;
extern IOQ	printq;
extern IOQ	mouseq;
extern KIOQ	kbdq;

struct Mount
{
	ulong	mountid;


@@ 271,16 277,18 @@ struct Note
	int	flag;			/* whether system posted it */
};

/* Fields for cache control of pages */
#define	PG_NOFLUSH	0
#define PG_TXTFLUSH	1
#define PG_DATFLUSH	2
/* Simulated modified and referenced bits */
#define PG_MOD		0x01
#define PG_REF		0x02
enum
{
	PG_NOFLUSH	= 0,		/* Fields for cache control of pages */
	PG_TXTFLUSH	= 1,
	PG_DATFLUSH	= 2,
	PG_MOD		= 0x01,		/* Simulated modified and referenced bits */
	PG_REF		= 0x02,
};

struct Page
{
	Lock;
	ulong	pa;			/* Physical address in memory */
	ulong	va;			/* Virtual address for user */
	ulong	daddr;			/* Disc address on swap */


@@ 328,17 336,19 @@ struct Pte
};

/* Segment types */
#define SG_TYPE		07		/* Mask type of segment */
#define SG_TEXT		00
#define SG_DATA		01
#define SG_BSS		02
#define SG_STACK	03
#define SG_SHARED	04
#define SG_PHYSICAL	05
#define SG_SHDATA	06

/* Segment flags */
#define SG_RONLY	040			/* Segment is read only */
enum
{
	SG_TYPE		= 07,		/* Mask type of segment */
	SG_TEXT		= 00,
	SG_DATA		= 01,
	SG_BSS		= 02,
	SG_STACK	= 03,
	SG_SHARED	= 04,
	SG_PHYSICAL	= 05,
	SG_SHDATA	= 06,

	SG_RONLY	= 040,		/* Segment is read only */
};

#define PG_ONSWAP	1
#define pagedout(s)	(((ulong)s)==0 || (((ulong)s)&PG_ONSWAP))


@@ 464,12 474,9 @@ enum
	SSEG, TSEG, DSEG, BSEG, ESEG, LSEG, SEG1, SEG2, NSEG
};

/*
 * Process states
 */
enum
{
	Dead = 0,
	Dead = 0,		/* Process states */
	Moribund,
	Ready,
	Scheding,


@@ 479,24 486,12 @@ enum
	Broken,
	Stopped,
	Rendezvous,
};

/*
 * devproc requests
 */
enum
{
	Proc_stopme = 1,
	Proc_exitme = 2,
	Proc_traceme = 3,
};
	Proc_stopme = 1, 	/* devproc requests */
	Proc_exitme,
	Proc_traceme,

/*
 * Proc.time
 */
enum
{
	TUser,
	TUser = 0, 		/* Proc.time */
	TSys,
	TReal,
	TCUser,


@@ 573,14 568,14 @@ struct Proc
 */
struct Qinfo
{
	void (*iput)(Queue*, Block*);	/* input routine */
	void (*oput)(Queue*, Block*);	/* output routine */
	void (*open)(Queue*, Stream*);
	void (*close)(Queue*);
	char *name;
	void (*reset)(void);		/* initialization */
	char nodelim;			/* True if stream does not preserve delimiters */
	Qinfo *next;
	Streamput	*iput;		/* input routine */
	Streamput	*oput;		/* output routine */
	Streamopen	*open;
	Streamclose	*close;
	char		*name;
	Streamreset	*reset;		/* initialization */
	char		nodelim;	/* True if stream does not preserve delimiters */
	Qinfo		*next;
};

/*


@@ 678,30 673,30 @@ struct Network
	Netinf	info[5];
	Netprot	*prot;			/* linked list of protections */
};
#define MAJOR(q) ((q) >> 8)
#define MINOR(q) ((q) & 0xff)
#define DEVICE(a,i) (((a)<<8) | (i))

#define MAXSYSARG	5		/* for mount(fd, mpt, flag, arg, srv) */
#define	PRINTSIZE	256
#define	NUMSIZE		12		/* size of formatted number */

extern	FPsave	initfp;
extern	Conf	conf;
extern	ulong	initcode[];
extern	char*	conffile;
extern	int	cpuserver;
extern	char*	devchar;
extern	Dev	devtab[];
extern	char	*devchar;
extern	char	*conffile;
extern	char	*statename[];
extern	Palloc 	palloc;
extern	Pgrps 	pgrpalloc;
extern  Image	swapimage;
extern  char	eve[];
extern	ulong	initcode[];
extern	FPsave	initfp;
extern  KIOQ	kbdq;
extern  IOQ	lineq;
extern  IOQ	mouseq;
extern  Ref	noteidalloc;
extern	int	nrdy;
extern  IOQ	printq;
extern	char*	statename[];
extern  Image	swapimage;
extern	char	sysname[NAMELEN];
extern	int	cpuserver;
extern  Ref	noteidalloc;
extern	Talarm	talarm;
extern	Palloc 	palloc;
extern	Pgrps 	pgrpalloc;

#define	CHDIR		0x80000000L
#define	CHAPPEND 	0x40000000L


@@ 710,8 705,8 @@ extern	Talarm	talarm;
/*
 * auth messages
 */
#define AUTHLEN		8
enum{
enum
{
	FScchal	= 1,
	FSschal,
	FSok,


@@ 721,4 716,6 @@ enum{

	RXschal	= 0,
	RXstick	= 1,

	AUTHLEN	= 8,
};

M port/portfns.h => port/portfns.h +1 -3
@@ 99,7 99,6 @@ 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);


@@ 221,7 220,7 @@ 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		naildownstream(Stream*);
void		swapinit(void);
long		syscall(Ureg*);
void		tsleep(Rendez*, int (*)(void*), void*, int);


@@ 229,7 228,6 @@ 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);

M port/segment.c => port/segment.c +10 -12
@@ 15,15 15,14 @@ void imagereclaim(void);

#define IHASHSIZE	64
#define ihash(s)	imagealloc.hash[s%IHASHSIZE]
struct Imagealloc
struct
{
	Lock;
	Image	*free;
	Image	*hash[IHASHSIZE];
	QLock	ireclaim;
}imagealloc;

static QLock ireclaim;

void
initseg(void)
{


@@ 254,29 253,28 @@ imagereclaim(void)
{
	Page *p;

	if(!canqlock(&ireclaim))	/* Somebody is already cleaning the page cache */
	/* Somebody is already cleaning the page cache */
	if(!canqlock(&imagealloc.ireclaim))
		return;

	lock(&palloc);
	for(p = palloc.head; p; p = p->next) {
		if(p->image)
		if(p->ref == 0)
		if(p->image != &swapimage) {
			lockpage(p);
		if(p->image && p->ref == 0 && p->image != &swapimage) {
			lock(p);
			if(p->ref == 0)
				uncachepage(p);
			unlockpage(p);
			unlock(p);
		}
	}
	unlock(&palloc);
	qunlock(&ireclaim);
	qunlock(&imagealloc.ireclaim);
}

void
putimage(Image *i)
{
	Image *f, **l;
	Chan *c;
	Image *f, **l;

	if(i == &swapimage)
		return;


@@ 301,7 299,7 @@ putimage(Image *i)
		imagealloc.free = i;
		unlock(&imagealloc);

		close(c);		/* Delay close because we could error */
		close(c);
		return;
	}
	unlock(i);

M port/stream.c => port/stream.c +36 -43
@@ 275,7 275,7 @@ copyb(Block *bp, int count)
/*
 *  process end line discipline
 */
static void stputq(Queue*, Block*);
static Streamput stputq;
Qinfo procinfo =
{
	stputq,


@@ 626,15 626,6 @@ static Sthash ht[Nhash];

static void	hangup(Stream*);

void
streaminit(void)
{
	/*
	 *  make stream modules available
	 */
	streaminit0();
}

/*
 *  A stream device consists of the contents of streamdir plus
 *  any directory supplied by the actual device.


@@ 835,6 826,16 @@ streamexit(Stream *s, int locked)
}

/*
 *  nail down a stream so that it can't be closed
 */
void
naildownstream(Stream *s)
{
	s->opens++;
	s->inuse++;
}

/*
 *  Decrement the open count.  When it goes to zero, call the close
 *  routines for each queue in the stream.
 */


@@ 902,7 903,7 @@ streamclose(Chan *c)
void
stputq(Queue *q, Block *bp)
{
	int delim;
	int awaken;
	Stream *s;

	if(bp->type == M_HANGUP){


@@ 914,7 915,7 @@ stputq(Queue *q, Block *bp)
		q->flag |= QHUNGUP;
		q->other->flag |= QHUNGUP;
		wakeup(q->other->rp);
		delim = 1;
		awaken = 1;
	} else {
		lock(q);
		if(q->first)


@@ 923,21 924,21 @@ stputq(Queue *q, Block *bp)
			q->first = bp;
		q->len += BLEN(bp);
		q->nb++;
		delim = bp->flags & S_DELIM;
		awaken = bp->flags & S_DELIM;
		while(bp->next) {
			bp = bp->next;
			q->len += BLEN(bp);
			q->nb++;
			delim |= bp->flags & S_DELIM;
			awaken |= bp->flags & S_DELIM;
		}
		q->last = bp;
		if(q->len >= Streamhi || q->nb >= Streambhi){
			q->flag |= QHIWAT;
			delim = 1;
			awaken = 1;
		}
		unlock(q);
	}
	if(delim)
	if(awaken)
		wakeup(q->rp);
}



@@ 1177,7 1178,8 @@ streamwrite(Chan *c, void *a, long n, int docopy)
	Queue *q;
	long rem;
	int i;
	Block *bp, *first, *last;
	Block *bp;
	char *va;

	s = c->stream;



@@ 1199,32 1201,28 @@ streamwrite(Chan *c, void *a, long n, int docopy)
	}

	/*
	 *  copy the whole write into kernel space
	 *  Write the message using blocks <= Streamhi bytes longs
	 */
	first = last = 0;
	for(rem = n; ; rem -= i) {
		bp = allocb(rem);
		i = bp->lim - bp->wptr;
		if(i >= rem)
	va = a;
	rem = n;
	for(;;){
		if(rem > Streamhi)
			i = Streamhi;
		else
			i = rem;
		memmove(bp->wptr, a, i);
		bp = allocb(i);
		memmove(bp->wptr, va, i);
		bp->wptr += i;
		bp->type = M_DATA;
		a = ((char*)a) + i;
		if(first == 0)
			first = bp;
		else
			last->next = bp;
		last = bp;
		if(i == rem)
		va += i;
		rem -= i;
		if(rem > 0){
			FLOWCTL(q, bp);
		} else {
			bp->flags |= S_DELIM;
			FLOWCTL(q, bp);
			break;
		}
	}

	/*
	 *  send it down stream
	 */
	last->flags |= S_DELIM;
	FLOWCTL(q, first);
	return n;
}



@@ 1323,8 1321,3 @@ getfields(char *lp, char **fields, int n, char sep)
	}
	return i;
}

void
dumpqueues(void)
{
}

M port/swap.c => port/swap.c +4 -4
@@ 264,10 264,10 @@ pagepte(int type, Segment *s, Page **pg)
	case SG_STACK:
	case SG_SHARED:
	case SG_SHDATA:
		lockpage(outp);
		lock(outp);
		outp->ref++;
		uncachepage(outp);
		unlockpage(outp);
		unlock(outp);

		daddr = newswap();
		outp->daddr = daddr;


@@ 314,9 314,9 @@ executeio(void)
		poperror();

		/* Free up the page after I/O */
		lockpage(out);
		lock(out);
		out->ref--;
		unlockpage(out);
		unlock(out);
		putpage(out);
	}
	ioptr = 0;

M power/dat.h => power/dat.h +1 -1
@@ 51,7 51,6 @@ struct Conf
	ulong	arp;		/* Arp table size */
	ulong	frag;		/* Ip fragment assemble queue size */
	ulong	cntrlp;		/* panic on ^P */
	ulong	dkif;		/* number of datakit interfaces */
};

/*


@@ 185,6 184,7 @@ struct User
	char	elem[NAMELEN];		/* last name element from namec */
	Chan	*slash;
	Chan	*dot;
	Sargs	s;
	/*
	 * Rest of structure controlled by devproc.c and friends.
	 * qlock(&p->debug) to modify.

M power/main.c => power/main.c +4 -3
@@ 222,8 222,10 @@ userinit(void)

	p = newproc();
	p->pgrp = newpgrp();
	p->egrp = newegrp();
	p->fgrp = newfgrp();
	p->egrp = smalloc(sizeof(Egrp));
	p->egrp->ref = 1;
	p->fgrp = smalloc(sizeof(Fgrp));
	p->fgrp->ref = 1;
	p->procmode = 0640;

	strcpy(p->text, "*init*");


@@ 537,7 539,6 @@ confinit(void)
	conf.nproc = 100;
	conf.nswap = 262144;
	conf.nimage = 200;
	conf.dkif = 1;
	conf.ipif = 8;
	conf.ip = 64;
	conf.arp = 32;

M power/trap.c => power/trap.c +14 -12
@@ 497,7 497,6 @@ syscall(Ureg *aur)
	ulong sp;
	ulong r1;
	Ureg *ur;
	char *msg;
	Proc *p;

	m->syscall++;


@@ 524,22 523,25 @@ syscall(Ureg *aur)
	u->nerrlab = 0;
	ret = -1;
	if(!waserror()){
		if(r1 >= sizeof systab/sizeof systab[0]){
			pprint("bad sys call number %d pc %lux\n", r1, ((Ureg*)UREGADDR)->pc);
			msg = "sys: bad sys call";
	    Bad:
			postnote(p, 1, msg, NDebug);
		if(r1 >= sizeof systab/sizeof systab[0]) {
			pprint("bad sys call number %d pc %lux\n", r1, ur->pc);
			postnote(p, 1, "sys: bad sys call", NDebug);
			error(Ebadarg);
		}

		if(sp & (BY2WD-1)){
			pprint("odd sp in sys call pc %lux sp %lux\n", ((Ureg*)UREGADDR)->pc, ((Ureg*)UREGADDR)->sp);
			msg = "sys: odd stack";
			goto Bad;
			pprint("odd sp in sys call pc %lux sp %lux\n", ur->pc, ur->sp);
			postnote(p, 1, "sys: odd stack", NDebug);
			error(Ebadarg);
		}
		if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-(1+MAXSYSARG)*BY2WD))
			validaddr(sp, (1+MAXSYSARG)*BY2WD, 0);

		if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)))
			validaddr(sp, sizeof(Sargs), 0);

		u->s = *((Sargs*)(sp+BY2WD));
		p->psstate = sysctab[r1];
		ret = (*systab[r1])((ulong*)(sp+BY2WD));

		ret = (*systab[r1])(u->s.args);
	}
	ur->pc += 4;
	u->nerrlab = 0;

M ss/dat.h => ss/dat.h +1 -3
@@ 67,15 67,12 @@ struct Conf
	ulong	nimage;		/* number of page cache image headers */
	ulong	nswap;		/* number of swap blocks */
	ulong	upages;		/* number of user pages */
	int	nurp;		/* max urp conversations */
	int	nasync;		/* number of async protocol modules */
	int	copymode;	/* 0 is copy on write, 1 is copy on reference */
	ulong	ipif;		/* Ip protocol interfaces */
	ulong	ip;		/* Ip conversations per interface */
	ulong	arp;		/* Arp table size */
	ulong	frag;		/* Ip fragment assemble queue size */
	int	cntrlp;		/* panic on ^P */
	int	dkif;		/* number of datakit interfaces */
};

/*


@@ 140,6 137,7 @@ struct User
	char	elem[NAMELEN];		/* last name element from namec */
	Chan	*slash;
	Chan	*dot;
	Sargs	s;
	/*
	 * Rest of structure controlled by devproc.c and friends.
	 * lock(&p->debug) to modify.

M ss/main.c => ss/main.c +0 -1
@@ 218,7 218,6 @@ confinit(void)
	conf.arp = 32;
	conf.frag = 32;
	conf.cntrlp = 0;
	conf.dkif = 1;
}

/*

M ss/trap.c => ss/trap.c +10 -8
@@ 351,7 351,6 @@ syscall(Ureg *aur)
	ulong sp;
	ulong r7;
	Ureg *ur;
	char *msg;

	ur = aur;
	if(ur->psr & PSRPSUPER)


@@ 377,20 376,23 @@ syscall(Ureg *aur)
	if(!waserror()){
		if(r7 >= sizeof systab/BY2WD){
			pprint("bad sys call number %d pc %lux\n", r7, ur->pc);
			msg = "sys: bad sys call";
			postnote(u->p, 1, msg, NDebug);
			postnote(u->p, 1, "sys: bad sys call", NDebug);
			error(Ebadarg);
		}

		if(sp & (BY2WD-1)){
			pprint("odd sp in sys call pc %lux sp %lux\n", ur->pc, ur->sp);
			msg = "sys: odd stack";
			postnote(u->p, 1, msg, NDebug);
			postnote(u->p, 1, "sys: odd stack", NDebug);
			error(Ebadarg);
		}
		if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-(1+MAXSYSARG)*BY2WD))
			validaddr(sp, ((1+MAXSYSARG)*BY2WD), 0);

		if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)))
			validaddr(sp, sizeof(Sargs), 0);

		u->s = *((Sargs*)(sp+1*BY2WD));
		u->p->psstate = sysctab[r7];
		ret = (*systab[r7])((ulong*)(sp+1*BY2WD));

		ret = (*systab[r7])(u->s.args);
		poperror();
	}