~kris/9p

9hist

a44fe20674d40b698ece9de0cc52a77328c7bcd0 — David du Colombier 35 years ago e1f1edb
Plan 9 from Bell Labs 1990-12-12
M gnot/dat.h => gnot/dat.h +3 -1
@@ 153,6 153,7 @@ struct Conf
	int	nservice;	/* number of services */
	int	nfsyschan;	/* number of filsys open channels */
	ulong	maxialloc;	/* maximum bytes used by ialloc */
	int	copymode;	/* 0 is copy on write, 1 is copy on reference */
};

struct Dev


@@ 448,7 449,8 @@ struct Queue {
	Queue	*next;		/* next queue in the stream */
	void	(*put)(Queue*, Block*);
	QLock	rlock;		/* mutex for processes sleeping at r */
	Rendez	r;
	Rendez	r;		/* standard place to wait for flow control */
	Rendez	*rp;		/* where flow control wakeups go to */
	void	*ptr;		/* private info for the queue */
};
#define QHUNGUP	0x1	/* flag bit meaning the stream has been hung up */

M gnot/devcons.c => gnot/devcons.c +3 -0
@@ 311,6 311,9 @@ echo(int c)
		case 'm':
			mntdump();
			return;
		case 'i':
			incontoggle();
			return;
		}
	}else if(c == 0x14){
		ctrlt++;

M gnot/devincon.c => gnot/devincon.c +11 -0
@@ 600,9 600,20 @@ inconoput(Queue *q, Block *bp)
		if(size >= 16){
			dev->cdata = 0;
			MICROSECOND;
			for(end = NOW+1000; dev->status & TX_FULL;){
				nop();	/* make sure we don't optimize too much */
				if(NOW > end){
					print("incon output stuck\n");
					freemsg(q, bp);
					qunlock(&ip->xmit);
					return;
				}
			}
			dev->cdata = chan;
			MICROSECOND;
		}
		if(dev->status & TX_FULL)
			print("inconfull\n");
		dev->cdata = ctl;
	}
	MICROSECOND;

D gnot/fault.c => gnot/fault.c +0 -347
@@ 1,347 0,0 @@
#include	"u.h"
#include	"lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"ureg.h"
#include	"errno.h"

#define	FORMAT(ur)	((((ur)->vo)>>12)&0xF)
#define	OFFSET(ur)	(((ur)->vo)&0xFFF)


struct FFrame
{
	ushort	ireg0;			/* internal register */
	ushort	ssw;			/* special status word */
	ushort	ipsc;			/* instr. pipe stage c */
	ushort	ipsb;			/* instr. pipe stage b */
	ulong	addr;			/* data cycle fault address */
	ushort	ireg1;			/* internal register */
	ushort	ireg2;			/* internal register */
	ulong	dob;			/* data output buffer */
	ushort	ireg3[4];		/* more stuff */
	ulong	baddr;			/* stage b address */
	ushort	ireg4[26];		/* more more stuff */
};

/*
 * SSW bits
 */
#define	RW	0x0040		/* read/write for data cycle */
#define	FC	0x8000		/* fault on stage C of instruction pipe */
#define	FB	0x4000		/* fault on stage B of instruction pipe */
#define	RC	0x2000		/* rerun flag for stage C of instruction pipe */
#define	RB	0x1000		/* rerun flag for stage B of instruction pipe */
#define	DF	0x0100		/* fault/rerun flag for data cycle */
#define	RM	0x0080		/* read-modify-write on data cycle */
#define	READ	0x0040
#define	WRITE	0x0000
#define	SIZ	0x0030		/* size code for data cycle */
#define	FC2	0x0004		/* address space for data cycle */
#define	FC1	0x0002
#define	FC0	0x0001

void
fault(Ureg *ur, FFrame *f)
{
	ulong addr, mmuvirt, mmuphys, n, badvaddr;
	Seg *s;
	PTE *opte, *pte, *npte;
	Orig *o;
	char *l;
	Page *pg;
	KMap *k, *k1;
	int zeroed = 0, head = 1;
	int i, user, read, insyscall;

	if(u == 0){
		dumpregs(ur);
		panic("fault u==0 pc=%lux", ur->pc);
	}
	insyscall = u->p->insyscall;
	u->p->insyscall = 1;
	addr = 0;	/* set */
	if(f->ssw & DF)
		addr = f->addr;
	else if(FORMAT(ur) == 0xA){
		if(f->ssw & FC)
			addr = ur->pc+2;
		else if(f->ssw & FB)
			addr = ur->pc+4;
		else
			panic("prefetch pagefault");
	}else if(FORMAT(ur) == 0xB){
		if(f->ssw & FC)
			addr = f->baddr-2;
		else if(f->ssw & FB)
			addr = f->baddr;
		else
			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); /**/

	s = seg(u->p, addr);
	if(s == 0){
		if(addr>USTKTOP){
	    cant:
			if(user){
				pprint("user %s error addr=0x%lux\n", read? "read" : "write", badvaddr);
				pprint("status=0x%lux pc=0x%lux sp=0x%lux\n", ur->sr, ur->pc, ur->sp);
				pexit("Suicide", 0);
			}
			u->p->state = MMUing;
			dumpregs(ur);
			panic("fault: 0x%lux", badvaddr);
			exit();
		}
		s = &u->p->seg[SSEG];
		if(s->o==0 || addr<s->maxva-USTACKSIZE || addr>=s->maxva)
			goto cant;
		/* grow stack */
		o = s->o;
		n = o->npte;
		if(waserror()){
			pprint("can't allocate stack page\n");
			goto cant;
		}
		growpte(o, (s->maxva-addr)>>PGSHIFT);
		poperror();
		/* stacks grown down, sigh */
		lock(o);
		memcpy(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)
		goto cant;
	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){
		if(o->chan==0 || addr>(o->va+(o->maxca-o->minca))){
			/*
			 * Zero fill page.  If we are really doing a copy-on-write
			 * (e.g. into shared bss) we'll move the page later.
			 */
			pte->page = newpage(0, o, addr);
			o->npage++;
			zeroed = 1;
		}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);
			if(waserror()){
				kunmap(k);
				qunlock(o->chan);
				pg->o = 0;
				pg->ref--;
				pexit("load i/o error", 0);
			}
			o->chan->offset = (addr-o->va) + o->minca;
			l = (char*)VA(k);
			if((*devtab[o->chan->type].read)(o->chan, l, n) != n)
				error(Eioload);
			qunlock(o->chan);
			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--;
			}
		}
	}
	/*
	 * Copy on write
	 */
	if((o->flag & OWRPERM) && !read
	&& ((head && ((o->flag&OPURE) || o->nproc>1))
	    || (!head && pte->page->ref>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;
		}
		if(head){
			/*
			 * Add to mod list
			 */
			pte = newmod();
			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;
		}
		pg = pte->page;
		if(zeroed){	/* move page */
			pg->ref--;
			o->npage--;
			opte->page = 0;
		}else{		/* copy page */
			pte->page = newpage(1, o, addr);
			k = kmap(pte->page);
			k1 = kmap(pg);
			memcpy((void*)VA(k), (void*)VA(k1), BY2PG);
			kunmap(k);
			kunmap(k1);
			if(pg->ref <= 1)
				panic("pg->ref <= 1");
			pg->ref--;
		}
    easy:
		mmuphys = 0;
	}else{
		mmuphys = PTERONLY;
		if(o->flag & OWRPERM)
			if(o->flag & OPURE){
				if(!head && pte->page->ref==1)
					mmuphys = 0;
			}else
				if((head && o->nproc==1)
	  			  || (!head && pte->page->ref==1))
					mmuphys = 0;
	}
	mmuvirt = addr;
	mmuphys |= PPN(pte->page->pa) | PTEVALID;
	usepage(pte->page, 1);
	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);
	}
	unlock(o);
	putmmu(mmuvirt, mmuphys);
	u->p->insyscall = insyscall;
}

/*
 * Called only in a system call
 */
void
validaddr(ulong addr, ulong len, int write)
{
	Seg *s, *ns;

	if((long)len < 0){
    Err:
		pprint("invalid address in sys call pc %lux sp %lux\n", ((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-USTACKSIZE || 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;
	}
}
/*
 * &s[0] is known to be a valid address.
 */
void*
vmemchr(void *s, int c, int n)
{
	int m;
	char *t;
	ulong a;

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

Seg*
seg(Proc *p, ulong addr)
{
	int i;
	Seg *s;

	for(i=0,s=p->seg; i<NSEG; i++,s++)
		if(s->o && s->minva<=addr && addr<s->maxva)
			return s;
	return 0;
}

A gnot/fault68020.c => gnot/fault68020.c +105 -0
@@ 0,0 1,105 @@
#include	"u.h"
#include	"lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"ureg.h"
#include	"errno.h"

#define	FORMAT(ur)	((((ur)->vo)>>12)&0xF)
#define	OFFSET(ur)	(((ur)->vo)&0xFFF)


struct FFrame
{
	ushort	ireg0;			/* internal register */
	ushort	ssw;			/* special status word */
	ushort	ipsc;			/* instr. pipe stage c */
	ushort	ipsb;			/* instr. pipe stage b */
	ulong	addr;			/* data cycle fault address */
	ushort	ireg1;			/* internal register */
	ushort	ireg2;			/* internal register */
	ulong	dob;			/* data output buffer */
	ushort	ireg3[4];		/* more stuff */
	ulong	baddr;			/* stage b address */
	ushort	ireg4[26];		/* more more stuff */
};

/*
 * SSW bits
 */
#define	RW	0x0040		/* read/write for data cycle */
#define	FC	0x8000		/* fault on stage C of instruction pipe */
#define	FB	0x4000		/* fault on stage B of instruction pipe */
#define	RC	0x2000		/* rerun flag for stage C of instruction pipe */
#define	RB	0x1000		/* rerun flag for stage B of instruction pipe */
#define	DF	0x0100		/* fault/rerun flag for data cycle */
#define	RM	0x0080		/* read-modify-write on data cycle */
#define	READ	0x0040
#define	WRITE	0x0000
#define	SIZ	0x0030		/* size code for data cycle */
#define	FC2	0x0004		/* address space for data cycle */
#define	FC1	0x0002
#define	FC0	0x0001

void
fault68020(Ureg *ur, FFrame *f)
{
	ulong addr, mmuvirt, mmuphys, n, badvaddr;
	Seg *s;
	PTE *opte, *pte, *npte;
	Orig *o;
	char *l;
	Page *pg;
	KMap *k, *k1;
	int zeroed = 0, head = 1;
	int i, user, read, insyscall;

	if(u == 0){
		dumpregs(ur);
		panic("fault u==0 pc=%lux", ur->pc);
	}
	insyscall = u->p->insyscall;
	u->p->insyscall = 1;
	addr = 0;	/* set */
	if(f->ssw & DF)
		addr = f->addr;
	else if(FORMAT(ur) == 0xA){
		if(f->ssw & FC)
			addr = ur->pc+2;
		else if(f->ssw & FB)
			addr = ur->pc+4;
		else
			panic("prefetch pagefault");
	}else if(FORMAT(ur) == 0xB){
		if(f->ssw & FC)
			addr = f->baddr-2;
		else if(f->ssw & FB)
			addr = f->baddr;
		else
			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){
		if(user){
			pprint("user %s error addr=0x%lux\n", read? "read" : "write", badvaddr);
			pprint("status=0x%lux pc=0x%lux sp=0x%lux\n", ur->sr, ur->pc, ur->sp);
			pexit("Suicide", 0);
		}
		u->p->state = MMUing;
		dumpregs(ur);
		panic("fault: 0x%lux", badvaddr);
		exit();
	}
	u->p->insyscall = insyscall;
}

M gnot/fns.h => gnot/fns.h +8 -6
@@ 49,7 49,8 @@ void	envpgclose(Env *);
void	error(int);
void	errors(char*);
void	exit(void);
void	fault(Ureg*, FFrame*);
int	fault(ulong, int);
void	fault68020(Ureg*, FFrame*);
void	fdclose(int);
Chan	*fdtochan(int, int);
void	filsys(Chan*, char*, long);


@@ 65,8 66,9 @@ void	fpregsave(char*);
void	fprestore(FPsave*);
void	fpregrestore(char*);
void	freeb(Block*);
int	freebroken(void);
void	freenextmod(PTE*);
void	freepage(Orig*);
void	freepage(Orig*, int);
void	freepte(Orig*);
void	freesegs(int);
void	freealarm(Alarm*);


@@ 102,7 104,7 @@ Chan	*namec(char*, int, int, ulong);
void	nexterror(void);
Alarm	*newalarm(void);
Chan	*newchan(void);
PTE	*newmod(void);
PTE	*newmod(Orig *o);
Mount	*newmount(void);
Orig	*neworig(ulong, ulong, int, Chan*);
Page	*newpage(int, Orig*, ulong);


@@ 126,6 128,9 @@ int	pprint(char*, ...);
void	printinit(void);
void	printslave(void);
void	procinit0(void);
void	procrestore(Proc*, uchar*);
void	procsave(uchar*, int);
void	procsetup(Proc*);
Proc	*proctab(int);
Queue	*pushq(Stream*, Qinfo*);
void	putbq(Blist*, Block*);


@@ 144,8 149,6 @@ void	qlock(QLock*);
void	qunlock(QLock*);
void	restartprint(Alarm*);
void	restfpregs(FPsave*);
void	restore(Proc*, uchar*);
void	save(uchar*, int);
void	savefpregs(FPsave*);
void	sched(void);
void	schedinit(void);


@@ 157,7 160,6 @@ int	segaddr(Seg*, ulong, ulong);
void	serviceinit(void);
void	service(char*, Chan*, Chan*, void (*)(Chan*, char*, long));
int	setlabel(Label*);
void	setup(Proc*);
char	*skipslash(char*);
void	sleep(Rendez*, int(*)(void*), void*);
int	splhi(void);

M gnot/l.s => gnot/l.s +1 -1
@@ 200,7 200,7 @@ TEXT	buserror(SB), $0
	MOVL	A0, ((8+8)*BY2WD)(A7)
	PEA	((8+8+1+2)*BY2WD)(A7)
	PEA	4(A7)
	BSR	fault(SB)
	BSR	fault68020(SB)
	ADDL	$8, A7
	MOVL	((8+8)*BY2WD)(A7), A0
	MOVL	A0, USP

M gnot/main.c => gnot/main.c +6 -5
@@ 339,13 339,14 @@ confinit(void)
	conf.npipe = conf.nstream/2;
	conf.nservice = 3*mul;			/* was conf.nproc/5 */
	conf.nfsyschan = 31 + conf.nchan/20;
	conf.copymode = 0;		/* copy on write */
}

/*
 *  set up floating point for a new process
 */
void
setup(Proc *p)
procsetup(Proc *p)
{
	long fpnull;



@@ 361,7 362,7 @@ setup(Proc *p)
 * Save the part of the process state.
 */
void
save(uchar *state, int len)
procsave(uchar *state, int len)
{
	Balu *balu;



@@ 385,12 386,12 @@ save(uchar *state, int len)
}

/*
 *  Restore what save() saves
 *  Restore what procsave() saves
 *
 *  Save() makes sure that what state points to is long enough
 *  Procsave() makes sure that what state points to is long enough
 */
void
restore(Proc *p, uchar *state)
procrestore(Proc *p, uchar *state)
{
	Balu *balu;


M gnot/mem.h => gnot/mem.h +1 -0
@@ 68,6 68,7 @@
 * MMU entries
 */
#define	PTEVALID	(1<<13)
#define PTEWRITE	0
#define	PTERONLY	(1<<14)
#define	PTEKERNEL	(1<<15)
#define	INVALIDPTE	0

D gnot/page.c => gnot/page.c +0 -674
@@ 1,674 0,0 @@
#include	"u.h"
#include	"lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#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;

struct{
	Lock;
	PTEA	*free;
}modalloc;

/*
 * Called to allocate permanent data structures, before calling pageinit().
 */
void*
ialloc(ulong n, int align)
{
	ulong p;

	if(palloc.addr == 0)
		palloc.addr = ((ulong)&end)&~KZERO;
	if(n == 0)	/* done by kmapinit */
		return (void*)(palloc.addr|KZERO);
	if(palloc.active)
		print("ialloc bad\n");
	if(align){
		palloc.addr += BY2PG-1;
		palloc.addr &= ~(BY2PG-1);
	}
	memset((void*)(palloc.addr|KZERO), 0, n);
	p = palloc.addr;
	palloc.addr += n;
	if(align){
		palloc.addr += BY2PG-1;
		palloc.addr &= ~(BY2PG-1);
	}
	if(palloc.addr >= (4*1024*1024-256*1024-BY2PG))
		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;
}

void
pageinit(void)
{
	ulong pa, nb, ppn;
	ulong i;
	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 */
	palloc.page = (Page *)((palloc.addr - ppn*sizeof(Page))|KZERO);
	/*
	 * Now palloc.page[ppn] describes first free page
	 */
	palloc.minppn = ppn;
	palloc.addr = ppn<<PGSHIFT;

	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);
	for(p=palloc.head; p<=palloc.tail; p++,ppn++){
		p->next = p+1;
		p->prev = p-1;
		if(ppn < conf.npage0)
			p->pa = conf.base0+(ppn<<PGSHIFT);
		else
			p->pa = conf.base1+((ppn-conf.npage0)<<PGSHIFT);
	}
	palloc.head->prev = 0;
	palloc.tail->next = 0;
}

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

	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);
				/* neworig will free the orig and pte's later */
				unlock(o1);
				if(p->ref == 0)
					goto out;
				print("newpage ref != 0");
			}
		}
#endif
	}
	print("no physical memory\n");
	unlock(&palloc);
	if(u == 0)
		panic("newpage");
	u->p->state = Wakeme;
	alarm(1000, wakeme, u->p);
	sched();
	goto loop;
    out:
	if(p->o){
		print("page in use %lux %lux %lux\n", 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){
		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)
{
	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);
}

/*
 * Move page to tail of list
 */
void
unusepage(Page *p, int dolock)
{
}

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 && eqqid(o->qid, c->qid) && 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 && eqqid(o->mqid, c->mqid) && o->type==c->type){
				if(o->chan == 0){
					o->chan = c;
					incref(c);
				}
				o->nproc++;
				unlock(o);
				return o;
			}
			unlock(o);
		}
	return 0;
}

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

	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;
		if(c){
			o->type = c->type;
			o->qid = c->qid;
			o->mchan = c->mchan;
			o->mqid = c->mqid;
			incref(c);
		}else{
			o->type = ~0;
			o->qid.path = -1;
			o->qid.vers = 0;
			o->mqid.path = -1;
			o->mqid.vers = 0;
			o->mchan = 0;
		}
		if(u && u->p && waserror()){
			unlock(&origalloc);
			nexterror();
		}
		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;
			}
			freepage(o);
			freepte(o);
			unlock(o);
			o->next = origalloc.free;
			origalloc.free = o;
			freed++;
		}
	}
	if(freed)
		goto loop;
	print("no origs freed\n");
	unlock(&origalloc);
	if(u == 0)
		panic("neworig");
	u->p->state = Wakeme;
	alarm(1000, wakeme, u->p);
	sched();
	lock(&origalloc);
	goto loop;
}

PTE*
newmod(void)
{
	PTEA *pte;

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

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

	o = old->o;
	ppte = 0;
	pte = old->mod;
	while(pte){
if(pte->page==0) panic("forkmod zero page");
if(pte->proc != u->p) panic("forkmod wrong page");
		npte = newmod();
		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;
	}
}

void
freesegs(int save)
{
	int i, j;
	Seg *s;
	Orig *o;
	PTE *pte, *opte;
	PTEA *old;
	Page *pg;
	Chan *c;

	s = u->p->seg;
	for(i=0; i<NSEG; i++,s++){
		if(i == save)
			continue;
		o = s->o;
		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);
				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);
		}
	}
}

/*
 * 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 = (max+(BY2PG-1)) & ~(BY2PG-1);
	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;
	}
	/*
	 * Shrink
	 */
	print("segaddr shrink");
	for(;;);
}

/*
 * o is locked
 */
void
freepage(Orig *o)
{
	PTE *pte;
	Page *pg;
	int i;

	pte = o->pte;
	for(i=0; i<o->npte; i++,pte++)
		if(pg = pte->page){	/* assign = */
			if(pg->ref == 1){
				pte->page = 0;
				pg->o = 0;
			}
			pg->ref--;
		}
	o->npage = 0;
}

/*
 * Compacting allocator
 */

void
freepte(Orig *o)	/* o is locked */
{
	PTEA *p;
	p = (PTEA*)(o->pte - 1);
	p->o = 0;
}

/*
 * 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)
{
	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;
			memcpy(p+1, o->pte, o->npte*sizeof(PTE));
			p->o = o;
			((PTEA*)(o->pte-1))->o = 0;
			o->pte = p+1;
		}
		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);
}

int
compactpte(Orig *o, ulong n)
{
	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;
			}
			memcpy(p1, p2, p2->n*sizeof(PTE));
			p2o->pte = p1+1;
			if(p2o != o)
				unlock(p2o);
		}
		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\n", o->va+n*BY2PG);
	return 0;
}

M port/fault.c => port/fault.c +25 -41
@@ 6,11 6,10 @@
#include	"ureg.h"
#include	"errno.h"

void
fault(Ureg *ur, int user, int code)
int
fault(ulong addr, int read)
{
	ulong addr, mmuvirt, mmuphys, n;
	extern char *excname[];
	ulong mmuvirt, mmuphys, n;
	Seg *s;
	PTE *opte, *pte, *npte;
	Orig *o;


@@ 18,34 17,21 @@ fault(Ureg *ur, int user, int code)
	Page *pg;
	int zeroed = 0, head = 1;
	int i;

	addr = ur->badvaddr;
	addr &= ~(BY2PG-1);
	KMap *k, *k1;

	s = seg(u->p, addr);
	if(s == 0){
		if(addr>USTKTOP){
	    cant:
			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);
			}
			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);
			u->p->state = MMUing;
			dumpregs(ur);
			panic("fault");
		}
		if(addr>USTKTOP)
			return -1;
		s = &u->p->seg[SSEG];
		if(s->o==0 || addr<s->maxva-USTACKSIZE || addr>=s->maxva)
			goto cant;
			return -1;
		/* grow stack */
		o = s->o;
		n = o->npte;
		if(waserror()){
			pprint("can't allocate stack page\n");
			goto cant;
			return -1;
		}
		growpte(o, (s->maxva-addr)>>PGSHIFT);
		poperror();


@@ 58,8 44,8 @@ fault(Ureg *ur, int user, int code)
		o->va = addr;
	}else
		o = s->o;
	if((code==CTLBM || code==CTLBS) && (o->flag&OWRPERM)==0)
		goto cant;
	if(!read && (o->flag&OWRPERM)==0)
		return -1;
	lock(o);
	opte = &o->pte[(addr-o->va)>>PGSHIFT];
	pte = opte;


@@ 92,23 78,25 @@ fault(Ureg *ur, int user, int code)
			if(n > BY2PG)
				n = BY2PG;
			pg = newpage(1, o, addr);
			k = kmap(pg);
			qlock(o->chan);
			if(waserror()){
				kunmap(k);
				qunlock(o->chan);
				pg->o = 0;
				pg->ref--;
				pexit("load i/o error", 0);
			}
			o->chan->offset = (addr-o->va) + o->minca;
			l = (char*)(pg->pa|KZERO);
			l = (char*)VA(k);
			if((*devtab[o->chan->type].read)(o->chan, l, n) != n)
				error(Eioload);
			qunlock(o->chan);
			poperror();
			/* BUG: if was first page of bss, move to data */
			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){


@@ 121,9 109,9 @@ fault(Ureg *ur, int user, int code)
		}
	}
	/*
	 * Copy on reference
	 * Copy on reference (conf.copymode==1) or write (conf.copymode==0)
	 */
	if((o->flag & OWRPERM)
	if((o->flag & OWRPERM) && (conf.copymode || !read)
	&& ((head && ((o->flag&OPURE) || o->nproc>1))
	    || (!head && pte->page->ref>1))){



@@ 173,7 161,11 @@ fault(Ureg *ur, int user, int code)
			opte->page = 0;
		}else{		/* copy page */
			pte->page = newpage(1, o, addr);
			memcpy((void*)(pte->page->pa|KZERO), (void*)(pg->pa|KZERO), BY2PG);
			k = kmap(pte->page);
			k1 = kmap(pg);
			memcpy((void*)VA(k), (void*)VA(k1), BY2PG);
			kunmap(k);
			kunmap(k1);
			if(pg->ref <= 1)
				panic("pg->ref <= 1");
			pg->ref--;


@@ 181,7 173,7 @@ fault(Ureg *ur, int user, int code)
    easy:
		mmuphys = PTEWRITE;
	}else{
		mmuphys = 0;
		mmuphys = PTERONLY;
		if(o->flag & OWRPERM)
			if(o->flag & OPURE){
				if(!head && pte->page->ref==1)


@@ 192,7 184,7 @@ fault(Ureg *ur, int user, int code)
					mmuphys = PTEWRITE;
	}
	mmuvirt = addr;
	mmuphys |= pte->page->pa | PTEVALID;
	mmuphys |= PPN(pte->page->pa) | PTEVALID;
	usepage(pte->page, 1);
	if(pte->page->va != addr)
		panic("wrong addr in tail %lux %lux", pte->page->va, addr);


@@ 203,6 195,7 @@ fault(Ureg *ur, int user, int code)
	}
	unlock(o);
	putmmu(mmuvirt, mmuphys);
	return 0;
}

/*


@@ 235,15 228,6 @@ validaddr(ulong addr, ulong len, int write)
	}
}

void
evenaddr(ulong addr)
{
	if(addr & 3){
		postnote(u->p, 1, "sys: odd address", NDebug);
		error(Ebadarg);
	}
}

/*
 * &s[0] is known to be a valid address.
 */

M port/page.c => port/page.c +6 -6
@@ 55,7 55,7 @@ ialloc(ulong n, int align)
{
	ulong p;

	if(palloc.active)
	if(palloc.active && n!=0)
		print("ialloc bad\n");
	if(palloc.addr == 0)
		palloc.addr = ((ulong)&end)&~KZERO;


@@ 185,7 185,7 @@ loop:
					continue;
				}
				print("free %d pages va %lux %lux %c\n", o1->npage, o->va, o1->qid, devchar[o1->type]);
				freepage(o1);
				freepage(o1, 0);
				/* neworig will free the orig and pte's later */
				unlock(o1);
				if(p->ref == 0)


@@ 367,7 367,7 @@ loop:
				unlock(o);
				continue;
			}
			freepage(o);
			freepage(o, 1);
			freepte(o);
			unlock(o);
			o->next = origalloc.free;


@@ 506,7 506,7 @@ freesegs(int save)
				close(c);
			}
			if(!(o->flag&OCACHED) || o->npage==0){
				freepage(o);
				freepage(o, 1);
				freepte(o);
				unlock(o);
				lock(&origalloc);


@@ 566,7 566,7 @@ segaddr(Seg *s, ulong min, ulong max)
 * o is locked
 */
void
freepage(Orig *o)
freepage(Orig *o, int dolock)
{
	PTE *pte;
	Page *pg;


@@ 576,7 576,7 @@ freepage(Orig *o)
	for(i=0; i<o->npte; i++,pte++)
		if(pg = pte->page){	/* assign = */
			if(pg->ref == 1){
				unusepage(pg, 1);
				unusepage(pg, dolock);
				pte->page = 0;
				pg->o = 0;
			}

M port/proc.c => port/proc.c +4 -3
@@ 59,7 59,6 @@ schedinit(void)		/* never returns */
		else if(p->state == Moribund){
			p->pid = 0;
			unlock(&p->debug);
			unusepage(p->upage, 1);
			p->upage->ref--;
			/* procalloc already locked */
			p->qnext = procalloc.free;


@@ 83,13 82,13 @@ sched(void)

	if(u){
		splhi();
		save(procstate, sizeof(procstate));
		procsave(procstate, sizeof(procstate));
		if(setlabel(&u->p->sched)){	/* woke up */
			p = u->p;
			p->state = Running;
			p->mach = m;
			m->proc = p;
			restore(p, procstate);
			procrestore(p, procstate);
			spllo();
			return;
		}


@@ 481,6 480,7 @@ pexit(char *s, int freemem)

	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) */
	c->state = Moribund;
	sched();	/* never returns */
}


@@ 567,6 567,7 @@ kproc(char *name, void (*func)(void *), void *arg)
	 * Kernel stack
	 */
	p = newproc();
	p->kp = 1;
	p->upage = newpage(1, 0, USERADDR|(p->pid&0xFFFF));
	k = kmap(p->upage);
	upa = VA(k);

M port/stream.c => port/stream.c +9 -5
@@ 314,6 314,7 @@ allocq(Qinfo *qi)
	q->put = qi->iput;
	q->len = q->nb = 0;
	q->ptr = 0;
	q->rp = &q->r;
	wq = q->other = q + 1;

	wq->flag = QINUSE;


@@ 323,6 324,7 @@ allocq(Qinfo *qi)
	wq->other = q;
	wq->ptr = 0;
	wq->len = wq->nb = 0;
	wq->rp = &wq->r;

	unlock(q);



@@ 495,7 497,7 @@ getq(Queue *q)
		q->len -= BLEN(bp);
		q->nb--;
		if((q->flag&QHIWAT) && q->len<Streamhi/2 && q->nb<Streambhi/2){
			wakeup(&q->other->next->other->r);
			wakeup(q->other->next->other->rp);
			q->flag &= ~QHIWAT;
		}
		bp->next = 0;


@@ 928,7 930,7 @@ stputq(Queue *q, Block *bp)
		freeb(bp);
		q->flag |= QHUNGUP;
		q->other->flag |= QHUNGUP;
		wakeup(&q->other->r);
		wakeup(q->other->rp);
		delim = 1;
	} else {
		delim = 0;


@@ 954,7 956,7 @@ stputq(Queue *q, Block *bp)
		unlock(q);
	}
	if(delim)
		wakeup(&q->r);
		wakeup(q->rp);
}

/*


@@ 1048,7 1050,8 @@ streamread(Chan *c, void *vbuf, long n)
				else
					error(Ehungup);
			}
			sleep(&q->r, &isinput, (void *)q);
			q->rp = &q->r;
			sleep(q->rp, &isinput, (void *)q);
			continue;
		}



@@ 1167,7 1170,8 @@ flowctl(Queue *q)
		qunlock(&q->rlock);
		nexterror();
	}
	sleep(&q->r, notfull, q->next);
	q->rp = &q->r;
	sleep(q->rp, notfull, q->next);
	qunlock(&q->rlock);
	poperror();
}

M port/sturp.c => port/sturp.c +1 -0
@@ 169,6 169,7 @@ urpopen(Queue *q, Stream *s)
	}

	q->ptr = q->other->ptr = up;
	q->rp = &urpkr;
	up->rq = q;
	up->wq = q->other;
	up->state = OPEN;

M port/sysproc.c => port/sysproc.c +8 -13
@@ 205,10 205,7 @@ sysexec(ulong *arg)

    Binary:
	t = (UTZERO+sizeof(Exec)+exec.text+(BY2PG-1)) & ~(BY2PG-1);
	/*
	 * Last partial page of data goes into BSS.
	 */
	d = (t + exec.data) & ~(BY2PG-1);
	d = (t + exec.data + (BY2PG-1)) & ~(BY2PG-1);
	bssend = t + exec.data + exec.bss;
	b = (bssend + (BY2PG-1)) & ~(BY2PG-1);
	if((t|d|b) & KZERO)


@@ 311,7 308,7 @@ sysexec(ulong *arg)
	if(o == 0){
		o = neworig(t, (d-t)>>PGSHIFT, OWRPERM|OPURE|OCACHED, tc);
		o->minca = p->seg[TSEG].o->maxca;
		o->maxca = o->minca + (exec.data & ~(BY2PG-1));
		o->maxca = o->minca + exec.data;
	}
	s->o = o;
	s->minva = t;


@@ 319,15 316,13 @@ sysexec(ulong *arg)
	s->mod = 0;

	/*
	 * BSS.  Created afresh, starting with last page of data.
	 * BUG: should pick up the last page of data, which should be cached in the
	 * data segment.
	 * BSS.  Created afresh.
	 */
	s = &p->seg[BSEG];
	s->proc = p;
	o = neworig(d, (b-d)>>PGSHIFT, OWRPERM, tc);
	o->minca = p->seg[DSEG].o->maxca;
	o->maxca = o->minca + (exec.data & (BY2PG-1));
	o = neworig(d, (b-d)>>PGSHIFT, OWRPERM, 0);
	o->minca = 0;
	o->maxca = 0;
	s->o = o;
	s->minva = d;
	s->maxva = b;


@@ 353,7 348,7 @@ sysexec(ulong *arg)
	unlock(o);

	flushmmu();
 	clearmmucache();
	clearmmucache();
	((Ureg*)UREGADDR)->pc = exec.entry + ENTRYOFFSET;
	sp = (ulong*)(USTKTOP - ssize);
	*--sp = nargs;


@@ 362,7 357,7 @@ sysexec(ulong *arg)
	u->nnote = 0;
	u->notify = 0;
	u->notified = 0;
	setup(p);
	procsetup(p);
	unlock(&p->debug);
	return 0;
}

M power/conf.h => power/conf.h +1 -0
@@ 29,6 29,7 @@ Conftab conftab[] = {
	{"maxialloc", &conf.maxialloc },
	{"base0", &conf.base0 },
	{"base1", &conf.base1 },
	{"copymode", &conf.copymode },
	{ 0, 0 },
};


M power/dat.h => power/dat.h +5 -1
@@ 152,6 152,7 @@ struct Conf
	ulong	maxialloc;	/* maximum bytes used by ialloc */
	ulong	base0;		/* base of bank 0 */
	ulong	base1;		/* base of bank 1 */
	ulong	copymode;	/* 0 is copy on write, 1 is copy on reference */
};

struct Dev


@@ 336,6 337,7 @@ struct Proc
	Rendez	sleep;			/* place for tsleep and syssleep */
	int	wokeup;			/* whether sleep was interrupted */
	ulong	pc;			/* DEBUG only */
	int	kp;			/* true if kernel process */

};



@@ 378,6 380,7 @@ typedef void		KMap;
#define	VA(k)		((ulong)(k))
#define	kmap(p)		(KMap*)(p->pa|KZERO)
#define	kunmap(k)
#define PPN(x)		x

/*
 *  operations available to a queue


@@ 438,7 441,8 @@ struct Queue {
	Queue	*next;		/* next queue in the stream */
	void	(*put)(Queue*, Block*);
	QLock	rlock;		/* mutex for r */
	Rendez	r;
	Rendez	r;		/* standard place to wait for flow control */
	Rendez	*rp;		/* where flow control wakeups go to */
	void	*ptr;		/* private info for the queue */
};
#define QHUNGUP	0x1	/* flag bit meaning the stream has been hung up */

M power/devrtc.c => power/devrtc.c +4 -1
@@ 27,7 27,7 @@ struct Rtc
QLock rtclock;	/* mutex on clock operations */

static Dirtab rtcdir[]={
	"rtc",		{1},	0,	0600,
	"rtc",		{1, 0},	0,	0600,
};

static uchar pattern[] =


@@ 145,6 145,9 @@ rtcread(Chan *c, void *buf, long n)
	char atime[64];
	Rtc rtc;

	if(c->qid.path & CHDIR)
		return devdirread(c, buf, n, rtcdir, 1, devgen);

	nv = RTC;

	/*

A power/faultmips.c => power/faultmips.c +47 -0
@@ 0,0 1,47 @@
#include	"u.h"
#include	"lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"ureg.h"
#include	"errno.h"

/*
 *  find out fault address and type of access.
 *  Call common fault handler.
 */
void
faultmips(Ureg *ur, int user, int code)
{
	ulong addr;
	extern char *excname[];
	int read;

	addr = ur->badvaddr;
	addr &= ~(BY2PG-1);
	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);
		}
		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);
		u->p->state = MMUing;
		dumpregs(ur);
		panic("fault");
	}
}

/*
 * called in sysfile.c
 */
void
evenaddr(ulong addr)
{
	if(addr & 3){
		postnote(u->p, 1, "sys: odd address", NDebug);
		error(Ebadarg);
	}
}

M power/fns.h => power/fns.h +10 -5
@@ 57,7 57,8 @@ void	error(int);
void	errors(char*);
void	evenaddr(ulong);
void	exit(void);
void	fault(Ureg*, int, int);
int	fault(ulong, int);
void	faultmips(Ureg*, int, int);
void	fdclose(int);
Chan*	fdtochan(int, int);
void	firmware(void);


@@ 66,7 67,7 @@ void	flushmmu(void);
void	forkmod(Seg*, Seg*, Proc*);
void	freeb(Block*);
int	freebroken(void);
void	freepage(Orig*);
void	freepage(Orig*, int);
void	freepte(Orig*);
void	freesegs(int);
void	freealarm(Alarm*);


@@ 155,11 156,9 @@ int	readnum(ulong, char*, ulong, ulong, int);
void	ready(Proc*);
void	qlock(QLock*);
void	qunlock(QLock*);
void	restore(Proc*, uchar*);
void	restfpregs(FPsave*);
int	return0(void*);
Proc	*runproc(void);
void	save(uchar*, int);
void	savefpregs(FPsave*);
void	sched(void);
void	schedinit(void);


@@ 167,7 166,6 @@ long	seconds(void);
Seg	*seg(Proc*, ulong);
int	segaddr(Seg*, ulong, ulong);
int	setlabel(Label*);
void	setup(Proc*);
void	setvmevec(int, void (*)(int));
void	sinit(void);
char*	skipslash(char*);


@@ 212,3 210,10 @@ void	wbflush(void);

#define	waserror()	setlabel(&u->errlab[u->nerrlab++])
#define	poperror()	u->nerrlab--

/*
 *  no external state to save on the SGI
 */
#define procsetup(x)
#define procsave(x,y)
#define procrestore(x,y)

M power/main.c => power/main.c +1 -24
@@ 631,6 631,7 @@ confinit(void)

	if(conf.nmach > MAXMACH)
		panic("confinit");
	conf.copymode = 1;		/* copy on reference */

}



@@ 695,27 696,3 @@ arginit(void)
	_argv = argv;
	argsize = ssize;
}

/*
 *  set up machine dependent process state for a new process
 */
void
setup(Proc *p)
{
}

/*
 *  Save machine dependent process state
 */
void
save(uchar *state, int len)
{
}

/*
 *  Restore what save() saves
 */
void
restore(Proc *p, uchar *state)
{
}

M power/mem.h => power/mem.h +1 -0
@@ 94,6 94,7 @@
#define	PTEGLOBL	(1<<8)
#define	PTEVALID	(1<<9)
#define	PTEWRITE	(1<<10)
#define PTERONLY	0
#define	PTEPID(n)	((n)<<6)

#define	NTLBPID	64	/* number of pids */

M power/trap.c => power/trap.c +1 -1
@@ 122,7 122,7 @@ trap(Ureg *ur)
		spllo();
		x = u->p->insyscall;
		u->p->insyscall = 1;
		fault(ur, user, ecode);
		faultmips(ur, user, ecode);
		u->p->insyscall = x;
		break;