~kris/9p

9hist

9f032393e9ff251d336308f07c8ec6ecbe6f3fed — David du Colombier 35 years ago 62b5b5d
Plan 9 from Bell Labs 1991-07-05
M gnot/dat.h => gnot/dat.h +5 -7
@@ 72,12 72,13 @@ struct Conf
	int	npgrp;		/* process groups */
	ulong	npage0;		/* total physical pages of memory, bank 0 */
	ulong	npage1;		/* total physical pages of memory, bank 1 */
	ulong	npage;
	ulong	base0;		/* base of bank 0 */
	ulong	base1;		/* base of bank 1 */
	ulong	npage;		/* total physical pages of memory */
	ulong	norig;		/* origins */
	ulong	npte;		/* contiguous page table entries */
	ulong	nmod;		/* single (modifying) page table entries */
	ulong	nseg;		/* number of segments */
	ulong	nimage;		/* number of page cache image headers */
	ulong 	npagetab;	/* number of pte tables */
	ulong	nswap;		/* number of swap blocks */
	int	nalarm;		/* alarms */
	int	nchan;		/* channels */
	int	nenv;		/* distinct environment values */


@@ 200,7 201,6 @@ struct Scsi

#define	NERR	15
#define	NNOTE	5
#define	NFD	100
struct User
{
	Proc	*p;


@@ 211,8 211,6 @@ struct User
	char	elem[NAMELEN];		/* last name element from namec */
	Chan	*slash;
	Chan	*dot;
	Chan	*fd[NFD];
	int	maxfd;			/* highest fd in use */
	/*
	 * Rest of structure controlled by devproc.c and friends.
	 * lock(&p->debug) to modify.

M gnot/fault68020.c => gnot/fault68020.c +3 -0
@@ 73,14 73,17 @@ fault68020(Ureg *ur, FFrame *f)
			panic("prefetch pagefault");
	}else
		panic("prefetch format");

	addr &= VAMASK;
	badvaddr = addr;
	addr &= ~(BY2PG-1);
	user = !(ur->sr&SUPER);

	if(f->ssw & DF)
		read = (f->ssw&READ) && !(f->ssw&RM);
	else
		read = f->ssw&(FB|FC);

/* print("fault pc=%lux addr=%lux read %d\n", ur->pc, badvaddr, read); /**/

	if(fault(addr, read) < 0){

M gnot/fns.h => gnot/fns.h +1 -0
@@ 22,6 22,7 @@ void	fpregrestore(char*);
void	fpregsave(char*);
void	fprestore(FPsave*);
void	fpsave(FPsave*);
#define icflush(a, b)
void	incontoggle(void);
KMap*	kmap(Page*);
void	kmapinit(void);

M gnot/lock.c => gnot/lock.c +0 -11
@@ 66,14 66,3 @@ unlock(Lock *l)
	if(u && u->p)
		u->p->hasspin = 0;
}

void
mklockseg(Seg *s)
{
	error(Esegaddr);
}

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

M gnot/main.c => gnot/main.c +27 -27
@@ 46,13 46,15 @@ main(void)
	print("bank 0: %dM  bank 1: %dM\n", bank[0], bank[1]);
	flushmmu();
	procinit0();
	pgrpinit();
	initseg();
	grpinit();
	chaninit();
	alarminit();
	chandevreset();
	streaminit();
/*	serviceinit(); /**/
/*	filsysinit(); /**/
	swapinit();
	pageinit();
	kmapinit();
	userinit();


@@ 89,7 91,7 @@ mmuinit(void)
	 * Invalidate user addresses
	 */
	for(l=0; l<4*1024*1024; l+=BY2PG)
		putmmu(l, INVALIDPTE);
		putmmu(l, INVALIDPTE, 0);
	/*
	 * Four meg of usable memory, with top 256K for screen
	 */


@@ 129,6 131,8 @@ init0(void)
		close(c);
	}
	poperror();

	kickpager();
	touser();
}



@@ 138,23 142,25 @@ void
userinit(void)
{
	Proc *p;
	Seg *s;
	Segment *s;
	User *up;
	KMap *k;

	p = newproc();
	p->pgrp = newpgrp();
	p->egrp = newegrp();
	p->fgrp = newfgrp();

	strcpy(p->text, "*init*");
	strcpy(p->pgrp->user, user);
	p->fpstate = FPinit;

	/*
	 * Kernel Stack
	 */
	p->sched.pc = (ulong)init0;
	p->sched.sp = USERADDR+BY2PG-20;	/* BUG */
	p->sched.sr = SUPER|SPL(0);
	p->upage = newpage(0, 0, USERADDR|(p->pid&0xFFFF));
	p->upage = newpage(1, 0, USERADDR|(p->pid&0xFFFF));

	/*
	 * User


@@ 167,25 173,18 @@ userinit(void)
	/*
	 * User Stack
	 */
	s = &p->seg[SSEG];
	s->proc = p;
	s->o = neworig(USTKTOP-BY2PG, 1, OWRPERM, 0);
	s->minva = USTKTOP-BY2PG;
	s->maxva = USTKTOP;
	s = newseg(SG_STACK, USTKTOP-BY2PG, 1);
	p->seg[SSEG] = s;

	/*
	 * Text
	 */
	s = &p->seg[TSEG];
	s->proc = p;
	s->o = neworig(UTZERO, 1, 0, 0);
	s->o->pte[0].page = newpage(0, 0, UTZERO);
	s->o->npage = 1;
	k = kmap(s->o->pte[0].page);
	s = newseg(SG_TEXT, UTZERO, 1);
	p->seg[TSEG] = s;
	segpage(s, newpage(1, 0, UTZERO));
	k = kmap(s->map[0]->pages[0]);
	memmove((ulong*)VA(k), initcode, sizeof initcode);
	kunmap(k);
	s->minva = UTZERO;
	s->maxva = UTZERO+BY2PG;

	ready(p);
}


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


@@ 314,11 313,12 @@ confinit(void)
	conf.maxialloc = (4*1024*1024-256*1024-BY2PG);
	mul = 1 + (conf.npage1>0);
	conf.nproc = 50*mul;
	conf.nseg = conf.nproc*4;
	conf.npagetab = conf.nseg*2;
	conf.nswap = 4096;
	conf.nimage = 50;
	conf.npgrp = 20*mul;
	conf.npte = 700*mul;
	conf.nmod = 400*mul;
	conf.nalarm = 1000;
	conf.norig = 150*mul;
	conf.nchan = 200*mul;
	conf.nenv = 100*mul;
	conf.nenvchar = 8000*mul;

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

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



@@ 74,6 75,10 @@
#define	PTEKERNEL	(1<<15)
#define PTEUNCACHED	0
#define	INVALIDPTE	0
#define PTEMAPMEM	(1024*1024)	
#define	PTEPERTAB	(PTEMAPMEM/BY2PG)
#define SEGMAPSIZE	16

#define	PPN(pa)		((pa>>13)&0x1FFF)

#define	KMAP	((unsigned long *)0xD0000000)

M gnot/mmu.c => gnot/mmu.c +9 -2
@@ 22,6 22,7 @@ mapstack(Proc *p)
	ulong next;
	MMU *mm, *mn, *me;


	if(p->upage->va != (USERADDR|(p->pid&0xFFFF)))
		panic("mapstack %d 0x%lux 0x%lux", p->pid, p->upage->pa, p->upage->va);
	tlbvirt = USERADDR;


@@ 29,6 30,12 @@ mapstack(Proc *p)
	putkmmu(tlbvirt, tlbphys);
	u = (User*)USERADDR;

	if(p->newtlb) {
		flushmmu();
		clearmmucache();
		p->newtlb = 0;
	}

	/*
	 *  if not a kernel process and this process was not the 
	 *  last process on this machine, flush & preload mmu


@@ 69,7 76,7 @@ putkmmu(ulong tlbvirt, ulong tlbphys)
}

void
putmmu(ulong tlbvirt, ulong tlbphys)
putmmu(ulong tlbvirt, ulong tlbphys, Page *p)
{
	if(tlbvirt&KZERO)
		panic("putmmu");


@@ 101,7 108,7 @@ void
clearmmucache(void)
{
	if(u == 0)
		panic("flushmmucache");
		panic("clearmmucache");
	u->mc.next = 0;
}


A gnot/segment.h => gnot/segment.h +20 -0
@@ 0,0 1,20 @@
/*
 * Attach segment types
 */

typedef struct Physseg Physseg;
struct Physseg
{
	ulong	attr;			/* Segment attributes */
	char	*name;			/* Attach name */
	ulong	pa;			/* Physical address */
	ulong	size;			/* Maximum segment size in pages */
	Page	*(*pgalloc)(ulong);	/* Allocation if we need it */
	void	(*pgfree)(Page*);
}physseg[] = {
	{ SG_SHARED,	"lock",		0,	SEGMAXSIZE,	&snewpage, 	&putpage },
	{ SG_SHARED,	"shared",	0,	SEGMAXSIZE,	&snewpage, 	&putpage },
	{ SG_PHYSICAL,	"kmem",		KZERO,	SEGMAXSIZE,	0,		0 	},
	{ SG_BSS,	"memory",	0,	SEGMAXSIZE,	&snewpage,	&putpage },
	{ 0,		0,		0,	0,		0,		0 	},
};

M gnot/trap.c => gnot/trap.c +18 -6
@@ 91,13 91,14 @@ trap(Ureg *ur)
	if(u)
		u->p->pc = ur->pc;		/* BUG */
	if(user){
		sprint(buf, "sys: trap: pc=0x%lux %s", ur->pc, excname(ur->vo));
		sprint(buf, "sys: %s pc=0x%lux", excname(ur->vo), ur->pc);
		postnote(u->p, 1, buf, NDebug);
	}else{
		print("kernel trap vo=0x%ux pc=0x%lux\n", ur->vo, ur->pc);
		dumpregs(ur);
		exit();
	}

	if(user && u->nnote)
		notify(ur);
}


@@ 130,6 131,7 @@ dumpregs(Ureg *ur)
	l = &ur->r0;
	for(i=0; i<sizeof regname/sizeof(char*); i+=2, l+=2)
		print("%s\t%.8lux\t%s\t%.8lux\n", regname[i], l[0], regname[i+1], l[1]);
	for(;;);
	dumpstack();
}



@@ 212,6 214,7 @@ Syscall	sysr1, sysfork, sysexec, sysgetpid, syssleep, sysexits, sysdeath, syswai
Syscall	sysopen, sysclose, sysread, syswrite, sysseek, syserrstr, sysaccess, sysstat, sysfstat;
Syscall sysdup, syschdir, sysforkpgrp, sysbind, sysmount, syspipe, syscreate;
Syscall	sysbrk_, sysremove, syswstat, sysfwstat, sysnotify, sysnoted, sysalarm;
Syscall syssegattach, syssegdetach, syssegfree, syssegflush, syssegbrk;

Syscall *systab[]={
	sysr1,


@@ 226,7 229,7 @@ Syscall *systab[]={
	sysfork,
	sysforkpgrp,
	sysfstat,
	sysdeath,
	syssegbrk,
	sysmount,
	sysopen,
	sysread,


@@ 244,7 247,10 @@ Syscall *systab[]={
	sysfwstat,
	sysnotify,
	sysnoted,
	sysdeath,	/* sysfilsys */
	syssegattach,
	syssegdetach,
	syssegfree,
	syssegflush,
};

long


@@ 289,7 295,8 @@ syscall(Ureg *aur)
			error(Ebadarg);
		}
		if(sp & (BY2WD-1)){
			pprint("odd sp in sys call pc %lux sp %lux\n", ((Ureg*)UREGADDR)->pc, ((Ureg*)UREGADDR)->sp);
			pprint("odd sp in sys call pc %lux sp %lux\n", 
				((Ureg*)UREGADDR)->pc, ((Ureg*)UREGADDR)->sp);
			msg = "sys: odd stack";
			goto Bad;
		}


@@ 298,14 305,19 @@ syscall(Ureg *aur)
		ret = (*systab[r0])((ulong*)(sp+BY2WD));
		poperror();
	}

#ifdef Check
	if(u->nerrlab){
		print("unbalanced error stack: %d extra\n", u->nerrlab);
		print("bad errstack [%d]: %d extra\n", r0, u->nerrlab);
		for(i = 0; i < NERR; i++)
			print("sp=%lux pc=%lux\n", u->errlab[i].sp, u->errlab[i].pc);
		panic("bad rob");
	}
#endif

	u->p->insyscall = 0;
	if(r0 == NOTED)	/* ugly hack */

	if(r0 == NOTED)		/* ugly hack */
		noted(aur);	/* doesn't return */
	if(u->nnote){
		ur->r0 = ret;

M pc/clock.c => pc/clock.c +20 -1
@@ 4,7 4,18 @@
#include	"dat.h"
#include	"fns.h"
#include	"io.h"
#include	"ureg.h"

/*
 *  8253 timer
 */
enum
{
	Timerctl=	0x43,		/* control port */
	Timercnt=	0x40,		/* timer count port (outb count-1) */
	Timericnt=	0x41,		/* timer count input port */

	Timerlatch=	0x40,		/* latch count into Timericnt */
};

void
clockinit(void)


@@ 12,3 23,11 @@ clockinit(void)
	setvec(Clockvec, clock, SEGIG);
}

void
clock(void *arg)
{
	m->ticks++;
	if((m->ticks%185)==0)
		print("%d secs\n", TK2SEC(m->ticks));
	INT0ENABLE;
}

M pc/fns.h => pc/fns.h +2 -2
@@ 1,5 1,7 @@
#include "../port/portfns.h"

void	clock(void*);
void	clockinit(void);
void	delay(int);
int	inb(int);
void	intr0(void);


@@ 31,8 33,6 @@ void	screeninit(void);
void	screenputc(int);
void	screenputs(char*, int);
void	setvec(int, void (*)(void*), int);
void	spllo(void);
void	splhi(void);
void	systrap(void);
void	trapinit(void);
int	tas(Lock*);

M pc/io.h => pc/io.h +1 -13
@@ 18,18 18,6 @@ enum
#define	INT1ENABLE	outb(Int1ctl, Intena)

/*
 *  8253 timer
 */
enum
{
	Timerctl=	0x43,		/* control port */
	Timercnt=	0x40,		/* timer count port (outb count-1) */
	Timericnt=	0x41,		/* timer count input port */

	Timerlatch=	0x40,		/* latch count into Timericnt */
};

/*
 *  8237 dma controllers
 */
enum


@@ 46,5 34,5 @@ enum
	 */
	Dma1=		0xC0,
	Dma1status=	Dma1+2*0x8,	/* status port */
	Dma0reset=	Dma1+2*0xD,	/* reset port */
	Dma1reset=	Dma1+2*0xD,	/* reset port */
};

M pc/kbd.c => pc/kbd.c +1 -1
@@ 378,6 378,6 @@ kbdintr(void *a)
	}
	kbdputc(&kbdq, c);
out:
	INTENABLE;			/* reenable interrupt */
	INT0ENABLE;			/* reenable interrupt */
	return;
}

M pc/l.s => pc/l.s +6 -0
@@ 305,3 305,9 @@ TEXT	spllo(SB),$0
TEXT	splhi(SB),$0
	CLI
	RET

/*
 *  set interrupt level
 */
TEXT	splx(SB),$0
	RET

M pc/main.c => pc/main.c +6 -1
@@ 11,7 11,7 @@ main(void)
	print("traps inited\n");
	kbdinit();
	print("kbd inited\n");
	sti();
	spllo();
	for(;;);
}



@@ 54,3 54,8 @@ panic(char *fmt, ...)
	screenputs(buf, n);
	for(;;);
}

void
sched(void)
{
}

M pc/mem.h => pc/mem.h +7 -7
@@ 17,15 17,15 @@
#define	MAXMACH		1			/* max # cpus system can run */

/*
 * Time (???)
 * Clock frequency is 68.3900 HZ
 * Time
 * Clock frequency is ??? HZ
 */

#define	HZ		(68)			/* clock frequency */
#define	MS2HZ		(1000/HZ)		/* millisec per clock tick */
#define	TK2SEC(t)	((t)*100/6839)		/* ticks to seconds */
#define	TK2MS(t)	((((ulong)(t))*100000)/6839)	/* ticks to milliseconds */
#define	MS2TK(t)	((((ulong)(t))*6839)/100000)	/* milliseconds to ticks */
#define	HZ		(18)			/* clock frequency */
#define	MS2HZ		(54)			/* millisec per clock tick */
#define	TK2SEC(t)	((t)*10/185)		/* ticks to seconds */
#define	TK2MS(t)	((((ulong)(t))*10000)/185)	/* ticks to milliseconds */
#define	MS2TK(t)	((((ulong)(t))*185)/10000)	/* milliseconds to ticks */

/*
 * Fundamental addresses

M pc/trap.c => pc/trap.c +5 -5
@@ 75,11 75,11 @@ trapinit(void)
	 *	 IBM technical reference manual.  I just
	 *	 changed the vector.
	 */
	outb(I8259ctl, 0x11);		/* ICW1 - edge, master, ICW4 */
	outb(I8259aux, I8259vec);	/* ICW2 - interrupt vector */
	outb(I8259aux, 0x04);		/* ICW3 - master level 2 */
	outb(I8259aux, 0x01);		/* ICW4 - master, 8086 mode */
	outb(I8259aux, 0x00);		/* mask - all enabled */
	outb(Int0ctl, 0x11);		/* ICW1 - edge, master, ICW4 */
	outb(Int0aux, Int0vec);		/* ICW2 - interrupt vector */
	outb(Int0aux, 0x04);		/* ICW3 - master level 2 */
	outb(Int0aux, 0x01);		/* ICW4 - master, 8086 mode */
	outb(Int0aux, 0x00);		/* mask - all enabled */
}



M port/chan.c => port/chan.c +2 -0
@@ 30,6 30,8 @@ decref(Ref *r)
	lock(r);
	x = --r->ref;
	unlock(r);
	if(x < 0)
		panic("decref");
	return x;
}


M port/devcons.c => port/devcons.c +21 -2
@@ 159,7 159,7 @@ pprint(char *fmt, ...)
	Chan *c;
	int n;

	c = u->fd[2];
	c = u->p->fgrp->fd[2];
	if(c==0 || (c->mode!=OWRITE && c->mode!=ORDWR))
		return 0;
	n = sprint(buf, "%s %d: ", u->p->text, u->p->pid);


@@ 294,6 294,7 @@ enum{
	Qmsec,
	Qclock,
	Qsysstat,
	Qswap,
};

Dirtab consdir[]={


@@ 312,6 313,7 @@ Dirtab consdir[]={
	"msec",		{Qmsec},	NUMSIZE,	0400,
	"clock",	{Qclock},	2*NUMSIZE,	0400,
	"sysstat",	{Qsysstat},	0,		0600,
	"swap",		{Qswap},	0,		0666,
};

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


@@ 581,6 583,12 @@ consread(Chan *c, void *buf, long n, ulong offset)
		}
		return readstr(offset, buf, n, xbuf);

	case Qswap:
		sprint(xbuf, "%d/%d memory %d/%d swap\n",
				palloc.user-palloc.freecount, palloc.user, 
				conf.nswap-swapalloc.free, conf.nswap);

		return readstr(offset, buf, n, xbuf);
	default:
		panic("consread %lux\n", c->qid);
		return 0;


@@ 637,7 645,8 @@ conswrite(Chan *c, void *va, long n, ulong offset)
	long l, m;
	char *a = va;
	Mach *mp;
	int id;
	int id, fd;
	Chan *swc;

	switch(c->qid.path){
	case Qrcons:


@@ 710,6 719,16 @@ conswrite(Chan *c, void *va, long n, ulong offset)
		}
		break;

	case Qswap:
		if(n >= sizeof buf)
			error(Egreg);
		memmove(buf, va, n);	/* so we can NUL-terminate */
		buf[n] = 0;
		fd = strtoul(buf, 0, 0);
		swc = fdtochan(fd, -1);
		setswapchan(swc);
		return n;

	default:
		error(Egreg);
	}

M port/devdup.c => port/devdup.c +3 -2
@@ 12,12 12,13 @@ int
dupgen(Chan *c, Dirtab *tab, int ntab, int s, Dir *dp)
{
	char buf[8];
	Fgrp *fgrp = u->p->fgrp;
	Chan *f;
	static int perm[] = { 0400, 0200, 0600, 0 };

	if(s >= NFD)
		return -1;
	if((f=u->fd[s]) == 0)
	if((f=fgrp->fd[s]) == 0)
		return 0;
	sprint(buf, "%ld", s);
	devdir(c, (Qid){s, 0}, buf, 0, perm[f->mode&3], dp);


@@ 72,7 73,7 @@ dupopen(Chan *c, int omode)
		return c;
	}
	fdtochan(c->qid.path, openmode(omode));	/* error check only */
	f = u->fd[c->qid.path];
	f = u->p->fgrp->fd[c->qid.path];
	close(c);
	incref(f);
	if(omode & OCEXEC)

M port/devenv.c => port/devenv.c +63 -63
@@ 211,15 211,15 @@ int
envgen(Chan *c, Dirtab *tab, int ntab, int s, Dir *dp)
{
	Env *e;
	Pgrp *pg;
	Egrp *eg;
	int ans;

	pg = u->p->pgrp;
	lock(pg);
	if(s >= pg->nenv)
	eg = u->p->egrp;
	lock(eg);
	if(s >= eg->nenv)
		ans = -1;
	else{
		e = pg->etab[s].env;
		e = eg->etab[s].env;
		if(e == 0)
			ans = 0;
		else{


@@ 229,7 229,7 @@ envgen(Chan *c, Dirtab *tab, int ntab, int s, Dir *dp)
			ans = 1;
		}
	}
	unlock(pg);
	unlock(eg);
	return ans;
}



@@ 242,13 242,13 @@ envattach(char *spec)
Chan*
envclone(Chan *c, Chan *nc)
{
	Pgrp *pg;
	Egrp *eg;

	if(!(c->qid.path&CHDIR)){
		pg = u->p->pgrp;
		lock(pg);
		pg->etab[c->qid.path-1].chref++;
		unlock(pg);
		eg = u->p->egrp;
		lock(eg);
		eg->etab[c->qid.path-1].chref++;
		unlock(eg);
	}
	return devclone(c, nc);
}


@@ 256,14 256,14 @@ envclone(Chan *c, Chan *nc)
int
envwalk(Chan *c, char *name)
{
	Pgrp *pg;
	Egrp *eg;

	if(devwalk(c, name, 0, 0, envgen)){
		if(!(c->qid.path&CHDIR)){
			pg = u->p->pgrp;
			lock(pg);
			pg->etab[c->qid.path-1].chref++;
			unlock(pg);
			eg = u->p->egrp;
			lock(eg);
			eg->etab[c->qid.path-1].chref++;
			unlock(eg);
			return 1;
		}
	}


@@ 281,17 281,17 @@ envopen(Chan *c, int omode)
{
	Env *e, *ne;
	Envp *ep;
	Pgrp *pg;
	Egrp *eg;

	if(omode & (OWRITE|OTRUNC)){
		if(c->qid.path & CHDIR)
			error(Eperm);
		pg = u->p->pgrp;
		lock(pg);
		ep = &pg->etab[c->qid.path-1];
		eg = u->p->egrp;
		lock(eg);
		ep = &eg->etab[c->qid.path-1];
		e = ep->env;
		if(!e){
			unlock(pg);
			unlock(eg);
			error(Egreg);
		}
		lock(&envalloc);


@@ 299,7 299,7 @@ envopen(Chan *c, int omode)
		if(waserror()){
			unlock(e);
			unlock(&envalloc);
			unlock(pg);
			unlock(eg);
			nexterror();
		}
		if(e->pgref == 0)


@@ 318,7 318,7 @@ envopen(Chan *c, int omode)
		poperror();
		unlock(e);
		unlock(&envalloc);
		unlock(pg);
		unlock(eg);
	}
	c->mode = openmode(omode);
	c->flag |= COPEN;


@@ 330,17 330,17 @@ void
envcreate(Chan *c, char *name, int omode, ulong perm)
{
	Env *e;
	Pgrp *pg;
	Egrp *eg;
	int i;

	if(c->qid.path != CHDIR)
		error(Eperm);
	pg = u->p->pgrp;
	lock(pg);
	eg = u->p->egrp;
	lock(eg);
	lock(&envalloc);
	if(waserror()){
		unlock(&envalloc);
		unlock(pg);
		unlock(eg);
		nexterror();
	}
	e = envalloc.efree;


@@ 352,21 352,21 @@ envcreate(Chan *c, char *name, int omode, ulong perm)
	e->next = 0;
	e->pgref = 1;
	strncpy(e->name, name, NAMELEN);
	if(pg->nenv == conf.npgenv){
		for(i = 0; i<pg->nenv; i++)
			if(pg->etab[i].chref == 0)
	if(eg->nenv == conf.npgenv){
		for(i = 0; i<eg->nenv; i++)
			if(eg->etab[i].chref == 0)
				break;
		if(i == pg->nenv){
			print("out of pgroup envs\n");
		if(i == eg->nenv){
			print("out of egroup envs\n");
			error(Enoenv);
		}
	}else
		i = pg->nenv++;
		i = eg->nenv++;
	c->qid.path = i+1;
	pg->etab[i].env = e;
	pg->etab[i].chref = 1;
	eg->etab[i].env = e;
	eg->etab[i].chref = 1;
	unlock(&envalloc);
	unlock(pg);
	unlock(eg);
	c->offset = 0;
	c->mode = openmode(omode);
	poperror();


@@ 378,22 378,22 @@ envremove(Chan *c)
{
	Env *e;
	Envp *ep;
	Pgrp *pg;
	Egrp *eg;

	if(c->qid.path & CHDIR)
		error(Eperm);
	pg = u->p->pgrp;
	lock(pg);
	ep = &pg->etab[c->qid.path-1];
	eg = u->p->egrp;
	lock(eg);
	ep = &eg->etab[c->qid.path-1];
	e = ep->env;
	if(!e){
		unlock(pg);
		unlock(eg);
		error(Enonexist);
	}
	ep->env = 0;
	ep->chref--;
	envpgclose(e);
	unlock(pg);
	unlock(eg);
}

void


@@ 407,14 407,14 @@ envwstat(Chan *c, char *db)
void
envclose(Chan * c)
{
	Pgrp *pg;
	Egrp *eg;

	if(c->qid.path & CHDIR)
		return;
	pg = u->p->pgrp;
	lock(pg);
	pg->etab[c->qid.path-1].chref--;
	unlock(pg);
	eg = u->p->egrp;
	lock(eg);
	eg->etab[c->qid.path-1].chref--;
	unlock(eg);
}

void


@@ 441,16 441,16 @@ envread(Chan *c, void *va, long n, ulong offset)
	Envval *ev;
	char *p;
	long vn;
	Pgrp *pg;
	Egrp *eg;
	char *a = va;

	if(c->qid.path & CHDIR)
		return devdirread(c, a, n, 0, 0, envgen);
	pg = u->p->pgrp;
	lock(pg);
	e = pg->etab[c->qid.path-1].env;
	eg = u->p->egrp;
	lock(eg);
	e = eg->etab[c->qid.path-1].env;
	if(!e){
		unlock(pg);
		unlock(eg);
		error(Eio);
	}
	lock(e);


@@ 463,7 463,7 @@ envread(Chan *c, void *va, long n, ulong offset)
	else
		memmove(a, ev->dat+offset, n);
	unlock(e);
	unlock(pg);
	unlock(eg);
	return n;
}



@@ 474,16 474,16 @@ envwrite(Chan *c, void *va, long n, ulong offset)
	char *p;
	Envval *ev;
	long vn;
	Pgrp *pg;
	Egrp *eg;
	char *a = va;

	if(n <= 0)
		return 0;
	pg = u->p->pgrp;
	lock(pg);
	e = pg->etab[c->qid.path-1].env; /* caller checks for CHDIR */
	eg = u->p->egrp;
	lock(eg);
	e = eg->etab[c->qid.path-1].env; /* caller checks for CHDIR */
	if(!e){
		unlock(pg);
		unlock(eg);
		error(Eio);
	}
	lock(&envalloc);


@@ 491,7 491,7 @@ envwrite(Chan *c, void *va, long n, ulong offset)
	if(waserror()){
		unlock(e);
		unlock(&envalloc);
		unlock(pg);
		unlock(eg);
		nexterror();
	}
	if(e->pgref>1)


@@ 506,7 506,7 @@ envwrite(Chan *c, void *va, long n, ulong offset)
	poperror();
	unlock(e);
	unlock(&envalloc);
	unlock(pg);
	unlock(eg);
	return n;
}



@@ 516,12 516,12 @@ dumpenv(void)
	Env *e;
	Envp *ep;
	Envval *ev;
	Pgrp *pg;
	Egrp *eg;
	int i;
	char hold;

	pg = u->p->pgrp;
	for(ep=pg->etab, i=0; i<pg->nenv; i++, ep++)
	eg = u->p->egrp;
	for(ep=eg->etab, i=0; i<eg->nenv; i++, ep++)
		print("P%d(%lux %d)",i, ep->env, ep->chref);
	for(e=envalloc.earena; e<&envalloc.earena[conf.nenv]; e++)
		if(e->pgref){

M port/devip.c => port/devip.c +1 -0
@@ 71,6 71,7 @@ ipreset(void)
	}

	initfrag(conf.frag);
	tcpinit();
}

void

M port/deviproute.c => port/deviproute.c +1 -1
@@ 190,7 190,7 @@ enum{
	Qdata,
};
Dirtab iproutetab[]={
	"iproute",		{Qdata},		0,	0666,
	"iproute",		{Qdata},		0,	0600,
};
#define Niproutetab (sizeof(iproutetab)/sizeof(Dirtab))


M port/devproc.c => port/devproc.c +78 -38
@@ 14,6 14,7 @@ enum{
	Qnote,
	Qnotepg,
	Qproc,
	Qsegment,
	Qstatus,
	Qtext,
};


@@ 24,10 25,20 @@ Dirtab procdir[]={
	"note",		{Qnote},	0,			0600,
	"notepg",	{Qnotepg},	0,			0200,
	"proc",		{Qproc},	sizeof(Proc),		0600,
	"segment",	{Qsegment},	0,			0400,
	"status",	{Qstatus},	NAMELEN+12+6*12,	0600,
	"text",		{Qtext},	0,			0600,
};

char *sname[]={ 			/* Segment type from portdat.h */
	"Text", 
	"Data", 
	"Bss", 
	"Stack", 
	"Shared", 
	"Phys",
};

/*
 * Qids are, in path:
 *	 4 bits of file type (qids above)


@@ 47,7 58,7 @@ procgen(Chan *c, Dirtab *tab, int ntab, int s, Dir *dp)
{
	Proc *p;
	char buf[NAMELEN];
	ulong pid;
	ulong pid, path;

	if(c->qid.path == CHDIR){
		if(s >= conf.nproc)


@@ 65,7 76,8 @@ procgen(Chan *c, Dirtab *tab, int ntab, int s, Dir *dp)
	if(tab)
		panic("procgen");
	tab = &procdir[s];
	devdir(c, (Qid){(~CHDIR)&(c->qid.path|tab->qid.path), c->qid.vers},
	path = c->qid.path&~(CHDIR|((1<<QSHIFT)-1));	/* slot component */
	devdir(c, (Qid){path|tab->qid.path, c->qid.vers},
		tab->name, tab->length, tab->perm, dp);
	return 1;
}


@@ 112,7 124,7 @@ procopen(Chan *c, int omode)
{
	Proc *p;
	Pgrp *pg;
	Orig *o;
	Segment *s;
	Chan *tc;

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


@@ 129,11 141,11 @@ procopen(Chan *c, int omode)

	switch(QID(c->qid)){
	case Qtext:
		o = p->seg[TSEG].o;
		if(o==0 || p->state==Dead) 
		s = p->seg[TSEG];
		if(s==0 || p->state==Dead || s->image==0) 
			goto Died;

		tc = o->chan;
		tc = s->image->c;
		if(tc == 0)
			goto Died;



@@ 154,6 166,7 @@ procopen(Chan *c, int omode)
		return tc;
	case Qctl:
	case Qnote:
	case Qsegment:
		break;

	case Qnotepg:


@@ 213,17 226,18 @@ long
procread(Chan *c, void *va, long n, ulong offset)
{
	char *a = va, *b;
	char statbuf[2*NAMELEN+12+6*12];
	char statbuf[NSEG*32];
	Proc *p;
	Seg *s;
	Orig *o;
	Pte *pte;
	Segment *s;
	Page *pg;
	KMap *k;
	PTE *pte, *opte;
	int i;
	int i, j;
	long l;
	long pid;
	User *up;
	ulong soff;
	Segment *sg;

	if(c->qid.path & CHDIR)
		return devdirread(c, a, n, 0, 0, procgen);


@@ 242,32 256,22 @@ procread(Chan *c, void *va, long n, ulong offset)
		 */
		if(((offset+n)&~(BY2PG-1)) != (offset&~(BY2PG-1)))
			n = BY2PG - (offset&(BY2PG-1));
		s = seg(p, offset);
		s = seg(p, offset, 1);
		if(s){
			o = s->o;
			if(o == 0)
				error(Eprocdied);
			lock(o);
			if(s->o!=o || p->pid!=PID(c->qid)){
				unlock(o);
			if(p->pid!=PID(c->qid)){
				qunlock(&s->lk);
				error(Eprocdied);
			}
			if(seg(p, offset) != s){
				unlock(o);
				error(Egreg);
			}
			pte = &o->pte[(offset-o->va)>>PGSHIFT];
			if(s->mod){
				opte = pte;
				while(pte = pte->nextmod)	/* assign = */
					if(pte->proc == p)
						break;
				if(pte == 0)
					pte = opte;
			}
			pg = pte->page;
			unlock(o);
			if(pg == 0){

			soff = offset-s->base;
			pte = s->map[soff/PTEMAPMEM];
			pg = 0;
			if(pte)
				pg = pte->pages[(soff&(PTEMAPMEM-1))/BY2PG];

			s->steal++;
			qunlock(&s->lk);
			if(pagedout(pg)){
				pprint("nonresident page addr %lux (complain to rob)\n", offset);
				memset(a, 0, n);
			}else{


@@ 276,6 280,9 @@ procread(Chan *c, void *va, long n, ulong offset)
				memmove(a, b+(offset&(BY2PG-1)), n);
				kunmap(k);
			}
			qlock(&s->lk);
			s->steal--;
			qunlock(&s->lk);
			return n;
		}
		/* u area */


@@ 355,6 362,19 @@ procread(Chan *c, void *va, long n, ulong offset)
		}
		memmove(a, statbuf+offset, n);
		return n;
	case Qsegment:
		j = 0;
		for(i = 0; i < NSEG; i++)
			if(sg = p->seg[i])
				j += sprint(&statbuf[j], "%-6s %c %.8lux %.8lux %4d\n",
				sname[sg->type&SG_TYPE], sg->type&SG_RONLY ? 'R' : ' ',
				sg->base, sg->top, sg->ref);
		if(offset >= j)
			return 0;
		if(offset+n > j)
			n = j-offset;
		memmove(a, &statbuf[offset], n);
		return n;
	}
	error(Egreg);
}


@@ 404,11 424,31 @@ procwrite(Chan *c, void *va, long n, ulong offset)

	switch(QID(c->qid)){
	case Qctl:
		if(p->state==Broken && n>=4 && strncmp(va, "exit", 4)==0)
			ready(p);
		if(n >= 4 && strncmp(va, "exit", 4) == 0) {
			if(p->state == Broken) {
				ready(p);
				break;
			}
		}
		else
			error(Ebadctl);
		break;
		if(n >= 4 && strncmp(va, "stop", 4) == 0) {
			p->procctl = Proc_stopme;
			break;
		}
		else
		if(n >= 5 && strncmp(va, "start", 5) == 0) {
			if(p->state == Stopped) {
				ready(p);
				break;
			}
			errors("not stopped");
		}
		else
		if(n >= 4 && strncmp(va, "kill", 4) == 0) {
			p->procctl = Proc_exitme;
			break;
		}
		error(Ebadctl);
	case Qnote:
		k = kmap(p->upage);
		up = (User*)VA(k);

M port/devscsi.c => port/devscsi.c +1 -5
@@ 104,7 104,7 @@ scsiwalk(Chan *c, char *name)
void
scsistat(Chan *c, char *db)
{
	devstat(c, db, 0, 0, scsigeno);
	devstat(c, db, 0, 0, scsigen);
}

Chan *


@@ 579,9 579,5 @@ scsictrlintr(void)
		default:
			panic("scsi status 0x%2.2ux", status);
		}
		kprint("resetting...");
		PUT(Own_id, ownid);
		PUT(Cmd, Reset);
		break;
	}
}

M port/devsrv.c => port/devsrv.c +1 -2
@@ 275,8 275,7 @@ srvwrite(Chan *c, void *va, long n, ulong offset)
	memmove(buf, va, n);	/* so we can NUL-terminate */
	buf[n] = 0;
	fd = strtoul(buf, 0, 0);
	fdtochan(fd, -1);	/* error check only */
	e->chan = u->fd[fd];
	e->chan = fdtochan(fd, -1);
	incref(e->chan);
	unlock(e);
	poperror();

M port/devwren.c => port/devwren.c +1 -1
@@ 150,7 150,7 @@ wrenattach(char *param)
	d = &wren[dev];
	d->blocksize = BGLONG(&buf[4]);

	plen = BGLONG(&buf[0])+1;
	plen = BGLONG(&buf[0]);
	d->p[Npart].firstblock = 0;
	d->p[Npart].maxblock = plen;
	plen = plen/Npart;

M port/fault.c => port/fault.c +230 -242
@@ 6,227 6,211 @@
#include	"ureg.h"
#include	"errno.h"

#define DPRINT

int
fault(ulong addr, int read)
{
	ulong mmuvirt, mmuphys, n;
	Seg *s;
	PTE *opte, *pte, *npte;
	Orig *o;
	char *l;
	Page *pg;
	int zeroed = 0, head = 1;
	int i, touched = 0;
	KMap *k, *k1;
	ulong mmuphys=0, soff;
	Segment *s;
	Pte **p;
	Page **pg, *lkp, *new = 0;
	int type;

	m->pfault++;
	s = seg(u->p, addr);
	if(s == 0){
		if(addr > USTKTOP)
			return -1;
		s = &u->p->seg[SSEG];
		if(s->o==0 || addr<s->maxva-USTKSIZE || addr>=s->maxva)
			return -1;
		/* grow stack */
		o = s->o;
		n = o->npte;
		if(waserror()){
			pprint("can't allocate stack page\n");
			return -1;
		}
		growpte(o, (s->maxva-addr)>>PGSHIFT);
		poperror();
		/* stacks grown down, sigh */
		lock(o);
		memmove(o->pte+(o->npte-n), o->pte, n*sizeof(PTE));
		memset(o->pte, 0, (o->npte-n)*sizeof(PTE));
		unlock(o);
		s->minva = addr;
		o->va = addr;
	}else
		o = s->o;
	if(!read && (o->flag&OWRPERM)==0)
again:
	s = seg(u->p, addr, 1);
	if(s == 0)
		return -1;

	if(!read && (s->type&SG_RONLY)) {
		qunlock(&s->lk);
		return -1;
	lock(o);
	opte = &o->pte[(addr-o->va)>>PGSHIFT];
	pte = opte;
	if(s->mod){
		while(pte = pte->nextmod)	/* assign = */
			if(pte->proc == u->p){
				if(pte->page==0 || pte->page->va!=addr)
					panic("bad page %lux", pte->page);
				head = 0;
				break;
			}
		if(pte == 0)
			pte = opte;
	}
	if(pte->page == 0){
		touched = 1;
		if(o->chan==0 || addr>(o->va+(o->maxca-o->minca))){
			/* Make a new bss or lock segment page */
			if(s - u->p->seg == LSEG) {
				pte->page = lkpage(o, addr);
				if(pte->page == 0) {
					unlock(o);
					return -1;
				}
			}
			else
				pte->page = newpage(0, o, addr);
			zeroed = 1;
			o->npage++;
		}else{
			/*
			 * Demand load.  Release o because it could take a while.
			 */
			unlock(o);
			n = (o->va+(o->maxca-o->minca)) - addr;
			if(n > BY2PG)
				n = BY2PG;
			pg = newpage(1, o, addr);
			k = kmap(pg);
			qlock(&o->chan->rdl);
			if(waserror()){
				kunmap(k);
				qunlock(&o->chan->rdl);
				pg->o = 0;
				pg->ref--;
				pexit("demand load i/o error", 0);
			}
			l = (char*)VA(k);
			if((*devtab[o->chan->type].read)(o->chan, l, n, (addr-o->va) + o->minca) != n)
				error(Eioload);
			flushpage(pg->pa);
			qunlock(&o->chan->rdl);
			if(n<BY2PG)
				memset(l+n, 0, BY2PG-n);
			lock(o);
			kunmap(k);
			poperror();
			opte = &o->pte[(addr-s->minva)>>PGSHIFT];	/* could move */
			pte = opte;
			if(pte->page == 0){
				pte->page = pg;
				o->npage++;
			}else{		/* someone beat us to it */
				pg->o = 0;
				pg->ref--;
			}

	addr &= ~(BY2PG-1);
	soff = addr-s->base;
	p = &s->map[soff/PTEMAPMEM];
	if(*p == 0) 
		*p = ptealloc();

	pg = &(*p)->pages[(soff&(PTEMAPMEM-1))/BY2PG];
	type = s->type&SG_TYPE;

	switch(type) {
	case SG_TEXT:
		if(pagedout(*pg)) 		/* No data - must demand load */
			pio(s, addr, soff, pg);
		
		mmuphys = PPN((*pg)->pa) | PTERONLY|PTEVALID;
		(*pg)->modref = PG_REF;
		break;
	case SG_SHARED:
	case SG_BSS:
	case SG_STACK:	
			/* Zero fill on demand */
		if(*pg == 0) {			
			if(new == 0 && (new = newpage(1, &s, addr)) && s == 0)
				goto again;
			*pg = new;
			new = 0;
		}
						/* NO break */
	case SG_DATA:
		if(pagedout(*pg))
			pio(s, addr, soff, pg);

		if(type == SG_SHARED)
			goto done;

		if(read && conf.copymode == 0) {
			mmuphys = PPN((*pg)->pa) | PTERONLY|PTEVALID;
			(*pg)->modref |= PG_REF;
			break;
		}

		lkp = *pg;
		lockpage(lkp);
		if(lkp->ref > 1) {
			unlockpage(lkp);
			if(new == 0 && (new = newpage(0, &s, addr)) && s == 0)
				goto again;
			*pg = new;
			new = 0;
			copypage(lkp, *pg);
			putpage(lkp);
		}
		else {
			/* put a duplicate of a text page back onto the free list */
			if(lkp->image)     
				duppage(lkp);	
		
			unlockpage(lkp);
		}
	done:
		mmuphys = PPN((*pg)->pa) | PTEWRITE|PTEVALID;
		(*pg)->modref = PG_MOD|PG_REF;
		break;
	case SG_PHYSICAL:
		if(*pg == 0)
			*pg = (*s->pgalloc)(addr);

		mmuphys = PPN((*pg)->pa) | PTEWRITE|PTEUNCACHED|PTEVALID;
		(*pg)->modref = PG_MOD|PG_REF;
		break;
	default:
		panic("fault");
	}

	qunlock(&s->lk);
	if(new)
		putpage(new);

	putmmu(addr, mmuphys, *pg);
	return 0;
}

void
pio(Segment *s, ulong addr, ulong soff, Page **p)
{
	Page *new;
	KMap *k;
	Chan *c;
	int n, ask;
	char *kaddr;
	ulong daddr;
	Page *loadrec;

	loadrec = *p;
	if(loadrec == 0) {
		daddr = s->fstart+soff;			/* Compute disc address */
		new = lookpage(s->image, daddr);
	}
	else {
		daddr = swapaddr(loadrec);
		new = lookpage(&swapimage, daddr);
		if(new)
			putswap(loadrec);
	}

	if(o->flag&OSHARED) {
		/* BUG: Does not cover enough flag options to shared data */
		mmuphys = PTERONLY;
		if(o->flag & OWRPERM)
			mmuphys = PTEWRITE;
	if(new) {			/* Page found from cache */
		*p = new;
		return;
	}
	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");
		touched = 1;
		/*
		 * Look for the easy way out: are we the last non-modified?
		 */
		if(head && !(o->flag&OPURE)){
			npte = opte;
			for(i=0; npte; i++)
				npte = npte->nextmod;
			if(i == o->nproc)
				goto easy;

	qunlock(&s->lk);

	new = newpage(0, 0, addr);
	k = kmap(new);
	kaddr = (char*)VA(k);
	
	if(loadrec == 0) {			/* This is demand load */
		c = s->image->c;
		qlock(&c->rdl);
		if(waserror()) {
			qunlock(&c->rdl);
			kunmap(k);
			putpage(new);
			qlock(&s->lk);
			qunlock(&s->lk);
			pexit("demand load I/O error", 0);
		}
		if(head){
			/*
			 * Add to mod list
			 */
			pte = newmod(o);
			pte->proc = u->p;
			pte->page = opte->page;
			pte->page->ref++;
			o->npage++;
			/*
			 * Link into opte mod list (same va)
			 */
			pte->nextmod = opte->nextmod;
			opte->nextmod = pte;
			/*
			 * Link into proc mod list (increasing va)
			 */
			npte = s->mod;
			if(npte == 0){
				s->mod = pte;
				pte->nextva = 0;
			}else{
				while(npte->nextva && npte->nextva->page->va<addr)
					npte = npte->nextva;
				pte->nextva = npte->nextva;
				npte->nextva = pte;
			}
			head = 0;

		ask = s->flen-soff;
		if(ask > BY2PG)
			ask = BY2PG;
		n = (*devtab[c->type].read)(c, kaddr, ask, daddr);
		if(n != ask)
			error(Eioload);
		if(ask < BY2PG)
			memset(kaddr+ask, 0, BY2PG-ask);

		if((s->type&SG_TYPE) == SG_TEXT)
			memset(new->cachectl, PG_TXTFLUSH, sizeof(new->cachectl));

		poperror();
		kunmap(k);
		qunlock(&c->rdl);
		qlock(&s->lk);
		if(*p == 0) { 			/* Someone may have got there first */
			new->daddr = daddr;
			cachepage(new, s->image);
			*p = new;
		}
		pg = pte->page;
		/* when creating pages in the bss which are zfod we create a double
		 * increment on the mod list which must be removed
		 */
		if(zeroed){
			pg->ref--;
			o->npage--;
			opte->page = 0;
		}else{		/* copy page */
			pte->page = newpage(1, o, addr);
			k = kmap(pte->page);
			k1 = kmap(pg);
			memmove((void*)VA(k), (void*)VA(k1), BY2PG);
		else 
			putpage(new);
	}
	else {					/* This is paged out */
		c = swapimage.c;
		qlock(&c->rdl);

		if(waserror()) {
			qunlock(&c->rdl);
			kunmap(k);
			kunmap(k1);
			if(pg->ref <= 1)
				panic("pg->ref <= 1");
			pg->ref--;
			putpage(new);
			qlock(&s->lk);
			qunlock(&s->lk);
			pexit("page in I/O error", 0);
		}

    easy:
		mmuphys = PTEWRITE;
	}else{
		mmuphys = PTERONLY;
		if(o->flag & OWRPERM)
			if(o->flag & OPURE){
				if(!head && pte->page->ref==1)
					mmuphys = PTEWRITE;
			}else
				if((head && o->nproc==1)
	  			  || (!head && pte->page->ref==1))
					mmuphys = PTEWRITE;
	}
	mmuvirt = addr;

	/* 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);
	if(pte->proc && pte->proc != u->p){
		print("wrong proc in tail %d %s\n", head, u->p->text);
		print("u->p %lux pte->proc %lux\n", u->p, pte->proc);
		panic("addr %lux seg %d wrong proc in tail", addr, s-u->p->seg);
	}
		n = (*devtab[c->type].read)(c, kaddr, BY2PG, daddr);
		if(n != BY2PG)
			error(Eioload);

	unlock(o);
	if(touched == 0)
		m->tlbfault++;
		poperror();
		kunmap(k);
		qunlock(&c->rdl);
		qlock(&s->lk);

	putmmu(mmuvirt, mmuphys);
	return 0;
		if(pagedout(*p)) {
			new->daddr = daddr;
			cachepage(new, &swapimage);
			putswap(*p);
			*p = new;
		}
		else
			putpage(new);
	}
}

/*


@@ 235,36 219,35 @@ fault(ulong addr, int read)
void
validaddr(ulong addr, ulong len, int write)
{
	Seg *s, *ns;
	Segment *s;

	if((long)len < 0){
    Err:
		pprint("invalid address %lux in sys call pc %lux sp %lux\n", 
			addr, ((Ureg*)UREGADDR)->pc, ((Ureg*)UREGADDR)->sp);
		postnote(u->p, 1, "sys: bad address", NDebug);
		error(Ebadarg);
	}
    Again:
	s = seg(u->p, addr);
	if(s==0){
		s = &u->p->seg[SSEG];
		if(s->o==0 || addr<s->maxva-USTKSIZE || addr>=s->maxva)
			goto Err;
	}
	if(write && (s->o->flag&OWRPERM)==0)
		goto Err;
	if(addr+len > s->maxva){
		len -= s->maxva - addr;
		addr = s->maxva;
		goto Again;
	if((long)len >= 0) {
		for(;;) {
			s = seg(u->p, addr, 0);
			if(s == 0 || (write && (s->type&SG_RONLY)))
				break;

			if(addr+len > s->top) {
				len -= s->top - addr;
				addr = s->top;
				continue;
			}
			return;
		}
	}
}

	pprint("invalid address %lux in sys call pc %lux sp %lux\n", 
			addr, ((Ureg*)UREGADDR)->pc, ((Ureg*)UREGADDR)->sp);

	postnote(u->p, 1, "sys: bad address", NDebug);
	error(Ebadarg);
}
  
/*
 * &s[0] is known to be a valid address.
 */
void*
vmemchr(void *s, int c, ulong n)
vmemchr(void *s, int c, int n)
{
	int m;
	char *t;


@@ 272,32 255,37 @@ vmemchr(void *s, int c, ulong n)

	a = (ulong)s;
	m = BY2PG - (a & (BY2PG-1));
	while(n){
		if(n < m)
			m = n;
		t = memchr(s, c, m);
	if(m < n){
		t = vmemchr(s, c, m);
		if(t)
			return t;
		if(n == m)
			return 0;
		if(!(a & KZERO))
			validaddr(a+m, 1, 0);
		n -= m;
		a += m;
		m = BY2PG;
		return vmemchr((void*)(a+m), c, n-m);
	}
	return 0;
	/*
	 * All in one page
	 */
	return memchr(s, c, n);
}

Seg*
seg(Proc *p, ulong addr)
Segment*
seg(Proc *p, ulong addr, int dolock)
{
	Seg *s, *et;
	Segment **s, **et, *n;

	et = &p->seg[NSEG];
	for(s=p->seg; s < et; s++)
		if(s->o && s->minva<=addr && addr<s->maxva)
			return s;
	for(s = p->seg; s < et; s++)
		if(n = *s)
		if(addr >= n->base && addr < n->top) {
			if(dolock == 0)
				return n;

			qlock(&n->lk);
			if(addr >= n->base && addr < n->top)
				return n;
			qunlock(&n->lk);
		}

	return 0;
}

M port/ipdat.h => port/ipdat.h +2 -0
@@ 248,6 248,8 @@ struct Ipconv {
#define TIMER_RUN	1
#define TIMER_EXPIRE	2

#define Nreseq		64

#define	set_timer(t,x)	(((t)->start) = (x)/MSPTICK)
#define	dur_timer(t)	((t)->start)
#define	read_timer(t)	((t)->count)

M port/page.c => port/page.c +303 -593
@@ 6,48 6,49 @@
#include	"ureg.h"
#include	"errno.h"

struct
{
	Lock;
	ulong	addr;
	int	active;
	Page	*page;		/* base of Page structures, indexed by phys page number */
	ulong	minppn;		/* index of first usable page */
	Page	*head;		/* most recently used */
	Page	*tail;		/* least recently used */
}palloc;

struct
{
	Lock;
	Orig	*arena;
	Orig	*free;
}origalloc;

typedef union PTEA	PTEA;
union PTEA{
	PTE;
	struct{
		ulong	n;	/* for growpte */
		Orig	*o;	/* for growpte */
		PTEA	*next;	/* for newmod */
	};
};

struct
{
	Lock;
	PTEA	*arena;
	PTEA	*free;
	PTEA	*end;
}ptealloc;
#define PGHFUN(x, y)	(((ulong)x^(ulong)y)%PGHSIZE)
#define	pghash(s)	palloc.hash[PGHFUN(s->image, p->daddr)]

struct Palloc palloc;

struct{
struct Ptealloc
{
	Lock;
	PTEA	*free;
}modalloc;
	Pte	*free;
	int	pages;
}ptealloclk;

extern long end;
static Lock pglock;

/* 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;
}

/*
 * Called to allocate permanent data structures, before calling pageinit().


@@ 72,73 73,24 @@ ialloc(ulong n, int align)

	if(palloc.addr >= conf.maxialloc)
		panic("keep bill joy away");
	return (void*)(p|KZERO);
}

void
audit(char *s)
{
	int nf, nb;
	Page *p;
	static int here;

	do;while(here);
	here=1;
	p = palloc.head;
	nf = nb = 0;
	while(p){
		print("%lux %lux %d\n", p->pa, p->va, p->ref);
		if(p->o){
			print("\t%d %lux %c\n", p->o->nproc, p->o->qid, devchar[p->o->type]);
			delay(100);	/* let it drain; there's a lot here */
		}
		nf++;
		p = p->next;
	}
	p = palloc.tail;
	while(p){
		nb++;
		p = p->prev;
	}
	print("%s: nf: %d nb: %d\n", s, nf, nb);
	delay(1000);
	here=0;
	return (void*)(p|KZERO);
}

void
pageinit(void)
{
	ulong pa, nb, ppn;
	ulong i;
	ulong i, vmem, pmem;
	Page *p;
	PTEA *pte;
	Orig *o;

	ptealloc.arena = ialloc(conf.npte*sizeof(PTEA), 0);
	ptealloc.free = ptealloc.arena;
	ptealloc.end = ptealloc.arena+conf.npte;

	modalloc.free = ialloc(conf.nmod*sizeof(PTEA), 0);

	pte = modalloc.free;
	for(i=0; i<conf.nmod-1; i++,pte++)
		pte->next = pte+1;
	pte->next = 0;

	origalloc.free = ialloc(conf.norig*sizeof(Orig), 0);
	origalloc.arena = origalloc.free;

	o = origalloc.free;
	for(i=0; i<conf.norig-1; i++,o++)
		o->next = o+1;
	o->next = 0;
	palloc.active = 1;

	nb = (conf.npage<<PGSHIFT) - palloc.addr;
	nb -= ((nb+(BY2PG-1))>>PGSHIFT)*sizeof(Page);	/* safe overestimate */
	nb &= ~(BY2PG-1);
	pa = (conf.npage<<PGSHIFT) - nb;	/* physical addr of first free page */
	ppn = pa >> PGSHIFT;			/* physical page number of first free page */
	pa = (conf.npage<<PGSHIFT) - nb; /* physical addr of first free page */
	ppn = pa >> PGSHIFT;		 /* physical page number of first free page */
	palloc.page = (Page *)((palloc.addr - ppn*sizeof(Page))|KZERO);
	/*
	 * Now palloc.page[ppn] describes first free page


@@ 149,7 101,12 @@ pageinit(void)
	palloc.head = &palloc.page[ppn];
	palloc.tail = &palloc.page[conf.npage-1];
	memset(palloc.head, 0, (conf.npage-ppn)*sizeof(Page));
	print("%lud free pages\n", conf.npage-ppn);

	pmem = ((conf.npage-ppn)*BY2PG)/1024;
	vmem = pmem + ((conf.nswap)*BY2PG)/1024;
	palloc.user = conf.npage-ppn;
	print("%lud free pages, %dK bytes, swap %dK bytes\n", palloc.user, pmem, vmem);

	for(p=palloc.head; p<=palloc.tail; p++,ppn++){
		p->next = p+1;
		p->prev = p-1;


@@ 157,583 114,336 @@ pageinit(void)
			p->pa = conf.base0+(ppn<<PGSHIFT);
		else
			p->pa = conf.base1+((ppn-conf.npage0)<<PGSHIFT);
		palloc.freecount++;
	}
	palloc.head->prev = 0;
	palloc.tail->next = 0;
}

Page*
newpage(int noclear, Orig *o, ulong va)
newpage(int clear, Segment **s, ulong va)
{
	Page *p;
	Orig *o1;
	KMap *k;
	int i;

	if(palloc.active == 0)
		print("newpage inactive\n");
loop:

	lock(&palloc);
	for(p=palloc.tail; p; p=p->prev){
		if(p->ref == 0)
			goto out;
#ifdef asdf
		if(p->ref == 1){	/* a pageout daemon should do this */
			o1 = p->o;
			if(o1 && o1->nproc==0 && canlock(o1)){
				if(o1->nproc){
					unlock(o1);
					continue;
				}
				print("free %d pages va %lux %lux %c\n", o1->npage, o->va, o1->qid, devchar[o1->type]);
				freepage(o1, 0);
				/* neworig will free the orig and pte's later */
				unlock(o1);
				if(p->ref == 0)
					goto out;
				print("newpage ref != 0");
			}

	/* The kp test is a poor guard against the pager deadlocking */
	while((palloc.freecount < HIGHWATER && u->p->kp == 0) || palloc.freecount == 0) {
		palloc.wanted++;
		unlock(&palloc);			
		if(s && *s) {
			qunlock(&((*s)->lk));
			*s = 0;
		}
#endif
		qlock(&palloc.pwait);			/* Hold memory requesters here */

		kickpager();
		tsleep(&palloc.r, ispages, 0, 1000);

		qunlock(&palloc.pwait);
		lock(&palloc);
		palloc.wanted--;
	}

	p = palloc.head;
	if(palloc.head = p->next)		/* = Assign */
		palloc.head->prev = 0;
	else
		palloc.tail = 0;

	palloc.freecount--;
	unlock(&palloc);
	if(freebroken())
		goto loop;
	if(u == 0)

	lockpage(p);

	if(p->ref != 0)
		panic("newpage");
	print("no physical memory\n");
	pprint("no physical memory\n");
	u->p->state = Wakeme;
	alarm(1000, wakeme, u->p);
	sched();
	goto loop;
    out:
	if(p->o){
		print("page in use %lux %lux %lux %lux\n", p, p->va, p->o, origalloc.arena);
		print("%c %lux %lux, %d %d %d\n", devchar[p->o->type], p->o->va, p->o->qid, p->o->flag, p->o->nproc, p->o->npte);
		panic("shit");
	}
	p->ref = 1;
	usepage(p, 0);
	unlock(&palloc);
	if(!noclear){

	uncachepage(p);
	p->ref++;
	p->va = va;
	p->modref = 0;
	for(i = 0; i < MAXMACH; i++)
		p->cachectl[i] = PG_NOFLUSH;
	unlockpage(p);

	if(clear){
		k = kmap(p);
		memset((void*)VA(k), 0, BY2PG);
		kunmap(k);
	}
	p->o = o;
	p->va = va;

	return p;
}

/*
 * Move page to head of list
 */
void
usepage(Page *p, int dolock)
int
ispages(void *p)
{
	if(dolock)
		lock(&palloc);
	/*
	 * Unlink
	 */
	if(p->prev)
		p->prev->next = p->next;
	else
		palloc.head = p->next;
	if(p->next)
		p->next->prev = p->prev;
	else
		palloc.tail = p->prev;
	/*
	 * Link
	 */
	p->next = palloc.head;
	p->prev = 0;
	if(p->next)
		p->next->prev = p;
	else
		palloc.tail = p;
	palloc.head = p;
	if(dolock)
		unlock(&palloc);
	return palloc.freecount >= HIGHWATER;
}

/*
 * Move page to tail of list
 */
void
unusepage(Page *p, int dolock)
putpage(Page *p)
{
	if(dolock)
		lock(&palloc);
	/*
	 * Unlink
	 */
	if(p->prev)
		p->prev->next = p->next;
	else
		palloc.head = p->next;
	if(p->next)
		p->next->prev = p->prev;
	else
		palloc.tail = p->prev;
	/*
	 * Link
	 */
	p->prev = palloc.tail;
	p->next = 0;
	if(p->prev)
		p->prev->next = p;
	else
		palloc.head = p;
	palloc.tail = p;
	if(dolock)
		unlock(&palloc);
}
	int count;

Orig*
lookorig(ulong va, ulong npte, int flag, Chan *c)
{
	Orig *o;
	ulong i;

	for(o=origalloc.arena,i=0; i<conf.norig; i++,o++)
		if(o->npage && o->qid.path==c->qid.path && o->va==va){
			lock(o);
			if(o->npage && eqqid(o->qid, c->qid))
			if(o->va==va && o->npte==npte && o->flag==flag)
			if(o->mchan==c->mchan && o->type==c->type && eqqid(o->mqid, c->mqid)){
				if(o->chan == 0){
					o->chan = c;
					incref(c);
				}
				o->nproc++;
				unlock(o);
				return o;
			}
			unlock(o);
		}
	return 0;
}
	if(onswap(p)) {
		putswap(p);
		return;
	}

Orig*
neworig(ulong va, ulong npte, int flag, Chan *c)
{
	Orig *o;
	int i, freed;

lockloop:
	lock(&origalloc);
loop:
	if(o = origalloc.free){		/* assign = */
		origalloc.free = o->next;
		o->va = va;
		o->pte = 0;
		o->flag = flag;
		o->nproc = 1;
		o->npage = 0;
		o->chan = c;
		o->freepg = unusepage;
		if(c){
			o->type = c->type;
			o->qid = c->qid;
			o->mchan = c->mchan;
			o->mqid = c->mqid;
			incref(c);
		}else{
			o->type = 0xFFFF;
			o->qid = (Qid){~0, ~0};
			o->mqid = (Qid){~0, ~0};
			o->mchan = 0;
		}
		if(u && u->p && waserror()){
			unlock(&origalloc);
			nexterror();
	lockpage(p);
	if(--p->ref == 0) {
		lock(&palloc);
		if(p->image) {
			if(palloc.tail) {
				p->prev = palloc.tail;
				palloc.tail->next = p;
				p->next = 0;
				palloc.tail = p;
			}
			else {
				palloc.head = palloc.tail = p;
				p->prev = p->next = 0;
			}
		}
		growpte(o, npte);
		if(u && u->p)
			poperror();
		unlock(&origalloc);
		return o;
	}
	/*
	 * This is feeble.  Orig's should perhaps be held in
	 * an LRU list.  This algorithm is too aggressive.
	 */
	freed = 0;
	for(o=origalloc.arena,i=0; i<conf.norig; i++,o++){
		if(o->nproc==0 && canlock(o)){
			if(o->nproc){
				unlock(o);
				continue;
		else {
			if(palloc.head) {
				p->next = palloc.head;
				palloc.head->prev = p;
				p->prev = 0;
				palloc.head = p;
			}
			else {
				palloc.head = palloc.tail = p;
				p->prev = p->next = 0;
			}
			freepage(o, 1);
			freepte(o);
			unlock(o);
			o->next = origalloc.free;
			origalloc.free = o;
			freed++;
		}
	}
	if(freed)
		goto loop;
	unlock(&origalloc);
	if(freebroken())
		goto lockloop;
	print("no origs freed\n");
	if(u == 0)
		panic("neworig");
	u->p->state = Wakeme;
	alarm(1000, wakeme, u->p);
	sched();
	lock(&origalloc);
	goto loop;
}

PTE*
newmod(Orig *o)
{
	PTEA *pte;

loop:
	lock(&modalloc);
	if(pte = modalloc.free){		/* assign = */
		modalloc.free = pte->next;
		unlock(&modalloc);
		memset(pte, 0, sizeof(PTE));
		return pte;
		palloc.freecount++;		/* Release people waiting for memory */
		unlock(&palloc);
	}
	unlock(&modalloc);
	print("no mods\n");
	if(u == 0)
		panic("newmod");
	u->p->state = Wakeme;
	alarm(1000, wakeme, u->p);
	sched();
	goto loop;
	unlockpage(p);

	if(palloc.wanted)
		wakeup(&palloc.r);
}

/*
 * Duplicate mod structure for this segment (old) in new process p.
 * old->o must be locked.
 */
void
forkmod(Seg *old, Seg *new, Proc *p)
duppage(Page *p)				/* Always call with p locked */
{
	Orig *o;
	PTE *pte, *ppte, *opte, *npte;
	ulong va;

	o = old->o;
	ppte = 0;
	pte = old->mod;
	while(pte){
		npte = newmod(o);
		npte->proc = p;
		npte->page = pte->page;
		pte->page->ref++;
		o->npage++;
		/*
		 * Link into mod list for this va
		 */
		npte->nextmod = pte->nextmod;
		pte->nextmod = npte;
		/*
		 * Link into mod list for new segment
		 */
		if(ppte == 0)
			new->mod = npte;
		else
			ppte->nextva = npte;
		npte->nextva = 0;
		ppte = npte;
		pte = pte->nextva;
	Page *np;

	lock(&palloc);

	if(palloc.freecount < HIGHWATER || /* No freelist cache when memory is very low */
	   p->image == &swapimage) {	   /* No dup for swap pages */
		unlock(&palloc);
		uncachepage(p);	
		return;
	}
}

void
freesegs(int save)
{
	int i, j;
	Seg *s;
	Orig *o;
	PTE *pte, *opte;
	PTEA *old;
	Page *pg;
	Chan *c;
	np = palloc.head;			/* Allocate a new page from freelist */
	if(palloc.head = np->next)		/* = Assign */
		palloc.head->prev = 0;
	else
		palloc.tail = 0;

	/*
	 * flushvirt() is a no-op on machines without virtual write-back caches.
	 * On such machines it is necessary to make sure the caches are flushed
	 * before the pages are remapped.
	 */
	flushvirt();
	s = u->p->seg;
	for(i=0; i<NSEG; i++,s++){
		if(i == save)
			continue;
		o = s->o;
		s->o = 0;	/* seg() won't match it (e.g. in procread()) */
		if(o == 0)
			continue;
		lock(o);
		if(pte = s->mod){	/* assign = */
			while(pte){
				opte = &o->pte[(pte->page->va-o->va)>>PGSHIFT];
				while(opte->nextmod != pte){
					if(opte->page && opte->page->va != pte->page->va)
						panic("pte %lux %lux\n", opte->page->va, pte->page->va);
					opte = opte->nextmod;
					if(opte == 0)
						panic("freeseg opte==0");
				}
				opte->nextmod = pte->nextmod;
				pg = pte->page;
				if(pg->ref == 1){
					pte->page = 0;
					pg->o = 0;
				}
				pg->ref--;
				o->npage--;
				old = (PTEA*)pte;
				pte = pte->nextva;
				lock(&modalloc);
				old->next = modalloc.free;
				modalloc.free = old;
				unlock(&modalloc);
			}
		}
		o->nproc--;
		if(o->nproc == 0){
			if(c = o->chan){	/* assign = */
				o->chan = 0;
				close(c);
			}
			if(!(o->flag&OCACHED) || o->npage==0){
				freepage(o, 1);
				freepte(o);
				unlock(o);
				lock(&origalloc);
				o->next = origalloc.free;
				origalloc.free = o;
				unlock(&origalloc);
			}else
				unlock(o);
		}else{
			/*
			 * BUG: there is a leak here. if the origin pte is being used only
			 * by the exiting process, the associated page will linger.  the fix
			 * is to remember either the length of the mod list at each va or
			 * the number of processes sharing the origin pte, and to promote one
			 * of the mods to the origin pte when no process is left using the
			 *  origin pte.
			 */
			unlock(o);
		}
	if(palloc.tail) {			/* Link back onto tail to give us lru */
		np->prev = palloc.tail;
		palloc.tail->next = np;
		np->next = 0;
		palloc.tail = np;
	}
	else {
		palloc.head = palloc.tail = np;
		np->prev = np->next = 0;
	}
}

/*
 * Adjust segment to desired size.  This implementation is rudimentary.
 */
int
segaddr(Seg *s, ulong min, ulong max)
{
	Orig *o;

	if(max < min)
		return 0;
	if(min != s->minva)	/* can't grow down yet (stacks: fault.c) */
		return 0;
	max = PGROUND(max);
	o = s->o;
	if(max == s->maxva)
		return 1;
	if(max > s->maxva){
		/*
		 * Grow
		 */
		/* BUG: check spill onto other segments */
		if(o->va+BY2PG*o->npte < max)
			growpte(o, (max-o->va)>>PGSHIFT);
		s->maxva = max;
		return 1;
	unlock(&palloc);

	lockpage(np);				/* Cache the new version */
	if(np->ref != 0) {			/* Stolen by new page */
		uncachepage(p);
		unlockpage(np);
		return;
	}
	/*
	 * Shrink
	 */
	print("segaddr shrink");
	pexit("Suicide", 0);
	
	uncachepage(np);
	np->va = p->va;
	np->daddr = p->daddr;
	copypage(p, np);
	cachepage(np, p->image);
	unlockpage(np);
	uncachepage(p);
}

/*
 * o is locked
 */
void
freepage(Orig *o, int dolock)
copypage(Page *f, Page *t)
{
	PTE *pte;
	Page *pg;
	int i;
	KMap *ks, *kd;

	ks = kmap(f);
	kd = kmap(t);
	memmove((void*)VA(kd), (void*)VA(ks), BY2PG);
	kunmap(ks);
	kunmap(kd);
}

	pte = o->pte;
	for(i=0; i<o->npte; i++,pte++) {
		if(pg = pte->page){	/* assign = */
			if(pg->ref == 1){
				(*o->freepg)(pg, dolock);
				pte->page = 0;
				pg->o = 0;
void
uncachepage(Page *p)				/* Alway 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;
			}
			pg->ref--;
			l = &f->hash;
		}
		unlock(&palloc.hashlock);
		putimage(p->image);
		p->image = 0;
	}
	o->npage = 0;
}

/*
 * Compacting allocator
 */

void
freepte(Orig *o)	/* o is locked */
cachepage(Page *p, Image *i)
{
	PTEA *p;
	p = (PTEA*)(o->pte - 1);
	p->o = 0;
	Page **l;

	incref(i);
	lock(&palloc.hashlock);
	p->image = i;
	l = &pghash(p);
	p->hash = *l;
	*l = p;
	unlock(&palloc.hashlock);
}

/*
 * o is locked.  this will always do a grow; if n<=o->npte someone
 * else got here first and we can just return.
 */
void
growpte(Orig *o, ulong n)
Page *
lookpage(Image *i, ulong daddr)
{
	PTEA *p;
	ulong nfree;

	lock(&ptealloc);
	lock(o);
	if(o->pte){
		if(o->npte >= n)
			goto Return;
		p = (PTEA*)(o->pte - 1);
		n++;
		if(p+p->n == ptealloc.free){
			if(!compactpte(o, n - p->n))
				goto Trouble;
			p = (PTEA*)(o->pte - 1);
			ptealloc.free += n - p->n;
		}else{
			if(!compactpte(o, n))
				goto Trouble;
			p = ptealloc.free;
			ptealloc.free += n;
			memmove(p+1, o->pte, o->npte*sizeof(PTE));
			p->o = o;
			((PTEA*)(o->pte-1))->o = 0;
			o->pte = p+1;
	Page *f;

	lock(&palloc.hashlock);
	for(f = palloc.hash[PGHFUN(i, daddr)]; f; f = f->hash) {
		if(f->image == i && f->daddr == daddr) {
			unlock(&palloc.hashlock);

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

			lock(&palloc);
			if(++f->ref == 1) {
				if(f->prev) 
					f->prev->next = f->next;
				else
					palloc.head = f->next;

				if(f->next)
					f->next->prev = f->prev;
				else
					palloc.tail = f->prev;
				palloc.freecount--;
			}
			unlock(&palloc);

			unlockpage(f);
			return f;	
		}
		memset(p+1+o->npte, 0, (n-(1+o->npte))*sizeof(PTE));
		p->n = n;
		o->npte = n-1;
		goto Return;
	}
	n++;
	if(!compactpte(o, n))
		goto Trouble;
	p = ptealloc.free;
	ptealloc.free += n;
	memset(p, 0, n*sizeof(PTE));
	p->n = n;
	p->o = o;
	o->pte = p+1;
	o->npte = n-1;
    Return:
	unlock(&ptealloc);
	unlock(o);
	return;

    Trouble:
	unlock(&ptealloc);
	unlock(o);
	if(u && u->p)
		error(Enovmem);
	panic("growpte fails %d %lux %d\n", n, o->va, o->npte);
	unlock(&palloc.hashlock);
	return 0;
}

int
compactpte(Orig *o, ulong n)
Pte*
ptecpy(Pte *old)
{
	PTEA *p1, *p2;
	Orig *p2o;

	if(ptealloc.end-ptealloc.free >= n)
		return 1;
	p1 = ptealloc.arena;	/* dest */
	p2 = ptealloc.arena;	/* source */
	while(p2 < ptealloc.free){
		p2o = p2->o;
		if(p2o == 0){
    Free:
			p2 += p2->n;
			continue;
		}
		if(p1 != p2){
			if(p2o != o)
				lock(p2o);
			if(p2->o != p2o){	/* freepte()d very recently */
				if(p2->o)
					panic("compactpte p2->o %lux\n", p2->o);
				unlock(p2o);
				goto Free;
	Page **src, **dst, **end;
	Pte *new;

	new = ptealloc();

	end = &old->pages[PTEPERTAB];
	for(src = old->pages, dst = new->pages; src < end; src++, dst++)
		if(*src) {
			if(onswap(*src))
				dupswap(*src);
			else {
				lockpage(*src);
				(*src)->ref++;
				unlockpage(*src);
			}
			memmove(p1, p2, p2->n*sizeof(PTE));
			p2o->pte = p1+1;
			if(p2o != o)
				unlock(p2o);
			*dst = *src;
		}
		p2 += p1->n;
		p1 += p1->n;
	}
	ptealloc.free = p1;
	if(ptealloc.end-ptealloc.free >= n)
		return 1;
	unlock(o);
	unlock(&ptealloc);
	if(u && u->p)
		print("%s: %s: ", u->p->text, u->p->pgrp->user);
	print("compactpte fails addr %lux %lux %d\n", o->va+n*BY2PG, o->va, n);
	return 0;

	return new;		
}

long
ibrk(ulong addr, int seg)
Pte*
ptealloc(void)
{
	Seg *s;
	Pte *new;
	int i, n;
	KMap *k;

	s = &u->p->seg[seg];
	if(seg == LSEG && s->o == 0)
		mklockseg(s);
	lock(&ptealloclk);
	while(ptealloclk.free == 0) {
		unlock(&ptealloclk);

	/* Allows us to determine the base of the segment */
	if(addr == 0)
		return s->minva;
		k = kmap(newpage(1, 0, 0));
		new = (Pte*)VA(k);
		n = (BY2PG/sizeof(Pte))-1;
		for(i = 0; i < n; i++)
			new[i].next = &new[i+1];

	if(addr < s->endseg){
		pprint("addr below segment\n");
		pexit("Suicide", 0);
		error(Esegaddr);
		lock(&ptealloclk);
		ptealloclk.pages++;
		new[i].next = ptealloclk.free;
		ptealloclk.free = new;
	}

	if(addr > PGROUND(s->endseg))
		if(segaddr(s, s->minva, addr) == 0){
			pprint("bad segaddr in brk\n");
			pexit("Suicide", 0);
			error(Esegaddr);
		}
	new = ptealloclk.free;
	ptealloclk.free = new->next;
	unlock(&ptealloclk);
	memset(new->pages, 0, sizeof(new->pages));
	return new;
}

	s->endseg = addr;
	return 0;
void
freepte(Segment *s, Pte *p)
{
	Page **pg, **ptop;

	ptop = &p->pages[PTEPERTAB];

	switch(s->type&SG_TYPE) {
	case SG_PHYSICAL:
		for(pg = p->pages; pg < ptop; pg++)
			if(*pg)
				(*s->pgfree)(*pg);
		break;
	default:
		for(pg = p->pages; pg < ptop; pg++)
			if(*pg)
				putpage(*pg);
	}

	lock(&ptealloclk);
	p->next = ptealloclk.free;
	ptealloclk.free = p;
	unlock(&ptealloclk);
}

M port/pgrp.c => port/pgrp.c +148 -26
@@ 5,13 5,26 @@
#include	"fns.h"
#include	"errno.h"

struct{
struct
{
	Lock;
	Pgrp	*arena;
	Pgrp	*free;
	ulong	pgrpid;
}pgrpalloc;

struct
{
	Lock;
	Egrp	*free;
}egrpalloc;

struct
{
	Lock;
	Fgrp	*free;
}fgrpalloc;

struct{
	Lock;
	Mount	*free;


@@ 19,11 32,13 @@ struct{
}mountalloc;

void
pgrpinit(void)
grpinit(void)
{
	int i;
	Pgrp *p;
	Mount *m;
	Egrp *e, *ee;
	Fgrp *f, *fe;
	Mount *m, *em;

	pgrpalloc.arena = ialloc(conf.npgrp*sizeof(Pgrp), 0);
	pgrpalloc.free = pgrpalloc.arena;


@@ 33,14 48,26 @@ pgrpinit(void)
		p->index = i;
		p->next = p+1;
		p->mtab = ialloc(conf.nmtab*sizeof(Mtab), 0);
		p->etab = ialloc(conf.npgenv*sizeof(Envp*), 0);
	}
	p[-1].next = 0;

	mountalloc.free = ialloc(conf.nmount*sizeof(Mount), 0);
	egrpalloc.free = ialloc(conf.npgrp*sizeof(Egrp), 0);
	ee = &egrpalloc.free[conf.npgrp];
	for(e = egrpalloc.free; e < ee; e++) {
		e->next = e+1;
		e->etab = ialloc(conf.npgenv*sizeof(Envp*), 0);
	}
	e[-1].next = 0;

	fgrpalloc.free = ialloc(conf.nproc*sizeof(Fgrp), 0);
	fe = &fgrpalloc.free[conf.nproc-1];
	for(f = fgrpalloc.free; f < fe; f++)
		f->next = f+1;
	f->next = 0;

	m = mountalloc.free;
	for(i=0; i<conf.nmount-1; i++,m++)
	mountalloc.free = ialloc(conf.nmount*sizeof(Mount), 0);
	em = &mountalloc.free[conf.nmount-1];
	for(m = mountalloc.free; m < em; m++)
		m->next = m+1;
	m->next = 0;
}


@@ 86,25 113,88 @@ newpgrp(void)
{
	Pgrp *p;

loop:
	lock(&pgrpalloc);
	if(p = pgrpalloc.free){		/* assign = */
		pgrpalloc.free = p->next;
		p->ref = 1;
		p->pgrpid = ++pgrpalloc.pgrpid;
		p->nmtab = 0;
		p->nenv = 0;
	for(;;) {
		lock(&pgrpalloc);
		if(p = pgrpalloc.free){
			pgrpalloc.free = p->next;
			p->ref = 1;
			p->pgrpid = ++pgrpalloc.pgrpid;
			p->nmtab = 0;
			unlock(&pgrpalloc);
			return p;
		}
		unlock(&pgrpalloc);
		return p;
		resrcwait("no pgrps");
	}
	unlock(&pgrpalloc);
	print("no pgrps\n");
}

Egrp*
newegrp(void)
{
	Egrp *e;

	for(;;) {
		lock(&egrpalloc);
		if(e = egrpalloc.free) {
			egrpalloc.free = e->next;
			e->ref = 1;
			e->nenv = 0;
			unlock(&egrpalloc);
			return e;
		}
		unlock(&egrpalloc);
		resrcwait("no envgrps");
	}
}

Fgrp*
newfgrp(void)
{
	Fgrp *f;

	for(;;) {
		lock(&fgrpalloc);
		if(f = fgrpalloc.free) {
			fgrpalloc.free = f->next;
			f->ref = 1;
			f->maxfd = 0;
			memset(f->fd, 0, sizeof(f->fd));
			unlock(&fgrpalloc);
			return f;
		}
		unlock(&fgrpalloc);
		resrcwait("no filegrps");
	}
}

Fgrp*
dupfgrp(Fgrp *f)
{
	Fgrp *new;
	Chan *c;
	int i;

	new = newfgrp();

	new->maxfd = f->maxfd;
	for(i = 0; i <= f->maxfd; i++)
		if(c = f->fd[i]){
			incref(c);
			new->fd[i] = c;
		}

	return new;
}

void
resrcwait(char *reason)
{
	print("%s\n", reason);
	if(u == 0)
		panic("newpgrp");
		panic("resched");
	u->p->state = Wakeme;
	alarm(1000, wakeme, u->p);
	sched();
	goto loop;
}

void


@@ 112,7 202,6 @@ closepgrp(Pgrp *p)
{
	int i;
	Mtab *m;
	Envp *ep;

	if(decref(p) == 0){
		qlock(&p->debug);


@@ 123,10 212,6 @@ closepgrp(Pgrp *p)
				close(m->c);
				closemount(m->mnt);
			}
		ep = p->etab;
		for(i=0; i<p->nenv; i++,ep++)
			if(ep->env)
				envpgclose(ep->env);
		lock(&pgrpalloc);
		p->next = pgrpalloc.free;
		pgrpalloc.free = p;


@@ 135,6 220,43 @@ closepgrp(Pgrp *p)
	}
}

void
closeegrp(Egrp *e)
{
	Envp *ep;
	int i;

	if(decref(e) == 0) {
		ep = e->etab;
		for(i=0; i<e->nenv; i++,ep++)
			if(ep->env)
				envpgclose(ep->env);
		lock(&egrpalloc);
		e->next = egrpalloc.free;
		egrpalloc.free = e;
		unlock(&egrpalloc);
	}
}

void
closefgrp(Fgrp *f)
{
	int i;
	Chan *c;

	if(decref(f) == 0) {
		for(i = 0; i <= f->maxfd; i++)
			if(c = f->fd[i])
				close(c);

		lock(&fgrpalloc);
		f->next = fgrpalloc.free;
		fgrpalloc.free = f;
		unlock(&fgrpalloc);
	}
}


Mount*
newmount(void)
{


@@ 182,7 304,7 @@ closemount(Mount *m)
}

void
envcpy(Pgrp *to, Pgrp *from)
envcpy(Egrp *to, Egrp *from)
{
	Envp *ep;
	Env *e;

M port/portdat.h => port/portdat.h +152 -61
@@ 5,27 5,30 @@ typedef struct Blist	Blist;
typedef struct Chan	Chan;
typedef struct Dev	Dev;
typedef struct Dirtab	Dirtab;
typedef struct Egrp	Egrp;
typedef struct Env	Env;
typedef struct Envp	Envp;
typedef struct Envval	Envval;
typedef struct Etherpkt	Etherpkt;
typedef struct Fgrp	Fgrp;
typedef struct Image	Image;
typedef struct IOQ	IOQ;
typedef struct KIOQ	KIOQ;
typedef struct List	List;
typedef struct Mount	Mount;
typedef struct Mtab	Mtab;
typedef struct Note	Note;
typedef struct Orig	Orig;
typedef struct PTE	PTE;
typedef struct Page	Page;
typedef struct Palloc	Palloc;
typedef struct Pgrp	Pgrp;
typedef struct Proc	Proc;
typedef struct Pte	Pte;
typedef struct Qinfo	Qinfo;
typedef struct QLock	QLock;
typedef struct Queue	Queue;
typedef struct Ref	Ref;
typedef struct Rendez	Rendez;
typedef struct Seg	Seg;
typedef struct Segment	Segment;
typedef struct Stream	Stream;

typedef int Devgen(Chan*, Dirtab*, int, int, Dir*);


@@ 177,7 180,7 @@ struct Env
	Lock;
	Envval	*val;
	char	name[NAMELEN];
	Env	*next;			/* in chain of Envs for a pgrp */
	Env	*next;			/* in chain of Envs for a egrp */
	int	pgref;			/* # pgrps pointing here */
};



@@ 259,57 262,146 @@ struct Note
	int	flag;			/* whether system posted it */
};

#define	OWRPERM	0x01	/* write permission */
#define	OPURE	0x02	/* original data mustn't be written */
#define	OCACHED	0x04	/* cached; don't discard on exit */
#define OISMEM	0x08	/* origin contains real memory */
#define OSHARED	0x10	/* origin does not copy on ref/wr */
/* 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

struct Orig
struct Page
{
	Lock;
	Orig	*next;			/* for allocation */
	ushort	nproc;			/* processes using it */
	ushort	npage;			/* sum of refs of pages in it */
	ushort	flag;
	ulong	va;			/* va of 0th pte */
	ulong	npte;			/* #pte's in list */
	PTE	*pte;
	Chan	*chan;			/* channel deriving segment (if open) */
	ushort	type;			/* of channel (which could be non-open) */
	Qid	qid;
	Chan	*mchan;
	ulong	pa;			/* Physical address in memory */
	ulong	va;			/* Virtual address for user */
	ulong	daddr;			/* Disc address on swap */
	ushort	ref;			/* Reference count */
	char	lock;			/* Software lock */
	char	modref;			/* Simulated modify/reference bits */
	char	cachectl[MAXMACH];	/* Cache flushing control for putmmu */
	Image	*image;			/* Associated text or swap image */
	Page	*next;			/* Lru free list */
	Page	*prev;
	Page	*hash;			/* Image hash chains */
};

struct Swapalloc
{
	Lock;			/* Free map lock */
	int	free;		/* Number of currently free swap pages */
	char	*swmap;		/* Base of swap map in memory */
	char	*alloc;		/* Round robin allocator */
	char	*top;		/* Top of swap map */
	Rendez	r;		/* Pager kproc idle sleep */
}swapalloc;

struct Image
{
	Ref;
	Chan	*c;			/* Channel associated with running image */
	Qid 	qid;			/* Qid for page cache coherence checks */
	Qid	mqid;
	ulong	minca;			/* base of region in chan */
	ulong	maxca;			/* end of region in chan */
	void	(*freepg)(Page*, int);	/* how to free pages for this origin */
	Page	(*allocpg)(int, Orig*, ulong);
	Chan	*mchan;
	ushort	type;			/* Device type of owning channel */
	Segment *s;			/* TEXT segment for image if running, may be null */
	Image	*hash;			/* Qid hash chains */
	Image	*next;			/* Free list */
};

struct Page
struct Pte
{
	Orig	*o;			/* origin of segment owning page */
	ulong	va;			/* virtual address */
	ulong	pa;			/* physical address */
	ushort	ref;
	Page	*next;
	Page	*prev;
	union {
		Pte	*next;			/* Free list */
		Page	*pages[PTEPERTAB];	/* Page map for this chunk of pte */
	};
};

/* Segment types */
#define SG_TYPE		007		/* Mask type of segment */
#define SG_TEXT		000
#define SG_DATA		001
#define SG_BSS		002
#define SG_STACK	003
#define SG_SHARED	004
#define SG_PHYSICAL	005
/* Segment flags */
#define SG_RONLY	040		/* Segment is read only */

#define HIGHWATER	((conf.npage*5)/100)
#define MAXHEADROOM	HIGHWATER*2	/* Silly but OK for debug */
#define PG_ONSWAP	1
#define pagedout(s)	(((ulong)s)==0 || (((ulong)s)&PG_ONSWAP))
#define swapaddr(s)	(((ulong)s)&~PG_ONSWAP)
#define onswap(s)	(((ulong)s)&PG_ONSWAP)

#define SEGMAXSIZE	(SEGMAPSIZE*PTEMAPMEM)

struct Segment
{
	Ref;
	QLock	lk;
	ushort	steal;			/* Page stealer lock */
	Segment	*next;			/* free list pointers */
	ushort	type;			/* segment type */
	ulong	base;			/* virtual base */
	ulong	top;			/* virtual top */
	ulong	size;			/* size in pages */
	ulong	fstart;			/* start address in file for demand load */
	ulong	flen;			/* length of segment in file */
	Image	*image;			/* image in file system attached to this segment */
	Page	*(*pgalloc)(ulong addr);/* SG_PHYSICAL page allocator */
	void	(*pgfree)(Page *);	/* SG_PHYSICAL page free */
	Pte	*map[SEGMAPSIZE];	/* segment pte map */
};

struct Pgrp
{
	Ref;				/* also used as a lock when mounting */
	Pgrp	*next;
	Pgrp	*next;			/* free list */
	int	index;			/* index in pgrp table */
	ulong	pgrpid;
	char	user[NAMELEN];
	int	nmtab;			/* highest active mount table entry, +1 */
	int	nenv;			/* highest active env table entry, +1 */
	QLock	debug;			/* single access via devproc.c */
	Mtab	*mtab;
};

struct Egrp
{
	Ref;
	Egrp	*next;
	int	nenv;			/* highest active env table entry, +1 */
	Envp	*etab;
};

#define	NFD	100
struct Fgrp
{
	Ref;
	Fgrp	*next;
	Chan	*fd[NFD];
	int	maxfd;			/* highest fd in use */
};

#define PGHSIZE	512
struct Palloc
{
	Lock;
	ulong	addr;
	int	active;
	Page	*page;		/* base of Page structures, indexed by phys page number */
	ulong	minppn;		/* index of first usable page */
	Page	*head;		/* most recently used */
	Page	*tail;		/* least recently used */
	ulong	freecount;	/* how many pages on free list now */
	ulong	user;		/* how many user pages */
	Page	*hash[PGHSIZE];
	Lock	hashlock;
	Rendez	r;		/* Sleep for free mem */
	QLock	pwait;		/* Queue of procs waiting for memory */
	int	wanted;		/* Do the wakeup at free */
};

enum					/* Argument to forkpgrp call */
{
	FPall 	  = 0,			/* Concession to back portablility */


@@ 324,17 416,7 @@ enum					/* Argument to forkpgrp call */
 */
enum
{
	SSEG, TSEG, DSEG, BSEG, ESEG, LSEG, NSEG
};

struct Seg
{
	Proc	*proc;			/* process owning this segment */
	Orig	*o;			/* root list of pte's */
	ulong	minva;			/* va of 0th pte (not necessarily Seg->o->va) */
	ulong	maxva;			/* va of last pte */
	PTE	*mod;			/* list of modified pte's */
	ulong	endseg;			/* segments end */
	SSEG, TSEG, DSEG, BSEG, ESEG, LSEG, SEG1, SEG2, NSEG
};

/*


@@ 354,6 436,16 @@ enum
	Inwait,
	Wakeme,
	Broken,
	Stopped,
};

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

/*


@@ 379,14 471,18 @@ struct Proc
	QLock	*qlock;			/* address of qlock being queued for DEBUG */
	int	state;
	Page	*upage;			/* BUG: should be unlinked from page list */
	Seg	seg[NSEG];
	Segment	*seg[NSEG];
	ulong	pid;
	int	nchild;
	QLock	wait;			/* exiting children to be waited for */
	Waitmsg	waitmsg;		/* this is large but must be addressable */
	Proc	*child;
	Proc	*parent;
	Pgrp	*pgrp;

	Pgrp	*pgrp;			/* Process group for notes and namespace */
	Egrp 	*egrp;			/* Environment group */
	Fgrp	*fgrp;			/* File descriptor group */

	ulong	parentpid;
	ulong	time[6];		/* User, Sys, Real; child U, S, R */
	short	exiting;


@@ 400,22 496,15 @@ struct Proc
	int	kp;			/* true if a kernel process */
	Proc	*palarm;		/* Next alarm time */
	ulong	alarm;			/* Time of call */
	int	hasspin;

	int 	hasspin;		/* I hold a spin lock */
	int	newtlb;			/* Pager has touched my tables so I must flush */
	int	procctl;		/* Control for /proc debugging */
	/*
	 *  machine specific MMU goo
	 */
	PMMU;
};

struct PTE
{
	Proc	*proc;			/* process owning this PTE (0 in Orig) */
	PTE	*nextmod;		/* next at this va */
	PTE	*nextva;		/* next in this proc at higher va */
	Page	*page;
};

/*
 *  operations available to a queue
 */


@@ 504,10 593,12 @@ extern	char	devchar[];
extern	char	user[NAMELEN];
extern	char	*errstrtab[];
extern	char	*statename[];
extern	Palloc 	palloc;
extern  Image	swapimage;

#define	CHDIR	0x80000000L
#define	CHAPPEND 0x40000000L
#define	CHEXCL	0x20000000L
#define	CHDIR		0x80000000L
#define	CHAPPEND 	0x40000000L
#define	CHEXCL		0x20000000L




M port/portfns.h => port/portfns.h +61 -36
@@ 1,19 1,23 @@

#define	SET(x)	x = 0
#define	USED(x)	if(x)

Alarm*	alarm(int, void (*)(Alarm*), void*);
void	alarminit(void);
Alarm*	alarm(int, void (*)(Alarm*), void*);
Block*	allocb(ulong);
Image*	attachimage(int, Chan*, ulong, ulong);
int	anyready(void);
void	append(List**, List*);
int	blen(Block *);
int	bround(Block *, int);
void	buzz(int, int);
void	cachepage(Page*, Image*);
void	cancel(Alarm*);
int	cangetc(void*);
int	canlock(Lock*);
int	canputc(void*);
int	canqlock(QLock*);
int	canpage(Proc*);
int	canputc(void*);
void	chandevinit(void);
void	chandevreset(void);
void	chaninit(void);


@@ 23,15 27,17 @@ Chan*	clone(Chan*, Chan*);
void	close(Chan*);
void	closemount(Mount*);
void	closepgrp(Pgrp*);
void	closeegrp(Egrp*);
void	closefgrp(Fgrp*);
long	clrfpintr(void);
int	compactpte(Orig*, ulong);
void	confinit(void);
int	consactive(void);
Env*	copyenv(Env*, int);
void	copypage(Page*, Page*);
int	decref(Ref*);
void	delay(int);
void	delete(List**, List*, List*);
void	delete0(List**, List*);
void	delete(List**, List*, List*);
Chan*	devattach(int, char*);
Chan*	devclone(Chan*, Chan*);
void	devdir(Chan*, Qid, char*, long, long, Dir*);


@@ 45,8 51,12 @@ void*	dmaalloc(ulong);
void	dumpqueues(void);
void	dumpregs(Ureg*);
void	dumpstack(void);
void	envcpy(Pgrp*, Pgrp*);
Fgrp*	dupfgrp(Fgrp*);
void	dupswap(Page*);
void	envpgclose(Env *);
void	duppage(Page*);
Segment* dupseg(Segment*);
void	envcpy(Egrp*, Egrp*);
int	eqchan(Chan*, Chan*, long);
int	eqqid(Qid, Qid);
void	error(int);


@@ 54,61 64,61 @@ void	errors(char*);
void	execpc(ulong);
void	exit(void);
int	fault(ulong, int);
void	fdclose(int);
void	fdclose(int, int);
Chan*	fdtochan(int, int);
void	firmware(void);
void	flowctl(Queue*);
void	flushmmu(void);
void	forkmod(Seg*, Seg*, Proc*);
void	freealarm(Alarm*);
void	freeb(Block*);
int	freebroken(void);
void	freechan(Chan*);
void	freepage(Orig*, int);
void	freepte(Orig*);
void	freepte(Segment*, Pte*);
void	freesegs(int);
Block*	getb(Blist*);
int	getc(IOQ*);
int	gets(IOQ*, void*, int);
int	getfields(char*, char**, int, char);
Block*	getq(Queue*);
int	gets(IOQ*, void*, int);
void	gotolabel(Label*);
void	growpte(Orig*, ulong);
void*	ialloc(ulong, int);
long	ibrk(ulong, int);
int	incref(Ref*);
void	initq(IOQ*);
void	initseg(void);
void	insert(List**, List*, List*);
void	invalidateu(void);
void	isdir(Chan*);
int	ispages(void*);
void	kbdclock(void);
int	kbdputc(IOQ*, int);
void	kbdrepeat(int);
int	kbdputc(IOQ*, int);
int	kprint(char*, ...);
void	kproc(char*, void(*)(void*), void*);
void	kickpager(void);
void	lights(int);
Page*	lkpage(Orig*, ulong);
void	lkpgfree(Page*, int);
void	lock(Lock*);
void	lockpage(Page*);
void	lockinit(void);
Orig*	lookorig(ulong, ulong, int, Chan*);
Page*	lookpage(Image*, ulong);
void	machinit(void);
void	mapstack(Proc*);
void	mklockseg(Seg*);
void	mmurelease(Proc*);
void	mfreeseg(Segment*, ulong, int);
void	mntdump(void);
int	mount(Chan*, Chan*, int);
void	mmurelease(Proc*);
int	mouseputc(IOQ*, int);
int	mount(Chan*, Chan*, int);
Chan*	namec(char*, int, int, ulong);
Alarm*	newalarm(void);
Chan*	newchan(void);
PTE*	newmod(Orig*);
Egrp*	newegrp(void);
Fgrp*	newfgrp(void);
Mount*	newmount(void);
Orig*	neworig(ulong, ulong, int, Chan*);
Page*	newpage(int, Orig*, ulong);
Page*	newpage(int, Segment **, ulong);
Pgrp*	newpgrp(void);
Proc*	newproc(void);
void	newqinfo(Qinfo*);
Segment* newseg(int, ulong, ulong);
char*	nextelem(char*, char*);
void	nexterror(void);
void	notify(Ureg*);


@@ 116,61 126,74 @@ void	nullput(Queue*, Block*);
int	openmode(ulong);
Block*	padb(Block*, int);
void	pageinit(void);
int	pagemeis0(void*);
void	panic(char*, ...);
void	pexit(char*, int);
void	pgrpcpy(Pgrp*, Pgrp*);
void	pgrpinit(void);
void	pio(Segment *, ulong, ulong, Page **);
Pte*	ptecpy(Pte*);
void	putseg(Segment*);
void	putswap(Page*);
void	grpinit(void);
void	pgrpnote(Pgrp*, char*, long, int);
Pgrp*	pgrptab(int);
#define	poperror()	u->nerrlab--
int	postnote(Proc*, int, char*, int);
int	pprint(char*, ...);
void	printinit(void);
void	procctl(Proc *p);
void	putimage(Image*);
void	putpage(Page*);
void	putstr(char*);
int	putc(IOQ*, int);
void	putstr(char*);
void	putstrn(char*, long);
void	puts(IOQ*, void*, int);
ulong 	procalarm(ulong);
void	procdump(void);
void	procinit0(void);
Proc*	proctab(int);
Pte*	ptealloc(void);
Block*	pullup(Block *, int);
Queue*	pushq(Stream*, Qinfo*);
int	putb(Blist*, Block*);
void	putbq(Blist*, Block*);
int	putc(IOQ*, int);
void	putmmu(ulong, ulong);
void	putmmu(ulong, ulong, Page*);
int	putq(Queue*, Block*);
void	puts(IOQ*, void*, int);
void	putstr(char*);
void	putstrn(char*, long);
ulong	pwait(Waitmsg*);
void	qlock(QLock*);
void	qunlock(QLock*);
int	readnum(ulong, char*, ulong, ulong, int);
void	ready(Proc*);
void	relocateseg(Segment*, ulong);
void	resched(char*);
void	resrcwait(char*);
int	return0(void*);
Proc*	runproc(void);
void	savefpregs(FPsave*);
void	sccintr(void);
void	sccputs(IOQ*, char*, int);
void	sccsetup(void*);
void	sccspecial(int, IOQ*, IOQ*, int);
void	sched(void);
void	schedinit(void);
void	sched(void);
long	seconds(void);
Seg*	seg(Proc*, ulong);
int	segaddr(Seg*, ulong, ulong);
Segment* seg(Proc*, ulong, int);
void	segpage(Segment*, Page*);
ulong	segattach(Proc*, ulong, char *, ulong, ulong);
int	setlabel(Label*);
void	setswapchan(Chan*);
char*	skipslash(char*);
void	sleep(Rendez*, int(*)(void*), void*);
int	splhi(void);
int	spllo(void);
void	splx(int);
int	streamclose(Chan*);
int	streamclose1(Stream*);
int	streamclose(Chan*);
int	streamenter(Stream*);
int	streamexit(Stream*, int);
Devgen	streamgen;
void	streaminit(void);
void	streaminit0(void);
void	streaminit(void);
Stream*	streamnew(ushort, ushort, ushort, Qinfo*, int);
void	streamopen(Chan*, Qinfo*);
int	streamparse(char*, Block*);


@@ 178,15 201,17 @@ long	streamread(Chan*, void*, long);
void	streamstat(Chan*, char*, char*);
long	streamwrite(Chan*, void*, long, int);
long	stringread(Chan*, void*, long, char*, ulong);
void	swapinit(void);
long	syscall(Ureg*);
void	tcpinit(void);
void	tsleep(Rendez*, int (*)(void*), void*, int);
void	twakeme(Alarm*);
void	uncachepage(Page*);
long	unionread(Chan*, void*, long);
void	unlock(Lock*);
void	unusepage(Page*, int);
void	usepage(Page*, int);
void	unlockpage(Page*);
void	userinit(void);
void	validaddr(ulong, ulong, int);
void*	vmemchr(void*, int, ulong);
void*	vmemchr(void*, int, int);
void	wakeme(Alarm*);
void	wakeup(Rendez*);

M port/proc.c => port/proc.c +103 -29
@@ 40,6 40,7 @@ char *statename[]={	/* BUG: generate automatically */
	"Inwait",
	"Wakeme",
	"Broken",
	"Stopped",
};

/*


@@ 49,6 50,7 @@ void
schedinit(void)		/* never returns */
{
	Proc *p;
	Page *pg;

	setlabel(&m->sched);
	if(u){


@@ 58,16 60,38 @@ schedinit(void)		/* never returns */
		u = 0;
		if(p->state == Running)
			ready(p);
		else if(p->state == Moribund){
		else if(p->state == Moribund) {
			/*
			 * The Grim Reaper lays waste the bodies of the dead
			 */
			p->pid = 0;
			mmurelease(p);
			/* procalloc already locked */
			/* 
			 * Holding locks:
			 * 	procalloc, debug, palloc
			 */
			pg = p->upage;
			pg->ref = 0;
			p->upage = 0;
			palloc.freecount++;
			if(palloc.head) {
				pg->next = palloc.head;
				palloc.head->prev = pg;
				pg->prev = 0;
				palloc.head = pg;
			}
			else {
				palloc.head = palloc.tail = pg;
				pg->prev = pg->next = 0;
			}

			p->qnext = procalloc.free;
			procalloc.free = p;
			p->upage->ref--;
			p->upage = 0;
		
			unlock(&palloc);
			unlock(&p->debug);
			unlock(&procalloc);

			p->state = Dead;
		}
		p->mach = 0;


@@ 78,7 102,7 @@ schedinit(void)		/* never returns */
void
sched(void)
{
	uchar procstate[64];		/* sleaze for portability */
	uchar procstate[64];
	Proc *p;
	ulong tlbvirt, tlbphys;
	void (*f)(ulong, ulong);


@@ 175,6 199,23 @@ loop:
	return p;
}

int
canpage(Proc *p)
{
	int ok = 0;

	splhi();
	lock(&runhiq);
	if(p->state != Running) {
		p->newtlb = 1;
		ok = 1;
	}
	unlock(&runhiq);
	spllo();

	return ok;
}

Proc*
newproc(void)
{


@@ 192,8 233,11 @@ loop:
		p->child = 0;
		p->exiting = 0;
		p->pgrp = 0;
		p->egrp = 0;
		p->fgrp = 0;
		p->fpstate = FPinit;
		p->kp = 0;
		p->procctl = 0;
		memset(p->seg, 0, sizeof p->seg);
		lock(&pidalloc);
		p->pid = ++pidalloc.pid;


@@ 300,8 344,8 @@ wakeup(Rendez *r)
	p = r->p;
	if(p){
		r->p = 0;
		if(p->state != Wakeme)
			panic("wakeup: not Wakeme");
		if(p->state != Wakeme) 
			panic("wakeup: state");
		p->r = 0;
		ready(p);
	}


@@ 359,7 403,8 @@ postnote(Proc *p, int dolock, char *n, int flag)
		kunmap(k);
	if(dolock)
		unlock(&p->debug);
	if(r = p->r){	/* assign = */

	if(r = p->r) {		/* assign = */
		/* wake up */
		s = splhi();
		lock(r);


@@ 432,27 477,29 @@ pexit(char *s, int freemem)
{
	ulong mypid;
	Proc *p, *c, *k, *l;
	int n;
	int n, i;
	Chan *ch;
	char msg[ERRLEN];
	ulong *up, *ucp, *wp;

	if(s)	/* squirrel away; we'll lose our address space */
	if(s) 	/* squirrel away; we'll lose our address space */
		strcpy(msg, s);
	else
		msg[0] = 0;
	
	c = u->p;
	c->alarm = 0;
	mypid = c->pid;

	for(n=0; n<=u->maxfd; n++)
		if(ch = u->fd[n])	/* assign = */
			close(ch);

	closefgrp(c->fgrp);

	if(freemem){
		freesegs(-1);
		flushvirt();
		for(i = 0; i < NSEG; i++)
			if(c->seg[i])
				putseg(c->seg[i]);
		closepgrp(c->pgrp);
		closeegrp(c->egrp);
		close(u->dot);
	}
	/*


@@ 502,18 549,27 @@ pexit(char *s, int freemem)
   out:
	if(!freemem){
		addbroken(c);
		freesegs(-1);
		flushvirt();
		for(i = 0; i < NSEG; i++)
			if(c->seg[i])
				putseg(c->seg[i]);
		closepgrp(c->pgrp);
		closeegrp(c->egrp);
		close(u->dot);
	}

    done:

	lock(&procalloc);	/* sched() can't do this */
	lock(&c->debug);	/* sched() can't do this */
	unusepage(c->upage, 1);	/* sched() can't do this (it locks) */
	/*
	 * sched() cannot wait on these locks
	 */
	lock(&procalloc);
	lock(&c->debug);
	lock(&palloc);

	c->state = Moribund;
	sched();	/* never returns */
	sched();
	panic("pexit");
}

ulong


@@ 568,15 624,14 @@ procdump(void)
{
	int i;
	Proc *p;
	Orig *o;

	print("DEBUG\n");
	print("process table:\n");
	for(i=0; i<conf.nproc; i++){
		p = procalloc.arena+i;
		if(p->state != Dead){
			print("%d:%s %s upc %lux %s ut %ld st %ld r %lux\n",
				p->pid, p->text, p->pgrp->user, p->pc, statename[p->state],
				p->time[0], p->time[1], p->r);
				p->pid, p->text, p->pgrp->user, p->pc, 
				statename[p->state], p->time[0], p->time[1], p->r);
		}
	}
}


@@ 591,6 646,7 @@ kproc(char *name, void (*func)(void *), void *arg)
	User *up;
	KMap *k;
	static Pgrp *kpgrp;
	char *user;

	/*
	 * Kernel stack


@@ 616,9 672,7 @@ kproc(char *name, void (*func)(void *), void *arg)
	 * Refs
	 */
	incref(up->dot);
	for(n=0; n<=up->maxfd; n++)
		up->fd[n] = 0;
	up->maxfd = 0;
	p->fgrp = newfgrp();
	kunmap(k);

	/*


@@ 633,13 687,19 @@ kproc(char *name, void (*func)(void *), void *arg)
		(*func)(arg);
		pexit(0, 1);
	}

	user = "bootes";
	if(kpgrp == 0){
		kpgrp = newpgrp();
		strcpy(kpgrp->user, "bootes");
		strcpy(kpgrp->user, user);
	}
	p->pgrp = kpgrp;
	incref(kpgrp);
	sprint(p->text, "%s.%.6s", name, u->p->pgrp->user);

	if(u->p->pgrp->user[0] != '\0')
		user = u->p->pgrp->user;
	sprint(p->text, "%s.%.6s", name, user);

	p->nchild = 0;
	p->parent = 0;
	memset(p->time, 0, sizeof(p->time));


@@ 652,3 712,17 @@ kproc(char *name, void (*func)(void *), void *arg)
	 */
	flushmmu();
}

void
procctl(Proc *p)
{
	switch(p->procctl) {
	case Proc_exitme:
		pexit("Killed", 1);
	case Proc_stopme:
		p->procctl = 0;
		p->state = Stopped;
		sched();
		return;
	}
}

M port/qlock.c => port/qlock.c +1 -4
@@ 10,11 10,8 @@ qlock(QLock *q)
{
	Proc *p;

	if(canlock(&q->use)){
		if(u)
			u->p->hasspin = 0;
	if(canlock(&q->use))
		return;
	}
	lock(&q->queue);
	if(canlock(&q->use)){
		unlock(&q->queue);

M port/queue.c => port/queue.c +1 -0
@@ 4,6 4,7 @@
#include	"dat.h"
#include	"fns.h"
#include	"io.h"
#include	"errno.h"

void
initq(IOQ *q)

A port/segment.c => port/segment.c +460 -0
@@ 0,0 1,460 @@
#include	"u.h"
#include	"lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"ureg.h"
#include	"errno.h"

#define DPRINT

Page *lkpage(ulong addr);
Page *snewpage(ulong addr);
void lkpgfree(Page*);

/* System specific segattach devices */
#include "segment.h"

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

struct segalloc
{
	Lock;
	Segment *free;
}segalloc;

void
initseg(void)
{
	Segment *s, *se;
	Image *i, *ie;

	segalloc.free = ialloc(conf.nseg*sizeof(Segment), 0);
	imagealloc.free = ialloc(conf.nimage*sizeof(Image), 0);

	se = &segalloc.free[conf.nseg-1];
	for(s = segalloc.free; s < se; s++)
		s->next = s+1;
	s->next = 0;

	ie = &imagealloc.free[conf.nimage-1];
	for(i = imagealloc.free; i < ie; i++)
		i->next = i+1;
	i->next = 0;
}

Segment *
newseg(int type, ulong base, ulong size)
{
	Segment *s;

	if(size > (SEGMAPSIZE*PTEPERTAB))
		errors("segment too large");

	for(;;) {
		lock(&segalloc);
		if(s = segalloc.free) {
			segalloc.free = s->next;
			unlock(&segalloc);

			s->ref = 1;
			s->steal = 0;
			s->type = type;
			s->base = base;
			s->top = base+(size*BY2PG);
			s->size = size;
			s->image = 0;
			s->fstart = 0;
			s->flen = 0;
			s->pgalloc = 0;
			s->pgfree = 0;
			memset(s->map, 0, sizeof(s->map));

			return s;
		}
		unlock(&segalloc);
		resrcwait("no segments");
	}
}

void
putseg(Segment *s)
{
	Pte **pp, **emap;
	Image *i;

	if(s && decref(s) == 0) {
		emap = &s->map[SEGMAPSIZE];
		for(pp = s->map; pp < emap; pp++)
			if(*pp)
				freepte(s, *pp);

		if(i = s->image) {
			lock(i);
			if(i->s == s)
				i->s = 0;
			unlock(i);
			putimage(i);
		}

		lock(&segalloc);
		s->next = segalloc.free;		
		segalloc.free = s;
		unlock(&segalloc);
	}
}

void
relocateseg(Segment *s, ulong offset)
{
	Pte **p, **endpte;
	Page **pg, **endpages;

	endpte = &s->map[SEGMAPSIZE];
	for(p = s->map; p < endpte; p++)
		if(*p) {
			endpages = &((*p)->pages[PTEPERTAB]);
			for(pg = (*p)->pages; pg < endpages; pg++)
				if(*pg)
					(*pg)->va += offset;
		}
}

Segment*
dupseg(Segment *s)
{
	Pte *pte;
	Segment *n;
	int i;

	switch(s->type&SG_TYPE) {
	case SG_TEXT:		/* new segment shares pte set */
	case SG_SHARED:
	case SG_PHYSICAL:
		incref(s);
		return s;
	case SG_DATA:		/* copy on write both old and new plus demand load info */
		lock(s);
		n = newseg(s->type, s->base, s->size);

		incref(s->image);
		n->image = s->image;
		n->fstart = s->fstart;
		n->flen = s->flen;
	copypte:
		for(i = 0; i < SEGMAPSIZE; i++)
			if(pte = s->map[i])
				n->map[i] = ptecpy(pte);
		unlock(s);
		return n;	
	case SG_BSS:		/* Just copy on write */
	case SG_STACK:
		lock(s);
		n = newseg(s->type, s->base, s->size);
		goto copypte;
	}

	panic("dupseg");
}

void
segpage(Segment *s, Page *p)
{
	Pte **pte;
	ulong off;

	if(p->va < s->base || p->va >= s->top)
		panic("segpage");

	off = p->va - s->base;
	pte = &s->map[off/PTEMAPMEM];
	if(*pte == 0)
		*pte = ptealloc();

	(*pte)->pages[(off&(PTEMAPMEM-1))/BY2PG] = p;
}

Image*
attachimage(int type, Chan *c, ulong base, ulong len)
{
	Image *i, **l;

	lock(&imagealloc);

	for(i = ihash(c->qid.path); i; i = i->hash) {
		if(c->qid.path == i->qid.path) {
			lock(i);
			if(eqqid(c->qid, i->qid))
			if(eqqid(c->mqid, i->mqid))
			if(c->mchan == i->mchan)
			if(c->type == i->type) {
				i->ref++;
				goto found;
			}
			unlock(i);
		}
	}
	
	while(!(i = imagealloc.free)) {
		unlock(&imagealloc);
		resrcwait("no images");
		lock(&imagealloc);
	}

	imagealloc.free = i->next;

	lock(i);
	incref(c);
	i->c = c;
	i->type = c->type;
	i->qid = c->qid;
	i->mqid = c->mqid;
	i->mchan = c->mchan;
	i->ref = 1;
	l = &ihash(c->qid.path);
	i->hash = *l;
	*l = i;
found:
	unlock(&imagealloc);

	if(i->s == 0) {
		i->s = newseg(type, base, len);
		i->s->image = i;
	}
	else
		incref(i->s);

	unlock(i);
	return i;
}

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

	if(i == &swapimage)
		return;

	lock(i);
	if(--i->ref == 0) {
		l = &ihash(i->qid.path);
		i->qid = (Qid){~0, ~0};	
		unlock(i);
		c = i->c;
	
		lock(&imagealloc);
		for(f = *l; f; f = f->hash) {
			if(f == i) {
				*l = i->hash;
				break;
			}
			l = &f->hash;
		}

		i->next = imagealloc.free;
		imagealloc.free = i;
		unlock(&imagealloc);

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

long
ibrk(ulong addr, int seg)		/* Called with a locked segment */
{
	Segment *s, *ns;
	ulong newtop, newsize;
	int i;

	s = u->p->seg[seg];
	if(s == 0)
		errors("no segment");

	qlock(&s->lk);

	if(addr == 0)
		return s->base;

	if(addr < s->base) {
		/* We may start with the bss overlapping the data */
		if(seg != BSEG || u->p->seg[DSEG] == 0 || addr < u->p->seg[DSEG]->base) {
			qunlock(&s->lk);
			pprint("addr below segment\n");
 		}
		addr = s->base;
	}
		
	newtop = PGROUND(addr);
	newsize = (newtop-s->base)/BY2PG;
	if(newtop < s->top) {
		print("down brk\n");
		mfreeseg(s, newtop, (s->top-newtop)/BY2PG);
		qunlock(&s->lk);
		return 0;
	}

	if(newsize > (PTEMAPMEM*SEGMAPSIZE)/BY2PG) {
		qunlock(&s->lk);
		pprint("exceeded max segment size\n");
		pexit("Suicide", 0);
		error(Esegaddr);
	}

	for(i = 0; i < NSEG; i++) {
		ns = u->p->seg[i];
		if(ns == 0 || ns == s)
			continue;
		if(newtop >= ns->base && newtop < ns->top) {
			qunlock(&s->lk);
			pprint("segments overlap\n");
			pexit("Suicide", 0);
			error(Esegaddr);
		}
	}

	s->top = newtop;
	s->size = newsize;

	qunlock(&s->lk);
	return 0;
}

void
mfreeseg(Segment *s, ulong start, int pages)
{
	int i, j;
	ulong soff;
	Page *pg;

	soff = start-s->base;
	j = (soff&(PTEMAPMEM-1))/BY2PG;

	for(i = soff/PTEMAPMEM; i < SEGMAPSIZE; i++) {
		if(pages <= 0) 
			goto done;
		if(s->map[i]) {
			while(j < PTEPERTAB) {
				if(pg = s->map[i]->pages[j]) {
					putpage(pg);
					s->map[i]->pages[j] = 0;	
				}
				if(--pages == 0)
					goto done;
				j++;
			}
			j = 0;
		}
		else
			pages -= PTEMAPMEM/BY2PG;
	}
done:
	flushmmu();
}

ulong
segattach(Proc *p, ulong attr, char *name, ulong va, ulong len)
{
	Segment *s, *ns, *new;
	Physseg *ps;
	ulong newtop;
	int i, sno;

	if(va&KZERO)					/* BUG: Only ok for now */
		errors("bad virtual address");

	validaddr((ulong)name, 1, 0);
	vmemchr(name, 0, ~0);

	for(sno = 0; sno < NSEG; sno++)
		if(u->p->seg[sno] == 0 && sno != ESEG)
			break;

	if(sno == NSEG)
		errors("no per process segments");

	va = va&~(BY2PG-1);
	len = PGROUND(len);
	newtop = va+len;
	for(i = 0; i < NSEG; i++) {
		ns = u->p->seg[i];
		if(ns == 0)
			continue;	
		if(newtop >= ns->base && newtop < ns->top) 
			errors("segments overlap");
	}

	for(ps = physseg; *(ps->name); ps++)
		if(strcmp(name, ps->name) == 0)
			goto found;

	errors("bad segment name");
found:
	if(len > ps->size)
		errors("segment too long");

	attr &= ~SG_TYPE;			/* Turn off what we are not allowed */
	attr |= ps->attr;			/* Copy in defaults */

	s = newseg(attr, va, len/BY2PG);
	s->pgalloc = ps->pgalloc;
	s->pgfree = ps->pgfree;
	u->p->seg[sno] = s;

	/* Need some code build mapped devices here */

	return 0;
}

long
syssegflush(ulong *arg)
{
	Segment *s;
	int i, j, pages;
	ulong soff;
	Page *pg;

	s = seg(u->p, arg[0], 1);
	if(s == 0)
		errors("bad segment address");

	soff = arg[0]-s->base;
	j = (soff&(PTEMAPMEM-1))/BY2PG;
	pages = ((arg[0]+arg[1]+(BY2PG-1))&~(BY2PG-1))-(arg[0]&~(BY2PG-1));

	for(i = soff/PTEMAPMEM; i < SEGMAPSIZE; i++) {
		if(pages <= 0) 
			goto done;
		if(s->map[i]) {
			while(j < PTEPERTAB) {
				if(pg = s->map[i]->pages[j]) 
					memset(pg->cachectl, PG_TXTFLUSH, sizeof pg->cachectl);
				if(--pages == 0)
					goto done;
				j++;
			}
			j = 0;
		}
		else
			pages -= PTEMAPMEM/BY2PG;
	}
done:
	qunlock(&s->lk);
	flushmmu();
}

Page*
snewpage(ulong addr)
{
	return newpage(1, 0, addr);
}

M port/stream.c => port/stream.c +2 -5
@@ 118,12 118,12 @@ newblock(Bclass *bcp)
	if(bcp->made > bcp->lim)
		return -1;

	page = newpage(1, 0, 0);
	page->va = VA(kmap(page));
	if(bcp == bclass){
		/*
		 *  create some level zero blocks and return
		 */
		page = newpage(1, 0, 0);
		page->va = VA(kmap(page));
		n = BY2PG/sizeof(Block);
		bp = (Block *)(page->va);
		while(n-- > 0){


@@ 141,8 141,6 @@ newblock(Bclass *bcp)
		/*
		 *  create a page worth of new blocks
		 */
		page = newpage(1, 0, 0);
		page->va = VA(kmap(page));
		n = BY2PG/bcp->size;
		cp = (uchar *)(page->va);
		


@@ 419,7 417,6 @@ popq(Stream *s)
		(*q->info->close)(RD(q));
	s->procq->next = q->next;
	RD(q->next)->next = RD(s->procq);
	poperror();
	qunlock(s);
	freeq(q);
}

M port/sturp.c => port/sturp.c +1 -1
@@ 11,7 11,7 @@ enum {
	Nmask=		0x7,
};

#define DPRINT if(q->flag&QDEBUG)kprint
#define DPRINT if(q->flag&QDEBUG)print

typedef struct Urp	Urp;


A port/swap.c => port/swap.c +333 -0
@@ 0,0 1,333 @@
#include	"u.h"
#include	"lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"ureg.h"
#include	"errno.h"

/* Predeclaration */
void	pageout(Proc *p, Segment*);
int	pagepte(int, Segment*, Page**);
void	openswap(void);
int	needpages(void*);
void	pager(void*);
void	executeio(void);
int	canflush(Proc *p, Segment*);

enum
{
	Maxpages = 500,		/* Max number of pageouts per process pass */
};

Image 	swapimage;
static 	int swopen;
Page	*iolist[Maxpages];
int	ioptr;

void
swapinit(void)
{
	swapalloc.swmap = ialloc(conf.nswap, 0);
	swapalloc.top = &swapalloc.swmap[conf.nswap];
	swapalloc.alloc = swapalloc.swmap;

	swapalloc.free = conf.nswap;
}

ulong
newswap(void)
{
	char *look;
	int n;

	lock(&swapalloc);
	if(swapalloc.free == 0)
		panic("out of swap space");

	n = swapalloc.top - swapalloc.alloc;
	look = swapalloc.alloc;
	while(n && *look) {
		n--;
		look++;
	}
	if(n == 0) {
		look = swapalloc.swmap;
		while(*look)
			look++;
	}
	if(look == swapalloc.top)
		swapalloc.alloc = swapalloc.swmap;
	else
		swapalloc.alloc = look+1;

	*look = 1;
	unlock(&swapalloc);
	return (look-swapalloc.swmap) * BY2PG; 
}

void
putswap(Page *p)
{
	lock(&swapalloc);
	if(--swapalloc.swmap[((ulong)p)/BY2PG] == 0)
		swapalloc.free++;
	unlock(&swapalloc);
}

void
dupswap(Page *p)
{
	lock(&swapalloc);
	swapalloc.swmap[((ulong)p)/BY2PG]++;
	unlock(&swapalloc);
}

void
kickpager(void)
{
	static int started;

	if(started)
		wakeup(&swapalloc.r);
	else {
		kproc("pager", pager, 0);
		started = 1;
	}
}

void
pager(void *junk)
{
	Proc *p, *ep;
	Segment *s;
	int i;

	p = proctab(0);
	ep = &p[conf.nproc];
	for(;;) {
		if(waserror()) 
			panic("pager: os error\n");

		for(p = proctab(0); p < ep; p++) {
			if(p->state == Dead || p->kp)
				continue;

			sleep(&swapalloc.r, needpages, 0);

			if(swapimage.c) {
				for(i = 0; i < NSEG; i++)
					if(s = p->seg[i]) {
						pageout(p, s);
						executeio();
					}
			}
			else {
				/* Emulate the old system if no swap channel */
				print("no physical memory\n");
				pprint("no physical memory\n");
				tsleep(&swapalloc.r, return0, 0, 1000);
				wakeup(&palloc.r);
			}
		}

		poperror();
	}
}

void			
pageout(Proc *p, Segment *s)
{
	Pte **sm, **endsm;
	Page **pg, **epg;
	int type;

	if(!canqlock(&s->lk))	/* We cannot afford to wait, we will surely deadlock */
		return;

	if(!canflush(p, s) || s->steal) {
		qunlock(&s->lk);
		putseg(s);
		return;
	}

	if(waserror()) {
		qunlock(&s->lk);
		putseg(s);
		return;
	}

	/* Pass through the pte tables looking for memory pages to swap out */
	type = s->type&SG_TYPE;
	endsm = &s->map[SEGMAPSIZE];
	for(sm = s->map; sm < endsm && ioptr < Maxpages; sm++)
		if(*sm) {
			pg = (*sm)->pages;
			for(epg = &pg[PTEPERTAB]; pg < epg && ioptr < Maxpages; pg++)
				if(!pagedout(*pg)) {
					if((*pg)->modref & PG_REF)
						(*pg)->modref &= ~PG_REF;
					else 
					if(pagepte(type, s, pg) == 0)
						break;
				}
		}

	poperror();
	qunlock(&s->lk);
	putseg(s);

	wakeup(&palloc.r);
}

int
canflush(Proc *p, Segment *s)
{
	Proc *ep;
	int i;

	lock(s);
	if(s->ref == 1) {		/* Easy if we are the only user */
		s->ref++;
		unlock(s);
		return canpage(p);
	}
	s->ref++;
	unlock(s);

	/* Now we must do hardwork to ensure all processes which have tlb
	 * entries for this segment are flushed
	 */
	p = proctab(0);
	ep = &p[conf.nproc];
	for(; p < ep; p++)
		if(p->state != Dead)
			for(i = 0; i < NSEG; i++)
				if(p->seg[i] == s)
					if(!canpage(p))
						return 0;
	return 1;						
}

int
pagepte(int type, Segment *s, Page **pg)
{
	ulong daddr;
	char *kaddr;
	int n;
	Chan *c;
	Page *outp;
	KMap *k;

	outp = *pg;

	switch(type) {
	case SG_TEXT:					/* Revert to demand load */
		putpage(outp);
		*pg = 0;
		break;
	case SG_DATA:
		/* Unmodified data may be reverted to a demand load record if it
		 * is not the last page in the DSEG
		 */
/*							BUG: needs to check the last page
		if((outp->modref&PG_MOD) == 0) {
			putpage(outp);
			*pg = 0;
			break;
		}
*/
							/* NO break */	
	case SG_BSS:
	case SG_STACK:
	case SG_SHARED:
		lockpage(outp);
		outp->ref++;
		uncachepage(outp);
		unlockpage(outp);

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

		/* Enter swap page into cache before segment is unlocked so that
		 * a fault will cause a cache recovery rather than a pagein on a
		 * partially written block.
		 */
		cachepage(outp, &swapimage);
		*pg = (Page*)(daddr|PG_ONSWAP);

		/* Add me to IO transaction list */
		iolist[ioptr++] = outp;
	}

	return 1;
}

void
executeio(void)
{
	Page *out;
	int i, n;
	Chan *c;
	char *kaddr;
	KMap *k;

	c = swapimage.c;

	for(i = 0; i < ioptr; i++) {
		out = iolist[i];
		if(out->ref > 2) {
			lockpage(out);
			if(out->ref > 2) {		/* Page was reclaimed, abort io */
				out->ref -= 2;
				unlockpage(out);
				continue;
			}
			unlockpage(out);
		}
		k = kmap(out);
		kaddr = (char*)VA(k);
		qlock(&c->wrl);

		/* BUG: what to do ? Nobody to tell, nowhere to go: open to suggestions 
		 *	the problem is I do not know whose page this is.
		 */
		if(waserror())
			panic("executeio: page out I/O error");

		n = (*devtab[c->type].write)(c, kaddr, BY2PG, out->daddr);
		if(n != BY2PG)
			nexterror();

		qunlock(&c->wrl);
		kunmap(k);
		poperror();

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

	ioptr = 0;
}

int
needpages(void *p)
{
	return palloc.freecount < HIGHWATER+MAXHEADROOM;
}

void
setswapchan(Chan *c)
{
	if(swapimage.c) {
		if(swapalloc.free != conf.nswap)
			errors("swap channel busy");
		close(swapimage.c);
	}
	incref(c);
	swapimage.c = c;
}


M port/sysfile.c => port/sysfile.c +79 -41
@@ 11,16 11,21 @@
 */

int
newfd(void)
newfd(Chan *c)
{
	Fgrp *f = u->p->fgrp;
	int i;

	lock(f);
	for(i=0; i<NFD; i++)
		if(u->fd[i] == 0){
			if(i > u->maxfd)
				u->maxfd = i;
		if(f->fd[i] == 0){
			if(i > f->maxfd)
				f->maxfd = i;
			f->fd[i] = c;
			unlock(f);
			return i;
		}
	unlock(f);
	error(Enofd);
}



@@ 29,8 34,8 @@ fdtochan(int fd, int mode)
{
	Chan *c;

	c = 0;		/* set */
	if(fd<0 || NFD<=fd || (c=u->fd[fd])==0)
	USED(c);
	if(fd<0 || NFD<=fd || (c = u->p->fgrp->fd[fd])==0)
		error(Ebadfd);
	if(mode<0 || c->mode==ORDWR)
		return c;


@@ 62,6 67,7 @@ syspipe(ulong *arg)
	int fd[2];
	Chan *c[2];
	Dev *d;
	Fgrp *f = u->p->fgrp;

	validaddr(arg[0], 2*BY2WD, 1);
	evenaddr(arg[0]);


@@ 75,9 81,9 @@ syspipe(ulong *arg)
		if(c[1])
			close(c[1]);
		if(fd[0] >= 0)
			u->fd[fd[0]]=0;
			f->fd[fd[0]]=0;
		if(fd[1] >= 0)
			u->fd[fd[1]]=0;
			f->fd[fd[1]]=0;
		nexterror();
	}
	c[1] = (*d->clone)(c[0], 0);


@@ 85,10 91,8 @@ syspipe(ulong *arg)
	(*d->walk)(c[1], "data1");
	c[0] = (*d->open)(c[0], ORDWR);
	c[1] = (*d->open)(c[1], ORDWR);
	fd[0] = newfd();
	u->fd[fd[0]] = c[0];
	fd[1] = newfd();
	u->fd[fd[1]] = c[1];
	fd[0] = newfd(c[0]);
	fd[1] = newfd(c[1]);
	((long*)arg[0])[0] = fd[0];
	((long*)arg[0])[1] = fd[1];
	poperror();


@@ 100,6 104,7 @@ sysdup(ulong *arg)
{
	int fd;
	Chan *c, *oc;
	Fgrp *f = u->p->fgrp;

	/*
	 * Close after dup'ing, so date > #d/1 works


@@ 109,17 114,26 @@ sysdup(ulong *arg)
	if(fd != -1){
		if(fd<0 || NFD<=fd)
			error(Ebadfd);
		if(fd > u->maxfd)
			u->maxfd = fd;
		oc = u->fd[fd];
	}else{
		oc = 0;
		fd = newfd();

		lock(f);
		if(fd > f->maxfd)
			f->maxfd = fd;
		incref(c);
		oc = f->fd[fd];
		f->fd[fd] = c;
		unlock(f);
		if(oc)
			close(oc);
	}else {
		if(waserror()) {
			close(c);
			nexterror();
		}
		incref(c);
		fd = newfd(c);
		poperror();
	}
	u->fd[fd] = c;
	incref(c);
	if(oc)
		close(oc);

	return fd;
}



@@ 127,25 141,43 @@ long
sysopen(ulong *arg)
{
	int fd;
	Chan *c;
	Chan *c = 0;

	openmode(arg[1]);	/* error check only */
	fd = newfd();
	if(waserror()) {
		if(c)
			close(c);
		nexterror();
	}
	validaddr(arg[0], 1, 0);
	c = namec((char*)arg[0], Aopen, arg[1], 0);
	u->fd[fd] = c;
	fd = newfd(c);
	poperror();
	return fd;
}

void
fdclose(int fd)
fdclose(int fd, int flag)
{
	int i;
	Chan *c;
	Fgrp *f = u->p->fgrp;

	lock(f);
	c = f->fd[fd];
	if(flag){
		if(c==0 || !(c->flag&flag)){
			unlock(f);
			return;
		}
	}
	f->fd[fd] = 0;
	if(fd == f->maxfd)
		for(i=fd; --i>=0 && f->fd[i]==0; )
			f->maxfd = i;

	u->fd[fd] = 0;
	if(fd == u->maxfd)
		for(i=fd; --i>=0 && u->fd[i]==0; )
			u->maxfd = i;
	unlock(f);
	close(c);
}

long


@@ 154,8 186,8 @@ sysclose(ulong *arg)
	Chan *c;

	c = fdtochan(arg[0], -1);
	close(c);
	fdclose(arg[0]);
	fdclose(arg[0], 0);

	return 0;
}



@@ 183,8 215,8 @@ unionread(Chan *c, void *va, long n)
		nexterror();
	}
	nc = clone(mc, 0);
	close(mc);
	poperror();
	close(mc);
	if(waserror()){
		close(nc);
		nexterror();


@@ 193,8 225,8 @@ unionread(Chan *c, void *va, long n)
	nc->offset = c->offset;
	nr = (*devtab[nc->type].read)(nc, va, n, nc->offset);
	c->offset = nc->offset;		/* devdirread e.g. changes it */
	close(nc);
	poperror();
	close(nc);
	if(nr > 0)
		return nr;
	/*


@@ 364,6 396,8 @@ bindmount(ulong *arg, int ismount)
	Chan *c0, *c1;
	ulong flag;
	long ret;
	char *p;
	int t;
	struct{
		Chan	*chan;
		char	*spec;


@@ 408,10 442,9 @@ bindmount(ulong *arg, int ismount)
	close(c1);
	poperror();
	close(c0);
	if(ismount){
		close(bogus.chan);
		fdclose(arg[0]);
	}
	if(ismount)
		fdclose(arg[0], 0);

	return ret;
}



@@ 431,13 464,18 @@ long
syscreate(ulong *arg)
{
	int fd;
	Chan *c;
	Chan *c = 0;

	openmode(arg[1]);	/* error check only */
	fd = newfd();
	if(waserror()) {
		if(c)
			close(c);
		nexterror();
	}
	validaddr(arg[0], 1, 0);
	c = namec((char*)arg[0], Acreate, arg[1], arg[2]);
	u->fd[fd] = c;
	fd = newfd(c);
	poperror();
	return fd;
}


M port/sysproc.c => port/sysproc.c +159 -145
@@ 21,19 21,19 @@ long
sysfork(ulong *arg)
{
	Proc *p;
	Seg *s;
	Segment *s;
	Page *np, *op;
	ulong usp, upa, pid;
	Chan *c;
	Orig *o;
	KMap *k;
	int n, on, i;
	int lastvar;	/* used to compute stack address */

	/*
	 * Kernel stack
	 */
	p = newproc();

	/* Page va of upage used as check in mapstack */
	p->upage = newpage(1, 0, USERADDR|(p->pid&0xFFFF));
	k = kmap(p->upage);
	upa = VA(k);


@@ 49,68 49,23 @@ sysfork(ulong *arg)
	((User *)upa)->p = p;
	kunmap(k);

	/*
	 * User stack
	 */
	p->seg[SSEG] = u->p->seg[SSEG];
	s = &p->seg[SSEG];
	s->proc = p;
	on = (s->maxva-s->minva)>>PGSHIFT;
	usp = ((Ureg*)UREGADDR)->usp;
	if(usp >= USTKTOP)
		panic("fork bad usp %lux", usp);
	if(usp < u->p->seg[SSEG].minva)
		s->minva = u->p->seg[SSEG].minva;
	else
		s->minva = usp & ~(BY2PG-1);
	usp = s->minva & (BY2PG-1);	/* just low bits */
	s->maxva = USTKTOP;
	n = (s->maxva-s->minva)>>PGSHIFT;
	s->o = neworig(s->minva, n, OWRPERM|OISMEM, 0);
	lock(s->o);
	/*
	 * Only part of last stack page
	 */
	for(i=0; i<n; i++){
		op = u->p->seg[SSEG].o->pte[i+(on-n)].page;
		if(op){
			np = newpage(1, s->o, op->va);
			k = kmap(np);
			p->seg[SSEG].o->pte[i].page = np;
			if(i == 0){	/* only part of last stack page */
				memset((void*)VA(k), 0, usp);
				memmove((void*)(VA(k)+usp),
					(void*)(op->va+usp), BY2PG-usp);
			}else		/* all of higher pages */
				memmove((void*)VA(k), (void*)op->va, BY2PG);
			kunmap(k);
		}
	}
	unlock(s->o);
	/*
	 * Duplicate segments
	 */
	for(s=&u->p->seg[0], n=0; n<NSEG; n++, s++){
		if(n == SSEG)		/* already done */
			continue;
		if(s->o == 0)
			continue;
		p->seg[n] = *s;
		p->seg[n].proc = p;
		o = s->o;
		lock(o);
		o->nproc++;
		if(s->mod)
			forkmod(s, &p->seg[n], p);
		unlock(o);
	}
	/* Make a new set of memory segments */
	for(i = 0; i < NSEG; i++)
		if(u->p->seg[i])
			p->seg[i] = dupseg(u->p->seg[i]);

	/*
	 * Refs
	 */
	incref(u->dot);
	for(n=0; n<=u->maxfd; n++)
		if(c = u->fd[n])	/* assign = */
			incref(c);
	incref(u->dot);				/* File descriptors etc. */
	p->fgrp = dupfgrp(u->p->fgrp);

	p->pgrp = u->p->pgrp;			/* Process groups */
	incref(p->pgrp);

	p->egrp = u->p->egrp;			/* Environment group */
	incref(p->egrp);

	/*
	 * Sched
	 */


@@ 122,11 77,11 @@ sysfork(ulong *arg)
		spllo();
		return 0;
	}

	p->parent = u->p;
	p->parentpid = u->p->pid;
	p->pgrp = u->p->pgrp;

	p->fpstate = u->p->fpstate;
	incref(p->pgrp);
	u->p->nchild++;
	pid = p->pid;
	memset(p->time, 0, sizeof(p->time));


@@ 147,11 102,10 @@ long
sysexec(ulong *arg)
{
	Proc *p;
	Seg *s;
	Segment *s, *ts;
	ulong l, t, d, b, v;
	int i;
	Chan *tc, *c;
	Orig *o;
	char **argv, **argp;
	char *a, *charp, *file;
	char *progarg[sizeof(Exec)/2+1], elem[NAMELEN];


@@ 160,6 114,8 @@ sysexec(ulong *arg)
	int indir;
	Exec exec;
	char line[sizeof(Exec)];
	Fgrp *f;
	Image *img;

	p = u->p;
	validaddr(arg[0], 1, 0);


@@ 209,6 165,7 @@ sysexec(ulong *arg)
	goto Header;

    Binary:
	poperror();
	t = (UTZERO+sizeof(Exec)+exec.text+(BY2PG-1)) & ~(BY2PG-1);
	d = (t + exec.data + (BY2PG-1)) & ~(BY2PG-1);
	bssend = t + exec.data + exec.bss;


@@ 237,7 194,7 @@ sysexec(ulong *arg)
		if(((ulong)argp&(BY2PG-1)) < BY2WD)
			validaddr((ulong)argp, BY2WD, 0);
		validaddr((ulong)a, 1, 0);
		nbytes += (vmemchr(a, 0, ~0) - a) + 1;
		nbytes += (vmemchr(a, 0, 0xFFFFFFFF) - a) + 1;
		nargs++;
	}
	ssize = BY2WD*(nargs+1) + ((nbytes+(BY2WD-1)) & ~(BY2WD-1));


@@ 248,11 205,8 @@ sysexec(ulong *arg)
	if(spage > TSTKSIZ)
		errors("not enough argument stack space");

	s = &p->seg[ESEG];
	s->proc = p;
	s->o = neworig(TSTKTOP-(spage<<PGSHIFT), spage, OWRPERM|OISMEM, 0);
	s->minva = s->o->va;
	s->maxva = TSTKTOP;
	 
	p->seg[ESEG] = newseg(SG_STACK, TSTKTOP-USTKSIZE, USTKSIZE/BY2PG);

	/*
	 * Args: pass 2: assemble; the pages will be faulted in


@@ 263,8 217,9 @@ sysexec(ulong *arg)
		argp = progarg;
	else
		argp = (char**)arg[1];

	for(i=0; i<nargs; i++){
		if(indir && *argp==0){
		if(indir && *argp==0) {
			indir = 0;
			argp = (char**)arg[1];
		}


@@ 276,87 231,65 @@ sysexec(ulong *arg)

	memmove(p->text, elem, NAMELEN);

	if(waserror())
		pexit("fatal exec error", 0);

	/*
	 * Committed.  Free old memory
	 * Committed.  Free old memory. Special segments are maintained accross exec
	 */
	freesegs(ESEG);
	putseg(p->seg[TSEG]);
	p->seg[TSEG] = 0;	/* prevent a second free if we have an error */
	putseg(p->seg[DSEG]);
	p->seg[DSEG] = 0;
	putseg(p->seg[BSEG]);
	p->seg[BSEG] = 0;
	putseg(p->seg[SSEG]);
	p->seg[SSEG] = 0;

	/*
	 * Close on exec
	 */
	for(i=0; i<=u->maxfd; i++)
		if((c=u->fd[i]) && c->flag&CCEXEC){
			close(c);
			fdclose(i);
		}
	f = u->p->fgrp;
	for(i=0; i<=f->maxfd; i++)
		fdclose(i, CCEXEC);

	/*
	 * Text.  Shared.
	 */
	s = &p->seg[TSEG];
	s->proc = p;
	o = lookorig(UTZERO, (t-UTZERO)>>PGSHIFT, OCACHED|OISMEM, tc);
	if(o == 0){
		o = neworig(UTZERO, (t-UTZERO)>>PGSHIFT, OCACHED|OISMEM, tc);
		o->minca = 0;
		o->maxca = sizeof(Exec)+exec.text;
	}
	s->o = o;
	s->minva = UTZERO;
	s->maxva = t;
	s->mod = 0;
	/* Text.  Shared. Attaches to cache image if possible */
	img = attachimage(SG_TEXT|SG_RONLY, tc, UTZERO, (t-UTZERO)>>PGSHIFT);
	ts = img->s;
	p->seg[TSEG] = ts;
	ts->fstart = 0;
	ts->flen = sizeof(Exec)+exec.text;

	/*
	 * Data.  Shared.
	 */
	s = &p->seg[DSEG];
	s->proc = p;
	o = lookorig(t, (d-t)>>PGSHIFT, OWRPERM|OPURE|OCACHED|OISMEM, tc);
	if(o == 0){
		o = neworig(t, (d-t)>>PGSHIFT, OWRPERM|OPURE|OCACHED|OISMEM, tc);
		o->minca = p->seg[TSEG].o->maxca;
		o->maxca = o->minca + exec.data;
	}
	s->o = o;
	s->minva = t;
	s->maxva = d;
	s->mod = 0;
	/* Data. Shared. */
	s = newseg(SG_DATA, t, (d-t)>>PGSHIFT);
	p->seg[DSEG] = s;

	/*
	 * BSS.  Created afresh.
	 */
	s = &p->seg[BSEG];
	s->proc = p;
	o = neworig(d, (b-d)>>PGSHIFT, OWRPERM|OISMEM, 0);
	o->minca = 0;
	o->maxca = 0;
	s->o = o;
	s->minva = d;
	s->maxva = b;
	s->mod = 0;
	/* Attached by hand */
	incref(img);
	s->image = img;
	s->fstart = ts->fstart+ts->flen;
	s->flen = exec.data;

	poperror();
	close(tc);

	p->seg[BSEG].endseg = bssend;
	/* BSS. Zero fill on demand */
	p->seg[BSEG] = newseg(SG_BSS, d, (b-d)>>PGSHIFT);

	close(tc);

	/*
	 * Move the stack
	 */
	s = &p->seg[SSEG];
	*s = p->seg[ESEG];
	p->seg[ESEG].o = 0;
	o = s->o;
	o->va += (USTKTOP-TSTKTOP);
	s->minva = o->va;
	s->maxva = USTKTOP;
	lock(o);
	for(i=0; i<o->npte; i++)
		o->pte[i].page->va += (USTKTOP-TSTKTOP);
	unlock(o);
	s = p->seg[ESEG];
	p->seg[SSEG] = s;
	s->base = USTKTOP-USTKSIZE;
	s->top = USTKTOP;
	relocateseg(s, TSTKTOP-USTKTOP);
	p->seg[ESEG] = 0;

	poperror();

	/*
	 *  at this point, the mmu contains info about the old address
	 *  At this point, the mmu contains info about the old address
	 *  space and needs to be flushed
	 */
	flushmmu();


@@ 437,6 370,7 @@ sysexits(ulong *arg)
			vmemchr(status, 0, ERRLEN);
		}
		poperror();

	}
	pexit(status, 1);
}


@@ 473,10 407,13 @@ sysforkpgrp(ulong *arg)
{
	int mask;
	Pgrp *pg;
	Egrp *eg;

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



@@ 490,7 427,7 @@ sysforkpgrp(ulong *arg)
		pgrpcpy(pg, u->p->pgrp);

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

	if((mask & FPnote) == 0) {
		u->nnote = 0;


@@ 500,7 437,9 @@ sysforkpgrp(ulong *arg)

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



@@ 521,17 460,92 @@ sysnoted(ulong *arg)
	return 0;
}

/*
 * Temporary; should be replaced by a generalized segment control operator
 */
long
sysbrk_(ulong *arg)
syssegbrk(ulong *arg)
{
	return ibrk(arg[0], BSEG);
	Segment *s;
	int i;

	for(i = 0; i < NSEG; i++)
		if(s = u->p->seg[i]) {
			if(arg[0] >= s->base && arg[0] < s->top) {
				switch(s->type&SG_TYPE) {
				case SG_TEXT:
				case SG_DATA:
					errors("bad segment type");
				default:
					return ibrk(arg[1], i);
				}
			}
		}

	errors("not in address space");
}

long
syslkbrk_(ulong *arg)
syssegattach(ulong *arg)
{
	return ibrk(arg[0], LSEG);
	return segattach(u->p, arg[0], (char*)arg[1], arg[2], arg[3]);
}

long
syssegdetach(ulong *arg)
{
	int i;
	Segment *s;

	for(i = 0; i < NSEG; i++)
		if(s = u->p->seg[i]) {
			qlock(&s->lk);
			if((arg[0] >= s->base && arg[0] < s->top) || 
			   (s->top == s->base && arg[0] == s->base))
				goto found;
			qunlock(&s->lk);
		}

	errors("not in address space");

found:
	if((ulong)arg >= s->base && (ulong)arg < s->top) {
		qunlock(&s->lk);
		errors("illegal address");
	}
	u->p->seg[i] = 0;
	qunlock(&s->lk);
	putseg(s);

	/* Ensure we flush any entries from the lost segment */
	flushmmu();
	return 0;
}

long
syssegfree(ulong *arg)
{
	Segment *s;
	ulong from, len;

	s = seg(u->p, arg[0], 1);
	if(s == 0)
		errors("not in address space");

	from = PGROUND(arg[1]);
	len = arg[2];

	if(from+len > s->top) {
		qunlock(&s->lk);
		errors("segment too short");
	}

	mfreeseg(s, from, len);
	qunlock(&s->lk);

	return 0;
}

/* For binary compatability */
long
sysbrk_(ulong *arg)
{
	return ibrk(arg[0], BSEG);
}

M port/tcpinput.c => port/tcpinput.c +13 -0
@@ 21,6 21,18 @@ char *tcpstate[] = {
	"Closing", 	"Last_ack", 	"Time_wait" };

void
tcpinit(void)
{
	Reseq *r;

	reseqfree = ialloc(sizeof(Reseq)*Nreseq, 0);
	for(r = reseqfree; r < &reseqfree[Nreseq-1]; r++)
		r->next = r+1;

	r->next = 0;
}

void
tcp_input(Ipconv *ipc, Block *bp)
{
	Ipconv *s, *new, *etab;


@@ 657,6 669,7 @@ add_reseq(Tcpctl *tcb, char tos, Tcp *seg, Block *bp, ushort length)
	qlock(&reseqlock);
	if(!reseqfree) {
		qunlock(&reseqlock);
		print("tcp: no resequence descriptors\n");
		freeb(bp);
		return;
	}

M power/boot.h => power/boot.h +312 -356
@@ 1,6 1,6 @@
ulong bootcode[]={
	0x000000407,
	0x000005638,
	0x000005588,
	0x0000007d0,
	0x000001190,
	0x000000000,


@@ 25,24 25,24 @@ ulong bootcode[]={
	0x0afa00018,
	0x023c282e1,
	0x0afa20004,
	0x00c000a83,
	0x00c000a73,
	0x0afa00008,
	0x023c382e9,
	0x0afa30004,
	0x020020001,
	0x00c000a83,
	0x00c000a73,
	0x0afa20008,
	0x023c382f1,
	0x0afa30004,
	0x020020001,
	0x00c000a83,
	0x00c000a73,
	0x0afa20008,
	0x023c282f9,
	0x0afa20004,
	0x020040001,
	0x0afa40008,
	0x0200201b6,
	0x00c000a6a,
	0x00c000a5f,
	0x0afa2000c,
	0x004210004,
	0x0afa1001c,


@@ 52,13 52,13 @@ ulong bootcode[]={
	0x08fa20028,
	0x000000027,
	0x08c420000,
	0x00c000a43,
	0x00c000a3b,
	0x0afa20004,
	0x0afa10014,
	0x08fa40028,
	0x000000027,
	0x08c840000,
	0x00c000a43,
	0x00c000a3b,
	0x0afa40004,
	0x0afa10010,
	0x08fa4001c,


@@ 70,7 70,7 @@ ulong bootcode[]={
	0x000000027,
	0x0afa30008,
	0x08fa40010,
	0x00c000a9c,
	0x00c000a87,
	0x0afa4000c,
	0x08fa30014,
	0x000000027,


@@ 80,14 80,14 @@ ulong bootcode[]={
	0x00c0008d0,
	0x0afa20004,
	0x08fa3001c,
	0x00c000a65,
	0x00c000a5b,
	0x0afa30004,
	0x023c38314,
	0x0afa30004,
	0x020040001,
	0x0afa40008,
	0x0200301b6,
	0x00c000a6a,
	0x00c000a5f,
	0x0afa3000c,
	0x004210004,
	0x0afa1001c,


@@ 95,7 95,7 @@ ulong bootcode[]={
	0x00c0008d0,
	0x0afa20004,
	0x023c48336,
	0x00c000a43,
	0x00c000a3b,
	0x0afa40004,
	0x0afa10014,
	0x08fa4001c,


@@ 103,7 103,7 @@ ulong bootcode[]={
	0x0afa40004,
	0x0afa20008,
	0x08fa40014,
	0x00c000a9c,
	0x00c000a87,
	0x0afa4000c,
	0x004210004,
	0x000000027,


@@ 111,7 111,7 @@ ulong bootcode[]={
	0x00c0008d0,
	0x0afa20004,
	0x08fa3001c,
	0x00c000a65,
	0x00c000a5b,
	0x0afa30004,
	0x08fa20028,
	0x000000027,


@@ 143,12 143,12 @@ ulong bootcode[]={
	0x023c28026,
	0x0afa20004,
	0x023c3834c,
	0x00c000a03,
	0x00c0009fc,
	0x0afa30008,
	0x023c298d2,
	0x0afa20004,
	0x023c38357,
	0x00c000a03,
	0x00c0009fc,
	0x0afa30008,
	0x08fa60028,
	0x08fa20024,


@@ 165,14 165,14 @@ ulong bootcode[]={
	0x000000027,
	0x018a00003,
	0x000000027,
	0x00c000a65,
	0x00c000a5b,
	0x0afa50004,
	0x08fc3801a,
	0x000000027,
	0x018600004,
	0x000000027,
	0x08fc2801a,
	0x00c000a65,
	0x00c000a5b,
	0x0afa20004,
	0x0afc0801a,
	0x0afc08006,


@@ 184,20 184,20 @@ ulong bootcode[]={
	0x000000027,
	0x0afa50004,
	0x08cc30000,
	0x00c000a03,
	0x00c0009fc,
	0x0afa30008,
	0x023c28026,
	0x0afa20004,
	0x08fa30028,
	0x000000027,
	0x08c630004,
	0x00c000a03,
	0x00c0009fc,
	0x0afa30008,
	0x00800049f,
	0x000000027,
	0x0afa50004,
	0x08cc30000,
	0x00c000a03,
	0x00c0009fc,
	0x0afa30008,
	0x00800049f,
	0x000000027,


@@ 206,7 206,7 @@ ulong bootcode[]={
	0x023c3835f,
	0x0afa30004,
	0x020020002,
	0x00c000a83,
	0x00c000a73,
	0x0afa20008,
	0x08fa20000,
	0x000000027,


@@ 224,7 224,7 @@ ulong bootcode[]={
	0x000000027,
	0x0afa30004,
	0x08fa40028,
	0x00c0009ed,
	0x00c0009e9,
	0x0afa40008,
	0x08fa50014,
	0x0142000a5,


@@ 248,7 248,7 @@ ulong bootcode[]={
	0x023c28395,
	0x0afa20004,
	0x020040002,
	0x00c000a83,
	0x00c000a73,
	0x0afa40008,
	0x004210008,
	0x000000027,


@@ 264,12 264,12 @@ ulong bootcode[]={
	0x023c483af,
	0x0afa40008,
	0x02003000d,
	0x00c000a9c,
	0x00c000a87,
	0x0afa3000c,
	0x08fa50020,
	0x00421000a,
	0x000000027,
	0x00c000a65,
	0x00c000a5b,
	0x0afa50004,
	0x023c383bd,
	0x00c0008be,


@@ 282,12 282,12 @@ ulong bootcode[]={
	0x023c483cb,
	0x0afa40008,
	0x02003000c,
	0x00c000a9c,
	0x00c000a87,
	0x0afa3000c,
	0x08fa50020,
	0x00421000a,
	0x000000027,
	0x00c000a65,
	0x00c000a5b,
	0x0afa50004,
	0x023c383d8,
	0x00c0008be,


@@ 300,12 300,12 @@ ulong bootcode[]={
	0x023c483e5,
	0x0afa40008,
	0x02003000c,
	0x00c000a9c,
	0x00c000a87,
	0x0afa3000c,
	0x00421000b,
	0x000000027,
	0x08fa20020,
	0x00c000a65,
	0x00c000a5b,
	0x0afa20004,
	0x023c383f2,
	0x00c0008be,


@@ 319,7 319,7 @@ ulong bootcode[]={
	0x023c283ff,
	0x0afa20004,
	0x020040002,
	0x00c000a83,
	0x00c000a73,
	0x0afa40008,
	0x004210008,
	0x0afa10018,


@@ 333,12 333,12 @@ ulong bootcode[]={
	0x023c38425,
	0x0afa30004,
	0x020040002,
	0x00c000a83,
	0x00c000a73,
	0x0afa40008,
	0x00421000c,
	0x0afa1001c,
	0x08fa20018,
	0x00c000a65,
	0x00c000a5b,
	0x0afa20004,
	0x023c28433,
	0x0afa20004,


@@ 351,7 351,7 @@ ulong bootcode[]={
	0x08fa40014,
	0x000000027,
	0x08c840004,
	0x00c000a43,
	0x00c000a3b,
	0x0afa40004,
	0x0afa10010,
	0x08fa4001c,


@@ 363,15 363,15 @@ ulong bootcode[]={
	0x000000027,
	0x0afa20008,
	0x08fa40010,
	0x00c000a9c,
	0x00c000a87,
	0x0afa4000c,
	0x004210012,
	0x000000027,
	0x08fa2001c,
	0x00c000a65,
	0x00c000a5b,
	0x0afa20004,
	0x08fa30018,
	0x00c000a65,
	0x00c000a5b,
	0x0afa30004,
	0x08fa30014,
	0x000000027,


@@ 404,7 404,7 @@ ulong bootcode[]={
	0x023c28457,
	0x0afa20004,
	0x020040002,
	0x00c000a83,
	0x00c000a73,
	0x0afa40008,
	0x004210008,
	0x0afc1801e,


@@ 419,12 419,12 @@ ulong bootcode[]={
	0x023c4846d,
	0x0afa40008,
	0x02003000a,
	0x00c000a9c,
	0x00c000a87,
	0x0afa3000c,
	0x08fc5801e,
	0x00421000a,
	0x000000027,
	0x00c000a65,
	0x00c000a5b,
	0x0afa50004,
	0x023c38478,
	0x00c0008be,


@@ 437,12 437,12 @@ ulong bootcode[]={
	0x023c48483,
	0x0afa40008,
	0x020030017,
	0x00c000a9c,
	0x00c000a87,
	0x0afa3000c,
	0x00421000b,
	0x000000027,
	0x08fc2801e,
	0x00c000a65,
	0x00c000a5b,
	0x0afa20004,
	0x023c3849b,
	0x00c0008be,


@@ 454,12 454,12 @@ ulong bootcode[]={
	0x020020001,
	0x0afc280ce,
	0x0200307d0,
	0x00c000a8d,
	0x00c000a7b,
	0x0afa30004,
	0x023c384b3,
	0x0afa30004,
	0x020040002,
	0x00c000a83,
	0x00c000a73,
	0x0afa40008,
	0x004210008,
	0x0afa10054,


@@ 473,12 473,12 @@ ulong bootcode[]={
	0x023c284d3,
	0x0afa20004,
	0x020040002,
	0x00c000a83,
	0x00c000a73,
	0x0afa40008,
	0x00421000c,
	0x0afc1801a,
	0x08fa30054,
	0x00c000a65,
	0x00c000a5b,
	0x0afa30004,
	0x023c384de,
	0x0afa30004,


@@ 496,7 496,7 @@ ulong bootcode[]={
	0x00c0009b1,
	0x0afa2000c,
	0x023a40014,
	0x00c000a43,
	0x00c000a3b,
	0x0afa40004,
	0x0afa10010,
	0x08fc4801a,


@@ 504,15 504,15 @@ ulong bootcode[]={
	0x0afa40004,
	0x0afa20008,
	0x08fa40010,
	0x00c000a9c,
	0x00c000a87,
	0x0afa4000c,
	0x004210010,
	0x000000027,
	0x08fc2801a,
	0x00c000a65,
	0x00c000a5b,
	0x0afa20004,
	0x08fa30054,
	0x00c000a65,
	0x00c000a5b,
	0x0afa30004,
	0x02002ffff,
	0x0afc2801a,


@@ 549,7 549,7 @@ ulong bootcode[]={
	0x08fa500d0,
	0x014200007,
	0x000000027,
	0x00c000a65,
	0x00c000a5b,
	0x0afa50004,
	0x08fa20000,
	0x023bd00d4,


@@ 562,14 562,14 @@ ulong bootcode[]={
	0x023c28509,
	0x0afa20010,
	0x023c4850a,
	0x00c000a7e,
	0x00c000a6f,
	0x0afa40014,
	0x004210004,
	0x000000027,
	0x023c2850b,
	0x00c0008d0,
	0x0afa20004,
	0x00c000a79,
	0x00c000a6b,
	0x000000027,
	0x02003ffff,
	0x01023002f,


@@ 577,7 577,7 @@ ulong bootcode[]={
	0x010200022,
	0x000000027,
	0x023a20018,
	0x00c000a97,
	0x00c000a83,
	0x0afa20004,
	0x083a3002c,
	0x000000027,


@@ 593,7 593,7 @@ ulong bootcode[]={
	0x00c00098c,
	0x0afa20008,
	0x020030bb8,
	0x00c000a8d,
	0x00c000a7b,
	0x0afa30004,
	0x020020002,
	0x0afa20004,


@@ 603,7 603,7 @@ ulong bootcode[]={
	0x023c2857b,
	0x0afa20004,
	0x020030002,
	0x00c000a83,
	0x00c000a73,
	0x0afa30008,
	0x08fa20000,
	0x000000027,


@@ 615,7 615,7 @@ ulong bootcode[]={
	0x0afa20008,
	0x023c38535,
	0x0afa3000c,
	0x00c000a4f,
	0x00c000a47,
	0x0afa00010,
	0x023c28545,
	0x00c0008d0,


@@ 637,14 637,14 @@ ulong bootcode[]={
	0x023c297d2,
	0x0afa20004,
	0x023c487d2,
	0x00c000ae9,
	0x00c000ad3,
	0x0afa40008,
	0x08fa30024,
	0x023c487d2,
	0x0afa30004,
	0x0afa40008,
	0x0afa1001c,
	0x00c000a9c,
	0x00c000a87,
	0x0afa1000c,
	0x08fa5001c,
	0x000000027,


@@ 666,7 666,7 @@ ulong bootcode[]={
	0x0afa20004,
	0x0afa40008,
	0x020021000,
	0x00c000a88,
	0x00c000a77,
	0x0afa2000c,
	0x01c200008,
	0x000000027,


@@ 687,7 687,7 @@ ulong bootcode[]={
	0x023c497d2,
	0x0afa40008,
	0x0afa1001c,
	0x00c000f10,
	0x00c000efa,
	0x0afa1000c,
	0x014200022,
	0x000000027,


@@ 756,14 756,14 @@ ulong bootcode[]={
	0x023c397d2,
	0x0afa30004,
	0x023c487d2,
	0x00c000ae9,
	0x00c000ad3,
	0x0afa40008,
	0x08fa20024,
	0x023c487d2,
	0x0afa20004,
	0x0afa40008,
	0x0afa1001c,
	0x00c000a9c,
	0x00c000a87,
	0x0afa1000c,
	0x08fa4001c,
	0x000000027,


@@ 781,7 781,7 @@ ulong bootcode[]={
	0x0afa20004,
	0x0afa40008,
	0x020021000,
	0x00c000a88,
	0x00c000a77,
	0x0afa2000c,
	0x01c200008,
	0x000000027,


@@ 796,7 796,7 @@ ulong bootcode[]={
	0x0afa30004,
	0x023c497d2,
	0x0afa40008,
	0x00c000f10,
	0x00c000efa,
	0x0afa1000c,
	0x014200008,
	0x000000027,


@@ 919,7 919,7 @@ ulong bootcode[]={
	0x020040001,
	0x0afa40008,
	0x0200201b6,
	0x00c000a6a,
	0x00c000a5f,
	0x0afa2000c,
	0x004210004,
	0x0afa10148,


@@ 934,11 934,11 @@ ulong bootcode[]={
	0x00c0009b1,
	0x0afa2000c,
	0x023c387d2,
	0x00c000a43,
	0x00c000a3b,
	0x0afa30004,
	0x0afa10014,
	0x023c487d2,
	0x00c000a43,
	0x00c000a3b,
	0x0afa40004,
	0x0afa10010,
	0x08fa40148,


@@ 946,7 946,7 @@ ulong bootcode[]={
	0x0afa40004,
	0x0afa30008,
	0x08fa40010,
	0x00c000a9c,
	0x00c000a87,
	0x0afa4000c,
	0x08fa30014,
	0x000000027,


@@ 956,14 956,14 @@ ulong bootcode[]={
	0x00c0008d0,
	0x0afa20004,
	0x08fa30148,
	0x00c000a65,
	0x00c000a5b,
	0x0afa30004,
	0x023c386ab,
	0x0afa30004,
	0x020040001,
	0x0afa40008,
	0x0200301b6,
	0x00c000a6a,
	0x00c000a5f,
	0x0afa3000c,
	0x004210004,
	0x0afa10148,


@@ 978,11 978,11 @@ ulong bootcode[]={
	0x00c0009b1,
	0x0afa3000c,
	0x023c287d2,
	0x00c000a43,
	0x00c000a3b,
	0x0afa20004,
	0x0afa10014,
	0x023c487d2,
	0x00c000a43,
	0x00c000a3b,
	0x0afa40004,
	0x0afa10010,
	0x08fa40148,


@@ 990,7 990,7 @@ ulong bootcode[]={
	0x0afa40004,
	0x0afa30008,
	0x08fa40010,
	0x00c000a9c,
	0x00c000a87,
	0x0afa4000c,
	0x08fa30014,
	0x000000027,


@@ 1000,7 1000,7 @@ ulong bootcode[]={
	0x00c0008d0,
	0x0afa20004,
	0x08fa30148,
	0x00c000a65,
	0x00c000a5b,
	0x0afa30004,
	0x023c286c3,
	0x00c000967,


@@ 1009,7 1009,7 @@ ulong bootcode[]={
	0x0afa20004,
	0x023c486ce,
	0x0afa40008,
	0x00c000a60,
	0x00c000a57,
	0x0afa0000c,
	0x004210004,
	0x000000027,


@@ 1025,7 1025,7 @@ ulong bootcode[]={
	0x023c486d7,
	0x0afa40010,
	0x023c286d8,
	0x00c000a7e,
	0x00c000a6f,
	0x0afa20014,
	0x004210004,
	0x000000027,


@@ 1038,7 1038,7 @@ ulong bootcode[]={
	0x023c286e7,
	0x0afa20004,
	0x023a40058,
	0x00c000a92,
	0x00c000a7f,
	0x0afa40008,
	0x004210004,
	0x000000027,


@@ 1048,12 1048,12 @@ ulong bootcode[]={
	0x023a30058,
	0x0afa30004,
	0x023a200cc,
	0x00c0011e0,
	0x00c0011ca,
	0x0afa20008,
	0x023c286f0,
	0x0afa20004,
	0x020040001,
	0x00c000a83,
	0x00c000a73,
	0x0afa40008,
	0x0afa10148,
	0x023a20058,


@@ 1064,7 1064,7 @@ ulong bootcode[]={
	0x00c0009b1,
	0x0afa2000c,
	0x023a20058,
	0x00c000a43,
	0x00c000a3b,
	0x0afa20004,
	0x0afa10014,
	0x08fa20148,


@@ 1072,10 1072,10 @@ ulong bootcode[]={
	0x0afa20004,
	0x0afa30008,
	0x08fa20014,
	0x00c000a9c,
	0x00c000a87,
	0x0afa2000c,
	0x08fa30148,
	0x00c000a65,
	0x00c000a5b,
	0x0afa30004,
	0x023c286fc,
	0x00c000967,


@@ 1095,13 1095,13 @@ ulong bootcode[]={
	0x023a20018,
	0x0afa30004,
	0x0afa20008,
	0x00c000a60,
	0x00c000a57,
	0x0afa0000c,
	0x08fc3812a,
	0x023c2870d,
	0x0afa30004,
	0x0afa20008,
	0x00c000a60,
	0x00c000a57,
	0x0afa0000c,
	0x08fc58022,
	0x000000027,


@@ 1122,7 1122,7 @@ ulong bootcode[]={
	0x0afa30004,
	0x023c28748,
	0x0afa20008,
	0x00c000a60,
	0x00c000a57,
	0x0afa0000c,
	0x08fa30154,
	0x000000027,


@@ 1134,7 1134,7 @@ ulong bootcode[]={
	0x0afa30008,
	0x023c28769,
	0x0afa2000c,
	0x00c000a4f,
	0x00c000a47,
	0x0afa00010,
	0x023c3877c,
	0x00c0008d0,


@@ 1147,7 1147,7 @@ ulong bootcode[]={
	0x0afa30004,
	0x023c28777,
	0x0afa20008,
	0x00c000a4f,
	0x00c000a47,
	0x0afa0000c,
	0x023c3877c,
	0x00c0008d0,


@@ 1160,7 1160,7 @@ ulong bootcode[]={
	0x00c000967,
	0x0afa30004,
	0x0200203e8,
	0x00c000a8d,
	0x00c000a7b,
	0x0afa20004,
	0x08fc68006,
	0x08fa20144,


@@ 1216,7 1216,7 @@ ulong bootcode[]={
	0x023bdffac,
	0x0afbf0000,
	0x023a20014,
	0x00c000a6f,
	0x00c000a63,
	0x0afa20004,
	0x020030002,
	0x0afa30004,


@@ 1234,7 1234,7 @@ ulong bootcode[]={
	0x023bdffac,
	0x0afbf0000,
	0x023a30014,
	0x00c000a6f,
	0x00c000a63,
	0x0afa30004,
	0x020020002,
	0x0afa20004,


@@ 1265,7 1265,7 @@ ulong bootcode[]={
	0x023a30010,
	0x0afa30008,
	0x08fa40120,
	0x00c000a88,
	0x00c000a77,
	0x0afa4000c,
	0x014200003,
	0x000012825,


@@ 1287,7 1287,7 @@ ulong bootcode[]={
	0x08fa3011c,
	0x023a20010,
	0x0afa30004,
	0x00c000a03,
	0x00c0009fc,
	0x0afa20008,
	0x08fa50110,
	0x000000027,


@@ 1376,7 1376,7 @@ ulong bootcode[]={
	0x00800094f,
	0x02484ffff,
	0x08fa30014,
	0x00c000a5b,
	0x00c000a53,
	0x0afa30004,
	0x08fa20000,
	0x000000027,


@@ 1392,14 1392,14 @@ ulong bootcode[]={
	0x023a41020,
	0x0afa3000c,
	0x024840004,
	0x00c00129d,
	0x00c001284,
	0x0afa40010,
	0x023a6001c,
	0x020020001,
	0x0afa20004,
	0x0afa60008,
	0x000261023,
	0x00c000a9c,
	0x00c000a87,
	0x0afa2000c,
	0x0afa10014,
	0x00421000c,


@@ 1429,14 1429,14 @@ ulong bootcode[]={
	0x023a41024,
	0x0afa3000c,
	0x024840004,
	0x00c00129d,
	0x00c001284,
	0x0afa40010,
	0x08fa21020,
	0x023a6001c,
	0x0afa20004,
	0x0afa60008,
	0x000261023,
	0x00c000a9c,
	0x00c000a87,
	0x0afa2000c,
	0x0afa10014,
	0x00421000c,


@@ 1468,7 1468,7 @@ ulong bootcode[]={
	0x023a40024,
	0x0afa2000c,
	0x024840004,
	0x00c00129d,
	0x00c001284,
	0x0afa40010,
	0x08fa20014,
	0x000000027,


@@ 1480,10 1480,9 @@ ulong bootcode[]={
	0x000000027,
	0x000400008,
	0x023bd001c,
	0x023bdfffc,
	0x08fa70010,
	0x08fa6000c,
	0x08fa50008,
	0x08fa7000c,
	0x08fa60008,
	0x08fa50004,
	0x000000027,
	0x024e7ffff,
	0x004e00007,


@@ 1492,11 1491,10 @@ ulong bootcode[]={
	0x000061025,
	0x080420000,
	0x000000027,
	0x01062000f,
	0x01062000d,
	0x024c60001,
	0x004e10004,
	0x004e10003,
	0x000000027,
	0x023bd0004,
	0x003e00008,
	0x000000825,
	0x080a10000,


@@ 1505,42 1503,36 @@ ulong bootcode[]={
	0x000010e03,
	0x000021600,
	0x000021603,
	0x023bd0004,
	0x003e00008,
	0x000220823,
	0x000051825,
	0x080630000,
	0x000000027,
	0x01460ffe5,
	0x01460ffe7,
	0x024a50001,
	0x023bd0004,
	0x003e00008,
	0x000000825,
	0x023bdfffc,
	0x08fa30008,
	0x08fa2000c,
	0x08fa30004,
	0x08fa20008,
	0x000000027,
	0x080410000,
	0x080640000,
	0x01020000c,
	0x01020000b,
	0x000000027,
	0x024630001,
	0x01024fffa,
	0x024420001,
	0x00024082b,
	0x014200004,
	0x014200003,
	0x000000027,
	0x023bd0004,
	0x003e00008,
	0x02001ffff,
	0x003e00008,
	0x023bd0004,
	0x023bd0004,
	0x000000027,
	0x003e00008,
	0x00024082b,
	0x023bdfffc,
	0x08fa30008,
	0x08fa4000c,
	0x08fa30004,
	0x08fa40008,
	0x000000027,
	0x000830826,
	0x030210003,


@@ 1557,9 1549,9 @@ ulong bootcode[]={
	0x024630001,
	0x014a0fff8,
	0x024840001,
	0x08fa10008,
	0x08fa10004,
	0x003e00008,
	0x023bd0004,
	0x000000027,
	0x08c850000,
	0x024840004,
	0x000a60824,


@@ 1572,42 1564,42 @@ ulong bootcode[]={
	0x030a200ff,
	0x01440fff5,
	0x0ac65fffc,
	0x08fa10008,
	0x08fa10004,
	0x003e00008,
	0x023bd0004,
	0x000000027,
	0x000050e02,
	0x0a061fffc,
	0x000052c02,
	0x0a065fffd,
	0x0a060fffe,
	0x08fa10008,
	0x08fa10004,
	0x003e00008,
	0x023bd0004,
	0x000000027,
	0x000052e02,
	0x0a065fffc,
	0x0a060fffd,
	0x08fa10008,
	0x08fa10004,
	0x003e00008,
	0x023bd0004,
	0x000000027,
	0x0a060fffc,
	0x08fa10008,
	0x08fa10004,
	0x003e00008,
	0x023bd0004,
	0x000000027,
	0x080850000,
	0x000000027,
	0x0a0650000,
	0x024630001,
	0x014a0fffb,
	0x024840001,
	0x08fa10008,
	0x08fa10004,
	0x003e00008,
	0x023bd0004,
	0x000000027,
	0x023bdfff4,
	0x0afbf0000,
	0x08fa20010,
	0x000000027,
	0x0afa20004,
	0x00c00180c,
	0x00c0017e7,
	0x0afa00008,
	0x08fa30010,
	0x08fa20000,


@@ 1620,82 1612,68 @@ ulong bootcode[]={
	0x023a30010,
	0x0afa20004,
	0x024630004,
	0x00c000a74,
	0x00c000a67,
	0x0afa30008,
	0x08fa20000,
	0x000000027,
	0x000400008,
	0x023bd000c,
	0x023bdfffc,
	0x020010008,
	0x00000000c,
	0x003e00008,
	0x023bd0004,
	0x023bdfffc,
	0x000000027,
	0x020010002,
	0x00000000c,
	0x003e00008,
	0x023bd0004,
	0x023bdfffc,
	0x000000027,
	0x020010004,
	0x00000000c,
	0x003e00008,
	0x023bd0004,
	0x023bdfffc,
	0x000000027,
	0x020010016,
	0x00000000c,
	0x003e00008,
	0x023bd0004,
	0x023bdfffc,
	0x000000027,
	0x020010001,
	0x00000000c,
	0x003e00008,
	0x023bd0004,
	0x023bdfffc,
	0x000000027,
	0x020010007,
	0x00000000c,
	0x003e00008,
	0x023bd0004,
	0x023bdfffc,
	0x000000027,
	0x020010009,
	0x00000000c,
	0x003e00008,
	0x023bd0004,
	0x023bdfffc,
	0x000000027,
	0x02001000d,
	0x00000000c,
	0x003e00008,
	0x023bd0004,
	0x023bdfffc,
	0x000000027,
	0x02001000e,
	0x00000000c,
	0x003e00008,
	0x023bd0004,
	0x023bdfffc,
	0x000000027,
	0x02001000f,
	0x00000000c,
	0x003e00008,
	0x023bd0004,
	0x023bdfffc,
	0x000000027,
	0x020010011,
	0x00000000c,
	0x003e00008,
	0x023bd0004,
	0x023bdfffc,
	0x000000027,
	0x020010012,
	0x00000000c,
	0x003e00008,
	0x023bd0004,
	0x023bdfffc,
	0x000000027,
	0x020010013,
	0x00000000c,
	0x003e00008,
	0x023bd0004,
	0x023bdfffc,
	0x000000027,
	0x020010014,
	0x00000000c,
	0x003e00008,
	0x023bd0004,
	0x000000027,
	0x023bdffe4,
	0x0afbf0000,
	0x023c280ea,


@@ 1713,7 1691,7 @@ ulong bootcode[]={
	0x08fa2002c,
	0x000000027,
	0x08c420000,
	0x00c000a88,
	0x00c000a77,
	0x0afa2000c,
	0x014200015,
	0x0afa10018,


@@ 1749,7 1727,7 @@ ulong bootcode[]={
	0x08fa40028,
	0x000000027,
	0x0afa40008,
	0x00c000f10,
	0x00c000efa,
	0x0afa1000c,
	0x014200009,
	0x0afa10018,


@@ 1759,7 1737,7 @@ ulong bootcode[]={
	0x00c00098c,
	0x0afa30008,
	0x023c28121,
	0x008000abb,
	0x008000aa5,
	0x0afa20010,
	0x08fa3002c,
	0x000000027,


@@ 1859,7 1837,7 @@ ulong bootcode[]={
	0x024a20008,
	0x0afa20008,
	0x020030040,
	0x00c0018c5,
	0x00c00189a,
	0x0afa3000c,
	0x08fa20010,
	0x000000027,


@@ 1885,7 1863,7 @@ ulong bootcode[]={
	0x024a20008,
	0x0afa20008,
	0x02003001c,
	0x00c0018c5,
	0x00c00189a,
	0x0afa3000c,
	0x08fa20010,
	0x02003001c,


@@ 1896,7 1874,7 @@ ulong bootcode[]={
	0x000000027,
	0x024420024,
	0x0afa20008,
	0x00c0018c5,
	0x00c00189a,
	0x0afa3000c,
	0x08fa20010,
	0x02003001c,


@@ 1907,7 1885,7 @@ ulong bootcode[]={
	0x000000027,
	0x024420040,
	0x0afa20008,
	0x00c0018c5,
	0x00c00189a,
	0x0afa3000c,
	0x08fa20010,
	0x000000027,


@@ 2039,7 2017,7 @@ ulong bootcode[]={
	0x024a3000e,
	0x0afa30008,
	0x02002001c,
	0x00c0018c5,
	0x00c00189a,
	0x0afa2000c,
	0x08fa30010,
	0x08fa2001c,


@@ 2188,7 2166,7 @@ ulong bootcode[]={
	0x024a2000e,
	0x0afa20008,
	0x02003001c,
	0x00c0018c5,
	0x00c00189a,
	0x0afa3000c,
	0x08fa70018,
	0x08fa20010,


@@ 2268,7 2246,7 @@ ulong bootcode[]={
	0x000000027,
	0x0afa20008,
	0x08ca3000c,
	0x00c0018c5,
	0x00c00189a,
	0x0afa3000c,
	0x08fa20018,
	0x08fa30010,


@@ 2412,7 2390,7 @@ ulong bootcode[]={
	0x000000027,
	0x0afa20008,
	0x08ca3000c,
	0x00c0018c5,
	0x00c00189a,
	0x0afa3000c,
	0x08fa20018,
	0x08fa30010,


@@ 2543,7 2521,7 @@ ulong bootcode[]={
	0x024a30008,
	0x0afa30008,
	0x020020074,
	0x00c0018c5,
	0x00c00189a,
	0x0afa2000c,
	0x08fa30010,
	0x08fa2001c,


@@ 2599,7 2577,7 @@ ulong bootcode[]={
	0x024a20008,
	0x0afa20008,
	0x020030074,
	0x00c0018c5,
	0x00c00189a,
	0x0afa3000c,
	0x08fa20010,
	0x000000027,


@@ 2647,7 2625,7 @@ ulong bootcode[]={
	0x024a2000e,
	0x0afa20008,
	0x02003001c,
	0x00c0018c5,
	0x00c00189a,
	0x0afa3000c,
	0x08fa20010,
	0x000000027,


@@ 2684,7 2662,7 @@ ulong bootcode[]={
	0x08fa30018,
	0x000000027,
	0x0afa30008,
	0x00c0018c5,
	0x00c00189a,
	0x0afa2000c,
	0x08fa30010,
	0x02002001c,


@@ 2695,7 2673,7 @@ ulong bootcode[]={
	0x000000027,
	0x02463001c,
	0x0afa30008,
	0x00c0018c5,
	0x00c00189a,
	0x0afa2000c,
	0x08fa30010,
	0x02002001c,


@@ 2706,7 2684,7 @@ ulong bootcode[]={
	0x000000027,
	0x024630038,
	0x0afa30008,
	0x00c0018c5,
	0x00c00189a,
	0x0afa2000c,
	0x08fa40018,
	0x08fa30010,


@@ 2916,17 2894,17 @@ ulong bootcode[]={
	0x000031a00,
	0x000431025,
	0x024a50002,
	0x008000f42,
	0x008000f2c,
	0x0a4c20008,
	0x024c20008,
	0x0afa20004,
	0x0afa50010,
	0x0afa50008,
	0x020020040,
	0x00c0018c5,
	0x00c00189a,
	0x0afa2000c,
	0x08fa30010,
	0x008000f42,
	0x008000f2c,
	0x024650040,
	0x090a20000,
	0x090a30001,


@@ 2941,7 2919,7 @@ ulong bootcode[]={
	0x0afa50010,
	0x0afa50008,
	0x02002001c,
	0x00c0018c5,
	0x00c00189a,
	0x0afa2000c,
	0x08fa30010,
	0x08fa2001c,


@@ 2951,7 2929,7 @@ ulong bootcode[]={
	0x0afa50010,
	0x0afa50008,
	0x02002001c,
	0x00c0018c5,
	0x00c00189a,
	0x0afa2000c,
	0x08fa30010,
	0x08fa2001c,


@@ 2961,10 2939,10 @@ ulong bootcode[]={
	0x0afa50010,
	0x0afa50008,
	0x02002001c,
	0x00c0018c5,
	0x00c00189a,
	0x0afa2000c,
	0x08fa30010,
	0x008000f42,
	0x008000f2c,
	0x02465001c,
	0x02003003e,
	0x00062202a,


@@ 2992,7 2970,7 @@ ulong bootcode[]={
	0x000031a00,
	0x000431025,
	0x024a50002,
	0x008000f42,
	0x008000f2c,
	0x0a4c20002,
	0x090a20000,
	0x090a30001,


@@ 3009,7 2987,7 @@ ulong bootcode[]={
	0x000031a00,
	0x000431025,
	0x024a50002,
	0x008000f42,
	0x008000f2c,
	0x0a4c2000c,
	0x090a20000,
	0x090a30001,


@@ 3050,7 3028,7 @@ ulong bootcode[]={
	0x000031e00,
	0x000431025,
	0x024a50004,
	0x008000f42,
	0x008000f2c,
	0x0acc20010,
	0x090a20000,
	0x090a30001,


@@ 3065,10 3043,10 @@ ulong bootcode[]={
	0x0afa50010,
	0x0afa50008,
	0x02002001c,
	0x00c0018c5,
	0x00c00189a,
	0x0afa2000c,
	0x08fa30010,
	0x008000f42,
	0x008000f2c,
	0x02465001c,
	0x02003003f,
	0x010430040,


@@ 3122,7 3100,7 @@ ulong bootcode[]={
	0x000031e00,
	0x000431025,
	0x024a50004,
	0x008000f42,
	0x008000f2c,
	0x0acc20010,
	0x090a20000,
	0x090a30001,


@@ 3134,7 3112,7 @@ ulong bootcode[]={
	0x024a30002,
	0x024650001,
	0x080630000,
	0x008000f42,
	0x008000f2c,
	0x0a0c3002a,
	0x090a20000,
	0x090a30001,


@@ 3175,7 3153,7 @@ ulong bootcode[]={
	0x000031e00,
	0x000431025,
	0x024a50004,
	0x008000f42,
	0x008000f2c,
	0x0acc20010,
	0x090a20000,
	0x090a30001,


@@ 3190,7 3168,7 @@ ulong bootcode[]={
	0x0afa50010,
	0x0afa50008,
	0x02002001c,
	0x00c0018c5,
	0x00c00189a,
	0x0afa2000c,
	0x08fa6001c,
	0x08fa30010,


@@ 3214,7 3192,7 @@ ulong bootcode[]={
	0x024a30004,
	0x024650001,
	0x080630000,
	0x008000f42,
	0x008000f2c,
	0x0a0c3002a,
	0x02003004a,
	0x00062202a,


@@ 3260,7 3238,7 @@ ulong bootcode[]={
	0x024650001,
	0x0acc50010,
	0x08cc3000c,
	0x008000f42,
	0x008000f2c,
	0x000a32821,
	0x090a20000,
	0x090a30001,


@@ 3293,7 3271,7 @@ ulong bootcode[]={
	0x000031a00,
	0x000431025,
	0x024a50002,
	0x008000f42,
	0x008000f2c,
	0x0acc2000c,
	0x090a20000,
	0x090a30001,


@@ 3334,7 3312,7 @@ ulong bootcode[]={
	0x000031e00,
	0x000431025,
	0x024a50004,
	0x008000f42,
	0x008000f2c,
	0x0acc20010,
	0x090a20000,
	0x090a30001,


@@ 3371,7 3349,7 @@ ulong bootcode[]={
	0x024650001,
	0x0acc50010,
	0x08cc3000c,
	0x008000f42,
	0x008000f2c,
	0x000a32821,
	0x020030047,
	0x01043001d,


@@ 3393,7 3371,7 @@ ulong bootcode[]={
	0x000031a00,
	0x000431025,
	0x024a50002,
	0x008000f42,
	0x008000f2c,
	0x0a4c20002,
	0x090a20000,
	0x090a30001,


@@ 3402,7 3380,7 @@ ulong bootcode[]={
	0x000031a00,
	0x000431025,
	0x024a50002,
	0x008000f42,
	0x008000f2c,
	0x0a4c20002,
	0x090a20000,
	0x090a30001,


@@ 3419,7 3397,7 @@ ulong bootcode[]={
	0x000031a00,
	0x000431025,
	0x024a50002,
	0x008000f42,
	0x008000f2c,
	0x0acc2000c,
	0x090a20000,
	0x090a30001,


@@ 3428,7 3406,7 @@ ulong bootcode[]={
	0x000031a00,
	0x000431025,
	0x024a50002,
	0x008000f42,
	0x008000f2c,
	0x0a4c20002,
	0x02003004e,
	0x00062202a,


@@ 3462,10 3440,10 @@ ulong bootcode[]={
	0x0afa50010,
	0x0afa50008,
	0x020020074,
	0x00c0018c5,
	0x00c00189a,
	0x0afa2000c,
	0x08fa30010,
	0x008000f42,
	0x008000f2c,
	0x024650074,
	0x090a20000,
	0x090a30001,


@@ 3474,7 3452,7 @@ ulong bootcode[]={
	0x000031a00,
	0x000431025,
	0x024a50002,
	0x008000f42,
	0x008000f2c,
	0x0a4c20002,
	0x090a20000,
	0x090a30001,


@@ 3483,7 3461,7 @@ ulong bootcode[]={
	0x000031a00,
	0x000431025,
	0x024a50002,
	0x008000f42,
	0x008000f2c,
	0x0a4c20002,
	0x090a20000,
	0x090a30001,


@@ 3498,10 3476,10 @@ ulong bootcode[]={
	0x0afa50010,
	0x0afa50008,
	0x020020074,
	0x00c0018c5,
	0x00c00189a,
	0x0afa2000c,
	0x08fa30010,
	0x008000f42,
	0x008000f2c,
	0x024650074,
	0x02003004f,
	0x010430025,


@@ 3537,10 3515,10 @@ ulong bootcode[]={
	0x0afa50010,
	0x0afa50008,
	0x02002001c,
	0x00c0018c5,
	0x00c00189a,
	0x0afa2000c,
	0x08fa30010,
	0x008000f42,
	0x008000f2c,
	0x02465001c,
	0x090a20000,
	0x090a30001,


@@ 3549,7 3527,7 @@ ulong bootcode[]={
	0x000031a00,
	0x000431025,
	0x024a50002,
	0x008000f42,
	0x008000f2c,
	0x0a4c20002,
	0x023bdffec,
	0x0afbf0000,


@@ 3560,7 3538,7 @@ ulong bootcode[]={
	0x0afa50010,
	0x0afa50008,
	0x02003001c,
	0x00c0018c5,
	0x00c00189a,
	0x0afa3000c,
	0x08fa20010,
	0x08fa3001c,


@@ 3570,7 3548,7 @@ ulong bootcode[]={
	0x0afa50010,
	0x0afa50008,
	0x02003001c,
	0x00c0018c5,
	0x00c00189a,
	0x0afa3000c,
	0x08fa20010,
	0x08fa3001c,


@@ 3580,7 3558,7 @@ ulong bootcode[]={
	0x0afa50010,
	0x0afa50008,
	0x02003001c,
	0x00c0018c5,
	0x00c00189a,
	0x0afa3000c,
	0x08fa5001c,
	0x08fa20010,


@@ 3704,16 3682,14 @@ ulong bootcode[]={
	0x000000027,
	0x000400008,
	0x023bd0014,
	0x023bdfffc,
	0x08fc780ca,
	0x083a2000b,
	0x083a20007,
	0x028e3001e,
	0x03042007f,
	0x000022e00,
	0x000052e03,
	0x014600004,
	0x014600003,
	0x023c68146,
	0x023bd0004,
	0x003e00008,
	0x020010001,
	0x000051e00,


@@ 3734,10 3710,9 @@ ulong bootcode[]={
	0x000021600,
	0x000021603,
	0x000021080,
	0x08fa4000c,
	0x08fa40008,
	0x000431021,
	0x000000825,
	0x023bd0004,
	0x003e00008,
	0x0ac440000,
	0x023bdffcc,


@@ 3799,7 3774,7 @@ ulong bootcode[]={
	0x02002000a,
	0x014a20003,
	0x000000027,
	0x0080012ae,
	0x008001295,
	0x0afc080de,
	0x020020009,
	0x014a2ffd2,


@@ 3809,7 3784,7 @@ ulong bootcode[]={
	0x024630007,
	0x0201cfff8,
	0x0007c1824,
	0x0080012ae,
	0x008001295,
	0x0afc380de,
	0x02007fc18,
	0x0200bfc18,


@@ 3823,7 3798,7 @@ ulong bootcode[]={
	0x000052e03,
	0x014a00003,
	0x000000027,
	0x0080012ae,
	0x008001295,
	0x024c6ffff,
	0x02002002e,
	0x014a20007,


@@ 3832,7 3807,7 @@ ulong bootcode[]={
	0x014e20002,
	0x000000027,
	0x000003825,
	0x0080012e7,
	0x0080012ce,
	0x000005825,
	0x028a20031,
	0x014400025,


@@ 3854,11 3829,11 @@ ulong bootcode[]={
	0x000000027,
	0x014a0ffe4,
	0x000083825,
	0x0080012ae,
	0x008001295,
	0x024c6ffff,
	0x014a0ffe0,
	0x000085825,
	0x0080012ae,
	0x008001295,
	0x024c6ffff,
	0x02002000a,
	0x001020018,


@@ 3871,7 3846,7 @@ ulong bootcode[]={
	0x000000027,
	0x000052e00,
	0x000052e03,
	0x008001303,
	0x0080012ea,
	0x02468ffd0,
	0x020030030,
	0x014a30006,


@@ 3879,7 3854,7 @@ ulong bootcode[]={
	0x02003fc18,
	0x010e30003,
	0x000000027,
	0x008001302,
	0x0080012e9,
	0x000000027,
	0x02002002a,
	0x014a20009,


@@ 3888,9 3863,9 @@ ulong bootcode[]={
	0x02002fc18,
	0x014e20003,
	0x025290004,
	0x0080012e7,
	0x0080012ce,
	0x000053825,
	0x0080012e7,
	0x0080012ce,
	0x000055825,
	0x030a5007f,
	0x0afa90044,


@@ 3923,9 3898,9 @@ ulong bootcode[]={
	0x000000027,
	0x08fa40028,
	0x000011023,
	0x0080012e7,
	0x0080012ce,
	0x000825025,
	0x0080012ae,
	0x008001295,
	0x001214821,
	0x023bdfff0,
	0x0afbf0000,


@@ 3943,13 3918,13 @@ ulong bootcode[]={
	0x0afa30004,
	0x0afa40008,
	0x08fa3001c,
	0x00c00144b,
	0x00c001432,
	0x0afa3000c,
	0x08fa20000,
	0x000000027,
	0x000400008,
	0x023bd0010,
	0x008001363,
	0x00800134a,
	0x000042023,
	0x023bdffa8,
	0x0afbf0000,


@@ 4042,7 4017,7 @@ ulong bootcode[]={
	0x02002fc18,
	0x0afa30008,
	0x0afa2000c,
	0x00c001358,
	0x00c00133f,
	0x0afa70010,
	0x08fa10028,
	0x08fa20000,


@@ 4061,12 4036,12 @@ ulong bootcode[]={
	0x024a5ffff,
	0x001651021,
	0x020040030,
	0x0080013bf,
	0x0080013a6,
	0x0a0440000,
	0x024a5ffff,
	0x001651021,
	0x020040078,
	0x0080013db,
	0x0080013c2,
	0x0a0440000,
	0x030e30040,
	0x01060001e,


@@ 4088,27 4063,27 @@ ulong bootcode[]={
	0x000000027,
	0x01d000003,
	0x000000027,
	0x0080013b0,
	0x008001397,
	0x000000027,
	0x01d400003,
	0x000000027,
	0x0080013b0,
	0x008001397,
	0x000000027,
	0x030e20040,
	0x01440ffa0,
	0x024a5ffff,
	0x00149001b,
	0x0080013a5,
	0x00800138c,
	0x000003010,
	0x00149001b,
	0x0080013ec,
	0x0080013d3,
	0x000005012,
	0x0200d0001,
	0x00800139d,
	0x008001384,
	0x0000a5023,
	0x08caa0000,
	0x020030004,
	0x008001398,
	0x00800137f,
	0x0afa30028,
	0x08ca20000,
	0x000000027,


@@ 4120,15 4095,15 @@ ulong bootcode[]={
	0x000031c03,
	0x020020004,
	0x0afa20028,
	0x008001398,
	0x00800137f,
	0x000035025,
	0x08caa0000,
	0x020030004,
	0x008001398,
	0x00800137f,
	0x0afa30028,
	0x08caa0000,
	0x020030004,
	0x008001398,
	0x00800137f,
	0x0afa30028,
	0x020030030,
	0x01043000a,


@@ 4136,11 4111,11 @@ ulong bootcode[]={
	0x020030048,
	0x010430003,
	0x000000027,
	0x008001395,
	0x00800137c,
	0x000000027,
	0x08ca80000,
	0x020030004,
	0x008001398,
	0x00800137f,
	0x0afa30028,
	0x08ca30000,
	0x000000027,


@@ 4150,14 4125,14 @@ ulong bootcode[]={
	0x03042ffff,
	0x020030004,
	0x0afa30028,
	0x008001398,
	0x00800137f,
	0x000025025,
	0x008001385,
	0x00800136c,
	0x02009000a,
	0x0200e0001,
	0x008001385,
	0x00800136c,
	0x020090010,
	0x008001385,
	0x00800136c,
	0x020090008,
	0x020030075,
	0x011230006,


@@ 4165,15 4140,15 @@ ulong bootcode[]={
	0x020030078,
	0x01123fff7,
	0x000000027,
	0x008001385,
	0x00800136c,
	0x000000027,
	0x02009000a,
	0x008001385,
	0x00800136c,
	0x034e70020,
	0x023bdfff0,
	0x0afbf0000,
	0x08fa30014,
	0x00c000a43,
	0x00c000a3b,
	0x0afa30004,
	0x08fac0014,
	0x08faa0018,


@@ 4198,7 4173,7 @@ ulong bootcode[]={
	0x000000027,
	0x01ce00003,
	0x000000027,
	0x00800145b,
	0x008001442,
	0x000000027,
	0x000c9202b,
	0x010800005,


@@ 4216,7 4191,7 @@ ulong bootcode[]={
	0x02003fc18,
	0x010e3ffe3,
	0x000000027,
	0x00800145b,
	0x008001442,
	0x024e7ffff,
	0x020020009,
	0x01562fff9,


@@ 4227,7 4202,7 @@ ulong bootcode[]={
	0x02003fc18,
	0x010e3ffd8,
	0x0afc880de,
	0x00800145b,
	0x008001442,
	0x024e7ffff,
	0x02002fc18,
	0x011420003,


@@ 4252,7 4227,7 @@ ulong bootcode[]={
	0x0a0640000,
	0x025080001,
	0x024a50001,
	0x008001490,
	0x008001477,
	0x0afc880de,
	0x000aa202a,
	0x01080ffba,


@@ 4267,7 4242,7 @@ ulong bootcode[]={
	0x0a0440000,
	0x025080001,
	0x024a50001,
	0x00800149f,
	0x008001486,
	0x0afc880de,
	0x023bdffec,
	0x0afbf0000,


@@ 4282,7 4257,7 @@ ulong bootcode[]={
	0x0afa30004,
	0x0afa00008,
	0x02002fc18,
	0x00c00144b,
	0x00c001432,
	0x0afa2000c,
	0x08fa20000,
	0x023bd0014,


@@ 4300,7 4275,7 @@ ulong bootcode[]={
	0x08fa3001c,
	0x02002fc18,
	0x0afa30008,
	0x00c00144b,
	0x00c001432,
	0x0afa2000c,
	0x08fa20000,
	0x023bd0014,


@@ 4320,13 4295,12 @@ ulong bootcode[]={
	0x000000027,
	0x0afa3000c,
	0x08fa20024,
	0x00c001358,
	0x00c00133f,
	0x0afa20010,
	0x08fa20000,
	0x023bd0014,
	0x000400008,
	0x020010004,
	0x023bdfffc,
	0x08fc5805e,
	0x08fc280da,
	0x000000027,


@@ 4337,62 4311,51 @@ ulong bootcode[]={
	0x0afc2805e,
	0x020040025,
	0x0a0a40000,
	0x023bd0004,
	0x003e00008,
	0x000000825,
	0x023bdfffc,
	0x08fa30018,
	0x08fa30014,
	0x020020068,
	0x00043202a,
	0x01480001b,
	0x014800016,
	0x000000027,
	0x010620016,
	0x010620012,
	0x000000027,
	0x020020023,
	0x010620010,
	0x01062000d,
	0x000000027,
	0x02002002b,
	0x01062000a,
	0x010620008,
	0x000000027,
	0x02002002d,
	0x010620004,
	0x010620003,
	0x000000027,
	0x023bd0004,
	0x003e00008,
	0x000000825,
	0x023bd0004,
	0x003e00008,
	0x02001fffe,
	0x023bd0004,
	0x003e00008,
	0x02001ffff,
	0x023bd0004,
	0x003e00008,
	0x02001fffc,
	0x023bd0004,
	0x003e00008,
	0x02001fff0,
	0x02002006c,
	0x01062000a,
	0x010620008,
	0x000000027,
	0x020020075,
	0x010620004,
	0x010620003,
	0x000000027,
	0x023bd0004,
	0x003e00008,
	0x000000825,
	0x023bd0004,
	0x003e00008,
	0x02001ffe0,
	0x08fa20014,
	0x08fa20010,
	0x000000027,
	0x030420008,
	0x010400004,
	0x010400003,
	0x000000027,
	0x023bd0004,
	0x003e00008,
	0x02001ffc0,
	0x023bd0004,
	0x003e00008,
	0x02001fff8,
	0x023bdff60,


@@ 4406,7 4369,7 @@ ulong bootcode[]={
	0x0e7a6004c,
	0x0e7a70004,
	0x0e7a60008,
	0x00c00193d,
	0x00c001911,
	0x000000027,
	0x01020000e,
	0x000000027,


@@ 4417,7 4380,7 @@ ulong bootcode[]={
	0x0afa30008,
	0x0afa2000c,
	0x08fa300b0,
	0x00c001358,
	0x00c00133f,
	0x0afa30010,
	0x08fa20000,
	0x023bd00a0,


@@ 4428,7 4391,7 @@ ulong bootcode[]={
	0x020030001,
	0x0e7a10004,
	0x0e7a00008,
	0x00c00196d,
	0x00c001941,
	0x0afa3000c,
	0x01020000e,
	0x000000027,


@@ 4439,7 4402,7 @@ ulong bootcode[]={
	0x0afa30008,
	0x0afa2000c,
	0x08fa300b0,
	0x00c001358,
	0x00c00133f,
	0x0afa30010,
	0x08fa20000,
	0x023bd00a0,


@@ 4450,7 4413,7 @@ ulong bootcode[]={
	0x02003ffff,
	0x0e7a10004,
	0x0e7a00008,
	0x00c00196d,
	0x00c001941,
	0x0afa3000c,
	0x08fad00b4,
	0x08fac00ac,


@@ 4464,7 4427,7 @@ ulong bootcode[]={
	0x0afa30008,
	0x0afa2000c,
	0x08fa300b0,
	0x00c001358,
	0x00c00133f,
	0x0afa30010,
	0x08fa20000,
	0x023bd00a0,


@@ 4508,7 4471,7 @@ ulong bootcode[]={
	0x023a20034,
	0x0e7a10004,
	0x0e7a00008,
	0x00c00183e,
	0x00c001813,
	0x0afa2000c,
	0x08fa20034,
	0x04444f800,


@@ 4532,7 4495,7 @@ ulong bootcode[]={
	0x000023043,
	0x0afa60030,
	0x000061023,
	0x00c0017e3,
	0x00c0017be,
	0x0afa20004,
	0x0c7a30048,
	0x0c7a2004c,


@@ 4544,7 4507,7 @@ ulong bootcode[]={
	0x08fa30034,
	0x000000027,
	0x000431023,
	0x00c0017e3,
	0x00c0017be,
	0x0afa20004,
	0x08fad00b4,
	0x023ae0078,


@@ 4567,7 4530,7 @@ ulong bootcode[]={
	0x08fa30034,
	0x000000027,
	0x000431023,
	0x00c0017e3,
	0x00c0017be,
	0x0afa20004,
	0x08fad00b4,
	0x08fac00ac,


@@ 4576,7 4539,7 @@ ulong bootcode[]={
	0x0c7a2003c,
	0x000000027,
	0x046201182,
	0x0080015cc,
	0x0080015a7,
	0x023ae0078,
	0x0c7c180e2,
	0x0c7c080e6,


@@ 4593,7 4556,7 @@ ulong bootcode[]={
	0x08fa30034,
	0x000000027,
	0x000431023,
	0x00c0017e3,
	0x00c0017be,
	0x0afa20004,
	0x08fad00b4,
	0x08fac00ac,


@@ 4602,7 4565,7 @@ ulong bootcode[]={
	0x0c7a2003c,
	0x000000027,
	0x046201182,
	0x0080015e3,
	0x0080015be,
	0x023ae0078,
	0x02003fc18,
	0x015830002,


@@ 4637,7 4600,7 @@ ulong bootcode[]={
	0x0200cffff,
	0x0afac00ac,
	0x0200d0065,
	0x008001590,
	0x00800156b,
	0x0afad00b4,
	0x0c7a70048,
	0x0c7a6004c,


@@ 4651,7 4614,7 @@ ulong bootcode[]={
	0x08fa30034,
	0x02002ffff,
	0x000431023,
	0x00c0017e3,
	0x00c0017be,
	0x0afa20004,
	0x08fad00b4,
	0x023ae0078,


@@ 4673,7 4636,7 @@ ulong bootcode[]={
	0x000671823,
	0x004600134,
	0x0afa7002c,
	0x00c0017e3,
	0x00c0017be,
	0x0afa30004,
	0x0c7a30040,
	0x0c7a20044,


@@ 4682,7 4645,7 @@ ulong bootcode[]={
	0x046201083,
	0x0e7a30004,
	0x0e7a20008,
	0x00c0017a1,
	0x00c00177c,
	0x000000027,
	0x08fad00b4,
	0x023ae0078,


@@ 4740,7 4703,7 @@ ulong bootcode[]={
	0x024e70001,
	0x02484fff6,
	0x0a0440001,
	0x008001673,
	0x00800164e,
	0x024c6ffff,
	0x010e00007,
	0x0200b0001,


@@ 4808,7 4771,7 @@ ulong bootcode[]={
	0x020030030,
	0x0a0430000,
	0x024e7ffff,
	0x0080016ba,
	0x008001695,
	0x024c60001,
	0x019000013,
	0x000000027,


@@ 4828,7 4791,7 @@ ulong bootcode[]={
	0x0256b0001,
	0x0a0430000,
	0x02508ffff,
	0x0080016cb,
	0x0080016a6,
	0x024c60001,
	0x08fa300b0,
	0x000000027,


@@ 4857,7 4820,7 @@ ulong bootcode[]={
	0x0afa30008,
	0x0afa2000c,
	0x08fa300b0,
	0x00c001358,
	0x00c00133f,
	0x0afa30010,
	0x08fa20000,
	0x023bd00a0,


@@ 4913,19 4876,19 @@ ulong bootcode[]={
	0x000001810,
	0x024630030,
	0x0a0430000,
	0x0080016f2,
	0x0080016cd,
	0x024c60001,
	0x000061825,
	0x001231021,
	0x02003002b,
	0x0a0430000,
	0x008001713,
	0x0080016ee,
	0x024c60001,
	0x000061025,
	0x001221821,
	0x020020065,
	0x0a0620000,
	0x008001709,
	0x0080016e4,
	0x024c60001,
	0x020030067,
	0x011a30006,


@@ 4933,7 4896,7 @@ ulong bootcode[]={
	0x020030068,
	0x011a30003,
	0x000000027,
	0x0080016ec,
	0x0080016c7,
	0x000000027,
	0x024c7ffff,
	0x004e00006,


@@ 4953,11 4916,11 @@ ulong bootcode[]={
	0x000000027,
	0x01107ff93,
	0x000073025,
	0x0080016ec,
	0x0080016c7,
	0x024c60001,
	0x008001751,
	0x00800172c,
	0x02508ffff,
	0x008001749,
	0x008001724,
	0x024e7ffff,
	0x08fa30034,
	0x02002ffff,


@@ 4967,7 4930,7 @@ ulong bootcode[]={
	0x000003825,
	0x08fa30034,
	0x0200d0068,
	0x0080016a7,
	0x008001682,
	0x001835023,
	0x08fa200b0,
	0x000000027,


@@ 4978,7 4941,7 @@ ulong bootcode[]={
	0x001221821,
	0x02002002b,
	0x0a0620000,
	0x008001698,
	0x008001673,
	0x024c60001,
	0x0c7c180e2,
	0x0c7c080e6,


@@ 4988,7 4951,7 @@ ulong bootcode[]={
	0x0e7a60044,
	0x0e7a70004,
	0x0e7a60008,
	0x00c0017a1,
	0x00c00177c,
	0x000000027,
	0x08fad00b4,
	0x023ae0078,


@@ 5015,14 4978,14 @@ ulong bootcode[]={
	0x046222181,
	0x0e7a70040,
	0x0e7a60044,
	0x00800166a,
	0x008001645,
	0x000000027,
	0x008001606,
	0x0080015e1,
	0x0258cffff,
	0x020020001,
	0x0afa20014,
	0x025ad0020,
	0x008001590,
	0x00800156b,
	0x0afad00b4,
	0x023bdffe8,
	0x0afbf0000,


@@ 5039,7 5002,7 @@ ulong bootcode[]={
	0x04624c081,
	0x0e7a30004,
	0x0e7a20008,
	0x00c00188c,
	0x00c001861,
	0x0afa2000c,
	0x04620c032,
	0x000000027,


@@ 5068,7 5031,7 @@ ulong bootcode[]={
	0x023a2001c,
	0x0e7a30004,
	0x0e7a20008,
	0x00c00188c,
	0x00c001861,
	0x0afa2000c,
	0x0c7a1001c,
	0x0c7a00020,


@@ 5084,7 5047,7 @@ ulong bootcode[]={
	0x04624c081,
	0x0e7a30004,
	0x0e7a20008,
	0x00c0017a1,
	0x00c00177c,
	0x000000027,
	0x08fa20000,
	0x023bd000c,


@@ 5097,7 5060,7 @@ ulong bootcode[]={
	0x004810008,
	0x000000027,
	0x000041023,
	0x00c0017e3,
	0x00c0017be,
	0x0afa20004,
	0x08fa20000,
	0x023bd0014,


@@ 5118,12 5081,12 @@ ulong bootcode[]={
	0x000042843,
	0x0afa50010,
	0x000851823,
	0x00c0017e3,
	0x00c0017be,
	0x0afa30004,
	0x0e7a10008,
	0x0e7a0000c,
	0x08fa20010,
	0x00c0017e3,
	0x00c0017be,
	0x0afa20004,
	0x0c7a30008,
	0x0c7a2000c,


@@ 5131,9 5094,8 @@ ulong bootcode[]={
	0x023bd0014,
	0x000400008,
	0x046220002,
	0x023bdfffc,
	0x083a4000f,
	0x08fa30008,
	0x083a4000b,
	0x08fa30004,
	0x01080000a,
	0x000000027,
	0x080610000,


@@ 5144,15 5106,14 @@ ulong bootcode[]={
	0x000000027,
	0x02461ffff,
	0x003e00008,
	0x023bd0004,
	0x000000027,
	0x030610003,
	0x010200008,
	0x010200007,
	0x000000027,
	0x080610000,
	0x000000027,
	0x01420fffa,
	0x024630001,
	0x023bd0004,
	0x003e00008,
	0x02461ffff,
	0x03c06ff00,


@@ 5161,24 5122,20 @@ ulong bootcode[]={
	0x000000027,
	0x000a60824,
	0x000a71024,
	0x010200010,
	0x01020000d,
	0x024630004,
	0x01040000b,
	0x010400009,
	0x030a1ff00,
	0x010200006,
	0x010200005,
	0x030a200ff,
	0x01440fff5,
	0x000000027,
	0x023bd0004,
	0x003e00008,
	0x02461ffff,
	0x023bd0004,
	0x003e00008,
	0x02461fffe,
	0x023bd0004,
	0x003e00008,
	0x02461fffd,
	0x023bd0004,
	0x003e00008,
	0x02461fffc,
	0x023bdfff4,


@@ 5314,12 5271,11 @@ ulong bootcode[]={
	0x08fa4000c,
	0x000000027,
	0x000821024,
	0x0080018ad,
	0x008001882,
	0x0afa2000c,
	0x023bdfffc,
	0x08fa30010,
	0x08fa40008,
	0x08fa5000c,
	0x08fa3000c,
	0x08fa40004,
	0x08fa50008,
	0x000833021,
	0x028620004,
	0x000a4082b,


@@ 5375,9 5331,9 @@ ulong bootcode[]={
	0x0a0880000,
	0x014e5fffc,
	0x024840001,
	0x08fa10008,
	0x08fa10004,
	0x003e00008,
	0x023bd0004,
	0x000000027,
	0x014400028,
	0x000000027,
	0x000e60826,


@@ 5425,7 5381,7 @@ ulong bootcode[]={
	0x000000027,
	0x0a0c8ffff,
	0x024c6ffff,
	0x00800192c,
	0x008001900,
	0x024e7ffff,
	0x023bdfff4,
	0x03c027ff0,


@@ 5455,7 5411,7 @@ ulong bootcode[]={
	0x000000825,
	0x0e7a50004,
	0x0e7a40008,
	0x00c00196d,
	0x00c001941,
	0x0afa0000c,
	0x014200005,
	0x000000027,


@@ 5638,13 5594,13 @@ ulong bootcode[]={
	0x000010000,
	0x002000000,
	0x000000000,
	0x0000052b8,
	0x0000053d4,
	0x000004dc0,
	0x0000054b0,
	0x000005304,
	0x00000534c,
	0x00000539c,
	0x000005254,
	0x000005368,
	0x000004d5c,
	0x00000541c,
	0x0000052a0,
	0x0000052e8,
	0x000005338,
	0x000000000,
	0x000000000,
	0x000000000,


@@ 6025,6 5981,6 @@ ulong bootcode[]={
	0x020726562,
	0x06f6f7400,
	0x000000000,
	0x00005e28,
	0x00005d78,
	0x0,
};

M power/conf.h => power/conf.h +4 -3
@@ 4,9 4,10 @@ Conftab conftab[] = {
	{"npgrp", &conf.npgrp },
	{"npage0", &conf.npage0 },
	{"npage", &conf.npage },
	{"norig", &conf.norig },
	{"npte", &conf.npte },
	{"nmod", &conf.nmod },
	{"nseg", &conf.nseg },
	{"nimage", &conf.nimage },
	{"npagetab", &conf.npagetab },
	{"nswap", &conf.nswap },
	{"nalarm", &conf.nalarm },
	{"nchan", &conf.nchan },
	{"nenv", &conf.nenv },

M power/dat.h => power/dat.h +6 -7
@@ 41,9 41,10 @@ struct Conf
	ulong	npgrp;		/* process groups */
	ulong	npage0;		/* total physical pages of memory */
	ulong	npage;		/* total physical pages of memory */
	ulong	norig;		/* origins */
	ulong	npte;		/* contiguous page table entries */
	ulong	nmod;		/* single (modifying) page table entries */
	ulong	nseg;		/* number of segments */
	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 */


@@ 133,6 134,7 @@ struct Mach
	char	pidhere[NTLBPID];	/* is this pid possibly in this mmu? */
	int	lastpid;		/* last pid allocated on this machine */
	Proc	*pidproc[NTLBPID];	/* process that owns this tlbpid on this mach */
	Page	*ufreeme;		/* address of upage of exited process */

	int	tlbfault;
	int	tlbpurge;


@@ 159,7 161,7 @@ struct Softtlb
 */
typedef void		KMap;
#define	VA(k)		((ulong)(k))
#define	kmap(p)		(KMap*)(p->pa|KZERO)
#define	kmap(p)		(KMap*)((p)->pa|KZERO)
#define	kunmap(k)
#define PPN(x)		x



@@ 205,7 207,6 @@ struct

#define	NERR	15
#define	NNOTE	5
#define	NFD	100
struct User
{
	Proc	*p;


@@ 216,8 217,6 @@ struct User
	char	elem[NAMELEN];		/* last name element from namec */
	Chan	*slash;
	Chan	*dot;
	Chan	*fd[NFD];
	int	maxfd;			/* highest fd in use */
	/*
	 * Rest of structure controlled by devproc.c and friends.
	 * lock(&p->debug) to modify.

M power/faultmips.c => power/faultmips.c +6 -3
@@ 15,6 15,7 @@ faultmips(Ureg *ur, int user, int code)
{
	ulong addr;
	extern char *excname[];
	char buf[ERRLEN];
	int read;

	addr = ur->badvaddr;


@@ 22,9 23,11 @@ faultmips(Ureg *ur, int user, int code)
	read = !(code==CTLBM || code==CTLBS);
	if(fault(addr, read) < 0){
		if(user){
			pprint("user %s badvaddr=0x%lux\n", excname[code], ur->badvaddr);
			pprint("status=0x%lux pc=0x%lux sp=0x%lux\n", ur->status, ur->pc, ur->sp);
			pexit("Suicide", 0);
			sprint(buf, "sys: fault %s pc=0x%lux addr=0x%lux",
				read? "read" : "write", ur->pc, ur->badvaddr);
			postnote(u->p, 1, buf, NDebug);
			notify(ur);
			return;
		}
		print("kernel %s badvaddr=0x%lux\n", excname[code], ur->badvaddr);
		print("status=0x%lux pc=0x%lux sp=0x%lux\n", ur->status, ur->pc, ur->sp);

M power/fns.h => power/fns.h +11 -3
@@ 7,24 7,29 @@ ulong	confeval(char*);
void	confread(void);
void	confprint(void);
void	confset(char*);
void	duartspecial(int, IOQ*, IOQ*, int);
int	conschar(void);
void	dcflush(void*, ulong);
int	duartactive(void);
void	duartenable0(void);
void	duartinit(void);
void	duartintr(void);
void	duartreset(void);
void	duartslave(void);
void	duartspecial(int, IOQ*, IOQ*, int);
void	duartxmit(int);
void	evenaddr(ulong);
void	faultmips(Ureg*, int, int);
ulong	fcr31(void);
void	flushmmu(void);
#define	flushpage(x)
#define	flushpage(s)	icflush((void*)(s), BY2PG)
#define	flushvirt()
void	gettlb(int, ulong*);
ulong	gettlbvirt(int);
void	gotopc(ulong);
void	icflush(void *, int);
void	icflush(void *, ulong);
void	ioboardinit(void);
void	intr(Ureg*);
void	kbdchar(int);
void	lanceintr(void);
void	lanceparity(void);
void	lancesetup(Lance*);


@@ 36,6 41,7 @@ void	novme(int);
void	online(void);
Block*	prepend(Block*, int);
void	prflush(void);
void	printslave(void);
#define procsetup(p)	((p)->fpstate = FPinit)
#define procsave(x,y)
#define procrestore(x,y)


@@ 51,6 57,8 @@ void	setvmevec(int, void (*)(int));
void	sinit(void);
uchar*	smap(int, uchar*);
void	sunmap(int, uchar*);
void	sysloginit(void);
void	syslog(char*, int);
void	tlbinit(void);
Block*	tolance(Block*, int);
void	touser(void*);

M power/l.s => power/l.s +195 -82
@@ 148,14 148,14 @@ TEXT	gotolabel(SB), $-4

TEXT	gotopc(SB), $8

	MOVW	$(64*1024), R1
	MOVW	R1, 8(SP)
	JAL	icflush(SB)
	MOVW	0(FP), R7		/* save arguments for later */
	MOVW	_argc(SB), R4
	MOVW	_argv(SB), R5
	MOVW	_env(SB), R6
	MOVW	R0, 4(SP)
	MOVW	$(64*1024), R1
	MOVW	R1, 8(SP)
	JAL	icflush(SB)
	JMP	(R7)

TEXT	puttlb(SB), $4


@@ 515,99 515,212 @@ TEXT	fcr31(SB), $0
	MOVW	FCR31, R1
	RET

/*
 *  we avoid using R4, R5, R6, and R7 so gotopc can call us without saving them
 */
TEXT icflush(SB), $-4			/* icflush(physaddr, nbytes) */

	MOVW	M(STATUS), R10
	MOVW	0(FP), R8
	MOVW	4(FP), R9
	MOVW	$KSEG0, R3
	OR	R3, R8
	MOVW	$0, M(STATUS)
	MOVW	$WBFLUSH, R1		/* wbflush */
	MOVW	0(R1), R1
	NOOP
	MOVW	$KSEG1, R3
	MOVW	$icflush0(SB), R2	/* make sure PC is in uncached address space */
	MOVW	$(SWC|ISC), R1
	OR	R3, R2
#define NOP	WORD	$0x0

TEXT icflush(SB), $-4
	MOVW	0(FP), R4
	MOVW	4(FP), R5
	MOVW	$icflush0(SB), R2	/* Jump to uncache space */
	MOVW	$0xA0000000, R1
	OR	R1, R2
	JMP	(R2)
	NOP

TEXT icflush0(SB), $-4

	MOVW	R1, M(STATUS)		/* swap and isolate cache, splhi */
	MOVW	$833, R12		/* cache_pass magic */
	MOVW	$0x10000, R9		/* icache size */

	MOVW	$0, R13
	MOVW	M(STATUS), R11

	BEQ	R9, R0, _icflush3
	MOVW	$0x30000, R2		/* swap and isolate */

	NOP
	NOP
	NOP
	NOP
	NOP
	MOVW	R2, M(STATUS)
	NOP
	NOP
	NOP
	NOP
	NOP
	
	MOVW	R4, R8
	MOVW	R5, R9
	AND	$0xFFFC, R8
	MOVW	$0x9F200000, R1
	OR	R1, R8

	MOVW	$icflush1(SB), R2
	JMP	(R2)
	NOP

TEXT icflush1(SB), $-4

_icflush1:
	MOVBU	R0, 0x00(R8)
	MOVBU	R0, 0x04(R8)
	MOVBU	R0, 0x08(R8)
	MOVBU	R0, 0x0C(R8)
	MOVBU	R0, 0x10(R8)
	MOVBU	R0, 0x14(R8)
	MOVBU	R0, 0x18(R8)
	MOVBU	R0, 0x1C(R8)
	MOVBU	R0, 0x20(R8)
	MOVBU	R0, 0x24(R8)
	MOVBU	R0, 0x28(R8)
	MOVBU	R0, 0x2C(R8)
	MOVBU	R0, 0x30(R8)
	MOVBU	R0, 0x34(R8)
	MOVBU	R0, 0x38(R8)
	MOVBU	R0, 0x3C(R8)
	SUB	$0x40, R9
	ADD	$0x40, R8
	SGT	R12, R13, R1
	BNE	R1, _icflush2

	MOVW	$0, R13
	MOVW	R11, M(STATUS)
	MOVW	$0x30000, R2		/* swap and isolate */

	NOP
	NOP
	NOP
	NOP
	NOP
	MOVW	R2, M(STATUS)
	NOP
	NOP
	NOP
	NOP
	NOP

_icflush2:
	MOVW	R0, 0(R8)
	MOVW	R0, 4(R8)
	MOVW	R0, 8(R8)
	MOVW	R0, 12(R8)
	MOVW	R0, 16(R8)
	MOVW	R0, 20(R8)
	MOVW	R0, 24(R8)
	MOVW	R0, 28(R8)
	ADDU	$-32, R9
	ADDU	$1, R13
	ADDU	$32, R8
	BGTZ	R9, _icflush1
	MOVW	$icflush2(SB), R2	/* make sure PC is in uncached address space */
	OR	R3, R2
	JMP	(R2)

TEXT icflush2(SB), $-4
	MOVW	$icflush3(SB), R2	/* Jump to uncache space */
	MOVW	$0xA0000000, R1
	OR	R1, R2
	JMP	(R2)
	NOP

TEXT icflush3(SB), $-4
_icflush3:
	NOP
	NOP
	NOP
	NOP
	NOP
	MOVW	R11, M(STATUS)
	NOP
	NOP
	NOP
	NOP
	NOP

	MOVW	$icflush4(SB), R2
	JMP	(R2)
	NOP

	MOVW	$0, M(STATUS)		/* swap back caches, de-isolate them, and stay splhi */
	NOOP				/* +++ */
	MOVW	R10, M(STATUS)
TEXT icflush4(SB), $-4
	RET

TEXT dcflush(SB), $-4			/* dcflush(physaddr, nbytes) */

	MOVW	M(STATUS), R6
TEXT dcflush(SB), $-4
	MOVW	0(FP), R4
	MOVW	4(FP), R5
	MOVW	$KSEG0, R3
	OR	R3, R4
	MOVW	$0, M(STATUS)
	MOVW	$WBFLUSH, R1
	MOVW	0(R1), R1
	NOOP
	MOVW	$ISC, R1
	MOVW	R1, M(STATUS)
_dcflush0:
	MOVBU	R0, 0x00(R4)
	MOVBU	R0, 0x04(R4)
	MOVBU	R0, 0x08(R4)
	MOVBU	R0, 0x0C(R4)
	MOVBU	R0, 0x10(R4)
	MOVBU	R0, 0x14(R4)
	MOVBU	R0, 0x18(R4)
	MOVBU	R0, 0x1C(R4)
	MOVBU	R0, 0x20(R4)
	MOVBU	R0, 0x24(R4)
	MOVBU	R0, 0x28(R4)
	MOVBU	R0, 0x2C(R4)
	MOVBU	R0, 0x30(R4)
	MOVBU	R0, 0x34(R4)
	MOVBU	R0, 0x38(R4)
	MOVBU	R0, 0x3C(R4)
	SUB	$0x40, R5
	ADD	$0x40, R4
	BGTZ	R5, _dcflush0
	MOVW	$0, M(STATUS)
	NOOP				/* +++ */
	MOVW	R6, M(STATUS)
	MOVW	$dcflush0(SB), R2	/* Jump to uncache space */
	MOVW	$0xA0000000, R1
	OR	R1, R2
	JMP	(R2)
	NOP

TEXT dcflush0(SB), $-4

	MOVW	$833, R12		/* cache_pass magdc */
	MOVW	$0x10000, R9		/* dcache size */

	MOVW	$0, R13
	MOVW	M(STATUS), R11

	BEQ	R9, R0, _dcflush3
	MOVW	$0x10000, R2		/* isolate data cache */

	NOP
	NOP
	NOP
	NOP
	NOP
	MOVW	R2, M(STATUS)
	NOP
	NOP
	NOP
	NOP
	NOP
	
	MOVW	R4, R8
	MOVW	R5, R9
	AND	$0xFFFC, R8
	MOVW	$0x9F200000, R1
	OR	R1, R8

	MOVW	$dcflush1(SB), R2
	JMP	(R2)
	NOP

TEXT dcflush1(SB), $-4
_dcflush1:
	SGT	R12, R13, R1
	BNE	R1, _dcflush2

	MOVW	$0, R13
	MOVW	R11, M(STATUS)
	MOVW	$0x10000, R2		/* isolate data cache */

	NOP
	NOP
	NOP
	NOP
	NOP
	MOVW	R2, M(STATUS)
	NOP
	NOP
	NOP
	NOP
	NOP

_dcflush2:
	MOVW	R0, 0(R8)
	MOVW	R0, 4(R8)
	MOVW	R0, 8(R8)
	MOVW	R0, 12(R8)
	MOVW	R0, 16(R8)
	MOVW	R0, 20(R8)
	MOVW	R0, 24(R8)
	MOVW	R0, 28(R8)
	ADDU	$-32, R9
	ADDU	$1, R13
	ADDU	$32, R8
	BGTZ	R9, _dcflush1

	MOVW	$dcflush3(SB), R2	/* Jump to uncache space */
	MOVW	$0xA0000000, R1
	OR	R1, R2
	JMP	(R2)
	NOP

TEXT dcflush3(SB), $-4
_dcflush3:
	NOP
	NOP
	NOP
	NOP
	NOP
	MOVW	R11, M(STATUS)
	NOP
	NOP
	NOP
	NOP
	NOP

	MOVW	$dcflush4(SB), R2
	JMP	(R2)
	NOP

TEXT dcflush4(SB), $-4
	RET

M power/lock.c => power/lock.c +2 -27
@@ 59,7 59,7 @@ lkpgalloc(void)

/* Moral equivalent of newpage for pages of hardware lock */
Page*
lkpage(Orig *o, ulong va)
lkpage(ulong va)
{
	uchar *p, *top;
	Page *pg;


@@ 82,7 82,6 @@ lkpage(Orig *o, ulong va)
	pg = &lkpgheader[i];
	pg->pa = (ulong)((i*WD2PG) + SBSEM) & ~UNCACHED;
	pg->va = va;
	pg->o = o;
	pg->ref = 1;

	unlock(&semalloc.lock);


@@ 90,7 89,7 @@ lkpage(Orig *o, ulong va)
}

void
lkpgfree(Page *pg, int dolock)
lkpgfree(Page *pg)
{
	uchar *p;



@@ 135,15 134,11 @@ lock(Lock *ll)
	 */
	if((*sbsem&1) == 0){
		l->pc = ((ulong*)&ll)[PCOFF];
		if(u && u->p)
			u->p->hasspin = 1;
		return;
	}
	for(i=0; i<10000000; i++)
    		if((*sbsem&1) == 0){
			l->pc = ((ulong*)&ll)[PCOFF];
			if(u && u->p)
				u->p->hasspin = 1;
			return;
	}
	*sbsem = 0;


@@ 172,8 167,6 @@ canlock(Lock *l)
	}
	if(*sbsem & 1)
		return 0;
	if(u && u->p)
		u->p->hasspin = 1;
	return 1;
}



@@ 182,22 175,4 @@ unlock(Lock *l)
{
	l->pc = 0;
	*l->sbsem = 0;
	if(u && u->p)
		u->p->hasspin = 0;
}

void
mklockseg(Seg *s)
{
	Orig *o;

	s->proc = u->p;
	o = neworig(LKSEGBASE, 0, OWRPERM|OSHARED, 0);
	o->minca = 0;
	o->maxca = 0;
	o->freepg = lkpgfree;
	s->o = o;
	s->minva = LKSEGBASE;
	s->maxva = LKSEGBASE;
	s->mod = 0;
}

M power/main.c => power/main.c +30 -29
@@ 61,13 61,15 @@ main(void)
	tlbinit();
	vecinit();
	procinit0();
	pgrpinit();
	initseg();
	grpinit();
	chaninit();
	clockinit();
	alarminit();
	ioboardinit();
	chandevreset();
	streaminit();
	swapinit();
	pageinit();
	userinit();
	launchinit();


@@ 228,6 230,7 @@ init0(void)

	sp = (ulong*)(USTKTOP - argsize);

	kickpager();
	touser(sp);
}



@@ 237,14 240,18 @@ void
userinit(void)
{
	Proc *p;
	Seg *s;
	Segment *s;
	User *up;
	KMap *k;
	int i;
	char **av;
	Page *pg;

	p = newproc();
	p->pgrp = newpgrp();
	p->egrp = newegrp();
	p->fgrp = newfgrp();

	strcpy(p->text, "*init*");
	strcpy(p->pgrp->user, "bootes");
	savefpregs(&initfp);


@@ 269,35 276,27 @@ userinit(void)
	/*
	 * User Stack, pass input arguments to boot process
	 */
	s = &p->seg[SSEG];
	s->proc = p;
	s->o = neworig(USTKTOP-BY2PG, 1, OWRPERM|OISMEM, 0);
	s->o->pte[0].page = newpage(0, 0, USTKTOP-BY2PG);
	memmove((ulong*)(s->o->pte[0].page->pa|KZERO|(BY2PG-argsize)), 
	s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG);
	p->seg[SSEG] = s;
	pg = newpage(1, 0, USTKTOP-BY2PG);
	segpage(s, pg);

	memmove((ulong*)(pg->pa|KZERO|(BY2PG-argsize)), 
		argbuf + sizeof(argbuf) - argsize, argsize);
	av = (char **)(s->o->pte[0].page->pa|KZERO|(BY2PG-argsize));

	av = (char **)(pg->pa|KZERO|(BY2PG-argsize));
	for(i = 0; i < _argc; i++)
		av[i] += (char *)USTKTOP - (argbuf + sizeof(argbuf));
	s->minva = USTKTOP-BY2PG;
	s->maxva = USTKTOP;

	/*
	 * Text
	 */
	s = &p->seg[TSEG];
	s->proc = p;
	/*
	 * On the mips, init text must be OCACHED to avoid reusing page
	 * and getting in trouble with the hardware instruction cache.
	 */
	s->o = neworig(UTZERO, 1, OCACHED|OISMEM, 0);
	s->o->pte[0].page = newpage(0, 0, UTZERO);
	s->o->npage = 1;
	k = kmap(s->o->pte[0].page);
	s = newseg(SG_TEXT, UTZERO, 1);
	p->seg[TSEG] = s;
	segpage(s, newpage(1, 0, UTZERO));
	k = kmap(s->map[0]->pages[0]);
	memmove((ulong*)VA(k), initcode, sizeof initcode);
	kunmap(k);
	s->minva = 0x1000;
	s->maxva = 0x2000;

	ready(p);
}


@@ 372,13 371,13 @@ exit(void)
	unlock(&active);
	spllo();
	print("cpu %d exiting\n", m->machno);
	while(active.machs || duartactive())
	while(active.machs || consactive())
		for(i=0; i<1000; i++)
			;
	splhi();
	for(i=0; i<2000000; i++)
		;
	duartenable0();
	duartreset();
	firmware();
}



@@ 625,14 624,15 @@ confinit(void)
	conf.nenv = 4 * conf.nproc;
	conf.nenvchar = 20 * conf.nenv;
	conf.nmtab = conf.nproc;
	conf.norig = 4 * conf.nproc;
	conf.nmod = 10 * conf.norig;
	conf.nseg = 4 * conf.nproc;
	conf.npagetab = conf.nseg*3;
	conf.nswap = 20000;
	conf.nimage = 200;
	conf.nchan = 20 * conf.nproc;
	conf.nmntdev = conf.nproc;
	conf.nmntbuf = conf.nproc;
	conf.nmnthdr = conf.nproc;
	conf.nstream = 2 * conf.nproc;
	conf.npte = 4 * conf.npage;
	conf.nalarm = 500;
	conf.nmount = 500;
	conf.nsrv = 3;


@@ 645,15 645,15 @@ confinit(void)
	conf.ip = 64;
	conf.arp = 32;
	conf.frag = 32;
	conf.cntrlp = 1;

	confread();

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

	conf.copymode = 1;		/* copy on reference */
	conf.cntrlp = 1;
}

/*


@@ 830,6 830,7 @@ void
buzz(int f, int d)
{
}

int
mouseputc(IOQ *q, int c)
{

M power/mem.h => power/mem.h +6 -2
@@ 13,6 13,7 @@
#define	WD2PG		(BY2PG/BY2WD)		/* words per page */
#define	PGSHIFT		12			/* log(BY2PG) */
#define PGROUND(s)	(((s)+(BY2PG-1))&~(BY2PG-1))
#define ICACHESIZE	(64*1024)		/* Power series */

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



@@ 100,10 101,13 @@
#define PTERONLY	0
#define	PTEPID(n)	((n)<<6)
#define TLBPID(n)	(((n)>>6)&0x3F)

#define PTEMAPMEM	(1024*1024)	
#define	PTEPERTAB	(PTEMAPMEM/BY2PG)
#define STLBLOG		11
#define STLBSIZE	(1<<STLBLOG)

#define SEGMAPSIZE	64

#define	NTLBPID	64	/* number of pids */
#define	NTLB	64	/* number of entries */
#define	TLBROFF	8	/* offset of first randomly indexed entry */


@@ 115,7 119,7 @@
#define	UZERO		KUSEG			/* base of user address space */
#define	UTZERO		(UZERO+BY2PG)		/* first address in user text */
#define	USTKTOP		KZERO			/* byte just beyond user stack */
#define	TSTKTOP		(USERADDR+TSTKSIZ*BY2PG)/* top of temporary stack */
#define	TSTKTOP		(USERADDR+USTKSIZE)	/* top of temporary stack */
#define TSTKSIZ 	100
#define	KZERO		KSEG0			/* base of kernel address space */
#define	KTZERO		(KZERO+0x20000)		/* first address in kernel text */

M power/mmu.c => power/mmu.c +16 -1
@@ 13,6 13,12 @@ mapstack(Proc *p)
	short tp;
	ulong tlbvirt, tlbphys;

	if(p->newtlb) {
		/* see flushmmu. */
		memset(p->pidonmach, 0, sizeof p->pidonmach);
		p->newtlb = 0;
	}

	tp = p->pidonmach[m->machno];
	if(tp == 0)
		tp = newtlbpid(p);


@@ 70,12 76,21 @@ newtlbpid(Proc *p)
}

void
putmmu(ulong tlbvirt, ulong tlbphys)
putmmu(ulong tlbvirt, ulong tlbphys, Page *pg)
{
	short tp;
	Proc *p;
	char *ctl;

	splhi();

	ctl = &pg->cachectl[m->machno]; 
	if(*ctl == PG_TXTFLUSH) {
		dcflush((void*)pg->pa, BY2PG);
		icflush((void*)pg->pa, BY2PG);
		*ctl = PG_NOFLUSH;
	}

	p = u->p;
/*	if(p->state != Running)
		panic("putmmu state %lux %lux %s\n", u, p, statename[p->state]);

A power/segment.h => power/segment.h +20 -0
@@ 0,0 1,20 @@
/*
 * Attach segment types
 */

typedef struct Physseg Physseg;
struct Physseg
{
	ulong	attr;			/* Segment attributes */
	char	*name;			/* Attach name */
	ulong	pa;			/* Physical address */
	ulong	size;			/* Maximum segment size in pages */
	Page	*(*pgalloc)(ulong);	/* Allocation if we need it */
	void	(*pgfree)(Page*);
}physseg[] = {
	{ SG_SHARED,	"lock",		0,	1024*BY2PG,	&lkpage,	&lkpgfree },
	{ SG_SHARED,	"shared",	0,	SEGMAXSIZE,	&snewpage, 	&putpage },
	{ SG_PHYSICAL,	"kmem",		KZERO,	SEGMAXSIZE,	0,		0 	},
	{ SG_BSS,	"memory",	0,	SEGMAXSIZE,	&snewpage,	&putpage },
	{ 0,		0,		0,	0,		0,		0 	},
};

M power/trap.c => power/trap.c +36 -8
@@ 84,6 84,7 @@ trap(Ureg *ur)
	user = ur->status&KUP;
	if(u)
		u->p->pc = ur->pc;		/* BUG */

	switch(ecode){
	case CINT:
		if(u && u->p->state==Running){


@@ 142,15 143,15 @@ trap(Ureg *ur)
		}
	Default:
		/*
		 * This isn't good enough; can still deadlock because we may hold print's locks
		 * in this processor.
		 * This isn't good enough; can still deadlock because we may 
		 * hold print's locks in this processor.
		 */
		if(user){
			spllo();
			if(ecode == FPEXC)
				sprint(buf, "sys: fp: %s FCR31 %lux", fpexcname(x), x);
			else
				sprint(buf, "sys: trap: %s[%d]", excname[ecode], m->machno);
				sprint(buf, "sys: %s pc=0x%lux", excname[ecode], ur->pc);

			postnote(u->p, 1, buf, NDebug);
		}else{


@@ 163,8 164,14 @@ trap(Ureg *ur)
			exit();
		}
	}
	if(user && u->nnote)
		notify(ur);

	if(user) {
		if(u->p->procctl)
			procctl(u->p);
		if(u->nnote)
			notify(ur);
	}

	splhi();
	if(user && u && u->p->fpstate == FPinactive) {
		restfpregs(&u->fpsave, u->fpsave.fpstatus);


@@ 383,6 390,13 @@ notify(Ureg *ur)
		u->svstatus = ur->status;
		sp = ur->usp;
		sp -= sizeof(Ureg);
		if(waserror()){
			pprint("suicide: trap in notify\n");
			pexit("Suicide", 0);
		}
		validaddr((ulong)u->notify, 1, 0);
		validaddr(sp-ERRLEN-3*BY2WD, sizeof(Ureg)+ERRLEN-3*BY2WD, 0);
		poperror();
		u->ureg = (void*)sp;
		memmove((Ureg*)sp, ur, sizeof(Ureg));
		sp -= ERRLEN;


@@ 442,8 456,9 @@ Syscall sysbind, sysbrk_, syschdir, sysclose, syscreate, sysdeath;
Syscall	sysdup, syserrstr, sysexec, sysexits, sysfork, sysforkpgrp;
Syscall	sysfstat, sysfwstat, sysgetpid, sysmount, sysnoted;
Syscall	sysnotify, sysopen, syspipe, sysr1, sysread, sysremove, sysseek;
Syscall syssleep, sysstat, syswait, syswrite, syswstat, sysalarm, syslkbrk_;
#define LKBRK_ 12
Syscall syssleep, sysstat, syswait, syswrite, syswstat, sysalarm, syssegbrk;
Syscall syssegattach, syssegdetach, syssegfree, syssegflush;

Syscall *systab[]={
	[SYSR1]		sysr1,
	[ERRSTR]	syserrstr,


@@ 457,7 472,7 @@ Syscall *systab[]={
	[FORK]		sysfork,
	[FORKPGRP]	sysforkpgrp,
	[FSTAT]		sysfstat,
	[LKBRK_]	syslkbrk_,
	[SEGBRK]	syssegbrk,
	[MOUNT]		sysmount,
	[OPEN]		sysopen,
	[READ]		sysread,


@@ 475,6 490,10 @@ Syscall *systab[]={
	[FWSTAT]	sysfwstat,
	[NOTIFY]	sysnotify,
	[NOTED]		sysnoted,
	[SEGATTACH]	syssegattach,
	[SEGDETACH]	syssegdetach,
	[SEGFREE]	syssegfree,
	[SEGFLUSH]	syssegflush,
};

long


@@ 502,6 521,10 @@ syscall(Ureg *aur)
		ur->status &= ~CU1;
	}
	spllo();

	if(u->p->procctl)
		procctl(u->p);

	r1 = ur->r1;
	sp = ur->sp;
	u->nerrlab = 0;


@@ 527,6 550,10 @@ syscall(Ureg *aur)
	}
	ur->pc += 4;
	u->nerrlab = 0;
	
	if(u->p->procctl)
		procctl(u->p);

	splhi();
	u->p->insyscall = 0;
	if(r1 == NOTED)	/* ugly hack */


@@ 535,6 562,7 @@ syscall(Ureg *aur)
		ur->r1 = ret;
		notify(ur);
	}

	return ret;
}