~kris/9p

9hist

12762acd8943f4b34c08c087f2d2bf8fdf89ae4a — David du Colombier 35 years ago 1a3a798
Plan 9 from Bell Labs 1991-06-08
M gnot/dat.h => gnot/dat.h +1 -0
@@ 103,6 103,7 @@ struct Conf
	ulong	maxialloc;	/* maximum bytes used by ialloc */
	int	copymode;	/* 0 is copy on write, 1 is copy on reference */
	int	portispaged;	/* ??? */
	int	cntrlp;		/* panic on ^P */
};

#include "../port/portdat.h"

D gnot/devcons.c => gnot/devcons.c +0 -715
@@ 1,715 0,0 @@
#include	"u.h"
#include	"lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"io.h"
#include	"errno.h"

#include	"devtab.h"

struct {
	IOQ;			/* lock to klogputs */
	QLock;			/* qlock to getc */
}	klogq;

IOQ	lineq;			/* lock to getc; interrupt putc's */
IOQ	printq;
IOQ	mouseq;
KIOQ	kbdq;

Ref	raw;		/* whether kbd i/o is raw (rcons is open) */

/*
 *  init the queues and set the output routine
 */
void
printinit(void)
{
	initq(&printq);
	initq(&lineq);
	initq(&kbdq);
	initq(&klogq);
	initq(&mouseq);
	mouseq.putc = mouseputc;
}

/*
 *   Print a string on the console.  Convert \n to \r\n
 */
void
putstrn(char *str, int n)
{
	int s, c, m;
	char *t;

	while(n > 0){
		if(printq.puts && *str=='\n')
			(*printq.puts)(&printq, "\r", 1);
		m = n;
		t = memchr(str+1, '\n', m-1);
		if(t)
			if(t-str < m)
				m = t - str;
		if(printq.puts)
			(*printq.puts)(&printq, str, m);
		screenputs(str, m);
		n -= m;
		str += m;
	}
}

/*
 *   Print a string in the kernel log.  Ignore overflow.
 */
void
klogputs(char *str, long n)
{
	int s, m;
	uchar *nextin;

	s = splhi();
	lock(&klogq);
	while(n){
		m = &klogq.buf[NQ] - klogq.in;
		if(m > n)
			m = n;
		memmove(klogq.in, str, m);
		n -= m;
		str += m;
		nextin = klogq.in + m;
		if(nextin >= &klogq.buf[NQ])
			klogq.in = klogq.buf;
		else
			klogq.in = nextin;
	}
	unlock(&klogq);
	splx(s);
	wakeup(&klogq.r);
}

int
isbrkc(KIOQ *q)
{
	uchar *p;

	for(p=q->out; p!=q->in; ){
		if(raw.ref)
			return 1;
		if(*p==0x04 || *p=='\n')
			return 1;
		p++;
		if(p >= q->buf+sizeof(q->buf))
			p = q->buf;
	}
	return 0;
}

int
sprint(char *s, char *fmt, ...)
{
	return doprint(s, s+PRINTSIZE, fmt, (&fmt+1)) - s;
}

int
print(char *fmt, ...)
{
	char buf[PRINTSIZE];
	int n;

	n = doprint(buf, buf+sizeof(buf), fmt, (&fmt+1)) - buf;
	putstrn(buf, n);
	return n;
}

int
kprint(char *fmt, ...)
{
	char buf[PRINTSIZE];
	int n;

	n = doprint(buf, buf+sizeof(buf), fmt, (&fmt+1)) - buf;
	klogputs(buf, n);
	return n;
}

void
panic(char *fmt, ...)
{
	char buf[PRINTSIZE];
	int n;

	strcpy(buf, "panic: ");
	n = doprint(buf+7, buf+sizeof(buf), fmt, (&fmt+1)) - buf;
	buf[n] = '\n';
	putstrn(buf, n+1);
	dumpstack();
	for(;;);
}

int
pprint(char *fmt, ...)
{
	char buf[2*PRINTSIZE];
	Chan *c;
	int n;

	c = u->fd[2];
	if(c==0 || (c->mode!=OWRITE && c->mode!=ORDWR))
		return 0;
	n = sprint(buf, "%s %d: ", u->p->text, u->p->pid);
	n = doprint(buf+n, buf+sizeof(buf), fmt, (&fmt+1)) - buf;
	qlock(&c->wrl);
	if(waserror()){
		qunlock(&c->wrl);
		return 0;
	}
	(*devtab[c->type].write)(c, buf, n, c->offset);
	c->offset += n;
	qunlock(&c->wrl);
	poperror();
	return n;
}

void
prflush(void)
{
	while(printq.in != printq.out) ;
}

void
echo(int c)
{
	char ch;
	static int ctrlt;

	/*
	 * ^t hack BUG
	 */
	if(ctrlt == 2){
		ctrlt = 0;
		switch(c){
		case 0x14:
			break;	/* pass it on */
		case 'm':
			mntdump();
			return;
		case 'p':
			DEBUG();
			return;
		case 'q':
			dumpqueues();
			return;
		case 'r':
			firmware();
			break;
		}
	}else if(c == 0x14){
		ctrlt++;
		return;
	}
	ctrlt = 0;
	if(raw.ref)
		return;
	if(c == 0x15)
		putstrn("^U\n", 3);
	else{
		ch = c;
		putstrn(&ch, 1);
	}
}

/*
 * Put character into read queue at interrupt time.
 * Always called splhi from proc 0.
 */
int
kbdputc(IOQ *q, int ch)
{
	echo(ch);
	kbdq.c = ch;
	*kbdq.in++ = ch;
	if(kbdq.in == kbdq.buf+sizeof(kbdq.buf))
		kbdq.in = kbdq.buf;
	if(raw.ref || ch=='\n' || ch==0x04)
		wakeup(&kbdq.r);
	return 0;
}

void
kbdrepeat(int rep)
{
	kbdq.repeat = rep;
	kbdq.count = 0;
}

void
kbdclock(void)
{
	if(kbdq.repeat == 0)
		return;
	if(kbdq.repeat==1 && ++kbdq.count>HZ){
		kbdq.repeat = 2;
		kbdq.count = 0;
		return;
	}
	if(++kbdq.count&1)
		kbdputc(&kbdq, kbdq.c);
}

int
consactive(void)
{
	return printq.in != printq.out;
}

/*
 * I/O interface
 */
enum{
	Qdir,
	Qcons,
	Qcputime,
	Qlights,
	Qnoise,
	Qnull,
	Qpgrpid,
	Qpid,
	Qppid,
	Qrcons,
	Qtime,
	Quser,
	Qklog,
	Qmsec,
	Qclock,
	Qsysstat,
};

Dirtab consdir[]={
	"cons",		{Qcons},	0,		0600,
	"cputime",	{Qcputime},	6*NUMSIZE,	0600,
	"lights",	{Qlights},	0,		0600,
	"noise",	{Qnoise},	0,		0600,
	"null",		{Qnull},	0,		0600,
	"pgrpid",	{Qpgrpid},	NUMSIZE,	0600,
	"pid",		{Qpid},		NUMSIZE,	0600,
	"ppid",		{Qppid},	NUMSIZE,	0600,
	"rcons",	{Qrcons},	0,		0600,
	"time",		{Qtime},	NUMSIZE,	0600,
	"user",		{Quser},	0,		0600,
	"klog",		{Qklog},	0,		0400,
	"msec",		{Qmsec},	NUMSIZE,	0400,
	"clock",	{Qclock},	2*NUMSIZE,	0400,
	"sysstat",	{Qsysstat},	0,		0600,
};

#define	NCONS	(sizeof consdir/sizeof(Dirtab))

ulong	boottime;		/* seconds since epoch at boot */

long
seconds(void)
{
	return boottime + TK2SEC(MACHP(0)->ticks);
}

int
readnum(ulong off, char *buf, ulong n, ulong val, int size)
{
	char tmp[64];
	Op op = (Op){ tmp, tmp+sizeof(tmp), &val, size-1, 0, FUNSIGN|FLONG };

	numbconv(&op, 10);
	tmp[size-1] = ' ';
	if(off >= size)
		return 0;
	if(off+n > size)
		n = size-off;
	memmove(buf, tmp+off, n);
	return n;
}

int
readstr(ulong off, char *buf, ulong n, char *str)
{
	int size;

	size = strlen(str);
	if(off >= size)
		return 0;
	if(off+n > size)
		n = size-off;
	memmove(buf, str+off, n);
	return n;
}

void
consreset(void)
{
}

void
consinit(void)
{
}

Chan*
consattach(char *spec)
{
	return devattach('c', spec);
}

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

int
conswalk(Chan *c, char *name)
{
	return devwalk(c, name, consdir, NCONS, devgen);
}

void
consstat(Chan *c, char *dp)
{
	devstat(c, dp, consdir, NCONS, devgen);
}

Chan*
consopen(Chan *c, int omode)
{
	int ch;

	switch(c->qid.path){
	case Quser:
		if(omode==(OWRITE|OTRUNC)){
			/* truncate? */
			if(strcmp(u->p->pgrp->user, "bootes") == 0)	/* BUG */
				u->p->pgrp->user[0] = 0;
			else
				error(Eperm);
		}
		break;
	case Qrcons:
		if(incref(&raw) == 1){
			lock(&lineq);
			while((ch=getc(&kbdq)) != -1){
				*lineq.in++ = ch;
				if(lineq.in == lineq.buf+sizeof(lineq.buf))
					lineq.in = lineq.buf;
			}
			unlock(&lineq);
		}
		break;
	}
	return devopen(c, omode, consdir, NCONS, devgen);
}

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

void
consclose(Chan *c)
{
	if(c->qid.path==Qrcons && (c->flag&COPEN))
		decref(&raw);
}


long
consread(Chan *c, void *buf, long n, ulong offset)
{
	int ch, i, j, k, id;
	ulong l;
	uchar *out;
	char *cbuf = buf;
	char *user;
	int userlen;
	char tmp[6*NUMSIZE], xbuf[1024];
	Mach *mp;

	if(n <= 0)
		return n;
	switch(c->qid.path & ~CHDIR){
	case Qdir:
		return devdirread(c, buf, n, consdir, NCONS, devgen);

	case Qrcons:
	case Qcons:
		qlock(&kbdq);
		if(waserror()){
			qunlock(&kbdq);
			nexterror();
		}
		while(!cangetc(&lineq)){
			sleep(&kbdq.r, isbrkc, &kbdq);
			do{
				lock(&lineq);
				ch = getc(&kbdq);
				if(raw.ref){
					unlock(&lineq);
					goto Default;
				}
				switch(ch){
				case '\b':
					if(lineq.in != lineq.out){
						if(lineq.in == lineq.buf)
							lineq.in = lineq.buf+sizeof(lineq.buf);
						lineq.in--;
					}
					break;
				case 0x15:
					lineq.in = lineq.out;
					break;
				Default:
				default:
					*lineq.in = ch;
					if(lineq.in >= lineq.buf+sizeof(lineq.buf)-1)
						lineq.in = lineq.buf;
					else
						lineq.in++;
				}
				unlock(&lineq);
			}while(raw.ref==0 && ch!='\n' && ch!=0x04);
		}
		i = 0;
		while(n > 0){
			ch = getc(&lineq);
			if(ch==-1 || (raw.ref==0 && ch==0x04))
				break;
			i++;
			*cbuf++ = ch;
			--n;
		}
		qunlock(&kbdq);
		return i;

	case Qcputime:
		k = offset;
		if(k >= sizeof tmp)
			return 0;
		if(k+n > sizeof tmp)
			n = sizeof tmp - k;
		/* easiest to format in a separate buffer and copy out */
		for(i=0; i<6 && NUMSIZE*i<k+n; i++){
			l = u->p->time[i];
			if(i == TReal)
				l = MACHP(0)->ticks - l;
			l = TK2MS(l);
			readnum(0, tmp+NUMSIZE*i, NUMSIZE, l, NUMSIZE);
		}
		memmove(buf, tmp+k, n);
		return n;

	case Qpgrpid:
		return readnum(offset, buf, n, u->p->pgrp->pgrpid, NUMSIZE);

	case Qpid:
		return readnum(offset, buf, n, u->p->pid, NUMSIZE);

	case Qppid:
		return readnum(offset, buf, n, u->p->parentpid, NUMSIZE);

	case Qtime:
		return readnum(offset, buf, n, boottime+TK2SEC(MACHP(0)->ticks), 12);

	case Qclock:
		k = offset;
		if(k >= 2*NUMSIZE)
			return 0;
		if(k+n > 2*NUMSIZE)
			n = 2*NUMSIZE - k;
		readnum(0, tmp, NUMSIZE, MACHP(0)->ticks, NUMSIZE);
		readnum(0, tmp+NUMSIZE, NUMSIZE, HZ, NUMSIZE);
		memmove(buf, tmp+k, n);
		return n;

	case Quser:
		return readstr(offset, buf, n, u->p->pgrp->user);

	case Qnull:
		return 0;

	case Qklog:
		qlock(&klogq);
		if(waserror()){
			qunlock(&klogq);
			nexterror();
		}
		while(!cangetc(&klogq))
			sleep(&klogq.r, cangetc, &klogq);
		for(i=0; i<n; i++){
			if((ch=getc(&klogq)) == -1)
				break;
			*cbuf++ = ch;
		}
		poperror();
		qunlock(&klogq);
		return i;

	case Qmsec:
		return readnum(offset, buf, n, TK2MS(MACHP(0)->ticks), NUMSIZE);

	case Qsysstat:
		j = 0;
		for(id = 0; id < 32; id++) {
			if(active.machs & (1<<id)) {
				mp = MACHP(id);
				j += sprint(&xbuf[j], "%d %d %d %d %d %d %d %d\n",
					id, mp->cs, mp->intr, mp->syscall, mp->pfault,
					    mp->tlbfault, mp->tlbpurge, m->spinlock);
			}
		}
		return readstr(offset, buf, n, xbuf);

	default:
		panic("consread %lux\n", c->qid);
		return 0;
	}
}

void
conslights(char *a, int n)
{
	int l;
	char line[128];
	char *lp;
	int c;

	lp = line;
	while(n--){
		*lp++ = c = *a++;
		if(c=='\n' || n==0 || lp==&line[sizeof(line)-1])
			break;
	}
	*lp = 0;
	lights(strtoul(line, 0, 0));
}

void
consnoise(char *a, int n)
{
	int freq;
	int duration;
	char line[128];
	char *lp;
	int c;

	lp = line;
	while(n--){
		*lp++ = c = *a++;
		if(c=='\n' || n==0 || lp==&line[sizeof(line)-1]){
			*lp = 0;
			freq = strtoul(line, &lp, 0);
			while(*lp==' ' || *lp=='\t')
				lp++;
			duration = strtoul(lp, &lp, 0);
			buzz(freq, duration);
			lp = line;
		}
	}
}

long
conswrite(Chan *c, void *va, long n, ulong offset)
{
	char cbuf[64];
	char buf[256];
	long l, m;
	char *a = va;
	Mach *mp;
	int id;

	switch(c->qid.path){
	case Qrcons:
	case Qcons:
		/*
		 * Damn. Can't page fault in putstrn, so copy the data locally.
		 */
		l = n;
		while(l > 0){
			m = l;
			if(m > sizeof buf)
				m = sizeof buf;
			memmove(buf, a, m);
			putstrn(a, m);
			a += m;
			l -= m;
		}
		break;

	case Qtime:
		if(n<=0 || boottime!=0)	/* only one write please */
			return 0;
		if(n >= sizeof cbuf)
			n = sizeof cbuf - 1;
		memmove(cbuf, a, n);
		cbuf[n-1] = 0;
		boottime = strtoul(a, 0, 0);
		break;

	case Quser:
		if(u->p->pgrp->user[0])		/* trying to overwrite /dev/user */
			error(Eperm);
		if(offset >= NAMELEN-1)
			return 0;
		if(offset+n >= NAMELEN-1)
			n = NAMELEN-1 - offset;
		memmove(u->p->pgrp->user+offset, a, n);
		u->p->pgrp->user[offset+n] = 0;
		break;

	case Qcputime:
	case Qpgrpid:
	case Qpid:
	case Qppid:
		error(Eperm);

	case Qnull:
		break;

	case Qnoise:
		consnoise(a, n);
		break;

	case Qlights:
		conslights(a, n);
		break;

	case Qsysstat:
		for(id = 0; id < 32; id++) {
			if(active.machs & (1<<id)) {
				mp = MACHP(id);
				mp->cs = 0;
				mp->intr = 0;
				mp->syscall = 0;
				mp->pfault = 0;
				mp->tlbfault = 0;
				mp->tlbpurge = 0;
				mp->spinlock = 0;
			}
		}
		break;

	default:
		error(Egreg);
	}
	return n;
}

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

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

M gnot/devduart.c => gnot/devduart.c +3 -3
@@ 578,7 578,7 @@ duartputs(IOQ *cq, char *s, int n)
}

void
duartdevice(Duartport *dp)
duartenable(Duartport *dp)
{
	/*
	 *  set up i/o routines


@@ 602,7 602,7 @@ duartspecial(int port, IOQ *oq, IOQ *iq, int baud)
	dp->nostream = 1;
	dp->oq = oq;
	dp->iq = iq;
	duartdevice(dp);
	duartenable(dp);
	duartbaud(baud);
}



@@ 805,7 805,7 @@ duartreset(void)
	initq(dp->iq);
	dp->oq = ialloc(sizeof(IOQ), 0);
	initq(dp->oq);
	duartdevice(dp);
	duartenable(dp);
}

Chan*

M gnot/l.s => gnot/l.s +5 -0
@@ 45,6 45,11 @@ TEXT	touser(SB), $-4
	MOVL	R0, CACR
	RTE

TEXT	firmware(SB), $0

	MOVL	$0x40000090, A0
	JMP	(A0)

TEXT	splhi(SB), $0

	MOVL	m(SB), A0

M gnot/lock.c => gnot/lock.c +5 -0
@@ 64,3 64,8 @@ mklockseg(Seg *s)
{
	error(Esegaddr);
}

Page*
lkpage(Orig* o, ulong va)
{
}

M gnot/main.c => gnot/main.c +6 -9
@@ 196,10 196,12 @@ exit(void)
	int i;

	u = 0;
	spllo();
	while(consactive())
		for(i=0; i<1000; i++)
			;
	splhi();
	print("exiting\n");
	for(;;)
		;
	firmware();
}

/*


@@ 342,6 344,7 @@ confinit(void)
	conf.nfsyschan = 31 + conf.nchan/20;
	conf.copymode = 0;		/* copy on write */
	conf.portispaged = 0;
	conf.cntrlp = 0;
}

/*


@@ 422,9 425,3 @@ void
lights(int val)
{
}

void
firmware(void)
{
	panic("you asked for it");
}

M gnot/mem.h => gnot/mem.h +1 -0
@@ 72,6 72,7 @@
#define PTEWRITE	0
#define	PTERONLY	(1<<14)
#define	PTEKERNEL	(1<<15)
#define PTEUNCACHED	0
#define	INVALIDPTE	0
#define	PPN(pa)		((pa>>13)&0x1FFF)


M port/devcons.c => port/devcons.c +8 -3
@@ 27,6 27,7 @@ void
printinit(void)
{
	initq(&printq);
	printq.puts = 0;
	initq(&lineq);
	initq(&kbdq);
	kbdq.putc = kbdputc;


@@ 145,7 146,10 @@ panic(char *fmt, ...)
	buf[n] = '\n';
	putstrn(buf, n+1);
	dumpstack();
	exit();
	if(conf.cntrlp)
		exit();
	else
		for(;;);
}

int


@@ 187,8 191,9 @@ echo(int c)
	/*
	 * ^p hack
	 */
	if(c == 0x10)
	if(c==0x10 && conf.cntrlp)
		panic("^p");

	/*
	 * ^t hack BUG
	 */


@@ 201,7 206,7 @@ echo(int c)
			mntdump();
			return;
		case 'p':
			DEBUG();
			procdump();
			return;
		case 'q':
			dumpqueues();

M port/devnonet.c => port/devnonet.c +10 -8
@@ 912,7 912,6 @@ noreset(Noconv *cp)
	case Cconnected:
	case Cconnecting:
	case Chungup:
		print("resetting connection\n");
		cp->state = Creset;
		cp->rcvcircuit = -1;
 		bp = allocb(0);


@@ 1162,7 1161,7 @@ nonetrcvmsg(Noconv *cp, Block *bp)
	 *  Obey reset even if the message id is bogus
	 */
	if(f & NO_RESET){
		print("reset received\n");
		DPRINT("reset received\n");
		noreset(cp);
		freeb(bp);
		return;


@@ 1181,17 1180,19 @@ nonetrcvmsg(Noconv *cp, Block *bp)
		case Copen:
		case Cannounced:
		case Creset:
			panic("nonetrcvmsg %d %d\n", cp->rcvcircuit, cp - cp->ifc->conv);
			DPRINT("nonetrcvmsg %d %d\n", cp->rcvcircuit, cp - cp->ifc->conv);
			freeb(bp);
			return;
		case Chungup:
		case Cconnected:
			print("Nonet call on connected/hanging-up circ %d conv %d\n",
			DPRINT("Nonet call on connected/hanging-up circ %d conv %d\n",
				cp->rcvcircuit, cp - cp->ifc->conv); 
			freeb(bp);
			noreset(cp);
			return;
		case Cconnecting:
			if(h->mid != mp->mid){
				print("Nonet call on connecting circ %d conv %d\n",
				DPRINT("Nonet call on connecting circ %d conv %d\n",
					cp->rcvcircuit, cp - cp->ifc->conv); 
				freeb(bp);
				noreset(cp);


@@ 1266,6 1267,7 @@ nonetrcvmsg(Noconv *cp, Block *bp)
	if(mp->rem == 0){
		cp->hdr->flag &= ~(NO_NEWCALL|NO_SERVICE);
		norack(cp, h->ack);
		noqack(cp, h->mid);
		if(f & NO_ACKME)
			noqack(cp, h->mid);
		mp->last->flags |= S_DELIM;


@@ 1457,10 1459,10 @@ loop:
			 */
			if(cp->first!=cp->next && NOW>=cp->out[cp->first].time){
				mp = &(cp->out[cp->first]);
/*				if(cp->rexmit++ > 15){
				if(cp->rexmit++ > 15){
					norack(cp, mp->mid);
					noreset(cp);
				} else /**/
				} else
					nosend(cp, mp);
			}



@@ 1469,7 1471,7 @@ loop:
			 */
			while(cp->afirst!=cp->anext && cp->rq->next->len<16*1024){
				DPRINT("sending ack %d\n", cp->ack[cp->afirst]);
				nosendctl(cp, NO_NULL, 0);
				nosendctl(cp, /*NO_NULL*/0, 0);
			}
			qunlock(cp);
		}

M port/fault.c => port/fault.c +22 -8
@@ 9,7 9,7 @@
int
fault(ulong addr, int read)
{
	ulong mmuvirt, mmuphys, uncache = 0, n;
	ulong mmuvirt, mmuphys, n;
	Seg *s;
	PTE *opte, *pte, *npte;
	Orig *o;


@@ 71,7 71,6 @@ fault(ulong addr, int read)
					unlock(o);
					return -1;
				}
				uncache = PTEUNCACHED;
			}
			else
				pte->page = newpage(0, o, addr);


@@ 116,12 115,19 @@ fault(ulong addr, int read)
			}
		}
	}
	/*
	 * Copy on reference (conf.copymode==1) or write (conf.copymode==0)
	 */
	if((o->flag & (OWRPERM|OSHARED))==OWRPERM && (conf.copymode || !read)

	if(o->flag&OSHARED) {
		/* BUG: Does not cover enough flag options to shared data */
		mmuphys = PTERONLY;
		if(o->flag & OWRPERM)
			mmuphys = PTEWRITE;
	}
	else if((o->flag&OWRPERM) && (conf.copymode || !read)
	&& ((head && ((o->flag&OPURE) || o->nproc>1))
	    || (!head && pte->page->ref>1))){
		/*
		 * Copy on reference (conf.copymode==1) or write (conf.copymode==0)
		 */

		if(!(o->flag&OISMEM))
			panic("copy on ref/wr to non memory");


@@ 199,9 205,13 @@ fault(ulong addr, int read)
					mmuphys = PTEWRITE;
	}
	mmuvirt = addr;
	mmuphys |= PPN(pte->page->pa) | PTEVALID | uncache;
	if(o->flag&OISMEM)

	/* Non memory is always uncached */
	if(o->flag&OISMEM) {
		mmuphys |= PPN(pte->page->pa) | PTEVALID;
		usepage(pte->page, 1);
	}else
		mmuphys |= PPN(pte->page->pa) | PTEVALID | PTEUNCACHED;

	if(pte->page->va != addr)
		panic("wrong addr in tail %lux %lux", pte->page->va, addr);


@@ 216,6 226,10 @@ fault(ulong addr, int read)
		m->tlbfault++;

	putmmu(mmuvirt, mmuphys);
/*
	if(s - u->p->seg == LSEG)
		print("%d: f %lux v %lux p %lux\n", u->p->pid, o->flag, mmuvirt, mmuphys);
*/
	return 0;
}


M port/portfns.h => port/portfns.h +3 -0
@@ 26,6 26,7 @@ void	closepgrp(Pgrp*);
long	clrfpintr(void);
int	compactpte(Orig*, ulong);
void	confinit(void);
int	consactive(void);
Env*	copyenv(Env*, int);
int	decref(Ref*);
void	delay(int);


@@ 94,6 95,7 @@ Orig*	lookorig(ulong, ulong, int, Chan*);
void	machinit(void);
void	mapstack(Proc*);
void	mklockseg(Seg*);
void	mntdump(void);
void	mmurelease(Proc*);
int	mount(Chan*, Chan*, int);
int	mouseputc(IOQ*, int);


@@ 129,6 131,7 @@ void	putstr(char*);
void	putstrn(char*, long);
void	puts(IOQ*, void*, int);
ulong 	procalarm(ulong);
void	procdump(void);
void	procinit0(void);
Proc*	proctab(int);
Block*	pullup(Block *, int);

M port/proc.c => port/proc.c +1 -1
@@ 564,7 564,7 @@ proctab(int i)

#include <ureg.h>
void
DEBUG(void)
procdump(void)
{
	int i;
	Proc *p;

M port/stnoether.c => port/stnoether.c +6 -6
@@ 270,13 270,13 @@ etherparse(uchar *to, char *from)
		error(Ebadnet);

	for(i = 0; i < 6; i++){
		fdig = *from++;
		tdig = fdig > 'a' ? (fdig - 'a' + 10)
				: (fdig > 'A' ? (fdig - 'A' + 10) : (fdig - '0'));
		fdig = *from++;
		fdig = (*from++)&0x7f;
		tdig = fdig >= 'a' ? ((fdig - 'a') + 10)
				: (fdig >= 'A' ? ((fdig - 'A') + 10) : (fdig - '0'));
		fdig = (*from++)&0x7f;
		tdig <<= 4;
		tdig |= fdig > 'a' ? (fdig - 'a' + 10)
				: (fdig > 'A' ? (fdig - 'A' + 10) : (fdig - '0'));
		tdig |= fdig >= 'a' ? ((fdig - 'a') + 10)
				: (fdig >= 'A' ? ((fdig - 'A') + 10) : (fdig - '0'));
		*to++ = tdig;
	}
}

M power/conf.h => power/conf.h +1 -0
@@ 34,6 34,7 @@ Conftab conftab[] = {
	{"ip", &conf.ip },
	{"arp", &conf.arp },
	{"frag", &conf.frag },
	{"cntrlp", &conf.cntrlp },
	{ 0, 0 },
};


M power/dat.h => power/dat.h +1 -1
@@ 71,7 71,7 @@ struct Conf
	ulong	ip;		/* Ip conversations per interface */
	ulong	arp;		/* Arp table size */
	ulong	frag;		/* Ip fragment assemble queue size */

	ulong	cntrlp;		/* panic on ^P */
};

/*

M power/main.c => power/main.c +1 -0
@@ 645,6 645,7 @@ confinit(void)
	conf.ip = 64;
	conf.arp = 32;
	conf.frag = 32;
	conf.cntrlp = 1;

	confread();


M ss/dat.h => ss/dat.h +1 -0
@@ 93,6 93,7 @@ struct Conf
	int	nfsyschan;	/* number of filsys open channels */
	ulong	maxialloc;	/* maximum bytes used by ialloc */
	int	copymode;	/* 0 is copy on write, 1 is copy on reference */
	int	cntrlp;		/* panic on ^P */
};

/*

M ss/main.c => ss/main.c +13 -4
@@ 81,11 81,16 @@ ioinit(void)
{
	KMap *k;

	/* tell scc driver it's address */
	k = kmappa(KMDUART, PTEIO|PTENOCACHE);
	sccsetup((void*)(k->va));
	sccspecial(0, 0, &kbdq, 2400);		/* scc port 0 is the keyboard */

	/* scc port 0 is the keyboard */
	sccspecial(0, 0, &kbdq, 2400);
	kbdq.putc = kbdstate;
	sccspecial(1, 0, &mouseq, 2400);	/* scc port 1 is the mouse */

	/* scc port 1 is the mouse */
	sccspecial(1, 0, &mouseq, 2400);
}

void


@@ 170,9 175,12 @@ exit(void)
	int i;

	u = 0;
	spllo();
	print("cpu %d exiting\n", m->machno);
	while(consactive())
		for(i=0; i<1000; i++)
			;
	splhi();
	print("exiting\n");
	delay(30*1000);
	reset();
}



@@ 291,6 299,7 @@ confinit(void)
	conf.nservice = 3*mul;			/* was conf.nproc/5 */
	conf.nfsyschan = 31 + conf.nchan/20;
	conf.copymode = 0;		/* copy on write */
	conf.cntrlp = 0;
}

/*