~kris/9p

9hist

e1f1edbeee60812fff3666210c00973f66dfa30d — David du Colombier 35 years ago f32a6c1
Plan 9 from Bell Labs 1990-12-11
18 files changed, 323 insertions(+), 1444 deletions(-)

M gnot/clock.c
M gnot/dat.h
M gnot/fns.h
M gnot/main.c
M gnot/mmu.c
M gnot/page.c
D gnot/proc.c
D gnot/sysproc.c
A port/alarm.c
M port/page.c
M port/proc.c
M port/sysproc.c
M power/clock.c
M power/conf.h
M power/dat.h
M power/fns.h
M power/main.c
M power/mmu.c
M gnot/clock.c => gnot/clock.c +1 -96
@@ 7,75 7,6 @@

#include	"ureg.h"

Alarm	*alarmtab;

Alarm*
alarm(int ms, void (*f)(Alarm*), void *arg)
{
	Alarm *a, *w, *pw;
	ulong s;
	a = newalarm();
	a->dt = MS2TK(ms);
	if(a->dt < 0)
		a->dt = 0;
	a->f = f;
	a->arg = arg;
	s = splhi();
	lock(&m->alarmlock);
	pw = 0;
	for(w=m->alarm; w; pw=w, w=w->next){
		if(w->dt <= a->dt){
			a->dt -= w->dt;
			continue;
		}
		w->dt -= a->dt;
		break;
	}
	insert(&m->alarm, pw, a);
	unlock(&m->alarmlock);
	splx(s);
	return a;
}

void
cancel(Alarm *a)
{
	a->f = 0;
}

Alarm*
newalarm(void)
{
	int i;
	Alarm *a;

	for(i=0,a=alarmtab; i<conf.nalarm; i++,a++)
		if(a->busy==0 && a->f==0 && canlock(a)){
			if(a->busy){
				unlock(a);
				continue;
			}
			a->f = 0;
			a->arg = 0;
			a->busy = 1;
			unlock(a);
			return a;
		}
	panic("newalarm");
}

void
alarminit(void)
{
	int i;

	alarmtab = ialloc(conf.nalarm*sizeof(Alarm), 0);
	for(i=0; i<conf.nalarm; i++){
		lock(&alarmtab[i]);	/* allocate locks, as they are used at interrupt time */
		unlock(&alarmtab[i]);
	}
}

void
delay(int ms)
{


@@ 87,15 18,10 @@ delay(int ms)
		;
}

#define NA 10
void
clock(Ureg *ur)
{
	int i, n;
	Alarm *a;
	void (*f)(void*);
	Proc *p;
	Alarm *alist[NA];

	SYNCREG[1] = 0x5F;	/* clear interrupt */
	m->ticks++;


@@ 105,28 31,7 @@ clock(Ureg *ur)
		if (p->state==Running)
			p->time[p->insyscall]++;
	}
	if(canlock(&m->alarmlock)){
		a = m->alarm;
		if(a){
			for(n=0; a && a->dt<=0 && n<NA; n++){
				alist[n] = a;
				delete(&m->alarm, 0, a);
				a = m->alarm;
			}
			if(a)
				a->dt--;
			unlock(&m->alarmlock);

			/*  execute alarm functions outside the lock */
			for(i = 0; i < n; i++){
				f = alist[i]->f;	/* avoid race with cancel */
				if(f)
					(*f)(alist[i]);
				alist[i]->busy = 0;
			}
		} else
			unlock(&m->alarmlock);
	}
	checkalarms();
	kbdclock();
	mouseclock();
	if((ur->sr&SPL(7)) == 0 && p && p->state==Running){

M gnot/dat.h => gnot/dat.h +11 -0
@@ 152,6 152,7 @@ struct Conf
	int	npipe;		/* number of pipes */
	int	nservice;	/* number of services */
	int	nfsyschan;	/* number of filsys open channels */
	ulong	maxialloc;	/* maximum bytes used by ialloc */
};

struct Dev


@@ 214,6 215,9 @@ struct Mach
	Lock	alarmlock;		/* access to alarm list */
	void	*alarm;			/* alarms bound to this clock */
	int	fpstate;		/* state of fp registers on machine */
	void	(*intr)(ulong, ulong);	/* !!Compatability with mips!! */
	ulong	cause;			/*	... */
	ulong	pc;			/*	... */
	int	stack[1];
};



@@ 342,6 346,7 @@ struct Proc
	int	wokeup;			/* whether sleep was interrupted */
	ulong	pc;			/* DEBUG only */
	int	kp;			/* true if a kernel process */
	int	pidonmach[1];		/* !!Compatability with mips!! */
};

struct MMU


@@ 598,3 603,9 @@ extern	char	user[NAMELEN];
extern	char	*errstrtab[];

extern  void	(*kprofp)(ulong);

/*
 *  parameters for sysproc.c
 */
#define AOUT_MAGIC	A_MAGIC
#define ENTRYOFFSET	0

M gnot/fns.h => gnot/fns.h +8 -3
@@ 8,7 8,7 @@ int	canqlock(QLock*);
void	chaninit(void);
void	chandevreset(void);
void	chandevinit(void);
void	checksched(void);
void	checkalarms(void);
void	clearmmucache(void);
void	clock(Ureg*);
Chan	*clone(Chan*, Chan*);


@@ 79,6 79,7 @@ void	growpte(Orig*, ulong);
void	*ialloc(ulong, int);
int	incref(Ref*);
void	insert(List**, List*, List*);
void	invalidateu(void);
void	isdir(Chan*);
void	kbdchar(int);
void	kbdrepeat(int);


@@ 86,7 87,7 @@ void	kbdclock(void);
void	kmapinit(void);
KMap	*kmap(Page*);
int	kprint(char*, ...);
void	*kproc(char*, void(*)(void*), void*);
void	kproc(char*, void(*)(void*), void*);
void	kunmap(KMap*);
void	lock(Lock*);
void	lockinit(void);


@@ 138,11 139,13 @@ int	readnum(ulong, char*, ulong, ulong, int);
void	ready(Proc*);
int	return0(void*);
void	rs232ichar(int);
Proc	*runproc(void);
void	qlock(QLock*);
void	qunlock(QLock*);
void	restartprint(Alarm*);
void	restfpregs(FPsave*);
void	restore(void);
void	restore(Proc*, uchar*);
void	save(uchar*, int);
void	savefpregs(FPsave*);
void	sched(void);
void	schedinit(void);


@@ 154,6 157,7 @@ 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);


@@ 181,6 185,7 @@ void	twakeme(Alarm*);
long	unionread(Chan*, void*, long);
void	unlock(Lock*);
void	usepage(Page*, int);
void	unusepage(Page*, int);
void	userinit(void);
void	validaddr(ulong, ulong, int);
void	*vmemchr(void*, int, int);

M gnot/main.c => gnot/main.c +80 -2
@@ 7,6 7,9 @@
#include	"ureg.h"
#include	"init.h"

#include	<libg.h>
#include	<gnot.h>

typedef struct Boot Boot;

struct Boot


@@ 103,7 106,12 @@ init0(void)
{
	Chan *c;

	restore();
	u->nerrlab = 0;
	m->proc = u->p;
	u->p->state = Running;
	u->p->mach = m;
	spllo();

	chandevinit();
	
	u->slash = (*devtab[0].attach)(0);


@@ 137,6 145,7 @@ userinit(void)
	p->pgrp = newpgrp();
	strcpy(p->text, "*init*");
	strcpy(p->pgrp->user, user);
	p->fpstate = FPinit;

	/*
	 * Kernel Stack


@@ 177,7 186,6 @@ userinit(void)
	s->minva = UTZERO;
	s->maxva = UTZERO+BY2PG;

	m->proc = p;
	ready(p);
}



@@ 300,6 308,7 @@ confinit(void)
	conf.npage1 = (bank[1]*1024*1024)/BY2PG;
	conf.base1 = 16*1024*1024;
	conf.npage = conf.npage0+conf.npage1;
	conf.maxialloc = (4*1024*1024-256*1024-BY2PG);
	mul = 1 + (conf.npage1>0);
	conf.nproc = 50*mul;
	conf.npgrp = 12*mul;


@@ 331,3 340,72 @@ confinit(void)
	conf.nservice = 3*mul;			/* was conf.nproc/5 */
	conf.nfsyschan = 31 + conf.nchan/20;
}

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

	fpnull = 0;
	splhi();
	m->fpstate = FPinit;
	p->fpstate = FPinit;
	fprestore((FPsave*)&fpnull);
	spllo();
}

/*
 * Save the part of the process state.
 */
void
save(uchar *state, int len)
{
	Balu *balu;

	if(len < sizeof(Balu))
		panic("save state too small");
	balu = (Balu *)state;
	fpsave(&u->fpsave);
	if(u->fpsave.type){
		if(u->fpsave.size > sizeof u->fpsave.junk)
			panic("fpsize %d max %d\n", u->fpsave.size, sizeof u->fpsave.junk);
		fpregsave(u->fpsave.reg);
		u->p->fpstate = FPactive;
		m->fpstate = FPdirty;
	}
	if(BALU->cr0 != 0xFFFFFFFF)	/* balu busy */
		memcpy(balu, BALU, sizeof(Balu));
	else{
		balu->cr0 = 0xFFFFFFFF;
		BALU->cr0 = 0xFFFFFFFF;
	}
}

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

	balu = (Balu *)state;
	if(p->fpstate != m->fpstate){
		if(p->fpstate == FPinit){
			u->p->fpstate = FPinit;
			fprestore(&initfp);
			m->fpstate = FPinit;
		}else{
			fpregrestore(u->fpsave.reg);
			fprestore(&u->fpsave);
			m->fpstate = FPdirty;
		}
	}
	if(balu->cr0 != 0xFFFFFFFF)	/* balu busy */
		memcpy(BALU, balu, sizeof balu);
}

M gnot/mmu.c => gnot/mmu.c +7 -0
@@ 27,6 27,7 @@ mapstack(Proc *p)
	tlbvirt = USERADDR;
	tlbphys = PPN(p->upage->pa) | PTEVALID | PTEKERNEL;
	putkmmu(tlbvirt, tlbphys);
	u = (User*)USERADDR;

	/*
	 *  if not a kernel process and this process was not the 


@@ 150,3 151,9 @@ kunmap(KMap *k)
	putkmmu(k->va, INVALIDPTE);
	unlock(&kmapalloc);
}

void
invalidateu(void)
{
	putkmmu(USERADDR, INVALIDPTE);
}

M gnot/page.c => gnot/page.c +8 -0
@@ 258,6 258,14 @@ usepage(Page *p, int 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)
{

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

#include	<libg.h>
#include	<gnot.h>

struct
{
	Lock;
	ulong	pid;
}pidalloc;

struct
{
	Lock;
	Proc	*arena;
	Proc	*free;
}procalloc;

struct
{
	Lock;
	Proc	*head;
	Proc	*tail;
}runq;

char *statename[]={	/* BUG: generate automatically */
	"Dead",
	"Moribund",
	"Zombie",
	"Ready",
	"Scheding",
	"Running",
	"Queueing",
	"MMUing",
	"Exiting",
	"Inwait",
	"Wakeme",
	"Broken",
};

int page_alloc(int);	/* !ORIG */
void page_free(int, int);

/*
 * Called as the last routine in main().  Wait for a process on the run queue, grab it,
 * and run it.  Note that in this routine the interrupts are enabled for the first time.
 */
void
schedinit(void)		/* never returns */
{
	Proc *p;

	/*
	 * At init time:  wait for a process on the run queue.
	 */
	for(;;){
		spllo();
		while (runq.head == 0)
			/* idle loop */;
		splhi();
		lock(&runq);
		if(runq.head != 0)
			break;
		unlock(&runq);
	}

	/*
	 * Set the u pointer and leave it there.  In fact, it might as well be a define.
	 */
	u = (User *) USERADDR;

	/*
	 * For later rescheduling.  Jumped to by sched() on stack switch.
	 */
	setlabel(&m->sched);

	/*
	 * Take a process from the run queue.  The run queue is locked here, and guaranteed
	 * to have a process on it.
	 */
	p = runq.head;
	if((runq.head = p->rnext) == 0)
		runq.tail = 0;
	unlock(&runq);

	/*
	 * Ok, here we go.  We have a process and we can start running.
	 */
	mapstack(p);
	gotolabel(&p->sched);
}

/*
 * Complete the restoring of a process after mapstack().  The interrupt level here is low.
 * However, since the process is not Running, it cannot be rescheduled at this point.  We
 * set the process state to Running.  If the previous process was dead, clean it up.
 */
void
restore(void)
{
	Proc *p = m->proc;	/* previous process */

	u->p->mach = m;
	m->proc = u->p;
	u->p->state = Running;
	if(p->state == Moribund){
		p->pid = 0;
		unlock(&p->debug);		/* set in pexit */
		p->upage->ref--;
		p->upage = 0;
		p->qnext = procalloc.free;
		procalloc.free = p;
		unlock(&procalloc);		/* set in pexit */
		p->state = Dead;
	}
}

/*
 * Save part of the process state.  Note: this is not the counterpart of restore().
 */
void
save(Balu *balu)
{
	fpsave(&u->fpsave);
	if(u->fpsave.type){
		if(u->fpsave.size > sizeof u->fpsave.junk)
			panic("fpsize %d max %d\n", u->fpsave.size, sizeof u->fpsave.junk);
		fpregsave(u->fpsave.reg);
		u->p->fpstate = FPactive;
		m->fpstate = FPdirty;
	}
	if(BALU->cr0 != 0xFFFFFFFF)	/* balu busy */
		memcpy(balu, BALU, sizeof(Balu));
	else{
		balu->cr0 = 0xFFFFFFFF;
		BALU->cr0 = 0xFFFFFFFF;
	}
}

/*
 * Reschedule the process.  We do not know whether the interrupt level is low or high
 * here, but we set it to low in any case.  If there is no other process to run, and
 * this process is Running, return immediately.  If this process is blocked, and there
 * is no other process to run, keep spinning until either this process or another
 * process becomes runnable.  If it was this process, we can return immediately.
 */
void
sched(void)
{
	Proc *p = u->p;
	long initfp;
	Balu balu;
	int saved = 0;

	/*
	 * Record that the process is spinning instead of blocked.  Ready() uses this
	 * information to decide what to do with the process.
	 */
	p->spin = 1;

	/*
	 * Look for a new process to be run.
	 */
	for (;;){
		spllo();

		/*
		 * Idle loop.  Return when this process becomes runnable.  If nothing else
		 * to do, start saving some of the process state.
		 */
		while (runq.head == 0)
			if(p->state == Running)
				return;
			else if(!saved){
				save(&balu);
				saved = 1;
			}
	
		/*
		 * Disable clock interrupts so that there will be no rescheduling in this
		 * section (on this machine).  If there is still a process on the run
		 * queue, break out of this loop.
		 */
		splhi();
		lock(&runq);
		if(runq.head != 0)
			break;
		unlock(&runq);
	}
	p->spin = 0;

	/*
	 * The first process on the run queue is the process we are going to run.  First
	 * save our state before we jump to schedinit.  If this process was running, put
	 * it on the run queue.
	 */
	if(p->state == Running){
		p->state = Ready;
		p->rnext = 0;
		runq.tail->rnext = p;
		runq.tail = p;
	}

	/*
	 * Save some process state (if we haven't done that already) and save/restore
	 * pc and sp.  We have to jump to schedinit() because we are going to remap the
	 * stack.
	 */
	if(!saved)
		save(&balu);
	if(setlabel(&p->sched) == 0)
		gotolabel(&m->sched);

	/*
	 * Interrupts are ok now.  Note that the process state is still not Running,
	 * so no rescheduling.
	 */
	spllo();

	/*
	 * Jumped to by schedinit.  Restore the process state.
	 */
	if(p->fpstate != m->fpstate)
		if(p->fpstate == FPinit){
			initfp = 0;
			fprestore((FPsave *) &initfp);
			m->fpstate = FPinit;
		}
		else{
			fpregrestore(u->fpsave.reg);
			fprestore(&u->fpsave);
			m->fpstate = FPdirty;
		}
	if(balu.cr0 != 0xFFFFFFFF)	/* balu busy */
		memcpy(BALU, &balu, sizeof balu);

	/*
	 * Complete restoring the process.
	 */
	restore();
}

void
ready(Proc *p)
{
	int s;

	s = splhi();
	if(p->spin){
		p->state = Running;
		splx(s);
		return;
	}
	lock(&runq);
	p->rnext = 0;
	if(runq.tail)
		runq.tail->rnext = p;
	else
		runq.head = p;
	runq.tail = p;
	p->state = Ready;
	unlock(&runq);
	splx(s);
}

Proc*
newproc(void)
{
	Proc *p;

loop:
	lock(&procalloc);
	if(p = procalloc.free){		/* assign = */
		procalloc.free = p->qnext;
		p->state = Zombie;
		unlock(&procalloc);
		p->mach = 0;
		p->qnext = 0;
		p->nchild = 0;
		p->child = 0;
		p->exiting = 0;
		p->fpstate = FPinit;
		p->kp = 0;
		memset(p->seg, 0, sizeof p->seg);
		lock(&pidalloc);
		p->pid = ++pidalloc.pid;
		unlock(&pidalloc);
		if(p->pid == 0)
			panic("pidalloc");
		return p;
	}
	unlock(&procalloc);
	print("no procs\n");
	if(u == 0)
		panic("newproc");
	u->p->state = Wakeme;
	alarm(1000, wakeme, u->p);
	sched();
	goto loop;
}

void
procinit0(void)		/* bad planning - clashes with devproc.c */
{
	Proc *p;
	int i;

	procalloc.free = ialloc(conf.nproc*sizeof(Proc), 0);
	procalloc.arena = procalloc.free;

	p = procalloc.free;
	for(i=0; i<conf.nproc-1; i++,p++)
		p->qnext = p+1;
	p->qnext = 0;
}

void
sleep1(Rendez *r, int (*f)(void*), void *arg)
{
	Proc *p;
	int s;

	/*
	 * spl is to allow lock to be called
	 * at interrupt time. lock is mutual exclusion
	 */
	s = splhi();
	lock(r);

	/*
	 * if condition happened, never mind
	 */
	if((*f)(arg)){	
		unlock(r);
		splx(s);
		return;
	}

	/*
	 * now we are committed to
	 * change state and call scheduler
	 */
	p = u->p;
	if(r->p)
		print("double sleep %lux %d %d\n", r, r->p->pid, p->pid);
	p->r = r;
	p->wokeup = 0;
	p->state = Wakeme;
	r->p = p;
	unlock(r);
}

void
sleep(Rendez *r, int (*f)(void*), void *arg)
{
	sleep1(r, f, arg);
	sched();
	if(u->p->wokeup){
		u->p->wokeup = 0;
		error(Eintr);
	}
}

void
tsleep(Rendez *r, int (*f)(void*), void *arg, int ms)
{
	Alarm *a;

	sleep1(r, f, arg);
	a = alarm(ms, twakeme, r);
	sched();
	cancel(a);
	if(u->p->wokeup){
		u->p->wokeup = 0;
		error(Eintr);
	}
}

void
wakeup(Rendez *r)
{
	Proc *p;
	int s;

	s = splhi();
	lock(r);
	p = r->p;
	if(p){
		r->p = 0;
		if(p->state != Wakeme)
			panic("wakeup: not Wakeme");
		p->r = 0;
		ready(p);
	}
	unlock(r);
	splx(s);
}

void
wakeme(Alarm *a)
{
	ready((Proc*)(a->arg));
	cancel(a);
}

void
twakeme(Alarm *a)
{
	wakeup((Rendez*)(a->arg));
}

int
postnote(Proc *p, int dolock, char *n, int flag)
{
	User *up;
	KMap *k;
	int s;
	Rendez *r;

	if(dolock)
		lock(&p->debug);
	k = kmap(p->upage);
	up = (User*)VA(k);
	if(flag!=NUser && (up->notify==0 || up->notified))
		up->nnote = 0;	/* force user's hand */
	else if(up->nnote == NNOTE-1){
		kunmap(k);
		return 0;
	}
	strcpy(up->note[up->nnote].msg, n);
	up->note[up->nnote++].flag = flag;
	kunmap(k);
	if(dolock)
		unlock(&p->debug);
	if(r = p->r){	/* assign = */
		/* wake up */
		s = splhi();
		lock(r);
		if(p->r==r && r->p==p){
			r->p = 0;
			if(p->state != Wakeme)
				panic("postnote wakeup: not Wakeme");
			p->wokeup = 1;
			p->r = 0;
			ready(p);
		}
		unlock(r);
		splx(s);
	}
	return 1;
}

void
pexit(char *s, int freemem)
{
	char status[64];
	ulong mypid;
	Proc *p, *c, *k, *l;
	Waitmsg w;
	int n;
	Chan *ch;
	ulong *up, *ucp, *wp;

	c = u->p;
	mypid = c->pid;
	if(s)
		strcpy(status, s);
	else
		status[0] = 0;
	if(freemem){
		freesegs(-1);
		closepgrp(c->pgrp);
		close(u->dot);
	}
	for(n=0; n<=u->maxfd; n++)
		if(ch = u->fd[n])	/* assign = */
			close(ch);
	/*
	 * Any of my children exiting?
	 */
	while(c->nchild){
		lock(&c->wait.queue);
		if(canlock(&c->wait.use)){	/* no child is exiting */
			c->exiting = 1;
			unlock(&c->wait.use);
			unlock(&c->wait.queue);
			break;
		}else{				/* must wait for child */
			unlock(&c->wait.queue);
			pwait(0);
		}
	}

	c->time[TReal] = MACHP(0)->ticks - c->time[TReal];
	/*
	 * Tell my parent
	 */
	p = c->parent;
	if(p == 0)
		goto out;
	qlock(&p->wait);
	lock(&p->wait.queue);
	if(p->pid==c->parentpid && !p->exiting){
		w.pid = mypid;
		strcpy(w.msg, status);
		wp = &w.time[TUser];
		up = &c->time[TUser];
		ucp = &c->time[TCUser];
		*wp++ = TK2MS(*up++ + *ucp++);
		*wp++ = TK2MS(*up++ + *ucp  );
		*wp   = TK2MS(*up           );
		p->child = c;
		/*
		 * Pass info through back door, to avoid huge Proc's
		 */
		p->waitmsg = (((ulong)&w)&(BY2PG-1));
		c->state = Exiting;
		if(p->state == Inwait)
			ready(p);
		unlock(&p->wait.queue);
		sched();
	}else{
		unlock(&p->wait.queue);
		qunlock(&p->wait);
	}
   out:
	if(!freemem){
		/*
		 * weird thing: keep at most NBROKEN around
		 */
		#define	NBROKEN 4
		static struct{
			Lock;
			int	n;
			Proc	*p[NBROKEN];
		}broken;
		int b;

		lock(&broken);
		if(broken.n == NBROKEN){
			ready(broken.p[0]);
			memcpy(&broken.p[0], &broken.p[1], sizeof(Proc*)*(NBROKEN-1));
			--broken.n;
		}
		broken.p[broken.n++] = c;
		unlock(&broken);
		c->state = Broken;
		sched();		/* until someone lets us go */
		lock(&broken);
		for(b=0; b<NBROKEN; b++)
			if(broken.p[b] == c){
				broken.n--;
				memcpy(&broken.p[b], &broken.p[b+1], sizeof(Proc*)*(NBROKEN-(b+1)));
				break;
			}
		unlock(&broken);
		freesegs(-1);
		closepgrp(c->pgrp);
		close(u->dot);
	}

    done:

	lock(&procalloc);	/* sched() can't do this */
	lock(&c->debug);	/* sched() can't do this */
	c->state = Moribund;

	/*
	 * Call the scheduler.  This process gets cleaned up in restore() by the next
	 * process that runs.  That means that if there is no other process, we'll
	 * hang around for a little while.
	 */
	sched();	/* never returns */
}

ulong
pwait(Waitmsg *w)
{
	Proc *c, *p;
	KMap *k;
	ulong cpid;

	p = u->p;
again:
	while(canqlock(&p->wait)){
		if(p->nchild == 0){
			qunlock(&p->wait);
			error(Enochild);
		}
		p->state = Inwait;
		qunlock(&p->wait);
		sched();
	}
	lock(&p->wait.queue);	/* wait until child is finished */
	c = p->child;
	if(c == 0){
		p->state = Inwait;
		unlock(&p->wait.queue);
		sched();
		goto again;
	}
	p->child = 0;
	k = kmap(c->upage);
	if(w)
		*w = *(Waitmsg*)(p->waitmsg|VA(k));
	cpid = ((Waitmsg*)(p->waitmsg|VA(k)))->pid;
	kunmap(k);
	p->time[TCUser] += c->time[TUser] + c->time[TCUser];
	p->time[TCSys] += c->time[TSys] + c->time[TCSys];
	p->time[TCReal] += c->time[TReal];
	p->nchild--;
	unlock(&p->wait.queue);
	qunlock(&p->wait);
	ready(c);
	return cpid;
}

Proc*
proctab(int i)
{
	return &procalloc.arena[i];
}

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

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

/*
 *  create a kernel process.  if func is nonzero put the process in the kernel
 *  process group, have it call func, and exit.
 *
 *  otherwise, the new process stays in the same process group and returns.
 */
Proc *
kproc(char *name, void (*func)(void *), void *arg)
{
	Proc *p;
	Chan *c;
	int n;
	ulong upa;
	int lastvar;	/* used to compute stack address */
	User *up;
	KMap *k;
	static Pgrp *kpgrp;

	/*
	 * Kernel stack
	 */
	p = newproc();
	p->kp = 1;
	p->upage = newpage(1, 0, USERADDR|(p->pid&0xFFFF));
	k = kmap(p->upage);
	upa = VA(k);
	up = (User*)upa;

	/*
	 * Save time: only copy u-> data and useful stack
	 */
	clearmmucache();
	memcpy(up, u, sizeof(User));
	n = USERADDR+BY2PG - (ulong)&lastvar;
	n = (n+32) & ~(BY2WD-1);	/* be safe & word align */
	memcpy((void*)(upa+BY2PG-n), (void*)(USERADDR+BY2PG-n), n);

	/*
	 * Refs
	 */
	incref(up->dot);
	for(n=0; n<=up->maxfd; n++)
		if(func)
			up->fd[n] = 0;
		else if(c = u->fd[n])		/* assign = */
			incref(c);
	if(!func)
		up->maxfd = 0;
	up->p = p;
	kunmap(k);

	/*
	 * Sched
	 */
	if(setlabel(&p->sched)){
		restore();
		if(func){
			(*func)(arg);
			pexit(0, 1);
		} else
			return 0;
	}
	if(func){
		if(kpgrp == 0){
			kpgrp = newpgrp();
			strcpy(kpgrp->user, "bootes");
		}
		p->pgrp = kpgrp;
	} else
		p->pgrp = u->p->pgrp;
	incref(p->pgrp);
	sprint(p->text, "%s.%.6s", name, u->p->pgrp->user);
	p->nchild = 0;
	p->parent = 0;
	memset(p->time, 0, sizeof(p->time));
	p->time[TReal] = MACHP(0)->ticks;
	ready(p);
	flushmmu();
	return p;
}

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

#include	<a.out.h>

int	shargs(char*, int, char**);

long
sysr1(ulong *arg)
{
	print("[%d] r1 = %d\n", u->p->pid, arg[0]);
	return 0;
}

long
sysfork(ulong *arg)
{
	Proc *p;
	Seg *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();
	p->upage = newpage(1, 0, USERADDR|(p->pid&0xFFFF));
	k = kmap(p->upage);
	upa = VA(k);

	/*
	 * Save time: only copy u-> data and useful stack
	 */
	clearmmucache();
	memcpy((void*)upa, u, sizeof(User));
	n = USERADDR+BY2PG - (ulong)&lastvar;
	n = (n+32) & ~(BY2WD-1);	/* be safe & word align */
	memcpy((void*)(upa+BY2PG-n), (void*)(USERADDR+BY2PG-n), n);
	((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, 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);
				memcpy((void*)(VA(k)+usp),
					(void*)(op->va+usp), BY2PG-usp);
			}else		/* all of higher pages */
				memcpy((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);
	}
	/*
	 * Refs
	 */
	incref(u->dot);
	for(n=0; n<=u->maxfd; n++)
		if(c = u->fd[n])	/* assign = */
			incref(c);
	/*
	 * Sched
	 */
	if(setlabel(&p->sched)){
		clearmmucache();
		restore();
		return 0;
	}
	p->parent = u->p;
	p->parentpid = u->p->pid;
	p->pgrp = u->p->pgrp;
	incref(p->pgrp);
	u->p->nchild++;
	pid = p->pid;
	memset(p->time, 0, sizeof(p->time));
	p->time[TReal] = MACHP(0)->ticks;
	memcpy(p->text, u->p->text, NAMELEN);
	ready(p);
	flushmmu();
	clearmmucache();
	return pid;
}

long
sysexec(ulong *arg)
{
	Proc *p;
	Seg *s;
	ulong l, t, d, b, v;
	int i;
	Chan *tc, *c;
	Orig *o;
	char **argv, **argp;
	char *a, *charp, *file;
	long fpnull = 0;
	char *progarg[sizeof(Exec)/2+1], elem[NAMELEN];
	ulong ssize, spage, nargs, nbytes, n, bssend;
	ulong *sp;
	int indir;
	Exec exec;
	char line[sizeof(Exec)];

	p = u->p;
	validaddr(arg[0], 1, 0);
	file = (char*)arg[0];
	indir = 0;
    Header:
	tc = namec(file, Aopen, OEXEC, 0);
	if(waserror()){
		close(tc);
		nexterror();
	}
	if(!indir)
		strcpy(elem, u->elem);
	n = (*devtab[tc->type].read)(tc, &exec, sizeof(Exec));
	if(n < 2)
    Err:
		error(Ebadexec);
	if(n==sizeof(Exec) && exec.magic==A_MAGIC){
		if((exec.text&KZERO)
		|| (ulong)exec.entry < UTZERO+sizeof(Exec)
		|| (ulong)exec.entry >= UTZERO+sizeof(Exec)+exec.text)
			goto Err;
		goto Binary;
	}

	/*
	 * Process #! /bin/sh args ...
	 */
	memcpy(line, &exec, sizeof(Exec));
	if(indir || line[0]!='#' || line[1]!='!')
		goto Err;
	n = shargs(line, n, progarg);
	if(n == 0)
		goto Err;
	indir = 1;
	/*
	 * First arg becomes complete file name
	 */
	progarg[n++] = file;
	progarg[n] = 0;
	validaddr(arg[1], BY2WD, 1);
	arg[1] += BY2WD;
	file = progarg[0];
	progarg[0] = elem;
	close(tc);
	poperror();
	goto Header;

    Binary:
	t = (UTZERO+sizeof(Exec)+exec.text+(BY2PG-1)) & ~(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)
		error(Ebadexec);

	/*
	 * Args: pass 1: count
	 */
	nbytes = 0;
	nargs = 0;
	if(indir){
		argp = progarg;
		while(*argp){
			a = *argp++;
			nbytes += strlen(a) + 1;
			nargs++;
		}
	}
	evenaddr(arg[1]);
	argp = (char**)arg[1];
	validaddr((ulong)argp, BY2WD, 0);
	while(*argp){
		a = *argp++;
		if(((ulong)argp&(BY2PG-1)) < BY2WD)
			validaddr((ulong)argp, BY2WD, 0);
		validaddr((ulong)a, 1, 0);
		nbytes += (vmemchr(a, 0, 0xFFFFFFFF) - a) + 1;
			nargs++;
	}
	ssize = BY2WD*(nargs+1) + ((nbytes+(BY2WD-1)) & ~(BY2WD-1));
	spage = (ssize+(BY2PG-1)) >> PGSHIFT;

	/*
	 * Build the stack segment, putting it in kernel virtual for the moment
	 */
	s = &p->seg[ESEG];
	s->proc = p;
	s->o = neworig(TSTKTOP-(spage<<PGSHIFT), spage, OWRPERM, 0);
	s->minva = s->o->va;
	s->maxva = TSTKTOP;

	/*
	 * Args: pass 2: assemble; the pages will be faulted in
	 */
	argv = (char**)(TSTKTOP - ssize);
	charp = (char*)(TSTKTOP - nbytes);
	if(indir)
		argp = progarg;
	else
		argp = (char**)arg[1];
	for(i=0; i<nargs; i++){
		if(indir && *argp==0){
			indir = 0;
			argp = (char**)arg[1];
		}
		*argv++ = charp + (USTKTOP-TSTKTOP);
		n = strlen(*argp) + 1;
		memcpy(charp, *argp++, n);
		charp += n;
	}

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

	/*
	 * Committed.  Free old memory
	 */
	freesegs(ESEG);

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

	/*
	 * Text.  Shared.
	 */
	s = &p->seg[TSEG];
	s->proc = p;
	o = lookorig(UTZERO, (t-UTZERO)>>PGSHIFT, OCACHED, tc);
	if(o == 0){
		o = neworig(UTZERO, (t-UTZERO)>>PGSHIFT, OCACHED, tc);
		o->minca = 0;
		o->maxca = sizeof(Exec)+exec.text;
	}
	s->o = o;
	s->minva = UTZERO;
	s->maxva = t;
	s->mod = 0;

	/*
	 * Data.  Shared.
	 */
	s = &p->seg[DSEG];
	s->proc = p;
	o = lookorig(t, (d-t)>>PGSHIFT, OWRPERM|OPURE|OCACHED, tc);
	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;
	}
	s->o = o;
	s->minva = t;
	s->maxva = d;
	s->mod = 0;

	/*
	 * BSS.  Created afresh.
	 */
	s = &p->seg[BSEG];
	s->proc = p;
	o = neworig(d, (b-d)>>PGSHIFT, OWRPERM, 0);
	o->minca = 0;
	o->maxca = 0;
	s->o = o;
	s->minva = d;
	s->maxva = b;
	s->mod = 0;

	close(tc);

	p->bssend = bssend;

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

	flushmmu();
	clearmmucache();
	((Ureg*)UREGADDR)->pc = exec.entry;
	sp = (ulong*)(USTKTOP - ssize);
	*--sp = nargs;
	((Ureg*)UREGADDR)->usp = (ulong)sp;
	lock(&p->debug);
	u->nnote = 0;
	u->notify = 0;
	u->notified = 0;
	splhi();
	m->fpstate = FPinit;
	p->fpstate = FPinit;
	fprestore((FPsave*)&fpnull);
	spllo();
	unlock(&p->debug);
	return 0;
}

int
shargs(char *s, int n, char **ap)
{
	int i;

	s += 2, n -= 2;		/* skip #! */
	for(i=0; s[i]!='\n'; i++)
		if(i == n-1)
			return 0;
	s[i] = 0;
	*ap = 0;
	i = 0;
	for(;;){
		while(*s==' ' || *s=='\t')
			s++;
		if(*s == 0)
			break;
		i++;
		*ap++ = s;
		*ap = 0;
		while(*s && *s!=' ' && *s!='\t')
			s++;
		if(*s == 0)
			break;
		else
			*s++ = 0;
	}
	return i;
}

int
return0(void *a)
{
	return 0;
}

long
syssleep(ulong *arg)
{
	tsleep(&u->p->sleep, return0, 0, arg[0]);
	return 0;
}


long
sysexits(ulong *arg)
{
	char *status;

	status = (char*)arg[0];
	if(status){
		if(waserror())
			status = "invalid exit string";
		else{
			validaddr((ulong)status, 1, 0);
			vmemchr(status, 0, ERRLEN);
		}
	}
	pexit(status, 1);
}

long
syswait(ulong *arg)
{
	if(arg[0]){
		validaddr(arg[0], sizeof(Waitmsg), 1);
		evenaddr(arg[0]);
	}
	return pwait((Waitmsg*)arg[0]);
}

long
sysdeath(ulong *arg)
{
	pprint("deprecated system call");
	pexit("Suicide", 0);
}

long
syserrstr(ulong *arg)
{
	char buf[ERRLEN];

	validaddr(arg[0], ERRLEN, 1);
	memcpy((char*)arg[0], u->error, ERRLEN);
	return 0;
}

long
sysforkpgrp(ulong *arg)
{
	Pgrp *pg;

	pg = newpgrp();
	if(waserror()){
		closepgrp(pg);
		nexterror();
	}
	if(arg[0] == 0)
		pgrpcpy(pg, u->p->pgrp);
	else
		memcpy(pg->user, u->p->pgrp->user, NAMELEN);
	closepgrp(u->p->pgrp);
	u->p->pgrp = pg;
	return pg->pgrpid;
}

long
sysnotify(ulong *arg)
{
	validaddr(arg[0], sizeof(ulong), 0);
	u->notify = (int(*)(void*, char*))(arg[0]);
	return 0;
}

long
sysnoted(ulong *arg)
{
	if(u->notified == 0)
		error(Egreg);
	return 0;
}

/*
 * Temporary; should be replaced by a generalized segment control operator
 */
long
sysbrk_(ulong *arg)
{
	ulong addr;
	Seg *s;

	addr = arg[0];
	if(addr < u->p->bssend){
		pprint("addr below bss\n");
		pexit("Suicide", 0);
		error(Esegaddr);
	}
	if(addr <= ((u->p->bssend+(BY2PG-1))&~(BY2PG-1)))	/* still in DSEG */
		goto Return;
	if(segaddr(&u->p->seg[BSEG], u->p->seg[BSEG].minva, arg[0]) == 0){
		pprint("bad segaddr in brk\n");
		pexit("Suicide", 0);
		error(Esegaddr);
	}
    Return:
	u->p->bssend = addr;
	return 0;
}

A port/alarm.c => port/alarm.c +108 -0
@@ 0,0 1,108 @@
#include	"u.h"
#include	"lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"io.h"

Alarm	*alarmtab;

Alarm*
alarm(int ms, void (*f)(Alarm*), void *arg)
{
	Alarm *a, *w, *pw;
	ulong s;
	if(ms < 0)
		ms = 0;
	a = newalarm();
	a->dt = MS2TK(ms);
	a->f = f;
	a->arg = arg;
	s = splhi();
	lock(&m->alarmlock);
	pw = 0;
	for(w=m->alarm; w; pw=w, w=w->next){
		if(w->dt <= a->dt){
			a->dt -= w->dt;
			continue;
		}
		w->dt -= a->dt;
		break;
	}
	insert(&m->alarm, pw, a);
	unlock(&m->alarmlock);
	splx(s);
	return a;
}

void
cancel(Alarm *a)
{
	a->f = 0;
}

Alarm*
newalarm(void)
{
	int i;
	Alarm *a;

	for(i=0,a=alarmtab; i<conf.nalarm; i++,a++)
		if(a->busy==0 && a->f==0 && canlock(a)){
			if(a->busy){
				unlock(a);
				continue;
			}
			a->f = 0;
			a->arg = 0;
			a->busy = 1;
			unlock(a);
			return a;
		}
	panic("newalarm");
}

void
alarminit(void)
{
	int i;

	alarmtab = ialloc(conf.nalarm*sizeof(Alarm), 0);
	for(i=0; i<conf.nalarm; i++){
		lock(&alarmtab[i]);	/* allocate locks, as they are used at interrupt time */
		unlock(&alarmtab[i]);
	}
}

#define NA 10		/* alarms per clock tick */
void
checkalarms(void)
{
	int i, n;
	Alarm *a;
	void (*f)(void*);
	Alarm *alist[NA];

	if(canlock(&m->alarmlock)){
		a = m->alarm;
		if(a){
			for(n=0; a && a->dt<=0 && n<NA; n++){
				alist[n] = a;
				delete(&m->alarm, 0, a);
				a = m->alarm;
			}
			if(a)
				a->dt--;
			unlock(&m->alarmlock);

			/*  execute alarm functions outside the lock */
			for(i = 0; i < n; i++){
				f = alist[i]->f;	/* avoid race with cancel */
				if(f)
					(*f)(alist[i]);
				alist[i]->busy = 0;
			}
		} else
			unlock(&m->alarmlock);
	}
}

M port/page.c => port/page.c +6 -1
@@ 70,6 70,8 @@ ialloc(ulong n, int align)
		palloc.addr += BY2PG-1;
		palloc.addr &= ~(BY2PG-1);
	}
	if(palloc.addr >= conf.maxialloc)
		panic("keep bill joy away");
	return (void*)(p|KZERO);
}



@@ 151,7 153,10 @@ pageinit(void)
	for(p=palloc.head; p<=palloc.tail; p++,ppn++){
		p->next = p+1;
		p->prev = p-1;
		p->pa = ppn<<PGSHIFT;
		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;

M port/proc.c => port/proc.c +6 -2
@@ 52,7 52,7 @@ schedinit(void)		/* never returns */
	if(u){
		m->proc = 0;
		p = u->p;
		puttlbx(0, KZERO | PTEPID(0), 0);	/* safety first */
		invalidateu();	/* safety first */
		u = 0;
		if(p->state == Running)
			ready(p);


@@ 76,17 76,20 @@ schedinit(void)		/* never returns */
void
sched(void)
{
	uchar procstate[64];		/* sleeze for portability */
	Proc *p;
	ulong tlbvirt, tlbphys;
	void (*f)(ulong, ulong);

	if(u){
		splhi();
		save(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);
			spllo();
			return;
		}


@@ 132,7 135,7 @@ runproc(void)

loop:
	while(runq.head == 0)
		for(i=0; i<10; i++)
		for(i=0; i<10; i++)	/* keep out of shared memory for a while */
			;
	splhi();
	lock(&runq);


@@ 573,6 576,7 @@ kproc(char *name, void (*func)(void *), void *arg)
	/*
	 * Save time: only copy u-> data and useful stack
	 */
	clearmmucache();
	memcpy(up, u, sizeof(User));
	n = USERADDR+BY2PG - (ulong)&lastvar;
	n = (n+32) & ~(BY2WD-1);	/* be safe & word align */

M port/sysproc.c => port/sysproc.c +31 -5
@@ 41,6 41,7 @@ sysfork(ulong *arg)
	/*
	 * Save time: only copy u-> data and useful stack
	 */
	clearmmucache();
	memcpy((void*)upa, u, sizeof(User));
	n = USERADDR+BY2PG - (ulong)&lastvar;
	n = (n+32) & ~(BY2WD-1);	/* be safe & word align */


@@ 114,6 115,7 @@ sysfork(ulong *arg)
	 * Sched
	 */
	if(setlabel(&p->sched)){
		clearmmucache();
		u->p = p;
		p->state = Running;
		p->mach = m;


@@ 132,6 134,7 @@ sysfork(ulong *arg)
	memcpy(p->text, u->p->text, NAMELEN);
	ready(p);
	flushmmu();
	clearmmucache();
	return pid;
}



@@ 147,7 150,7 @@ sysexec(ulong *arg)
	char **argv, **argp;
	char *a, *charp, *file;
	char *progarg[sizeof(Exec)/2+1], elem[NAMELEN];
	ulong ssize, spage, nargs, nbytes, n;
	ulong ssize, spage, nargs, nbytes, n, bssend;
	ulong *sp;
	int indir;
	Exec exec;


@@ 169,7 172,7 @@ sysexec(ulong *arg)
	if(n < 2)
    Err:
		error(Ebadexec);
	if(n==sizeof(Exec) && exec.magic==V_MAGIC){
	if(n==sizeof(Exec) && exec.magic==AOUT_MAGIC){
		if((exec.text&KZERO)
		|| (ulong)exec.entry < UTZERO+sizeof(Exec)
		|| (ulong)exec.entry >= UTZERO+sizeof(Exec)+exec.text)


@@ 206,7 209,8 @@ sysexec(ulong *arg)
	 * Last partial page of data goes into BSS.
	 */
	d = (t + exec.data) & ~(BY2PG-1);
	b = (t + exec.data + exec.bss + (BY2PG-1)) & ~(BY2PG-1);
	bssend = t + exec.data + exec.bss;
	b = (bssend + (BY2PG-1)) & ~(BY2PG-1);
	if((t|d|b) & KZERO)
		error(Ebadexec);



@@ 331,6 335,8 @@ sysexec(ulong *arg)

	close(tc);

	p->bssend = bssend;

	/*
	 * Move the stack
	 */


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

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


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


@@ 488,7 496,25 @@ sysnoted(ulong *arg)
long
sysbrk_(ulong *arg)
{
	if(segaddr(&u->p->seg[BSEG], u->p->seg[BSEG].minva, arg[0]) == 0)
	ulong addr;
	Seg *s;

	addr = arg[0];
#ifdef WHYROB
	if(addr < u->p->bssend){
		pprint("addr below bss\n");
		pexit("Suicide", 0);
		error(Esegaddr);
	}
#endif WHYROB
	if(addr <= ((u->p->bssend+(BY2PG-1))&~(BY2PG-1)))	/* still in DSEG */
		goto Return;
	if(segaddr(&u->p->seg[BSEG], u->p->seg[BSEG].minva, arg[0]) == 0){
		pprint("bad segaddr in brk\n");
		pexit("Suicide", 0);
		error(Esegaddr);
	}
    Return:
	u->p->bssend = addr;
	return 0;
}

M power/clock.c => power/clock.c +2 -96
@@ 7,75 7,6 @@

#include	"ureg.h"

Alarm	*alarmtab;

Alarm*
alarm(int ms, void (*f)(Alarm*), void *arg)
{
	Alarm *a, *w, *pw;
	ulong s;
	if(ms < 0)
		ms = 0;
	a = newalarm();
	a->dt = MS2TK(ms);
	a->f = f;
	a->arg = arg;
	s = splhi();
	lock(&m->alarmlock);
	pw = 0;
	for(w=m->alarm; w; pw=w, w=w->next){
		if(w->dt <= a->dt){
			a->dt -= w->dt;
			continue;
		}
		w->dt -= a->dt;
		break;
	}
	insert(&m->alarm, pw, a);
	unlock(&m->alarmlock);
	splx(s);
	return a;
}

void
cancel(Alarm *a)
{
	a->f = 0;
}

Alarm*
newalarm(void)
{
	int i;
	Alarm *a;

	for(i=0,a=alarmtab; i<conf.nalarm; i++,a++)
		if(a->busy==0 && a->f==0 && canlock(a)){
			if(a->busy){
				unlock(a);
				continue;
			}
			a->f = 0;
			a->arg = 0;
			a->busy = 1;
			unlock(a);
			return a;
		}
	panic("newalarm");
}

void
alarminit(void)
{
	int i;

	alarmtab = ialloc(conf.nalarm*sizeof(Alarm), 0);
	for(i=0; i<conf.nalarm; i++){
		lock(&alarmtab[i]);	/* allocate locks, as they are used at interrupt time */
		unlock(&alarmtab[i]);
	}
}

void
delay(int ms)
{


@@ 147,15 78,11 @@ clockinit(void)



#define NA 10
void
clock(ulong n, ulong pc)
{
	int i, na;
	Alarm *a;
	void (*f)(void*);
	int i;
	Proc *p;
	Alarm *alist[NA];

	if(n&INTR2){
		i = *CLRTIM0;


@@ 180,28 107,7 @@ clock(ulong n, ulong pc)
			print("someone's exiting\n");
			exit();
		}
		if(canlock(&m->alarmlock)){
			a = m->alarm;
			if(a){
				for(n=0; a && a->dt<=0 && n<NA; n++){
					alist[n] = a;
					delete(&m->alarm, 0, a);
					a = m->alarm;
				}
				if(a)
					a->dt--;
				unlock(&m->alarmlock);
	
				/*  execute alarm functions outside the lock */
				for(i = 0; i < n; i++){
					f = alist[i]->f;	/* avoid race with cancel */
					if(f)
						(*f)(alist[i]);
					alist[i]->busy = 0;
				}
			} else
				unlock(&m->alarmlock);
		}
		checkalarms();
		return;
	}
	if(n & INTR4){

M power/conf.h => power/conf.h +3 -0
@@ 26,6 26,9 @@ Conftab conftab[] = {
	{"nurp", &conf.nurp },
	{"nasync", &conf.nasync },
	{"npipe", &conf.npipe },
	{"maxialloc", &conf.maxialloc },
	{"base0", &conf.base0 },
	{"base1", &conf.base1 },
	{ 0, 0 },
};


M power/dat.h => power/dat.h +9 -0
@@ 149,6 149,9 @@ struct Conf
	ulong	nurp;		/* max urp conversations */
	ulong	nasync;		/* number of async protocol modules */
	ulong	npipe;		/* number of pipes */
	ulong	maxialloc;	/* maximum bytes used by ialloc */
	ulong	base0;		/* base of bank 0 */
	ulong	base1;		/* base of bank 1 */
};

struct Dev


@@ 315,6 318,7 @@ struct Proc
	short	pidonmach[MAXMACH];	/* TLB pid on each mmu */
	Page	*upage;			/* BUG: should be unlinked from page list */
	Seg	seg[NSEG];
	ulong	bssend;			/* initial top of bss seg */
	ulong	pid;
	int	nchild;
	QLock	wait;			/* exiting children to be waited for */


@@ 698,3 702,8 @@ extern	Dev	devtab[];
extern	char	devchar[];
extern	FPsave	initfp;

/*
 *  parameters for sysproc.c
 */
#define AOUT_MAGIC	V_MAGIC
#define ENTRYOFFSET	(-4)

M power/fns.h => power/fns.h +6 -0
@@ 9,12 9,14 @@ int	canqlock(QLock*);
void	chaninit(void);
void	chandevreset(void);
void	chandevinit(void);
void	checkalarms(void);
void	clock(ulong, ulong);
void	clockinit(void);
Chan	*clone(Chan*, Chan*);
void	close(Chan*);
void	closemount(Mount*);
void	closepgrp(Pgrp*);
void	clearmmucache(void);
long	clrfpintr(void);
int	compactpte(Orig*, ulong);
ulong	confeval(char*);


@@ 81,6 83,7 @@ void	icflush(void *, int);
int	incref(Ref*);
void	insert(List**, List*, List*);
void	intr(ulong, ulong);
void	invalidateu(void);
void	ioboardinit(void);
void	isdir(Chan*);
void	kbdchar(int);


@@ 152,9 155,11 @@ 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);


@@ 162,6 167,7 @@ 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*);

M power/main.c => power/main.c +26 -0
@@ 590,7 590,9 @@ confinit(void)
		x += 0x3141526;
	}
	conf.npage0 = i*1024/4;
	conf.base0 = 0;
	conf.npage = conf.npage0;
	conf.maxialloc = (128*1024*1024-256*1024-BY2PG);

	/*
 	 *  clear MP bus error caused by sizing memory


@@ 693,3 695,27 @@ 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/mmu.c => power/mmu.c +11 -0
@@ 101,3 101,14 @@ flushmmu(void)
	mapstack(u->p);
	spllo();
}

void
clearmmucache(void)
{
}

void
invalidateu(void)
{
	puttlbx(0, KZERO | PTEPID(0), 0);
}