shithub: riscv

Download patch

ref: 81d393942d8834b6e071ab0957b655a99e737486
parent: a3e9415aa8cdba6059c972c582e3645c4c112139
author: aiju <[email protected]>
date: Fri Jun 24 11:10:22 EDT 2011

updated 5e

--- a/sys/src/cmd/5e/5e.c
+++ b/sys/src/cmd/5e/5e.c
@@ -4,10 +4,9 @@
 #include "dat.h"
 #include "fns.h"
 
-Process **PP;
+int nflag, pflag, bflag;
+Ref nproc;
 
-static int nflag;
-
 void
 dump(void)
 {
@@ -37,8 +36,12 @@
 	if(P == nil)
 		return;
 
+	remproc(P);
+	decref(&nproc);
 	freesegs();
 	fddecref(P->fd);
+	if(P->path != nil && decref(P->path) == 0)
+		free(P->path);
 	free(P);
 }
 
@@ -45,15 +48,32 @@
 static void
 usage(void)
 {
-	fprint(2, "usage: 5e [ -n ] text [ args ]\n");
+	fprint(2, "usage: 5e [-npb] text [...]\n");
 	exits(nil);
 }
 
 void
+suicide(char *fmt, ...)
+{
+	va_list va;
+	char buf[1024];
+	
+	va_start(va, fmt);
+	vsnprint(buf, sizeof(buf), fmt, va);
+	va_end(va);
+	fprint(2, "%s\n", buf);
+	if(!bflag)
+		exits(buf);
+	abort();
+}
+
+void
 main(int argc, char **argv)
 {
 	ARGBEGIN {
 	case 'n': nflag++; break;
+	case 'p': pflag++; break;
+	case 'b': bflag++; break;
 	default: usage();
 	} ARGEND;
 	if(argc < 1)
@@ -65,6 +85,8 @@
 	atexit(cleanup);
 	if(nflag)
 		adjustns();
+	if(pflag)
+		initfs("armproc", "/proc");
 	initproc();
 	if(loadtext(argv[0], argc, argv) < 0)
 		sysfatal("%r");
--- a/sys/src/cmd/5e/arm.c
+++ b/sys/src/cmd/5e/arm.c
@@ -22,7 +22,7 @@
 static void
 invalid(u32int instr)
 {
-	sysfatal("undefined instruction %8ux @ %8ux", instr, P->R[15] - 4);
+	suicide("undefined instruction %8ux @ %8ux", instr, P->R[15] - 4);
 }
 
 static u32int
@@ -81,7 +81,7 @@
 		addr = *Rn;
 	if(instr & fP)
 		addr += offset;
-	targ = vaddr(addr, &seg);
+	targ = vaddr(addr, 4, &seg);
 	switch(instr & (fB | fL)) {
 	case 0:
 		*(u32int*) targ = *Rd;
@@ -120,7 +120,7 @@
 	Rn = P->R + ((instr >> 16) & 15);
 	if(Rm == P->R + 15 || Rd == P->R + 15 || Rn == P->R + 15)
 		invalid(instr);
-	targ = (u32int *) vaddr(*Rn, &seg);
+	targ = (u32int *) vaddr(*Rn, 4, &seg);
 	lock(&seg->lock);
 	if(instr & fB) {
 		tmp = *(u8int*) targ;
@@ -256,11 +256,11 @@
 	if(instr & fP)
 		target += offset;
 	switch(instr & (fSg | fH | fL)) {
-	case fSg: *(u8int*) vaddr(target, &seg) = *Rd; break;
-	case fSg | fL: *Rd = (long) *(char*) vaddr(target, &seg); break;
-	case fH: case fSg | fH: *(u16int*) vaddr(target, &seg) = *Rd; break;
-	case fH | fL: *Rd = *(u16int*) vaddr(target, &seg); break;
-	case fH | fL | fSg: *Rd = (long) *(short*) vaddr(target, &seg); break;
+	case fSg: *(u8int*) vaddr(target, 1, &seg) = *Rd; break;
+	case fSg | fL: *Rd = (long) *(char*) vaddr(target, 1, &seg); break;
+	case fH: case fSg | fH: *(u16int*) vaddr(target, 2, &seg) = *Rd; break;
+	case fH | fL: *Rd = *(u16int*) vaddr(target, 2, &seg); break;
+	case fH | fL | fSg: *Rd = (long) *(short*) vaddr(target, 2, &seg); break;
 	}
 	segunlock(seg);
 	if(!(instr & fP))
@@ -289,9 +289,9 @@
 			if(instr & fP)
 				targ += 4;
 			if(instr & fL)
-				P->R[i] = *(u32int*) vaddr(targ, &seg);
+				P->R[i] = *(u32int*) vaddr(targ, 4, &seg);
 			else
-				*(u32int*) vaddr(targ, &seg) = P->R[i];
+				*(u32int*) vaddr(targ, 4, &seg) = P->R[i];
 			segunlock(seg);
 			if(!(instr & fP))
 				targ += 4;
@@ -303,9 +303,9 @@
 			if(instr & fP)
 				targ -= 4;
 			if(instr & fL)
-				P->R[i] = *(u32int*) vaddr(targ, &seg);
+				P->R[i] = *(u32int*) vaddr(targ, 4, &seg);
 			else
-				*(u32int*) vaddr(targ, &seg) = P->R[i];
+				*(u32int*) vaddr(targ, 4, &seg) = P->R[i];
 			segunlock(seg);
 			if(!(instr & fP))
 				targ -= 4;
@@ -382,7 +382,7 @@
 	if(Rd == P->R + 15 || Rn == P->R + 15)
 		invalid(instr);
 	if(instr & fS) {
-		targ = vaddr(*Rn, &seg);
+		targ = vaddr(*Rn, 4, &seg);
 		lock(&seg->lock);
 		*Rd = *targ;
 		segunlock(seg);
@@ -390,11 +390,11 @@
 		Rm = P->R + (instr & 15);
 		if(Rm == P->R + 15)
 			invalid(instr);
-		targ = vaddr(*Rn, &seg);
+		targ = vaddr(*Rn, 4, &seg);
 		if(canlock(&seg->lock)) {
 			*Rd = 1;
 		} else {
-			*targ = *Rd;
+			*targ = *Rm;
 			unlock(&seg->lock);
 			*Rd = 0;
 		}
@@ -408,7 +408,7 @@
 	u32int instr;
 	Segment *seg;
 
-	instr = *(u32int*) vaddr(P->R[15], &seg);
+	instr = *(u32int*) vaddr(P->R[15], 4, &seg);
 	segunlock(seg);
 	if(fulltrace) {
 		print("%d ", P->pid);
--- a/sys/src/cmd/5e/dat.h
+++ b/sys/src/cmd/5e/dat.h
@@ -4,9 +4,10 @@
 typedef struct Fd Fd;
 
 enum {
-	STACKTOP = 0x80000000UL,
-	STACKSIZE = 0x10000,
+	STACKSIZE = 0x100000,
 	
+	NAMEMAX = 27,
+	
 	FDBLOCK = 16,
 	SEGNUM = 8,
 
@@ -25,17 +26,23 @@
 };
 
 struct Process {
-	Segment* S[SEGNUM];
+	Segment *S[SEGNUM];
 	u32int R[16];		/* general purpose registers / PC (R15) */
 	u32int CPSR;		/* status register */
 	char errbuf[ERRMAX];
+	char name[NAMEMAX+1];
+	Ref *path; /* Ref + string data */
 	Fd *fd;
 	int pid;
+	Process *prev, *next;
 };
 
 extern void **_privates;
 extern int _nprivates;
 #define P (*(Process**)_privates)
+extern Ref nproc;
+extern Process plist;
+extern Lock plistlock;
 
 enum {
 	SEGFLLOCK = 1,
@@ -44,16 +51,16 @@
 struct Segment {
 	Ref;
 	int flags;
-	RWLock rw; /* lock for SEGLOCK segments */
+	RWLock rw; /* lock for SEGFLLOCK segments */
 	Lock lock; /* atomic accesses */
 	u32int start, size;
 	void *data;
-	Ref *ref;
+	Ref *dref;
 };
 
 struct Fd {
 	RWLock;
-	Ref ref;
+	Ref;
 	u8int *fds;
 	int nfds;
 };
--- a/sys/src/cmd/5e/fns.h
+++ b/sys/src/cmd/5e/fns.h
@@ -4,8 +4,8 @@
 void initproc(void);
 int loadtext(char *, int, char **);
 Segment *newseg(u32int, u32int, int);
-void *vaddr(u32int, Segment **);
-void *vaddrnol(u32int);
+void *vaddr(u32int, u32int, Segment **);
+void *vaddrnol(u32int, u32int);
 void step(void);
 void syscall(void);
 void cherrstr(char *, ...);
@@ -20,4 +20,10 @@
 void segunlock(Segment *);
 void *copyifnec(u32int, int, int *);
 void *bufifnec(u32int, int, int *);
-void copyback(u32int, int, void *);
\ No newline at end of file
+void copyback(u32int, int, void *);
+void initfs(char *, char *);
+void suicide(char *, ...);
+void fdclear(Fd *);
+void addproc(Process *);
+void remproc(Process *);
+Process *findproc(int);
--- /dev/null
+++ b/sys/src/cmd/5e/fs.c
@@ -1,0 +1,437 @@
+#include <u.h>
+#include <libc.h>
+#include <fcall.h>
+#include <thread.h>
+#include <9p.h>
+#include "dat.h"
+#include "fns.h"
+
+static char *luser;
+extern int pflag;
+
+enum
+{
+	Qdir,
+	Qtrace,
+	Qargs,
+	Qctl,
+	Qfd,
+	Qfpregs,
+	Qkregs,
+	Qmem,
+	Qnote,
+	Qnoteid,
+	Qnotepg,
+	Qns,
+	Qproc,
+	Qregs,
+	Qsegment,
+	Qstatus,
+	Qtext,
+	Qwait,
+	Qprofile,
+	Qsyscall,
+	NQid,
+};
+
+typedef struct Aux Aux;
+typedef struct Dirtab Dirtab;
+struct Dirtab {
+	char name[28];
+	Qid qid;
+	vlong length;
+	long perm;
+};
+struct Aux {
+	Process *p;
+	int fd;
+	Dirtab *d;
+};
+
+Dirtab procdir[] =
+{
+	"args",		{Qargs},	0,			0660,
+	"ctl",		{Qctl},		0,			0600,
+	"fd",		{Qfd},		0,			0444,
+	"fpregs",	{Qfpregs},	0,			0400,
+	"kregs",	{Qkregs},	18 * 4,			0400,
+	"mem",		{Qmem},		0,			0400,
+	"note",		{Qnote},	0,			0000,
+	"noteid",	{Qnoteid},	0,			0664,
+	"notepg",	{Qnotepg},	0,			0000,
+	"ns",		{Qns},		0,			0444,
+	"proc",		{Qproc},	0,			0400,
+	"regs",		{Qregs},	18 * 4,			0400,
+	"segment",	{Qsegment},	0,			0444,
+	"status",	{Qstatus},	176,			0444,
+	"text",		{Qtext},	0,			0400,
+	"wait",		{Qwait},	0,			0400,
+	"profile",	{Qprofile},	0,			0400,
+	"syscall",	{Qsyscall},	0,			0400,	
+	"",		{0},		0,			0,
+};
+
+static char *
+readin(int pid, char *file)
+{
+	char *name, *buf;
+	int fd, rc;
+	
+	name = smprint("#p/%d/%s", pid, file);
+	fd = open(name, OREAD);
+	if(fd < 0)
+		return nil;
+	buf = malloc(1024);
+	rc = read(fd, buf, 1023);
+	if(rc < 0)
+		return nil;
+	buf[rc] = 0;
+	free(name);
+	close(fd);
+	return buf;
+}
+
+static int
+calcmem(Process *p)
+{
+	int i, r;
+	
+	r = 0;
+	for(i = 0; i < SEGNUM; i++) {
+		if(i == SEGSTACK)
+			continue;
+		if(p->S[i] == nil)
+			continue;
+		r += p->S[i]->size;
+	}
+	r = (r + 1023) / 1024;
+	return r;
+}
+
+static int
+copymem(Process *p, char *buf, u32int addr, int len)
+{
+	int i, n, r;
+
+	r = len;
+	while(len > 0) {
+		for(i = 0; i < SEGNUM; i++) {
+			if(p->S[i] == nil)
+				continue;
+			if(p->S[i]->start <= addr && p->S[i]->start + p->S[i]->size > addr)
+				break;
+		}
+		if(i == SEGNUM) {
+			werrstr("bad arg in syscall");
+			return -1;
+		}
+		n = p->S[i]->start + p->S[i]->size - addr;
+		if(n > len)
+			n = len;
+		memcpy(buf, (char*)p->S[i]->data + addr - p->S[i]->start, n);
+		len -= n;
+		buf += n;
+	}
+	return r;
+}
+
+static char *
+segments(Process *p)
+{
+	char *r, *s;
+	static char *names[] = {
+		[SEGTEXT] "Text",
+		[SEGSTACK] "Stack",
+		[SEGDATA] "Data",
+		[SEGBSS] "Bss",
+	};
+	int i;
+	
+	r = emalloc(1024);
+	s = r;
+	for(i = 0; i < SEGNUM; i++) {
+		if(p->S[i] == nil)
+			continue;
+		s += sprint(s, "%-7s%c  %.8ux %.8ux %4ld\n", names[i], i == SEGTEXT ? 'R' : ' ', p->S[i]->start, p->S[i]->start + p->S[i]->size, p->S[i]->dref->ref);
+	}
+	return r;
+}
+
+static void
+procattach(Req *req)
+{
+	req->fid->qid = (Qid) {0, 0, 0x80};
+	req->fid->aux = emallocz(sizeof(Aux));
+	((Aux *) req->fid->aux)->fd = -1;
+	req->ofcall.qid = req->fid->qid;
+	respond(req, nil);
+}
+
+static char *
+procwalk(Fid *fid, char *name, Qid *qid)
+{
+	int pid;
+	char buf[20];
+	Dirtab *d;
+	Aux *a;
+	
+	a = fid->aux;
+	if(fid->qid.path == 0) {
+		pid = atoi(name);
+		sprint(buf, "%d", pid);
+		if(strcmp(buf, name) != 0 || (a->p = findproc(pid)) == nil)
+			return "file does not exist";
+		*qid = (Qid) {pid * NQid, 0, 0x80};
+		fid->qid = *qid;
+		return nil;
+	}
+	if((fid->qid.path % NQid) == 0) {
+		for(d = procdir; d->name[0] != 0; d++)
+			if(strcmp(d->name, name) == 0)
+				break;
+		if(d->name[0] == 0)
+			return "file does not exist";
+		*qid = d->qid;
+		qid->path += fid->qid.path;
+		fid->qid = *qid;
+		a->d = d;
+		return nil;
+	}
+	return "the front fell off";
+}
+
+static char *
+procclone(Fid *old, Fid *new)
+{
+	new->aux = emallocz(sizeof(Aux));
+	memcpy(new->aux, old->aux, sizeof(Aux));
+	return nil;
+}
+
+static void
+procopen(Req *req)
+{
+	Aux *a;
+	
+	a = req->fid->aux;
+	switch((int)(req->fid->qid.path % NQid)) {
+	case Qtext:
+		a->fd = open((char*)(a->p->path + 1), OREAD);
+		break;
+	default:
+		respond(req, nil);
+		return;
+	}
+	if(a->fd < 0)
+		responderror(req);
+	else
+		respond(req, nil);
+}
+
+static void
+procdestroyfid(Fid *fid)
+{
+	Aux *a;
+	
+	a = fid->aux;
+	free(a);
+}
+
+static int
+procgen(int n, Dir *d, void *)
+{
+	int i;
+	Process *p;
+	
+	p = &plist;
+	for(i = 0;; i++) {
+		p = p->next;
+		if(p == &plist)
+			return -1;
+		if(i == n)
+			break;
+	}
+	d->uid = estrdup9p(luser);
+	d->gid = estrdup9p(luser);
+	d->muid = estrdup9p(luser);
+	d->name = smprint("%d", p->pid);
+	d->mode = DMDIR | 0555;
+	d->qid = (Qid) {p->pid * NQid, 0, 0x80};
+	return 0;
+}
+
+static int
+procsubgen(int n, Dir *d, void *)
+{
+	Dirtab *di;
+	
+	if(n >= nelem(procdir) - 1)
+		return -1;
+	
+	di = procdir + n;
+	d->uid = estrdup9p(luser);
+	d->gid = estrdup9p(luser);
+	d->muid = estrdup9p(luser);
+	d->name = estrdup9p(di->name);
+	d->mode = di->perm;
+	d->length = di->length;
+	d->qid = di->qid;
+	return 0;
+}
+
+static void
+procread(Req *req)
+{
+	Aux *a;
+	Process *p;
+	char *buf;
+	int rc;
+
+	a = req->fid->aux;
+	if(a == nil) {
+		respond(req, "the front fell off");
+		return;
+	}
+	if(req->fid->qid.path == 0) {
+		dirread9p(req, procgen, nil);
+		respond(req, nil);
+		return;
+	}
+	p = a->p;
+	switch((int)(req->fid->qid.path % NQid)) {
+	case Qdir:
+		dirread9p(req, procsubgen, nil);
+		respond(req, nil);
+		break;
+	case Qstatus:
+		buf = readin(p->pid, "status");
+		if(buf == nil)
+			responderror(req);
+		else {
+			memset(buf, ' ', 27);
+			memcpy(buf, p->name, strlen(p->name));
+			sprint(buf + 149, "%d", calcmem(p));
+			buf[strlen(buf)] = ' ';
+			readstr(req, buf);
+			free(buf);
+			respond(req, nil);
+		}
+		break;
+	case Qsegment:
+		buf = segments(p);
+		readstr(req, buf);
+		free(buf);
+		respond(req, nil);
+		break;
+	case Qtext:
+		rc = pread(a->fd, req->ofcall.data, req->ifcall.count, req->ifcall.offset);
+		if(rc >= 0) {
+			req->ofcall.count = rc;
+			respond(req, nil);
+		} else
+			responderror(req);
+		break;
+	case Qmem:
+		rc = copymem(p, req->ofcall.data, req->ifcall.offset, req->ifcall.count);
+		if(rc >= 0) {
+			req->ofcall.count = rc;
+			respond(req, nil);
+		} else
+			responderror(req);
+		break;
+	case Qregs:
+		buf = emallocz(18 * 4);
+		memcpy(buf, p->R, 15 * 4);
+		memcpy(buf + 16 * 4, &p->CPSR, 4);
+		memcpy(buf + 17 * 4, p->R + 15, 4);
+		readbuf(req, buf, 18 * 4);
+		free(buf);
+		respond(req, nil);
+		break;
+	default:
+		respond(req, "the front fell off");
+	}
+}
+
+static void
+writeto(Req *req, char *fmt, ...)
+{
+	int fd, rc;
+	va_list va;
+	char *file;
+	
+	va_start(va, fmt);
+	file = vsmprint(fmt, va);
+	va_end(va);
+	fd = open(file, OWRITE);
+	free(file);
+	if(fd < 0) {
+		responderror(req);
+		return;
+	}
+	rc = write(fd, req->ifcall.data, req->ifcall.count);
+	req->ofcall.count = rc;
+	if(rc < req->ifcall.count)
+		responderror(req);
+	else
+		respond(req, nil);
+	close(fd);
+}
+
+static void
+procwrite(Req *req)
+{
+	switch((int)(req->fid->qid.path % NQid)) {
+	case Qnote:
+		writeto(req, "#p/%lld/note", req->fid->qid.path / NQid);
+		break;
+	default:
+		respond(req, "the front fell off");
+	}
+}
+
+static void
+procstat(Req *req)
+{
+	Aux *a;
+	Dir *d;
+	
+	d = &req->d;
+	a = req->fid->aux;
+	if(a == nil) {
+		respond(req, "the front fell off");
+		return;
+	}
+	d->qid = req->fid->qid;
+	if(a->d != nil) {
+		d->mode = a->d->perm;
+		d->length = a->d->length;
+		d->name = strdup(a->d->name);
+	} else {
+		d->mode = 0555 | DMDIR;
+		if(d->qid.path != 0)
+			d->name = smprint("%lld", d->qid.path / NQid);
+	}
+	d->uid = strdup(luser);
+	d->gid = strdup(luser);
+	d->muid = strdup(luser);
+	respond(req, nil);
+}
+
+static Srv procsrv = {
+	.attach = procattach,
+	.walk1 = procwalk,
+	.clone = procclone,
+	.destroyfid = procdestroyfid,
+	.open = procopen,
+	.read = procread,
+	.stat = procstat,
+};
+
+void
+initfs(char *name, char *mtpt)
+{
+	luser = getuser();
+	remove("/srv/armproc");
+	postmountsrv(&procsrv, name, mtpt, MREPL);
+}
--- a/sys/src/cmd/5e/mkfile
+++ b/sys/src/cmd/5e/mkfile
@@ -1,7 +1,7 @@
 </$objtype/mkfile
 
 TARG=5e
-OFILES=5e.$O seg.$O proc.$O util.$O arm.$O sys.$O
+OFILES=5e.$O seg.$O proc.$O util.$O arm.$O sys.$O fs.$O
 HFILES=dat.h fns.h
 BIN=/$objtype/bin
 
--- a/sys/src/cmd/5e/proc.c
+++ b/sys/src/cmd/5e/proc.c
@@ -8,6 +8,9 @@
 #include "dat.h"
 #include "fns.h"
 
+Process plist;
+Lock plistlock;
+
 void
 initproc(void)
 {
@@ -14,14 +17,73 @@
 	P = emallocz(sizeof(Process));
 	P->pid = getpid();
 	P->fd = newfd();
+	incref(&nproc);
+	plist.prev = P;
+	plist.next = P;
+	P->prev = &plist;
+	P->next = &plist;
 }
 
+void
+addproc(Process *p)
+{
+	lock(&plistlock);
+	p->prev = plist.prev;
+	p->next = &plist;
+	plist.prev->next = p;
+	plist.prev = p;
+	unlock(&plistlock);
+}
+
+void
+remproc(Process *p)
+{
+	lock(&plistlock);
+	p->prev->next = p->next;
+	p->next->prev = p->prev;
+	unlock(&plistlock);
+}
+
+Process *
+findproc(int pid)
+{
+	Process *p;
+
+	lock(&plistlock);
+	for(p = plist.next; p != &plist; p = p->next)
+		if(p->pid == pid)
+			break;
+	unlock(&plistlock);
+	if(p != &plist)
+		return p;
+	return nil;
+}
+
 static void
+copyname(char *file)
+{
+	char *p;
+	
+	p = strrchr(file, '/');
+	if(p == nil)
+		p = file;
+	else
+		p++;
+	strncpy(P->name, p, NAMEMAX);
+
+	if(P->path != nil && decref(P->path) == 0)
+		free(P->path);
+	P->path = emallocz(5 + strlen(file));
+	incref(P->path);
+	strcpy((char*)(P->path + 1), file);
+}
+
+static void
 initstack(int argc, char **argv)
 {
 	ulong tos, sp, ap, size, i, len;
 	
-	tos = STACKTOP - sizeof(Tos) * 2;
+	tos = mach->utop - sizeof(Tos) * 2;
 	sp = tos;
 	
 	size = 8;
@@ -31,22 +93,22 @@
 	sp -= size;
 	sp &= ~7;
 	P->R[0] = tos;
-	P->R[1] = STACKTOP - 4;
+	P->R[1] = mach->utop - 4;
 	P->R[13] = sp;
 	
-	*(ulong *) vaddrnol(sp) = argc;
+	*(ulong *) vaddrnol(sp, 4) = argc;
 	sp += 4;
 	ap = sp + (argc + 1) * 4;
 	for(i = 0; i < argc; i++) {
-		*(ulong *) vaddrnol(sp) = ap;
+		*(ulong *) vaddrnol(sp, 4) = ap;
 		sp += 4;
 		len = strlen(argv[i]) + 1;
-		memcpy(vaddrnol(ap), argv[i], len);
+		memcpy(vaddrnol(ap, len), argv[i], len);
 		ap += len;
 	}
-	*(ulong *) vaddrnol(sp) = 0;
+	*(ulong *) vaddrnol(sp, 4) = 0;
 
-	((Tos *) vaddrnol(tos))->pid = getpid();
+	((Tos *) vaddrnol(tos, sizeof(Tos)))->pid = getpid();
 }
 
 static int
@@ -104,9 +166,9 @@
 int
 loadtext(char *file, int argc, char **argv)
 {
-	int fd, i;
+	int fd;
 	Fhdr fp;
-	Segment *text, *data, *bss, *stack;
+	Segment *text, *data, *bss;
 	char buf[2];
 	
 	fd = open(file, OREAD);
@@ -114,14 +176,11 @@
 	if(pread(fd, buf, 2, 0) == 2 && buf[0] == '#' && buf[1] == '!')
 		return loadscript(fd, file, argc, argv);
 	seek(fd, 0, 0);
-	if(crackhdr(fd, &fp) == 0) {
+	if(crackhdr(fd, &fp) == 0 || fp.magic != E_MAGIC) {
 		werrstr("exec header invalid");
 		return -1;
 	}
-	if(fp.magic != E_MAGIC) {
-		werrstr("exec header invalid");
-		return -1;
-	}
+	copyname(file);
 	freesegs();
 	memset(P->R, 0, sizeof(P->R));
 	P->CPSR = 0;
@@ -128,7 +187,7 @@
 	text = newseg(fp.txtaddr - fp.hdrsz, fp.txtsz + fp.hdrsz, SEGTEXT);
 	data = newseg(fp.dataddr, fp.datsz, SEGDATA);
 	bss = newseg(fp.dataddr + fp.datsz, fp.bsssz, SEGBSS);
-	stack = newseg(STACKTOP - STACKSIZE, STACKSIZE, SEGSTACK);
+	newseg(mach->utop - STACKSIZE, STACKSIZE, SEGSTACK);
 	seek(fd, fp.txtoff - fp.hdrsz, 0);
 	if(readn(fd, text->data, fp.txtsz + fp.hdrsz) < fp.txtsz + fp.hdrsz)
 		sysfatal("%r");
@@ -136,19 +195,11 @@
 	if(readn(fd, data->data, fp.datsz) < fp.datsz)
 		sysfatal("%r");
 	memset(bss->data, 0, bss->size);
-	memset(stack->data, 0, stack->size);
 	P->R[15] = fp.entry;
 	if(havesymbols && syminit(fd, &fp) < 0)
 		fprint(2, "initializing symbol table: %r\n");
 	close(fd);
-	for(i = 0; i < P->fd->nfds * 8; i++)
-		if(iscexec(P->fd, i))
-			close(i);
-	wlock(P->fd);
-	free(P->fd->fds);
-	P->fd->fds = nil;
-	P->fd->nfds = 0;
-	wunlock(P->fd);
+	fdclear(P->fd);
 	initstack(argc, argv);
 	return 0;
 }
@@ -178,7 +229,7 @@
 	Fd *fd;
 	
 	fd = emallocz(sizeof(*fd));
-	incref(&fd->ref);
+	incref(fd);
 	return fd;
 }
 
@@ -201,7 +252,7 @@
 void
 fddecref(Fd *fd)
 {
-	if(decref(&fd->ref) == 0) {
+	if(decref(fd) == 0) {
 		free(fd->fds);
 		free(fd);
 	}
@@ -240,5 +291,27 @@
 		fd->fds[n / 8] &= ~(1 << (n % 8));
 	else
 		fd->fds[n / 8] |= (1 << (n % 8));
+	wunlock(fd);
+}
+
+void
+fdclear(Fd *fd)
+{
+	int i, j, k;
+
+	wlock(fd);
+	if(fd->nfds == 0) {
+		wunlock(fd);
+		return;
+	}
+	for(i = 0; i < fd->nfds; i++) {
+		j = fd->fds[i];
+		for(k = 0; k < 8; k++)
+			if(j & (1<<k))
+				close(8 * i + k);
+	}
+	free(fd->fds);
+	fd->nfds = 0;
+	fd->fds = nil;
 	wunlock(fd);
 }
--- a/sys/src/cmd/5e/seg.c
+++ b/sys/src/cmd/5e/seg.c
@@ -13,10 +13,10 @@
 	incref(s);
 	s->start = start;
 	s->size = size;
-	s->ref = emalloc(size + sizeof(Ref));
-	memset(s->ref, 0, sizeof(Ref));
-	incref(s->ref);
-	s->data = s->ref + 1;
+	s->dref = emalloc(size + sizeof(Ref));
+	memset(s->dref, 0, sizeof(Ref));
+	incref(s->dref);
+	s->data = s->dref + 1;
 	if(idx == SEGBSS)
 		s->flags = SEGFLLOCK;
 	P->S[idx] = s;
@@ -31,8 +31,8 @@
 	for(s = P->S; s < P->S + SEGNUM; s++) {
 		if(*s == nil)
 			continue;
-		if(decref((*s)->ref) == 0)
-			free((*s)->ref);
+		if(decref((*s)->dref) == 0)
+			free((*s)->dref);
 		if(decref(*s) == 0)
 			free(*s);
 		*s = nil;
@@ -40,7 +40,7 @@
 }
 
 void *
-vaddr(u32int addr, Segment **seg)
+vaddr(u32int addr, u32int len, Segment **seg)
 {
 	Segment **ss, *s;
 
@@ -49,6 +49,8 @@
 			continue;
 		s = *ss;
 		if(addr >= s->start && addr < s->start + s->size) {
+			if(addr + len > s->start + s->size)
+				break;
 			if(s->flags & SEGFLLOCK)
 				rlock(&s->rw);
 			*seg = s;
@@ -55,17 +57,17 @@
 			return (char *)s->data + (addr - s->start);
 		}
 	}
-	sysfatal("fault %.8ux @ %.8ux", addr, P->R[15]);
+	suicide("fault %.8ux (%d) @ %.8ux", addr, len, P->R[15]);
 	return nil;
 }
 
 void *
-vaddrnol(u32int addr)
+vaddrnol(u32int addr, u32int len)
 {
 	Segment *seg;
 	void *ret;
 	
-	ret = vaddr(addr, &seg);
+	ret = vaddr(addr, len, &seg);
 	segunlock(seg);
 	return ret;
 }
@@ -84,7 +86,7 @@
 	void *targ, *ret;
 	Segment *seg;
 	
-	targ = vaddr(addr, &seg);
+	targ = vaddr(addr, len > 0 ? len : 0, &seg);
 	if((seg->flags & SEGFLLOCK) == 0) {
 		*copied = 0;
 		return targ;
@@ -104,7 +106,7 @@
 	void *targ;
 	Segment *seg;
 	
-	targ = vaddr(addr, &seg);
+	targ = vaddr(addr, len, &seg);
 	if((seg->flags & SEGFLLOCK) == 0) {
 		*buffered = 0;
 		return targ;
@@ -122,7 +124,7 @@
 
 	if(len <= 0)
 		return;
-	targ = vaddr(addr, &seg);
+	targ = vaddr(addr, len, &seg);
 	memmove(targ, data, len);
 	segunlock(seg);
 	free(data);
--- a/sys/src/cmd/5e/sys.c
+++ b/sys/src/cmd/5e/sys.c
@@ -9,7 +9,7 @@
 arg(int n)
 {
 	/* no locking necessary, since we're on the stack */
-	return *(u32int*) vaddrnol(P->R[13] + 4 + 4 * n);
+	return *(u32int*) vaddrnol(P->R[13] + 4 + 4 * n, 4);
 }
 
 static u64int
@@ -127,7 +127,7 @@
 	vlong n, *ret;
 	Segment *seg;
 	
-	ret = vaddr(arg(0), &seg);
+	ret = vaddr(arg(0), 8, &seg);
 	fd = arg(1);
 	n = argv(2);
 	type = arg(4);
@@ -202,7 +202,7 @@
 	if(arg(0) == 0)
 		exits(nil);
 	else
-		exits(vaddrnol(arg(0)));
+		exits(vaddrnol(arg(0), 0));
 }
 
 static void
@@ -218,10 +218,10 @@
 		sysfatal("bss length < 0, wtf?");
 	s = P->S[SEGBSS];
 	wlock(&s->rw);
-	s->ref = realloc(s->ref, v - s->start + 4);
-	if(s->ref == nil)
+	s->dref = realloc(s->dref, v - s->start + 4);
+	if(s->dref == nil)
 		sysfatal("error reallocating");
-	s->data = s->ref + 1;
+	s->data = s->dref + 1;
 	if(s->size < v - s->start)
 		memset((char*)s->data + s->size, 0, v - s->start - s->size);
 	s->size = v - s->start;
@@ -276,16 +276,17 @@
 	Process *p;
 	Segment *s, *t;
 	Fd *old;
-	enum {
-		RFORKPASS = RFENVG | RFCENVG | RFNOTEG | RFNOMNT | RFNAMEG | RFCNAMEG | RFNOWAIT | RFREND | RFFDG | RFCFDG,
-		RFORKHANDLED = RFPROC | RFMEM,
-	};
 	
 	flags = arg(0);
 	if(systrace)
 		fprint(2, "rfork(%#o)\n", flags);
-	if(flags & ~(RFORKPASS | RFORKHANDLED))
-		sysfatal("rfork with unhandled flags %#o", flags & ~(RFORKPASS | RFORKHANDLED));
+	if((flags & (RFFDG | RFCFDG)) == (RFFDG | RFCFDG) ||
+	   (flags & (RFNAMEG | RFCNAMEG)) == (RFNAMEG | RFCNAMEG) ||
+	   (flags & (RFENVG | RFCENVG)) == (RFENVG | RFCENVG)) {
+		P->R[0] = -1;
+		cherrstr("bad arg in syscall");
+		return;
+	}
 	if((flags & RFPROC) == 0) {
 		if(flags & RFFDG) {
 			old = P->fd;
@@ -297,9 +298,10 @@
 			P->fd = newfd();
 			fddecref(old);
 		}
-		P->R[0] = noteerr(rfork(flags & RFORKPASS), 0);
+		P->R[0] = noteerr(rfork(flags), 0);
 		return;
 	}
+	incref(&nproc);
 	p = emallocz(sizeof(Process));
 	memcpy(p, P, sizeof(Process));
 	for(i = 0; i < SEGNUM; i++) {
@@ -311,15 +313,15 @@
 			incref(t);
 			t->size = s->size;
 			t->start = s->start;
-			t->ref = emalloc(sizeof(Ref) + s->size);
-			memset(t->ref, 0, sizeof(Ref));
-			incref(t->ref);
-			t->data = t->ref + 1;
+			t->dref = emalloc(sizeof(Ref) + s->size);
+			memset(t->dref, 0, sizeof(Ref));
+			incref(t->dref);
+			t->data = t->dref + 1;
 			memcpy(t->data, s->data, s->size);
 			p->S[i] = t;
 		} else {
+			incref(s->dref);
 			incref(s);
-			incref(s->ref);
 		}
 	}
 	
@@ -328,15 +330,17 @@
 	else if(flags & RFCFDG)
 		p->fd = newfd();
 	else
-		incref(&P->fd->ref);
+		incref(P->fd);
 
-	rc = rfork(RFPROC | RFMEM | (flags & RFORKPASS));
-	if(rc < 0)
-		sysfatal("rfork: %r");
+	incref(P->path);
+	rc = rfork(RFMEM | flags);
+	if(rc < 0) /* this should NEVER happen */
+		sysfatal("rfork failed wtf: %r");
 	if(rc == 0) {
 		P = p;
 		atexit(cleanup);
 		P->pid = getpid();
+		addproc(P);
 	}
 	P->R[0] = rc;
 }
@@ -351,9 +355,9 @@
 	
 	name = arg(0);
 	argv = arg(1);
-	namet = strdup(vaddr(name, &seg1));
+	namet = strdup(vaddr(name, 0, &seg1));
 	segunlock(seg1);
-	argvt = vaddr(argv, &seg1);
+	argvt = vaddr(argv, 0, &seg1);
 	if(systrace)
 		fprint(2, "exec(%#ux=\"%s\", %#ux)\n", name, namet, argv);
 	for(argc = 0; argvt[argc]; argc++)
@@ -360,7 +364,7 @@
 		;
 	argvv = emalloc(sizeof(char *) * argc);
 	for(i = 0; i < argc; i++) {
-		argvv[i] = strdup(vaddr(argvt[i], &seg2));
+		argvv[i] = strdup(vaddr(argvt[i], 0, &seg2));
 		segunlock(seg2);
 	}
 	segunlock(seg1);