shithub: riscv

Download patch

ref: 8d51e7fa1a1dbcbde513c2b756d504c879598907
parent: 60bb408acca3b48b17f9158132849b894ad9f234
author: cinap_lenrek <[email protected]>
date: Sun Jan 26 14:01:36 EST 2020

kernel: implement portable userinit() and simplify process creation

replace machine specific userinit() by a portable
implemntation that uses kproc() to create the first
process. the initcode text is mapped using kmap(),
so there is no need for machine specific tmpmap()
functions.

initcode stack preparation should be done in init0()
where the stack is mapped and can be accessed directly.

replacing the machine specific userinit() allows some
big simplifications as sysrfork() and kproc() are now
the only callers of newproc() and we can avoid initializing
fields that we know are being initialized by these
callers.

rename autogenerated init.h and reboot.h headers.
the initcode[] and rebootcode[] blobs are now in *.i
files and hex generation was moved to portmkfile. the
machine specific mkfile only needs to specify how to
build rebootcode.out and initcode.out.

--- a/sys/src/9/bcm/init9.s
+++ /dev/null
@@ -1,1 +1,0 @@
-#include "../omap/init9.s"
--- a/sys/src/9/bcm/main.c
+++ b/sys/src/9/bcm/main.c
@@ -6,10 +6,9 @@
 #include "fns.h"
 #include "io.h"
 
-#include "init.h"
 #include <pool.h>
 
-#include "reboot.h"
+#include "rebootcode.i"
 
 /* Firmware compatibility */
 #define	Minfirmrev	326770
@@ -131,19 +130,6 @@
 {
 	char buf[2*KNAMELEN], **sp;
 
-	up->nerrlab = 0;
-	coherence();
-	spllo();
-
-	/*
-	 * These are o.k. because rootinit is null.
-	 * Then early kproc's will have a root and dot.
-	 */
-	up->slash = namec("#/", Atodir, 0, 0);
-	pathclose(up->slash->path);
-	up->slash->path = newpath("/");
-	up->dot = cclone(up->slash);
-
 	chandevinit();
 
 	if(!waserror()){
@@ -166,74 +152,7 @@
 	sp = (char**)(USTKTOP - sizeof(Tos) - 8 - sizeof(sp[0])*4);
 	sp[3] = sp[2] = sp[1] = nil;
 	strcpy(sp[0] = (char*)&sp[4], "boot");
-
 	touser((uintptr)sp);
-	assert(0);			/* shouldn't have returned */
-}
-
-/*
- *  create the first process
- */
-void
-userinit(void)
-{
-	Proc *p;
-	Segment *s;
-	KMap *k;
-	Page *pg;
-
-	/* no processes yet */
-	up = nil;
-
-	p = newproc();
-	p->pgrp = newpgrp();
-	p->egrp = smalloc(sizeof(Egrp));
-	p->egrp->ref = 1;
-	p->fgrp = dupfgrp(nil);
-	p->rgrp = newrgrp();
-	p->procmode = 0640;
-
-	kstrdup(&eve, "");
-	kstrdup(&p->text, "*init*");
-	kstrdup(&p->user, eve);
-
-	/*
-	 * Kernel Stack
-	 */
-	p->sched.pc = (uintptr)init0;
-	p->sched.sp = (uintptr)p->kstack+KSTACK-sizeof(up->s.args)-sizeof(uintptr);
-	p->sched.sp = STACKALIGN(p->sched.sp);
-
-	/*
-	 * User Stack
-	 *
-	 * Technically, newpage can't be called here because it
-	 * should only be called when in a user context as it may
-	 * try to sleep if there are no pages available, but that
-	 * shouldn't be the case here.
-	 */
-	s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG);
-	s->flushme++;
-	p->seg[SSEG] = s;
-	pg = newpage(1, 0, USTKTOP-BY2PG);
-	segpage(s, pg);
-	k = kmap(pg);
-	memset((void*)VA(k), 0, BY2PG);
-	kunmap(k);
-
-	/*
-	 * Text
-	 */
-	s = newseg(SG_TEXT, UTZERO, 1);
-	p->seg[TSEG] = s;
-	pg = newpage(1, 0, UTZERO);
-	pg->txtflush = ~0;
-	segpage(s, pg);
-	k = kmap(s->map[0]->pages[0]);
-	memmove((void*)VA(k), initcode, sizeof initcode);
-	kunmap(k);
-
-	ready(p);
 }
 
 void
--- a/sys/src/9/bcm/mkfile
+++ b/sys/src/9/bcm/mkfile
@@ -39,6 +39,7 @@
 	taslock.$O\
 	tod.$O\
 	xalloc.$O\
+	userinit.$O\
 
 OBJ=\
 	l.$O\
@@ -104,36 +105,22 @@
 
 arch.$O clock.$O fpiarm.$O main.$O mmu.$O screen.$O syscall.$O trap.$O: \
 	/$objtype/include/ureg.h
-
+arch.$O trap.$O main.$O: /sys/include/tos.h
 fpi.$O fpiarm.$O fpimem.$O: fpi.h
 l.$O lexception.$O lproc.$O mmu.$O: mem.h
 l.$O lexception.$O lproc.$O armv6.$O armv7.$O: arm.s
 armv7.$O: cache.v7.s
-main.$O: errstr.h init.h reboot.h
+main.$O: errstr.h rebootcode.i
 devmouse.$O mouse.$O screen.$O: screen.h
 usbdwc.$O: dwcotg.h ../port/usb.h
-arch.$O archbcm.$O archbcm2.$O clock.$O coproc.$O fpiarn.$O mmu.$O trap.$O vfp3.$O: arm.h mem.h
+arch.$O archbcm.$O archbcm2.$O clock.$O coproc.$O fpiarn.$O mmu.$O trap.$O vfp3.$O rebootcode.$O: arm.h mem.h
+rebootcode.$O: arm.s cache.v7.s
 
-init.h:D:	../port/initcode.c init9.s
-	$CC ../port/initcode.c
-	$AS init9.s
-	$LD -l -R1 -s -o init.out init9.$O initcode.$O /$objtype/lib/libc.a
-	{echo 'uchar initcode[]={'
-	 xd -1x <init.out |
-		sed -e 's/^[0-9a-f]+ //' -e 's/ ([0-9a-f][0-9a-f])/0x\1,/g'
-	 echo '};'} > init.h
+init9.$O:	../omap/init9.s
+	$AS	../omap/init9.s
 
-reboot.h:D:	rebootcode.s arm.s arm.h mem.h
-	$AS rebootcode.s
-	# -T arg is REBOOTADDR
-	$LD -l -s -T0x1c00 -R4 -o reboot.out rebootcode.$O
-	{echo 'uchar rebootcode[]={'
-	 xd -1x reboot.out |
-		sed -e '1,2d' -e 's/^[0-9a-f]+ //' -e 's/ ([0-9a-f][0-9a-f])/0x\1,/g'
-	 echo '};'} > reboot.h
+initcode.out:		init9.$O initcode.$O /$objtype/lib/libc.a
+	$LD -l -R1 -s -o $target $prereq
 
-errstr.h:D:	../port/mkerrstr ../port/error.h
-	rc ../port/mkerrstr > errstr.h
-
-$CONF.clean:
-	rm -rf $p$CONF s$p$CONF errstr.h reboot.h $CONF.c boot$CONF.c
+rebootcode.out:		rebootcode.$O
+	$LD -l -R4 -T0x1c00 -s -o $target $prereq
--- a/sys/src/9/bcm64/main.c
+++ b/sys/src/9/bcm64/main.c
@@ -6,9 +6,8 @@
 #include "fns.h"
 #include "../port/error.h"
 #include "io.h"
-#include "init.h"
 #include "sysreg.h"
-#include "reboot.h"
+#include "rebootcode.i"
 
 #include <pool.h>
 #include <libsec.h>
@@ -23,17 +22,6 @@
 {
 	char buf[2*KNAMELEN], **sp;
 
-	up->nerrlab = 0;
-	spllo();
-
-	/*
-	 * These are o.k. because rootinit is null.
-	 * Then early kproc's will have a root and dot.
-	 */
-	up->slash = namec("#/", Atodir, 0, 0);
-	pathclose(up->slash->path);
-	up->slash->path = newpath("/");
-	up->dot = cclone(up->slash);
 	chandevinit();
 
 	if(!waserror()){
@@ -57,76 +45,7 @@
 	sp[3] = sp[2] = sp[1] = nil;
 	strcpy(sp[1] = (char*)&sp[4], "boot");
 	sp[0] = (void*)&sp[1];
-
 	touser((uintptr)sp);
-
-	assert(0);			/* shouldn't have returned */
-}
-
-/*
- *  create the first process
- */
-void
-userinit(void)
-{
-	Proc *p;
-	Segment *s;
-	KMap *k;
-	Page *pg;
-
-	/* no processes yet */
-	up = nil;
-
-	p = newproc();
-	p->pgrp = newpgrp();
-	p->egrp = smalloc(sizeof(Egrp));
-	p->egrp->ref = 1;
-	p->fgrp = dupfgrp(nil);
-	p->rgrp = newrgrp();
-	p->procmode = 0640;
-
-	kstrdup(&eve, "");
-	kstrdup(&p->text, "*init*");
-	kstrdup(&p->user, eve);
-
-	/*
-	 * Kernel Stack
-	 */
-	p->sched.pc = (uintptr)init0;
-	p->sched.sp = (uintptr)p->kstack+KSTACK-sizeof(up->s.args)-sizeof(uintptr);
-	p->sched.sp = STACKALIGN(p->sched.sp);
-	*(void**)p->sched.sp = kproc; // fake
-
-	/*
-	 * User Stack
-	 *
-	 * Technically, newpage can't be called here because it
-	 * should only be called when in a user context as it may
-	 * try to sleep if there are no pages available, but that
-	 * shouldn't be the case here.
-	 */
-	s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG);
-	s->flushme++;
-	p->seg[SSEG] = s;
-	pg = newpage(1, 0, USTKTOP-BY2PG);
-	segpage(s, pg);
-	k = kmap(pg);
-	memset((void*)VA(k), 0, BY2PG);
-	kunmap(k);
-
-	/*
-	 * Text
-	 */
-	s = newseg(SG_TEXT, UTZERO, 1);
-	p->seg[TSEG] = s;
-	pg = newpage(1, 0, UTZERO);
-	pg->txtflush = ~0;
-	segpage(s, pg);
-	k = kmap(pg);
-	memmove((void*)VA(k), initcode, sizeof initcode);
-	kunmap(k);
-
-	ready(p);
 }
 
 void
--- a/sys/src/9/bcm64/mkfile
+++ b/sys/src/9/bcm64/mkfile
@@ -37,6 +37,7 @@
 	taslock.$O\
 	tod.$O\
 	xalloc.$O\
+	userinit.$O\
 
 OBJ=\
 	l.$O\
@@ -99,11 +100,11 @@
 
 arch.$O clock.$O fpiarm.$O main.$O mmu.$O screen.$O syscall.$O trap.$O: \
 	/$objtype/include/ureg.h
+trap.$O main.$O: /sys/include/tos.h
+l.$O cache.v8.$O mmu.$O rebootcode.$O: mem.h
+l.$O cache.v8.$O archbcm3.$O clock.$O fpu.$O trap.$O mmu.$O rebootcode.$O: sysreg.h
+main.$O: rebootcode.i
 
-l.$O cache.v8.$O mmu.$O: mem.h
-l.$O cache.v8.$O archbcm3.$O clock.$O fpu.$O trap.$O mmu.$O: sysreg.h
-main.$O: reboot.h
-
 devmouse.$O mouse.$O screen.$O: screen.h
 usbdwc.$O: dwcotg.h ../port/usb.h
 
@@ -114,26 +115,11 @@
 dwcotg.h:D: ../bcm/dwcotg.h
 	echo '#include "../bcm/dwcotg.h"' > dwcotg.h
 
-init.h:D:	../port/initcode.c init9.s
-	$CC ../port/initcode.c
-	$AS init9.s
-	$LD -l -R1 -s -o init.out init9.$O initcode.$O /$objtype/lib/libc.a
-	{echo 'uchar initcode[]={'
-	 xd -1x <init.out |
-		sed -e 's/^[0-9a-f]+ //' -e 's/ ([0-9a-f][0-9a-f])/0x\1,/g'
-	 echo '};'} > init.h
+initcode.out:		init9.$O initcode.$O /$objtype/lib/libc.a
+	$LD -l -R1 -s -o $target $prereq
 
-reboot.h:D:	rebootcode.s cache.v8.$O mem.h sysreg.h
-	$AS rebootcode.s
-	# -T arg is REBOOTADDR
-	$LD -l -o reboot.out -H6 -R1 -T0x1c00 rebootcode.$O cache.v8.$O
-	{echo 'uchar rebootcode[]={'
-	 xd -1x reboot.out |
-		sed -e 's/^[0-9a-f]+ //' -e 's/ ([0-9a-f][0-9a-f])/0x\1,/g'
-	 echo '};'} > reboot.h
+rebootcode.out:		rebootcode.$O cache.v8.$O
+	$LD -l -H6 -R1 -T0x1c00 -s -o $target $prereq
 
-errstr.h:D:	../port/mkerrstr ../port/error.h
-	rc ../port/mkerrstr > errstr.h
-
 $CONF.clean:
-	rm -rf $p$CONF s$p$CONF errstr.h reboot.h screen.h dwcotg.h $CONF.c boot$CONF.c
+	rm -rf $p$CONF s$p$CONF errstr.h screen.h dwcotg.h $CONF.c boot$CONF.c
--- a/sys/src/9/bcm64/trap.c
+++ b/sys/src/9/bcm64/trap.c
@@ -628,9 +628,6 @@
 	cureg = (Ureg*) (p->sched.sp + 16);
 	memmove(cureg, ureg, sizeof(Ureg));
 	cureg->r0 = 0;
-
-	p->psstate = 0;
-	p->insyscall = 0;
 }
 
 uintptr
--- a/sys/src/9/cycv/main.c
+++ b/sys/src/9/cycv/main.c
@@ -1,13 +1,12 @@
 #include "u.h"
+#include "tos.h"
 #include "../port/lib.h"
 #include "mem.h"
 #include "dat.h"
 #include "fns.h"
-#include "init.h"
 #include "pool.h"
 #include "io.h"
 #include "../port/error.h"
-#include "tos.h"
 
 Conf conf;
 int normalprint, delaylink;
@@ -143,22 +142,14 @@
 	imagmem->maxsize = kmem - (kmem/10);
 }
 
-static void
+void
 init0(void)
 {
 	char buf[ERRMAX], **sp;
 	int i;
 
-	up->nerrlab = 0;
-	spllo();
-	
-	up->slash = namec("#/", Atodir, 0, 0);
-	pathclose(up->slash->path);
-	up->slash->path = newpath("/");
-	up->dot = cclone(up->slash);
-	
 	chandevinit();
-	
+
 	if(!waserror()){
 		ksetenv("cputype", "arm", 0);
 		if(cpuserver)
@@ -181,55 +172,7 @@
 	sp[3] = sp[2] = nil;
 	strcpy(sp[1] = (char*)&sp[4], "boot");
 	sp[0] = nil;
-	touser(sp);
-}
-
-void
-userinit(void)
-{
-	Proc *p;
-	Segment *s;
-	void *v;
-	Page *pg;
-	
-	p = newproc();
-	p->pgrp = newpgrp();
-	p->egrp = smalloc(sizeof(Egrp));
-	p->egrp->ref = 1;
-	p->fgrp = dupfgrp(nil);
-	p->rgrp = newrgrp();
-	p->procmode = 0640;
-	
-	kstrdup(&eve, "");
-	kstrdup(&p->text, "*init*");
-	kstrdup(&p->user, eve);
-	
-	procsetup(p);
-	
-	p->sched.pc = (ulong)init0;
-	p->sched.sp = (ulong)p->kstack + KSTACK - (sizeof(Sargs) + BY2WD);
-	
-	s = newseg(SG_STACK, USTKTOP - USTKSIZE, USTKSIZE / BY2PG);
-	p->seg[SSEG] = s;
-	pg = newpage(0, 0, USTKTOP - BY2PG);
-	segpage(s, pg);
-	v = tmpmap(pg->pa);
-	memset(v, 0, BY2PG);
-	tmpunmap(v);
-	
-	s = newseg(SG_TEXT, UTZERO, 1);
-	s->flushme++;
-	p->seg[TSEG] = s;
-	pg = newpage(0, 0, UTZERO);
-	pg->txtflush = ~0;
-
-	segpage(s, pg);
-	v = tmpmap(pg->pa);
-	memset(v, 0, BY2PG);
-	memmove(v, initcode, sizeof(initcode));
-	tmpunmap(v);
-	
-	ready(p);
+ 	touser(sp);
 }
 
 void
--- a/sys/src/9/cycv/mkfile
+++ b/sys/src/9/cycv/mkfile
@@ -39,6 +39,7 @@
 	random.$O\
 	rdb.$O\
 	syscallfmt.$O\
+	userinit.$O\
 
 OBJ=\
 	ltrap.$O\
@@ -74,14 +75,10 @@
 <../port/portmkfile
 <|../port/mkbootrules $CONF
 
-init.h:D: ../port/initcode.c init9.s
-	$CC ../port/initcode.c
-	$AS init9.s
-	$LD -l -R1 -s -o init.out init9.$O initcode.$O /arm/lib/libc.a
-	{echo 'uchar initcode[]={'
-	 xd -1x <init.out |
-		sed -e 's/^[0-9a-f]+ //' -e 's/ ([0-9a-f][0-9a-f])/0x\1,/g'
-	 echo '};'} > init.h
+trap.$O main.$O: /sys/include/tos.h
+
+initcode.out: init9.$O initcode.$O /$objtype/lib/libc.a
+	$LD -l -R1 -s -o $target $prereq
 
 install:V:	$p$CONF $p$CONF.u
 	cp $p$CONF $p$CONF.u /$objtype/
--- a/sys/src/9/cycv/trap.c
+++ b/sys/src/9/cycv/trap.c
@@ -569,9 +569,6 @@
 	cureg = (Ureg*) p->sched.sp;
 	memmove(cureg, ureg, sizeof(Ureg));
 	cureg->r0 = 0;
-
-	p->psstate = 0;
-	p->insyscall = 0;
 }
 
 uintptr
--- a/sys/src/9/kw/fns.h
+++ b/sys/src/9/kw/fns.h
@@ -104,7 +104,6 @@
 /*
  * Miscellaneous machine dependent stuff.
  */
-extern char* getenv(char*, char*, int);
 char*	getconf(char*);
 uintptr mmukmap(uintptr, uintptr, usize);
 uintptr mmukunmap(uintptr, uintptr, usize);
--- a/sys/src/9/kw/init9.s
+++ /dev/null
@@ -1,25 +1,0 @@
-/*
- * This is the same as the C programme:
- *
- *	void
- *	main(char* argv0)
- *	{
- *		startboot(argv0, &argv0);
- *	}
- *
- * It is in assembler because SB needs to be
- * set and doing this in C drags in too many
- * other routines.
- */
-TEXT main(SB), 1, $8
-	MOVW	$setR12(SB), R12		/* load the SB */
-	MOVW	$boot(SB), R0
-
-	ADD	$12, R13, R1			/* pointer to 0(FP) */
-
-	MOVW	R0, 4(R13)			/* pass argc, argv */
-	MOVW	R1, 8(R13)
-
-	BL	startboot(SB)
-_loop:
-	B	_loop
--- a/sys/src/9/kw/main.c
+++ b/sys/src/9/kw/main.c
@@ -1,14 +1,14 @@
 #include "u.h"
+#include "tos.h"
 #include "../port/lib.h"
 #include "mem.h"
 #include "dat.h"
 #include "fns.h"
 
-#include "init.h"
 #include "arm.h"
 #include <pool.h>
 
-#include "reboot.h"
+#include "rebootcode.i"
 
 /*
  * Where configuration info is left for the loaded programme.
@@ -26,21 +26,6 @@
 uintptr kseg0 = KZERO;
 Mach* machaddr[MAXMACH];
 
-/*
- * Option arguments from the command line.
- * oargv[0] is the boot file.
- * Optionsinit() is called from multiboot()
- * or some other machine-dependent place
- * to set it all up.
- */
-static int oargc;
-static char* oargv[20];
-static char oargb[128];
-static int oargblen;
-static char oenv[4096];
-
-static uintptr sp;		/* XXX - must go - user stack of init proc */
-
 int vflag;
 char debug[256];
 
@@ -150,44 +135,6 @@
 	}
 }
 
-static void
-optionsinit(char* s)
-{
-	char *o;
-
-	o = strecpy(oargb, oargb+sizeof(oargb), s)+1;
-	if(getenv("bootargs", o, o - oargb) != nil)
-		*(o-1) = ' ';
-
-	oargblen = strlen(oargb);
-	oargc = tokenize(oargb, oargv, nelem(oargv)-1);
-	oargv[oargc] = nil;
-}
-
-char*
-getenv(char* name, char* buf, int n)
-{
-	char *e, *p, *q;
-
-	p = oenv;
-	while(*p != 0){
-		if((e = strchr(p, '=')) == nil)
-			break;
-		for(q = name; p < e; p++){
-			if(*p != *q)
-				break;
-			q++;
-		}
-		if(p == e && *q == 0){
-			strecpy(buf, buf+n, e+1);
-			return buf;
-		}
-		p += strlen(p)+1;
-	}
-
-	return nil;
-}
-
 #include "io.h"
 
 typedef struct Spiregs Spiregs;
@@ -274,7 +221,6 @@
 	archreset();
 	mmuinit();
 
-	optionsinit("/boot/boot boot");
 	quotefmtinstall();
 	archconsole();
 wave(' ');
@@ -406,23 +352,9 @@
 void
 init0(void)
 {
+	char buf[2*KNAMELEN], **sp;
 	int i;
-	char buf[2*KNAMELEN];
 
-	assert(up != nil);
-	up->nerrlab = 0;
-	coherence();
-	spllo();
-
-	/*
-	 * These are o.k. because rootinit is null.
-	 * Then early kproc's will have a root and dot.
-	 */
-	up->slash = namec("#/", Atodir, 0, 0);
-	pathclose(up->slash->path);
-	up->slash->path = newpath("/");
-	up->dot = cclone(up->slash);
-
 	chandevinit();
 
 	if(!waserror()){
@@ -443,112 +375,10 @@
 	}
 	kproc("alarm", alarmkproc, 0);
 
-	touser(sp);
-}
-
-static void
-bootargs(uintptr base)
-{
-	int i;
-	ulong ssize;
-	char **av, *p;
-
-	/*
-	 * Push the boot args onto the stack.
-	 * The initial value of the user stack must be such
-	 * that the total used is larger than the maximum size
-	 * of the argument list checked in syscall.
-	 */
-	i = oargblen+1;
-	p = (void*)(STACKALIGN(base + BY2PG - sizeof(up->s.args) - i));
-	memmove(p, oargb, i);
-
-	/*
-	 * Now push argc and the argv pointers.
-	 * This isn't strictly correct as the code jumped to by
-	 * touser in init9.s calls startboot (port/initcode.c) which
-	 * expects arguments
-	 * 	startboot(char *argv0, char **argv)
-	 * not the usual (int argc, char* argv[]), but argv0 is
-	 * unused so it doesn't matter (at the moment...).
-	 */
-	av = (char**)(p - (oargc+2)*sizeof(char*));
-	ssize = base + BY2PG - (uintptr)av;
-	*av++ = (char*)oargc;
-	for(i = 0; i < oargc; i++)
-		*av++ = (oargv[i] - oargb) + (p - base) + (USTKTOP - BY2PG);
-	*av = nil;
-
-	/*
-	 * Leave space for the return PC of the
-	 * caller of initcode.
-	 */
-	sp = USTKTOP - ssize - sizeof(void*);
-}
-
-/*
- *  create the first process
- */
-void
-userinit(void)
-{
-	Proc *p;
-	Segment *s;
-	KMap *k;
-	Page *pg;
-
-	/* no processes yet */
-	up = nil;
-
-	p = newproc();
-	p->pgrp = newpgrp();
-	p->egrp = smalloc(sizeof(Egrp));
-	p->egrp->ref = 1;
-	p->fgrp = dupfgrp(nil);
-	p->rgrp = newrgrp();
-	p->procmode = 0640;
-
-	kstrdup(&eve, "");
-	kstrdup(&p->text, "*init*");
-	kstrdup(&p->user, eve);
-
-	/*
-	 * Kernel Stack
-	 */
-	p->sched.pc = (uintptr)init0;
-	p->sched.sp = (uintptr)p->kstack+KSTACK-sizeof(up->s.args)-sizeof(uintptr);
-	p->sched.sp = STACKALIGN(p->sched.sp);
-
-	/*
-	 * User Stack
-	 *
-	 * Technically, newpage can't be called here because it
-	 * should only be called when in a user context as it may
-	 * try to sleep if there are no pages available, but that
-	 * shouldn't be the case here.
-	 */
-	s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG);
-	p->seg[SSEG] = s;
-	pg = newpage(1, 0, USTKTOP-BY2PG);
-	segpage(s, pg);
-	k = kmap(pg);
-	bootargs(VA(k));
-	kunmap(k);
-
-	/*
-	 * Text
-	 */
-	s = newseg(SG_TEXT, UTZERO, 1);
-	s->flushme++;
-	p->seg[TSEG] = s;
-	pg = newpage(1, 0, UTZERO);
-	pg->txtflush = ~0;
-	segpage(s, pg);
-	k = kmap(s->map[0]->pages[0]);
-	memmove((void*)VA(k), initcode, sizeof initcode);
-	kunmap(k);
-
-	ready(p);
+	sp = (char**)(USTKTOP - sizeof(Tos) - 8 - sizeof(sp[0])*4);
+	sp[3] = sp[2] = sp[1] = nil;
+	strcpy(sp[0] = (char*)&sp[4], "boot");
+	touser((uintptr)sp);
 }
 
 Conf conf;			/* XXX - must go - gag */
--- a/sys/src/9/kw/mkfile
+++ b/sys/src/9/kw/mkfile
@@ -39,6 +39,7 @@
 	tod.$O\
 	xalloc.$O\
 	random.$O\
+	userinit.$O\
 
 OBJ=\
 	l.$O\
@@ -122,36 +123,25 @@
 
 arch.$O clock.$O fpiarm.$O main.$O mmu.$O screen.$O sdscsi.$O syscall.$O \
 	trap.$O: /$objtype/include/ureg.h
-
+arch.$O syscall.$O main.$O: /sys/include/tos.h
 archkw.$O devether.$O ether1116.$O ethermii.$O: \
 	ethermii.h ../port/etherif.h ../port/netif.h
 archkw.$O devflash.$O flashkw.$O: ../port/flashif.h
 fpi.$O fpiarm.$O fpimem.$O: fpi.h
-l.$O lexception.$O lproc.$O mmu.$O: arm.s arm.h mem.h
-main.$O:	errstr.h init.h reboot.h
+l.$O lexception.$O lproc.$O mmu.$O rebootcode.$O: arm.s arm.h mem.h
+main.$O:	errstr.h rebootcode.i
 mouse.$O:	screen.h
 devusb.$O:	../port/usb.h
 usbehci.$O usbohci.$O usbuhci.$O: ../port/usb.h usbehci.h
 
-init.h:D:	../port/initcode.c init9.s
-	$CC ../port/initcode.c
-	$AS init9.s
-	$LD -l -R1 -s -o init.out init9.$O initcode.$O /$objtype/lib/libc.a
-	{echo 'uchar initcode[]={'
-	 xd -1x <init.out |
-		sed -e 's/^[0-9a-f]+ //' -e 's/ ([0-9a-f][0-9a-f])/0x\1,/g'
-	 echo '};'} > init.h
+init9.$O:	../omap/init9.s
+	$AS ../omap/init9.s
 
-reboot.h:D:	rebootcode.s arm.s arm.h mem.h
-	$AS rebootcode.s
-	# -lc is only for memmove.  -T arg is PADDR(REBOOTADDR)
-	$LD -l -a -s -T0x100 -R4 -o reboot.out rebootcode.$O -lc >reboot.list
-	{echo 'uchar rebootcode[]={'
-	 xd -1x reboot.out |
-		sed -e '1,2d' -e 's/^[0-9a-f]+ //' -e 's/ ([0-9a-f][0-9a-f])/0x\1,/g'
-	 echo '};'} > reboot.h
-errstr.h:D:	../port/mkerrstr ../port/error.h
-	rc ../port/mkerrstr > errstr.h
+initcode.out:		init9.$O initcode.$O /$objtype/lib/libc.a
+	$LD -l -R1 -s -o $target $prereq
+
+rebootcode.out:		rebootcode.$O
+	$LD -l -R4 -T0x100 -s -o $target $prereq -lc
 
 plug.clean:
 	rm -rf $p$CONF s$p$CONF armpaq paqdisk $CONF.c boot$CONF.c ../boot/libboot.a5
--- a/sys/src/9/kw/syscall.c
+++ b/sys/src/9/kw/syscall.c
@@ -325,8 +325,4 @@
 
 	/* syscall returns 0 for child */
 	cureg->r0 = 0;
-
-	/* Things from bottom of syscall which were never executed */
-	p->psstate = 0;
-	p->insyscall = 0;
 }
--- a/sys/src/9/mtx/main.c
+++ b/sys/src/9/mtx/main.c
@@ -1,10 +1,10 @@
 #include	"u.h"
+#include	"tos.h"
 #include	"../port/lib.h"
 #include	"mem.h"
 #include	"dat.h"
 #include	"fns.h"
 #include	"io.h"
-#include	"init.h"
 #include	"pool.h"
 
 Conf	conf;
@@ -101,23 +101,8 @@
 void
 init0(void)
 {
-//	char **p, *q, name[KNAMELEN];
-//	int n;
 	char buf[2*KNAMELEN];
 
-	up->nerrlab = 0;
-
-	spllo();
-
-	/*
-	 * These are o.k. because rootinit is null.
-	 * Then early kproc's will have a root and dot.
-	 */
-	up->slash = namec("#/", Atodir, 0, 0);
-	pathclose(up->slash->path);
-	up->slash->path = newpath("/");
-	up->dot = cclone(up->slash);
-
 	chandevinit();
 
 	if(!waserror()){
@@ -128,82 +113,11 @@
 			ksetenv("service", "cpu", 0);
 		else
 			ksetenv("service", "terminal", 0);
-		
-/*
-		for(p = confenv; *p; p++) {
-			q = strchr(p[0], '=');
-			if(q == 0)
-				continue;
-			n = q-p[0];
-			if(n >= KNAMELEN)
-				n = KNAMELEN-1;
-			memmove(name, p[0], n);
-			name[n] = 0;
-			if(name[0] != '*')
-				ksetenv(name, q+1, 0);
-			ksetenv(name, q+1, 1);
-		}
-*/
 		poperror();
 	}
 	kproc("alarm", alarmkproc, 0);
 	kproc("mmusweep", mmusweep, 0);
-	touser((void*)(USTKTOP-8));
-}
-
-void
-userinit(void)
-{
-	Proc *p;
-	Segment *s;
-	KMap *k;
-	Page *pg;
-
-	p = newproc();
-	p->pgrp = newpgrp();
-	p->egrp = smalloc(sizeof(Egrp));
-	p->egrp->ref = 1;
-	p->fgrp = dupfgrp(nil);
-	p->rgrp = newrgrp();
-	p->procmode = 0640;
-
-	kstrdup(&eve, "");
-	kstrdup(&p->text, "*init*");
-	kstrdup(&p->user, eve);
-
-	p->fpstate = FPinit;
-
-	/*
-	 * Kernel Stack
-	 *
-	 * N.B. The -12 for the stack pointer is important.
-	 *	4 bytes for gotolabel's return PC
-	 */
-	p->sched.pc = (ulong)init0;
-	p->sched.sp = (ulong)p->kstack+KSTACK-(sizeof(Sargs)+BY2WD);
-
-	/*
-	 * User Stack
-	 */
-	s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG);
-	p->seg[SSEG] = s;
-	pg = newpage(1, 0, USTKTOP-BY2PG);
-	segpage(s, pg);
-
-	/*
-	 * Text
-	 */
-	s = newseg(SG_TEXT, UTZERO, 1);
-	s->flushme++;
-	p->seg[TSEG] = s;
-	pg = newpage(1, 0, UTZERO);
-	pg->txtflush = ~0;
-	segpage(s, pg);
-	k = kmap(s->map[0]->pages[0]);
-	memmove((ulong*)VA(k), initcode, sizeof initcode);
-	kunmap(k);
-
-	ready(p);
+	touser((void*)(USTKTOP - sizeof(Tos)));
 }
 
 /* still to do */
--- a/sys/src/9/mtx/mkfile
+++ b/sys/src/9/mtx/mkfile
@@ -36,6 +36,7 @@
 	tod.$O\
 	xalloc.$O\
 	random.$O\
+	userinit.$O\
 
 OBJ=\
 	l.$O\
@@ -79,15 +80,12 @@
 
 clock.$O:	/$objtype/include/ureg.h
 devether.$O:	/$objtype/include/ureg.h
-main.$O:	/$objtype/include/ureg.h errstr.h init.h
-trap.$O:	/$objtype/include/ureg.h
+main.$O:	/$objtype/include/ureg.h errstr.h
+trap.$O:	/$objtype/include/ureg.h /sys/include/tos.h
 
 $ETHER: 	../port/etherif.h ../port/netif.h
 
-init.h:	initcode /sys/src/libc/9syscall/sys.h
+initcode.$O:	initcode /sys/src/libc/9syscall/sys.h
 	$AS initcode
-	$LD -l -s -R4 -o init.out initcode.$O -lc
-	{echo 'uchar initcode[]={'
-	 xd -r -1x init.out |
-		sed -e 's/^[0-9a-f]+ //' -e 's/ ([0-9a-f][0-9a-f])/0x\1,/g'
-	 echo '};'} > init.h
+initcode.out:		initcode.$O
+	$LD -l -R4 -s -o $target $prereq
--- a/sys/src/9/mtx/trap.c
+++ b/sys/src/9/mtx/trap.c
@@ -560,10 +560,6 @@
 	cur = (Ureg*)(p->sched.sp+2*BY2WD);
 	memmove(cur, ur, sizeof(Ureg));
 	cur->r3 = 0;
-	
-	/* Things from bottom of syscall we never got to execute */
-	p->psstate = 0;
-	p->insyscall = 0;
 }
 
 uintptr
--- a/sys/src/9/omap/fns.h
+++ b/sys/src/9/omap/fns.h
@@ -120,7 +120,6 @@
 /*
  * Miscellaneous machine dependent stuff.
  */
-extern char* getenv(char*, char*, int);
 char*	getconf(char*);
 uintptr mmukmap(uintptr, uintptr, usize);
 uintptr mmukunmap(uintptr, uintptr, usize);
--- a/sys/src/9/omap/main.c
+++ b/sys/src/9/omap/main.c
@@ -1,4 +1,5 @@
 #include "u.h"
+#include "tos.h"
 #include "../port/lib.h"
 #include "mem.h"
 #include "dat.h"
@@ -5,10 +6,9 @@
 #include "fns.h"
 #include "io.h"
 
-#include "init.h"
 #include <pool.h>
 
-#include "reboot.h"
+#include "rebootcode.i"
 
 /*
  * Where configuration info is left for the loaded programme.
@@ -30,21 +30,6 @@
 uintptr kseg0 = KZERO;
 Mach* machaddr[MAXMACH];
 
-/*
- * Option arguments from the command line.
- * oargv[0] is the boot file.
- * Optionsinit() is called from multiboot()
- * or some other machine-dependent place
- * to set it all up.
- */
-static int oargc;
-static char* oargv[20];
-static char oargb[128];
-static int oargblen;
-static char oenv[4096];
-
-static uintptr sp;		/* XXX - must go - user stack of init proc */
-
 int vflag;
 int normalprint;
 char debug[256];
@@ -152,45 +137,6 @@
 	}
 }
 
-static void
-optionsinit(char* s)
-{
-	char *o;
-
-	strcpy(oenv, "");
-	o = strecpy(oargb, oargb+sizeof(oargb), s)+1;
-	if(getenv("bootargs", o, o - oargb) != nil)
-		*(o-1) = ' ';
-
-	oargblen = strlen(oargb);
-	oargc = tokenize(oargb, oargv, nelem(oargv)-1);
-	oargv[oargc] = nil;
-}
-
-char*
-getenv(char* name, char* buf, int n)
-{
-	char *e, *p, *q;
-
-	p = oenv;
-	while(*p != 0){
-		if((e = strchr(p, '=')) == nil)
-			break;
-		for(q = name; p < e; p++){
-			if(*p != *q)
-				break;
-			q++;
-		}
-		if(p == e && *q == 0){
-			strecpy(buf, buf+n, e+1);
-			return buf;
-		}
-		p += strlen(p)+1;
-	}
-
-	return nil;
-}
-
 void
 main(void)
 {
@@ -222,7 +168,6 @@
 	machinit();
 	mmuinit();
 
-	optionsinit("/boot/boot boot");
 	quotefmtinstall();
 
 	/* want plan9.ini to be able to affect memory sizing in confinit */
@@ -390,22 +335,9 @@
 void
 init0(void)
 {
+	char buf[2*KNAMELEN], **sp;
 	int i;
-	char buf[2*KNAMELEN];
 
-	up->nerrlab = 0;
-	coherence();
-	spllo();
-
-	/*
-	 * These are o.k. because rootinit is null.
-	 * Then early kproc's will have a root and dot.
-	 */
-	up->slash = namec("#/", Atodir, 0, 0);
-	pathclose(up->slash->path);
-	up->slash->path = newpath("/");
-	up->dot = cclone(up->slash);
-
 	dmatest();		/* needs `up' set, so can't do it earlier */
 	chandevinit();
 	i8250console();		/* might be redundant, but harmless */
@@ -430,112 +362,11 @@
 		poperror();
 	}
 	kproc("alarm", alarmkproc, 0);
-	touser(sp);
-}
 
-static void
-bootargs(uintptr base)
-{
-	int i;
-	ulong ssize;
-	char **av, *p;
-
-	/*
-	 * Push the boot args onto the stack.
-	 * The initial value of the user stack must be such
-	 * that the total used is larger than the maximum size
-	 * of the argument list checked in syscall.
-	 */
-	i = oargblen+1;
-	p = (void*)(STACKALIGN(base + BY2PG - sizeof(up->s.args) - i));
-	memmove(p, oargb, i);
-
-	/*
-	 * Now push argc and the argv pointers.
-	 * This isn't strictly correct as the code jumped to by
-	 * touser in init9.s calls startboot (port/initcode.c) which
-	 * expects arguments
-	 * 	startboot(char *argv0, char **argv)
-	 * not the usual (int argc, char* argv[]), but argv0 is
-	 * unused so it doesn't matter (at the moment...).
-	 */
-	av = (char**)(p - (oargc+2)*sizeof(char*));
-	ssize = base + BY2PG - (uintptr)av;
-	*av++ = (char*)oargc;
-	for(i = 0; i < oargc; i++)
-		*av++ = (oargv[i] - oargb) + (p - base) + (USTKTOP - BY2PG);
-	*av = nil;
-
-	/*
-	 * Leave space for the return PC of the
-	 * caller of initcode.
-	 */
-	sp = USTKTOP - ssize - sizeof(void*);
-}
-
-/*
- *  create the first process
- */
-void
-userinit(void)
-{
-	Proc *p;
-	Segment *s;
-	KMap *k;
-	Page *pg;
-
-	/* no processes yet */
-	up = nil;
-
-	p = newproc();
-	p->pgrp = newpgrp();
-	p->egrp = smalloc(sizeof(Egrp));
-	p->egrp->ref = 1;
-	p->fgrp = dupfgrp(nil);
-	p->rgrp = newrgrp();
-	p->procmode = 0640;
-
-	kstrdup(&eve, "");
-	kstrdup(&p->text, "*init*");
-	kstrdup(&p->user, eve);
-
-	/*
-	 * Kernel Stack
-	 */
-	p->sched.pc = (uintptr)init0;
-	p->sched.sp = (uintptr)p->kstack+KSTACK-sizeof(up->s.args)-sizeof(uintptr);
-	p->sched.sp = STACKALIGN(p->sched.sp);
-
-	/*
-	 * User Stack
-	 *
-	 * Technically, newpage can't be called here because it
-	 * should only be called when in a user context as it may
-	 * try to sleep if there are no pages available, but that
-	 * shouldn't be the case here.
-	 */
-	s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG);
-	s->flushme++;
-	p->seg[SSEG] = s;
-	pg = newpage(1, 0, USTKTOP-BY2PG);
-	segpage(s, pg);
-	k = kmap(pg);
-	bootargs(VA(k));
-	kunmap(k);
-
-	/*
-	 * Text
-	 */
-	s = newseg(SG_TEXT, UTZERO, 1);
-	p->seg[TSEG] = s;
-	pg = newpage(1, 0, UTZERO);
-	pg->txtflush = ~0;
-	segpage(s, pg);
-	k = kmap(s->map[0]->pages[0]);
-	memmove((void*)VA(k), initcode, sizeof initcode);
-	kunmap(k);
-
-	ready(p);
+	sp = (char**)(USTKTOP - sizeof(Tos) - 8 - sizeof(sp[0])*4);
+	sp[3] = sp[2] = sp[1] = nil;
+	strcpy(sp[0] = (char*)&sp[4], "boot");
+	touser((uintptr)sp);
 }
 
 Conf conf;			/* XXX - must go - gag */
--- a/sys/src/9/omap/mkfile
+++ b/sys/src/9/omap/mkfile
@@ -39,6 +39,7 @@
 	tod.$O\
 	xalloc.$O\
 	random.$O\
+	userinit.$O\
 
 OBJ=\
 	l.$O\
@@ -100,35 +101,20 @@
 
 arch.$O clock.$O fpiarm.$O main.$O mmu.$O screen.$O sdscsi.$O syscall.$O \
 	trap.$O: /$objtype/include/ureg.h
-
+arch.$O syscall.$O: /sys/include/tos.h
 archomap.$O devether.$0 ether9221.$O: ../port/etherif.h ../port/netif.h
 archomap.$O devflash.$O flashbeagle.$O flashigep.$O: ../port/flashif.h
 ecc.$O flashbeagle.$O flashigep.$O: ../port/nandecc.h io.h
 fpi.$O fpiarm.$O fpimem.$O: fpi.h
-l.$O lexception.$O lproc.$O mmu.$O: arm.s arm.h mem.h
+l.$O lexception.$O lproc.$O mmu.$O rebootcode.$O: arm.s arm.h mem.h
 l.$O rebootcode.$O: cache.v7.s
-main.$O: errstr.h init.h reboot.h
+main.$O: errstr.h rebootcode.i
 devdss.$O devmouse.$O mouse.$O screen.$O: screen.h
 devusb.$O: ../port/usb.h
 usbehci.$O usbohci.$O usbuhci.$O: ../port/usb.h usbehci.h
 
-init.h:D:	../port/initcode.c init9.s
-	$CC ../port/initcode.c
-	$AS init9.s
-	$LD -l -R1 -s -o init.out init9.$O initcode.$O /$objtype/lib/libc.a
-	{echo 'uchar initcode[]={'
-	 xd -1x <init.out |
-		sed -e 's/^[0-9a-f]+ //' -e 's/ ([0-9a-f][0-9a-f])/0x\1,/g'
-	 echo '};'} > init.h
+initcode.out:		init9.$O initcode.$O /$objtype/lib/libc.a
+	$LD -l -R1 -s -o $target $prereq
 
-reboot.h:D:	rebootcode.s cache.v7.s arm.s arm.h mem.h
-	$AS rebootcode.s
-	# -lc is only for memmove.  -T arg is PADDR(REBOOTADDR)
-#	$LD -l -a -s -T0x100 -R4 -o reboot.out rebootcode.$O -lc >reboot.list
-	$LD -l -s -T0x100 -R4 -o reboot.out rebootcode.$O -lc
-	{echo 'uchar rebootcode[]={'
-	 xd -1x reboot.out |
-		sed -e '1,2d' -e 's/^[0-9a-f]+ //' -e 's/ ([0-9a-f][0-9a-f])/0x\1,/g'
-	 echo '};'} > reboot.h
-errstr.h:D:	../port/mkerrstr ../port/error.h
-	rc ../port/mkerrstr > errstr.h
+rebootcode.out:		rebootcode.$O
+	$LD -l -R4 -T0x100 -s -o $target $prereq -lc
--- a/sys/src/9/omap/syscall.c
+++ b/sys/src/9/omap/syscall.c
@@ -322,8 +322,4 @@
 
 	/* syscall returns 0 for child */
 	cureg->r0 = 0;
-
-	/* Things from bottom of syscall which were never executed */
-	p->psstate = 0;
-	p->insyscall = 0;
 }
--- a/sys/src/9/pc/main.c
+++ b/sys/src/9/pc/main.c
@@ -1,14 +1,13 @@
 #include	"u.h"
+#include	"tos.h"
 #include	"../port/lib.h"
 #include	"mem.h"
 #include	"dat.h"
 #include	"fns.h"
 #include	"io.h"
-#include	"tos.h"
 #include	"ureg.h"
-#include	"init.h"
 #include	"pool.h"
-#include	"reboot.h"
+#include	"rebootcode.i"
 
 Mach *m;
 Conf conf;
@@ -110,19 +109,6 @@
 {
 	char buf[2*KNAMELEN], **sp;
 
-	up->nerrlab = 0;
-
-	spllo();
-
-	/*
-	 * These are o.k. because rootinit is null.
-	 * Then early kproc's will have a root and dot.
-	 */
-	up->slash = namec("#/", Atodir, 0, 0);
-	pathclose(up->slash->path);
-	up->slash->path = newpath("/");
-	up->dot = cclone(up->slash);
-
 	chandevinit();
 
 	if(!waserror()){
@@ -143,69 +129,6 @@
 	strcpy(sp[1] = (char*)&sp[4], "boot");
 	sp[0] = nil;
 	touser(sp);
-}
-
-void
-userinit(void)
-{
-	void *v;
-	Proc *p;
-	Segment *s;
-	Page *pg;
-
-	p = newproc();
-	p->pgrp = newpgrp();
-	p->egrp = smalloc(sizeof(Egrp));
-	p->egrp->ref = 1;
-	p->fgrp = dupfgrp(nil);
-	p->rgrp = newrgrp();
-	p->procmode = 0640;
-
-	kstrdup(&eve, "");
-	kstrdup(&p->text, "*init*");
-	kstrdup(&p->user, eve);
-
-	procsetup(p);
-
-	/*
-	 * Kernel Stack
-	 *
-	 * N.B. make sure there's enough space for syscall to check
-	 *	for valid args and 
-	 *	4 bytes for gotolabel's return PC
-	 */
-	p->sched.pc = (ulong)init0;
-	p->sched.sp = (ulong)p->kstack+KSTACK-(sizeof(Sargs)+BY2WD);
-
-	/*
-	 * User Stack
-	 *
-	 * N.B. cannot call newpage() with clear=1, because pc kmap
-	 * requires up != nil.  use tmpmap instead.
-	 */
-	s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG);
-	p->seg[SSEG] = s;
-	pg = newpage(0, 0, USTKTOP-BY2PG);
-	segpage(s, pg);
-	v = tmpmap(pg);
-	memset(v, 0, BY2PG);
-	tmpunmap(v);
-
-	/*
-	 * Text
-	 */
-	s = newseg(SG_TEXT, UTZERO, 1);
-	s->flushme++;
-	p->seg[TSEG] = s;
-	pg = newpage(0, 0, UTZERO);
-	pg->txtflush = ~0;
-	segpage(s, pg);
-	v = tmpmap(pg);
-	memset(v, 0, BY2PG);
-	memmove(v, initcode, sizeof initcode);
-	tmpunmap(v);
-
-	ready(p);
 }
 
 void
--- a/sys/src/9/pc/mkfile
+++ b/sys/src/9/pc/mkfile
@@ -42,6 +42,7 @@
 	taslock.$O\
 	tod.$O\
 	xalloc.$O\
+	userinit.$O\
 
 OBJ=\
 	l.$O\
@@ -109,7 +110,7 @@
 $VGA mouse.$O:			screen.h /sys/include/memdraw.h
 vgavesa.$O:			/386/include/ureg.h
 devfloppy.$O: 			floppy.h
-archmp.$O mp.$O:		apbootstrap.h
+mp.$O:				apbootstrap.i
 apic.$O archmp.$O mp.$O:	mp.h
 squidboy.$O:			mp.h
 $SDEV:				../port/sd.h
@@ -116,12 +117,12 @@
 sd53c8xx.$O:			sd53c8xx.i
 sdiahci.$O:			ahci.h
 devaoe.$O sdaoe.$O:		../port/aoe.h
-main.$O:			init.h reboot.h
+main.$O:			rebootcode.i
 wavelan.$O:			wavelan.c ../pc/wavelan.c ../pc/wavelan.h
 etherwavelan.$O:		etherwavelan.c ../pc/wavelan.h
 devusb.$O usbuhci.$O usbohci.$O usbehci.$O usbehcipc.$O usbxhci.$O: ../port/usb.h
 usbehci.$O usbehcipc.$O:	usbehci.h
-trap.$O:			/sys/include/tos.h
+trap.$O main.$O:		/sys/include/tos.h
 uartaxp.$O:			uartaxp.i
 ether8169.$O:			../port/ethermii.h
 etherdp83820.$O:		../port/ethermii.h
@@ -133,31 +134,16 @@
 etheriwl.$O:			../port/wifi.h
 etherwpi.$O:			../port/wifi.h
 etherrt2860.$O: 		../port/wifi.h
+l.$O rebootcode.$O apbootstrap.$O:	mem.h
 
-init.h:D:		../port/initcode.c init9.c
-	$CC ../port/initcode.c
-	$CC init9.c
-	$LD -l -R1 -s -o init.out init9.$O initcode.$O /386/lib/libc.a
-	{echo 'uchar initcode[]={'
-	 xd -1x <init.out |
-		sed -e 's/^[0-9a-f]+ //' -e 's/ ([0-9a-f][0-9a-f])/0x\1,/g'
-	 echo '};'} > init.h
+initcode.out:		init9.$O initcode.$O /$objtype/lib/libc.a
+	$LD -l -R1 -s -o $target $prereq
 
-reboot.h:D:	rebootcode.s mem.h
-	$AS rebootcode.s
-	$LD -l -s -T$REBOOTADDR -R4 -o reboot.out rebootcode.$O
-	{echo 'uchar rebootcode[]={'
-	 xd -1x reboot.out |
-		sed -e '1,2d' -e 's/^[0-9a-f]+ //' -e 's/ ([0-9a-f][0-9a-f])/0x\1,/g'
-	 echo '};'} > reboot.h
+rebootcode.out:		rebootcode.$O
+	$LD -l -R4 -s -o $target -T$REBOOTADDR $prereq
 
-apbootstrap.h:D:	apbootstrap.s mem.h
-	$AS $prereq
-	$LD -o apbootstrap.out -T$APBOOTSTRAP -R4 -l -s apbootstrap.$O
-	{echo 'uchar apbootstrap[]={'
-	 xd -1x apbootstrap.out |
-		sed -e '1,2d' -e 's/^[0-9a-f]+ //' -e 's/ ([0-9a-f][0-9a-f])/0x\1,/g'
-	 echo '};'} > $target
+apbootstrap.out:	apbootstrap.$O
+	$LD -l -R4 -s -o $target -T$APBOOTSTRAP $prereq
 
 sd53c8xx.i:	sd53c8xx.n
 	aux/na $prereq > $target
@@ -199,6 +185,3 @@
 	for(i in pcdisk pcflop)
 	for(j in checkvga checkether)
 		mk $i.$j
-
-%.clean:V:
-	rm -f $stem.c [9bz]$stem [9bz]$stem.gz boot$stem.* reboot.h apbootstrap.h init.h
--- a/sys/src/9/pc/mp.c
+++ b/sys/src/9/pc/mp.c
@@ -7,7 +7,7 @@
 #include "ureg.h"
 
 #include "mp.h"
-#include "apbootstrap.h"
+#include "apbootstrap.i"
 
 /* filled in by pcmpinit or acpiinit */
 Bus* mpbus;
--- a/sys/src/9/pc/trap.c
+++ b/sys/src/9/pc/trap.c
@@ -1107,10 +1107,6 @@
 	memmove(cureg, ureg, sizeof(Ureg));
 	/* return value of syscall in child */
 	cureg->ax = 0;
-
-	/* Things from bottom of syscall which were never executed */
-	p->psstate = 0;
-	p->insyscall = 0;
 }
 
 /* Give enough context in the ureg to produce a kernel stack for
--- a/sys/src/9/pc64/main.c
+++ b/sys/src/9/pc64/main.c
@@ -1,14 +1,13 @@
 #include	"u.h"
+#include	"tos.h"
 #include	"../port/lib.h"
 #include	"mem.h"
 #include	"dat.h"
 #include	"fns.h"
 #include	"io.h"
-#include	"tos.h"
 #include	"ureg.h"
-#include	"init.h"
 #include	"pool.h"
-#include	"reboot.h"
+#include	"rebootcode.i"
 
 Conf conf;
 int delaylink;
@@ -150,19 +149,6 @@
 {
 	char buf[2*KNAMELEN], **sp;
 
-	up->nerrlab = 0;
-
-	spllo();
-
-	/*
-	 * These are o.k. because rootinit is null.
-	 * Then early kproc's will have a root and dot.
-	 */
-	up->slash = namec("#/", Atodir, 0, 0);
-	pathclose(up->slash->path);
-	up->slash->path = newpath("/");
-	up->dot = cclone(up->slash);
-
 	chandevinit();
 
 	if(!waserror()){
@@ -186,74 +172,7 @@
 }
 
 void
-userinit(void)
-{
-	void *v;
-	Proc *p;
-	Segment *s;
-	Page *pg;
-
-	p = newproc();
-	p->pgrp = newpgrp();
-	p->egrp = smalloc(sizeof(Egrp));
-	p->egrp->ref = 1;
-	p->fgrp = dupfgrp(nil);
-	p->rgrp = newrgrp();
-	p->procmode = 0640;
-
-	kstrdup(&eve, "");
-	kstrdup(&p->text, "*init*");
-	kstrdup(&p->user, eve);
-
-	procsetup(p);
-
-	/*
-	 * Kernel Stack
-	 *
-	 * N.B. make sure there's enough space for syscall to check
-	 *	for valid args and 
-	 *	8 bytes for gotolabel's return PC
-	 */
-	p->sched.pc = (uintptr)init0;
-	p->sched.sp = (uintptr)p->kstack+KSTACK-(sizeof(Sargs)+BY2WD);
-
-	/* temporarily set up for kmap() */
-	up = p;
-
-	/*
-	 * User Stack
-	 */
-	s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG);
-	p->seg[SSEG] = s;
-	pg = newpage(0, 0, USTKTOP-BY2PG);
-	segpage(s, pg);
-	v = kmap(pg);
-	memset(v, 0, BY2PG);
-	kunmap(v);
-
-	/*
-	 * Text
-	 */
-	s = newseg(SG_TEXT, UTZERO, 1);
-	s->flushme++;
-	p->seg[TSEG] = s;
-	pg = newpage(0, 0, UTZERO);
-	pg->txtflush = ~0;
-	segpage(s, pg);
-	v = kmap(pg);
-	memset(v, 0, BY2PG);
-	memmove(v, initcode, sizeof initcode);
-	kunmap(v);
-
-	/* free kmap */
-	mmurelease(p);
-	up = nil;
-
-	ready(p);
-}
-
-void
-main()
+main(void)
 {
 	mach0init();
 	bootargsinit();
--- a/sys/src/9/pc64/mkfile
+++ b/sys/src/9/pc64/mkfile
@@ -40,6 +40,7 @@
 	taslock.$O\
 	tod.$O\
 	xalloc.$O\
+	userinit.$O\
 
 OBJ=\
 	l.$O\
@@ -100,7 +101,7 @@
 <../port/portmkfile
 <|../port/mkbootrules $CONF
 
-l.$O:				mem.h
+l.$O rebootcode.$O apbootstrap.$O:	mem.h
 
 $ETHER: 			../port/etherif.h ../port/netif.h
 $AUDIO:				../port/audioif.h
@@ -109,7 +110,7 @@
 $VGA mouse.$O:			screen.h /sys/include/memdraw.h
 vgavesa.$O:			/386/include/ureg.h
 
-mp.$O:				mp.h apbootstrap.h 
+mp.$O:				mp.h apbootstrap.i
 apic.$O squidboy.$O:		mp.h
 archmp.$O archacpi.$O:		mp.h
 
@@ -120,13 +121,12 @@
 $SDEV:				../port/sd.h
 sdiahci.$O:			ahci.h
 devaoe.$O sdaoe.$O:		../port/aoe.h
+main.$O:			rebootcode.i
 
-main.$O:			init.h reboot.h
-
 devusb.$O usbuhci.$O usbohci.$O usbehci.$O usbehcipc.$O usbxhci.$O: ../port/usb.h
 usbehci.$O usbehcipc.$O:	usbehci.h
 
-trap.$O:			/sys/include/tos.h
+trap.$O main.$O:		/sys/include/tos.h
 
 ether8169.$O:			../port/ethermii.h
 etherdp83820.$O:		../port/ethermii.h
@@ -139,32 +139,18 @@
 etherwpi.$O:			../port/wifi.h
 etherrt2860.$O: 		../port/wifi.h
 
-init.h:D:		../port/initcode.c ../pc/init9.c
-	$CC ../port/initcode.c
-	$CC ../pc/init9.c
-	$LD -l -R1 -s -o init.out init9.$O initcode.$O /$objtype/lib/libc.a
-	{echo 'uchar initcode[]={'
-	 xd -1x <init.out |
-		sed -e 's/^[0-9a-f]+ //' -e 's/ ([0-9a-f][0-9a-f])/0x\1,/g'
-	 echo '};'} > init.h
+initcode.out:		init9.$O initcode.$O /$objtype/lib/libc.a
+	$LD -l -R1 -s -o $target $prereq
 
-reboot.h:D:	rebootcode.s mem.h
-	$AS rebootcode.s
-	$LD -l -R1 -s -o reboot.out -T$REBOOTADDR rebootcode.$O
-	{echo 'uchar rebootcode[]={'
-	 dd -if reboot.out -bs 1 -iseek 40 | 
-	 xd -1x |
-	 sed -e 's/^[0-9a-f]+ //' -e 's/ ([0-9a-f][0-9a-f])/0x\1,/g'
-	 echo '};'} > $target
+$O.rebootcode:		rebootcode.$O
+	$LD -l -R1 -s -o $target -T$REBOOTADDR $prereq
+rebootcode.out:		$O.rebootcode
+	dd -if $prereq(1) -of $target -bs 1 -iseek 40
 
-apbootstrap.h:D:	apbootstrap.s mem.h
-	$AS apbootstrap.s
-	$LD -l -R1 -s -o apbootstrap.out -T$APBOOTSTRAP apbootstrap.$O
-	{echo 'uchar apbootstrap[]={'
-	 dd -if apbootstrap.out -bs 1 -iseek 40 | 
-	 xd -1x |
-	 sed -e 's/^[0-9a-f]+ //' -e 's/ ([0-9a-f][0-9a-f])/0x\1,/g'
-	 echo '};'} > $target
+$O.apbootstrap:		apbootstrap.$O
+	$LD -l -R1 -s -o $target -T$APBOOTSTRAP $prereq
+apbootstrap.out:	$O.apbootstrap
+	dd -if $prereq(1) -of $target -bs 1 -iseek 40
 
 sd53c8xx.i:	sd53c8xx.n
 	aux/na $prereq > $target
@@ -173,4 +159,4 @@
 	$CC -a -w main.c>acid
 
 %.clean:V:
-	rm -f $stem.c [9bz]$stem [9bz]$stem.gz boot$stem.* apbootstrap.h reboot.h init.h $PCHEADERS
+	rm -f $stem.c [9bz]$stem [9bz]$stem.gz boot$stem.* $O.rebootcode $O.apbootstrap $PCHEADERS
--- a/sys/src/9/pc64/trap.c
+++ b/sys/src/9/pc64/trap.c
@@ -1095,10 +1095,6 @@
 	memmove(cureg, ureg, sizeof(Ureg));
 
 	cureg->ax = 0;
-
-	/* Things from bottom of syscall which were never executed */
-	p->psstate = 0;
-	p->insyscall = 0;
 }
 
 /* Give enough context in the ureg to produce a kernel stack for
--- a/sys/src/9/port/initcode.c
+++ b/sys/src/9/port/initcode.c
@@ -18,7 +18,7 @@
 char env[] = "/env";
 
 void
-startboot(char *argv0, char **argv)
+startboot(char*, char **argv)
 {
 	char buf[200];	/* keep this fairly large to capture error details */
 
--- a/sys/src/9/port/portdat.h
+++ b/sys/src/9/port/portdat.h
@@ -661,6 +661,7 @@
 	QLock	seglock;	/* locked whenever seg[] changes */
 	ulong	pid;
 	ulong	noteid;		/* Equivalent of note group */
+	ulong	parentpid;
 	Proc	*pidhash;	/* next proc in pid hash */
 
 	Lock	exl;		/* Lock count and waitq */
@@ -678,8 +679,6 @@
 
 	Fgrp	*closingfgrp;	/* used during teardown */
 
-	ulong	parentpid;
-
 	int	insyscall;
 	ulong	time[6];	/* User, Sys, Real; child U, S, R */
 
@@ -698,6 +697,7 @@
 	Proc	*pdbg;		/* the debugging process */
 	ulong	procmode;	/* proc device default file mode */
 	int	privatemem;	/* proc does not let anyone read mem */
+	int	noswap;		/* process is not swappable */
 	int	hang;		/* hang at next exec for debug */
 	int	procctl;	/* Control for /proc debugging */
 	uintptr	pc;		/* DEBUG only */
@@ -710,7 +710,6 @@
 	Proc	*palarm;	/* Next alarm time */
 	ulong	alarm;		/* Time of call */
 	int	newtlb;		/* Pager has changed my pte's, I must flush */
-	int	noswap;		/* process is not swappable */
 
 	uintptr	rendtag;	/* Tag for rendezvous */
 	uintptr	rendval;	/* Value for rendezvous */
@@ -722,8 +721,8 @@
 	void	(*kpfun)(void*);
 	void	*kparg;
 
-	int	scallnr;	/* sys call number */
 	Sargs	s;		/* syscall arguments */
+	int	scallnr;	/* sys call number */
 	int	nerrlab;
 	Label	errlab[NERR];
 	char	*syserrstr;	/* last error from a system call, errbuf0 or 1 */
--- a/sys/src/9/port/portfns.h
+++ b/sys/src/9/port/portfns.h
@@ -136,6 +136,7 @@
 ulong		imagecached(void);
 ulong		imagereclaim(ulong);
 long		incref(Ref*);
+void		init0(void);
 void		initseg(void);
 int		iprint(char*, ...);
 void		isdir(Chan*);
--- a/sys/src/9/port/portmkfile
+++ b/sys/src/9/port/portmkfile
@@ -30,7 +30,7 @@
 		mk 'CONF='$i
 
 clean:V:
-	rm -f *.[$OS] *.i *.root.s *.rootc.c cfs.h fs.h init.h conf.h *.out *.m errstr.h boot bootfs.paq
+	rm -f *.[$OS] *.i *.root.s *.rootc.c cfs.h fs.h conf.h *.out *.m errstr.h init.h reboot.h boot bootfs.paq
 	for(i in $CONFLIST $CRAPLIST)
 		mk $i.clean
 
@@ -56,9 +56,15 @@
 	 echo 0,
 	 echo '};'} >> $CONF.c
 
-errstr.h:	../port/mkerrstr ../port/error.h
+errstr.h:D:	../port/mkerrstr ../port/error.h
 	rc ../port/mkerrstr > errstr.h
 
+%.i:	%.out
+	{echo 'uchar '^$stem^'[]={'
+	 xd -1x <$stem.out |
+		sed -e 's/^[0-9a-f]+ //' -e 's/ ([0-9a-f][0-9a-f])/0x\1,/g'
+	 echo '};'} > $target
+
 %.db:		main.$O
 	$CC -s$stem main.c | dbfmt > $stem.db
 
@@ -74,7 +80,7 @@
 sdaoe.$O:	../port/sd.h /$objtype/include/ureg.h
 trap.$O:	/$objtype/include/ureg.h
 devproc.$O:	/$objtype/include/ureg.h
-main.$O:	init.h
+userinit.$O:	initcode.i
 trap.$O:	../port/systab.h
 devpipe.$O:	../port/netif.h
 netif.$O:	../port/netif.h
--- a/sys/src/9/port/proc.c
+++ b/sys/src/9/port/proc.c
@@ -608,7 +608,7 @@
 	procalloc.free = p->qnext;
 	unlock(&procalloc);
 
-	p->state = Scheding;
+	assert(p->state == Dead);
 	p->psstate = "New";
 	p->mach = nil;
 	p->eql = nil;
@@ -628,8 +628,10 @@
 	p->syscalltrace = nil;	
 	p->notepending = 0;
 	p->ureg = nil;
+	p->dbgreg = nil;
 	p->privatemem = 0;
 	p->noswap = 0;
+	p->nerrlab = 0;
 	p->errstr = p->errbuf0;
 	p->syserrstr = p->errbuf1;
 	p->errbuf0[0] = '\0';
@@ -637,14 +639,11 @@
 	p->nlocks = 0;
 	p->delaysched = 0;
 	p->trace = 0;
-	kstrdup(&p->user, "*nouser");
-	kstrdup(&p->text, "*notext");
-	kstrdup(&p->args, "");
 	p->nargs = 0;
 	p->setargs = 0;
 	memset(p->seg, 0, sizeof p->seg);
 	p->parentpid = 0;
-	p->noteid = pidalloc(p);
+	p->noteid = 0;
 	if(p->kstack == nil)
 		p->kstack = smalloc(KSTACK);
 
@@ -924,7 +923,7 @@
 		return 0;
 	}
 
-	if(n != nil && flag != NUser && (p->notify == 0 || p->notified))
+	if(n != nil && flag != NUser && (p->notify == nil || p->notified))
 		p->nnote = 0;
 
 	ret = 0;
@@ -1443,44 +1442,49 @@
 void
 kproc(char *name, void (*func)(void *), void *arg)
 {
-	Proc *p;
 	static Pgrp *kpgrp;
+	Proc *p;
 
 	p = newproc();
-	p->psstate = nil;
-	p->procmode = 0640;
-	p->kp = 1;
-	p->noswap = 1;
 
-	p->scallnr = up->scallnr;
-	p->s = up->s;
-	p->nerrlab = 0;
-	p->slash = up->slash;
-	p->dot = up->slash;	/* unlike fork, do not inherit the dot for kprocs */
-	if(p->dot != nil)
-		incref(p->dot);
+	if(up != nil){
+		p->slash = up->slash;
+		p->dot = up->slash;	/* unlike fork, do not inherit the dot for kprocs */
+		if(p->dot != nil)
+			incref(p->dot);
+	} else {
+		p->slash = nil;
+		p->dot = nil;
+	}
 
-	memmove(p->note, up->note, sizeof(p->note));
-	p->nnote = up->nnote;
+	p->nnote = 0;
+	p->notify = nil;
 	p->notified = 0;
-	p->lastnote = up->lastnote;
-	p->notify = up->notify;
-	p->ureg = nil;
-	p->dbgreg = nil;
 
-	procpriority(p, PriKproc, 0);
+	p->procmode = 0640;
+	p->noswap = 1;
+	p->kp = 1;
 
 	kprocchild(p, func, arg);
 
-	kstrdup(&p->user, eve);
 	kstrdup(&p->text, name);
+	kstrdup(&p->user, eve);
+	kstrdup(&p->args, "");
+
 	if(kpgrp == nil)
 		kpgrp = newpgrp();
 	p->pgrp = kpgrp;
 	incref(kpgrp);
 
+	p->insyscall = 1;
 	memset(p->time, 0, sizeof(p->time));
 	p->time[TReal] = MACHP(0)->ticks;
+
+	pidalloc(p);
+
+	procpriority(p, PriKproc, 0);
+
+	p->psstate = nil;
 	ready(p);
 }
 
--- a/sys/src/9/port/sysproc.c
+++ b/sys/src/9/port/sysproc.c
@@ -80,7 +80,7 @@
 			closeegrp(oeg);
 		}
 		if(flag & RFNOTEG)
-			up->noteid = pidalloc(0);
+			up->noteid = pidalloc(nil);
 		return 0;
 	}
 
@@ -88,21 +88,39 @@
 
 	p->scallnr = up->scallnr;
 	p->s = up->s;
-	p->nerrlab = 0;
 	p->slash = up->slash;
 	p->dot = up->dot;
 	incref(p->dot);
 
 	memmove(p->note, up->note, sizeof(p->note));
-	p->privatemem = up->privatemem;
-	p->noswap = up->noswap;
 	p->nnote = up->nnote;
+	p->notify = up->notify;
 	p->notified = 0;
 	p->lastnote = up->lastnote;
-	p->notify = up->notify;
-	p->ureg = up->ureg;
-	p->dbgreg = 0;
 
+	p->parentpid = up->pid;
+	p->procmode = up->procmode;
+	p->privatemem = up->privatemem;
+	p->noswap = up->noswap;
+	p->hang = up->hang;
+	if(up->procctl == Proc_tracesyscall)
+		p->procctl = Proc_tracesyscall;
+
+	/* Craft a return frame which will cause the child to pop out of
+	 * the scheduler in user mode with the return register zero
+	 */
+	forkchild(p, up->dbgreg);
+
+	kstrdup(&p->text, up->text);
+	kstrdup(&p->user, up->user);
+	kstrdup(&p->args, "");
+
+	p->insyscall = 0;
+	memset(p->time, 0, sizeof(p->time));
+	p->time[TReal] = MACHP(0)->ticks;
+
+	pid = pidalloc(p);
+
 	/* Abort the child process on error */
 	if(waserror()){
 		p->kp = 1;
@@ -169,19 +187,14 @@
 		p->egrp = up->egrp;
 		incref(p->egrp);
 	}
-	p->hang = up->hang;
-	p->procmode = up->procmode;
-	if(up->procctl == Proc_tracesyscall)
-		p->procctl = Proc_tracesyscall;
 
-	poperror();	/* abortion */
+	if(flag & RFNOTEG)
+		p->noteid = pid;
 
-	/* Craft a return frame which will cause the child to pop out of
-	 * the scheduler in user mode with the return register zero
-	 */
-	forkchild(p, up->dbgreg);
+	procfork(p);
 
-	p->parentpid = up->pid;
+	poperror();	/* abortion */
+
 	if((flag&RFNOWAIT) == 0){
 		p->parent = up;
 		lock(&up->exl);
@@ -188,18 +201,7 @@
 		up->nchild++;
 		unlock(&up->exl);
 	}
-	if((flag&RFNOTEG) == 0)
-		p->noteid = up->noteid;
 
-	pid = p->pid;
-	memset(p->time, 0, sizeof(p->time));
-	p->time[TReal] = MACHP(0)->ticks;
-
-	kstrdup(&p->text, up->text);
-	kstrdup(&p->user, up->user);
-
-	procfork(p);
-
 	/*
 	 *  since the bss/data segments are now shareable,
 	 *  any mmu info about this process is now stale
@@ -211,8 +213,9 @@
 	p->fixedpri = up->fixedpri;
 	p->mp = up->mp;
 	wm = up->wired;
-	if(wm)
+	if(wm != nil)
 		procwired(p, wm->machno);
+	p->psstate = nil;
 	ready(p);
 	sched();
 	return pid;
@@ -565,7 +568,7 @@
 	up->setargs = 0;
 
 	up->nnote = 0;
-	up->notify = 0;
+	up->notify = nil;
 	up->notified = 0;
 	up->privatemem = 0;
 	up->noswap = 0;
--- /dev/null
+++ b/sys/src/9/port/userinit.c
@@ -1,0 +1,88 @@
+#include	"u.h"
+#include	"../port/lib.h"
+#include	"mem.h"
+#include	"dat.h"
+#include	"fns.h"
+#include	"../port/error.h"
+
+/*
+ * The initcode array contains the binary text of the first
+ * user process. Its job is to invoke the exec system call
+ * for /boot/boot.
+ * Initcode does not link with standard plan9 libc _main()
+ * trampoline due to size constrains. Instead it is linked
+ * with a small machine specific trampoline init9.s that
+ * only sets the base address register and passes arguments
+ * to startboot() (see port/initcode.c).
+ */
+#include	"initcode.i"
+
+/*
+ * The first process kernel process starts here.
+ */
+static void
+proc0(void*)
+{
+	KMap *k;
+	Page *p;
+
+	spllo();
+
+	up->pgrp = newpgrp();
+	up->egrp = smalloc(sizeof(Egrp));
+	up->egrp->ref = 1;
+	up->fgrp = dupfgrp(nil);
+	up->rgrp = newrgrp();
+
+	/*
+	 * These are o.k. because rootinit is null.
+	 * Then early kproc's will have a root and dot.
+	 */
+	up->slash = namec("#/", Atodir, 0, 0);
+	pathclose(up->slash->path);
+	up->slash->path = newpath("/");
+	up->dot = cclone(up->slash);
+
+	/*
+	 * Setup Text and Stack segments for initcode.
+	 */
+	up->seg[SSEG] = newseg(SG_STACK | SG_NOEXEC, USTKTOP-USTKSIZE, USTKSIZE / BY2PG);
+	up->seg[TSEG] = newseg(SG_TEXT | SG_RONLY, UTZERO, 1);
+	p = newpage(1, 0, UTZERO);
+	k = kmap(p);
+	memmove((void*)VA(k), initcode, sizeof(initcode));
+	kunmap(k);
+	p->txtflush = ~0;
+	segpage(up->seg[TSEG], p);
+	up->seg[TSEG]->flushme++;
+
+	/*
+	 * Become a user process.
+	 */
+	up->kp = 0;
+	up->noswap = 0;
+	procpriority(up, PriNormal, 0);
+	procsetup(up);
+
+	flushmmu();
+
+	/*
+	 * init0():
+	 *	call chandevinit()
+	 *	setup environment variables
+	 *	prepare the stack for initcode
+	 *	switch to usermode to run initcode
+	 */
+	init0();
+
+	/* init0 will never return */
+	panic("init0");
+}
+
+void
+userinit(void)
+{
+	up = nil;
+	kstrdup(&eve, "");
+	kproc("*init*", proc0, nil);
+}
--- a/sys/src/9/ppc/initcode
+++ /dev/null
@@ -1,25 +1,0 @@
-#include "/sys/src/libc/9syscall/sys.h"
-
-/*
- *  we pass in the argument of the exec parameters as 0(FP)
- */
-
-TEXT	main(SB),$8
-
-	MOVW	$setSB(SB), R2
-	MOVW	$boot(SB), R3
-	ADD	$12, R1, R4	/* get a pointer to 0(FP) */
-	MOVW	R3, 4(R1)
-	MOVW	R4, 8(R1)
-	MOVW	$EXEC, R3
-	SYSCALL
-
-	/* should never get here */
-loop:
-	BR	loop
-
-DATA	boot+0(SB)/5,$"/boot"
-DATA	boot+5(SB)/5,$"/boot"
-DATA	bootv+0(SB)/4,$boot+6(SB)
-GLOBL	boot+0(SB),$11
-GLOBL	bootv+0(SB),$8
--- a/sys/src/9/ppc/main.c
+++ b/sys/src/9/ppc/main.c
@@ -1,12 +1,11 @@
 #include	"u.h"
+#include	"tos.h"
 #include	"../port/lib.h"
 #include	"mem.h"
 #include	"dat.h"
 #include	"fns.h"
 #include	"io.h"
-#include	"init.h"
 #include	"pool.h"
-#include	"tos.h"
 
 #define	MAXCONF		64
 
@@ -147,22 +146,9 @@
 void
 init0(void)
 {
-//	char **p, *q, name[KNAMELEN];
-	int i;
 	char buf[2*KNAMELEN];
+	int i;
 
-	up->nerrlab = 0;
-	spllo();
-
-	/*
-	 * These are o.k. because rootinit is null.
-	 * Then early kproc's will have a root and dot.
-	 */
-	up->slash = namec("#/", Atodir, 0, 0);
-	pathclose(up->slash->path);
-	up->slash->path = newpath("/");
-	up->dot = cclone(up->slash);
-
 	chandevinit();
 
 	if(!waserror()){
@@ -183,62 +169,7 @@
 	}
 	kproc("alarm", alarmkproc, 0);
 	kproc("mmusweep", mmusweep, 0);
-	touser((void*)(USTKTOP-sizeof(Tos)));
-}
-
-void
-userinit(void)
-{
-	Proc *p;
-	Segment *s;
-	KMap *k;
-	Page *pg;
-
-	p = newproc();
-	p->pgrp = newpgrp();
-	p->egrp = smalloc(sizeof(Egrp));
-	p->egrp->ref = 1;
-	p->fgrp = dupfgrp(nil);
-	p->rgrp = newrgrp();
-	p->procmode = 0640;
-
-	kstrdup(&eve, "");
-	kstrdup(&p->text, "*init*");
-	kstrdup(&p->user, eve);
-
-	p->fpstate = FPinit;
-
-	/*
-	 *  Stack
-	 *
-	 * N.B. The -12 for the stack pointer is important.
-	 *	4 bytes for gotolabel's return PC
-	 */
-	p->sched.pc = (ulong)init0;
-	p->sched.sp = (ulong)p->kstack+KSTACK-(sizeof(Sargs)+BY2WD);
-
-	/*
-	 * User Stack
-	 */
-	s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG);
-	p->seg[SSEG] = s;
-	pg = newpage(1, 0, USTKTOP-BY2PG);
-	segpage(s, pg);
-
-	/*
-	 * Text
-	 */
-	s = newseg(SG_TEXT, UTZERO, 1);
-	s->flushme++;
-	p->seg[TSEG] = s;
-	pg = newpage(1, 0, UTZERO);
-	pg->txtflush = ~0;
-	segpage(s, pg);
-	k = kmap(s->map[0]->pages[0]);
-	memmove((ulong*)VA(k), initcode, sizeof initcode);
-	kunmap(k);
-
-	ready(p);
+	touser((void*)(USTKTOP - sizeof(Tos)));
 }
 
 void
--- a/sys/src/9/ppc/mkfile
+++ b/sys/src/9/ppc/mkfile
@@ -53,7 +53,6 @@
 	dat.h\
 	errstr.h\
 	fns.h\
-	init.h\
 	io.h\
 	mem.h\
 
@@ -90,16 +89,11 @@
 <|../port/mkbootrules $CONF
 
 clock.$O devether.$O main.$O trap.$O:	/$objtype/include/ureg.h
+trap.$O main.$O: /sys/include/tos.h
 
 %.$O:	$HFILES
 
 $ETHER: 			../port/etherif.h ../port/netif.h
 
-init.h:	../port/initcode.c init9.s
-	$CC ../port/initcode.c
-	$AS init9.s
-	$LD -l -s -R4 -o init.out init9.$O initcode.$O /power/lib/libc.a
-	{echo 'uchar initcode[]={'
-	<init.out xd -1x |
-		sed -e 's/^[0-9a-f]+ //' -e 's/ ([0-9a-f][0-9a-f])/0x\1,/g'
-	 echo '};'} > init.h
+initcode.out:		init9.$O initcode.$O /$objtype/lib/libc.a
+	$LD -l -R4 -s -o $target $prereq
--- a/sys/src/9/ppc/trap.c
+++ b/sys/src/9/ppc/trap.c
@@ -553,10 +553,6 @@
 	cur = (Ureg*)(p->sched.sp+2*BY2WD);
 	memmove(cur, ur, sizeof(Ureg));
 	cur->r3 = 0;
-	
-	/* Things from bottom of syscall we never got to execute */
-	p->psstate = 0;
-	p->insyscall = 0;
 }
 
 uintptr
--- a/sys/src/9/sgi/main.c
+++ b/sys/src/9/sgi/main.c
@@ -1,21 +1,14 @@
 #include	"u.h"
+#include	"tos.h"
 #include	"../port/lib.h"
 #include	"mem.h"
 #include	"dat.h"
 #include	"fns.h"
 #include	"io.h"
-#include	"init.h"
 #include	"pool.h"
 #include	"../ip/ip.h"
-#include	<tos.h>
 #include	<../port/error.h>
 
-enum {
-	/* space for syscall args, return PC, top-of-stack struct */
-	Stkheadroom	= sizeof(Sargs) + sizeof(uintptr) + sizeof(Tos),
-};
-
-static uchar *sp;		/* XXX - must go - user stack of init proc */
 static FPsave initfp;
 
 /*
@@ -233,21 +226,8 @@
 void
 init0(void)
 {
-	char buf[128];
+	char buf[128], **sp;
 
-	up->nerrlab = 0;
-
-	spllo();
-
-	/*
-	 * These are o.k. because rootinit is null.
-	 * Then early kproc's will have a root and dot.
-	 */
-	up->slash = namec("#/", Atodir, 0, 0);
-	pathclose(up->slash->path);
-	up->slash->path = newpath("/");
-	up->dot = cclone(up->slash);
-
 	chandevinit();
 
 	if(!waserror()){
@@ -274,99 +254,11 @@
 		kproc("arcs", arcsproc, 0);
 
 	kproc("alarm", alarmkproc, 0);
-	touser(sp);
-}
 
-static uchar *
-pusharg(char *p)
-{
-	int n;
-	
-	n = strlen(p) + 1;
-	sp -= n;
-	memmove(sp, p, n);
-	return sp;
-}
-
-static void
-bootargs(uintptr base)
-{	int i, ac;
-	uchar *av[32];
-	uchar **lsp;
-	
-	sp = (uchar *) base + BY2PG - sizeof(Tos);
-	
-	ac = 0;
-	av[ac++] = pusharg("boot");
-	sp = (uchar *) ((ulong) sp & ~7);
-	sp -= ROUND((ac + 1) * sizeof(sp), 8) + 4;
-	lsp = (uchar **) sp;
-	for(i = 0; i < ac; i++)
-		lsp[i] = av[i] + ((USTKTOP - BY2PG) - (ulong) base);
-	lsp[i] = 0;
-	sp += (USTKTOP - BY2PG) - (ulong) base;
-}
-
-void
-userinit(void)
-{
-	Proc *p;
-	KMap *k;
-	Page *pg;
-	Segment *s;
-
-	p = newproc();
-	p->pgrp = newpgrp();
-	p->egrp = smalloc(sizeof(Egrp));
-	p->egrp->ref = 1;
-	p->fgrp = dupfgrp(nil);
-	p->rgrp = newrgrp();
-	p->procmode = 0640;
-
-	kstrdup(&eve, "");
-	kstrdup(&p->text, "*init*");
-	kstrdup(&p->user, eve);
-
-	procsetup(p);
-
-	/*
-	 * Kernel Stack
-	 */
-	p->sched.pc = (ulong)init0;
-	p->sched.sp = (ulong)p->kstack+KSTACK-Stkheadroom;
-	p->sched.sp = STACKALIGN(p->sched.sp);
-
-	/*
-	 * User Stack
-	 *
-	 * Technically, newpage can't be called here because it
-	 * should only be called when in a user context as it may
-	 * try to sleep if there are no pages available, but that
-	 * shouldn't be the case here.
-	 */
-	s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG);
-	p->seg[SSEG] = s;
-	pg = newpage(1, 0, USTKTOP-BY2PG);
-	segpage(s, pg);
-	k = kmap(pg);
-	bootargs(VA(k));
-	kunmap(k);
-
-	/*
-	 * Text
-	 */
-	s = newseg(SG_TEXT, UTZERO, 1);
-	s->flushme++;
-	p->seg[TSEG] = s;
-	pg = newpage(1, 0, UTZERO);
-	pg->txtflush = ~0;
-	segpage(s, pg);
-	k = kmap(s->map[0]->pages[0]);
-	memset((void *)VA(k), 0, BY2PG);
-	memmove((ulong*)VA(k), initcode, sizeof initcode);
-	kunmap(k);
-
-	ready(p);
+	sp = (char**)(USTKTOP-sizeof(Tos) - 8 - sizeof(sp[0])*4);
+	sp[3] = sp[2] = sp[1] = nil;
+	strcpy(sp[0] = (char*)&sp[4], "boot");
+	touser(sp);
 }
 
 void
--- a/sys/src/9/sgi/mkfile
+++ b/sys/src/9/sgi/mkfile
@@ -44,6 +44,7 @@
 	taslock.$O\
 	tod.$O\
 	xalloc.$O\
+	userinit.$O\
 
 OBJ=\
 	l.$O\
@@ -79,17 +80,12 @@
 <../port/portmkfile
 <|../port/mkbootrules $CONF
 
-init.h:	init9.s ../port/initcode.c /sys/src/libc/9syscall/sys.h
-	va init9.s
-	vc ../port/initcode.c
-	vl -T$UTZERO -R4 -o init.out init9.$O initcode.$O
-	{echo 'uchar initcode[]={'
-	 xd -r -1x init.out |
-		sed -e 's/^[0-9a-f]+ //' -e 's/ ([0-9a-f][0-9a-f])/0x\1,/g'
-	 echo '};'} > init.h
+initcode.out: init9.$O initcode.$O /$objtype/lib/libc.a
+	$LD -T$UTZERO -R4 -s -o $target $prereq
 
 faultmips.$O mmu.$O syscall.$O  trap.$O: /$objtype/include/ureg.h
-main.$O:	/$objtype/include/ureg.h errstr.h init.h
+main.$O:	/$objtype/include/ureg.h errstr.h
+main.$O trap.$O: /sys/include/tos.h
 
 %.clean:V:
-	rm -f $stem.c [9bz]$stem [9bz]$stem.gz boot$stem.* init.h
+	rm -f $stem.c [9bz]$stem [9bz]$stem.gz boot$stem.*
--- a/sys/src/9/sgi/trap.c
+++ b/sys/src/9/sgi/trap.c
@@ -2,6 +2,7 @@
  * traps, exceptions, faults and interrupts on ar7161
  */
 #include	"u.h"
+#include	"tos.h"
 #include	"../port/lib.h"
 #include	"mem.h"
 #include	"dat.h"
@@ -8,7 +9,6 @@
 #include	"fns.h"
 #include	"ureg.h"
 #include	"io.h"
-#include	<tos.h>
 #include	"../port/error.h"
 
 typedef struct Handler Handler;
@@ -792,10 +792,6 @@
 
 	cur->r1 = 0;
 	cur->pc += 4;
-
-	/* Things from bottom of syscall we never got to execute */
-	p->psstate = 0;
-	p->insyscall = 0;
 }
 
 static
--- a/sys/src/9/teg2/fns.h
+++ b/sys/src/9/teg2/fns.h
@@ -177,7 +177,6 @@
  * Miscellaneous machine dependent stuff.
  */
 extern int cas(int *, int, int);
-extern char* getenv(char*, char*, int);
 char*	getconf(char*);
 uintptr mmukmap(uintptr, uintptr, usize);
 uintptr mmukunmap(uintptr, uintptr, usize);
--- a/sys/src/9/teg2/init9.s
+++ /dev/null
@@ -1,25 +1,0 @@
-/*
- * This is the same as the C programme:
- *
- *	void
- *	main(char* argv0)
- *	{
- *		startboot(argv0, &argv0);
- *	}
- *
- * It is in assembler because SB needs to be
- * set and doing this in C drags in too many
- * other routines.
- */
-TEXT main(SB), 1, $8
-	MOVW	$setR12(SB), R12		/* load the SB */
-	MOVW	$boot(SB), R0
-
-	ADD	$12, R13, R1			/* pointer to 0(FP) */
-
-	MOVW	R0, 4(R13)			/* pass argc, argv */
-	MOVW	R1, 8(R13)
-
-	BL	startboot(SB)
-_loop:
-	B	_loop
--- a/sys/src/9/teg2/main.c
+++ b/sys/src/9/teg2/main.c
@@ -1,4 +1,5 @@
 #include "u.h"
+#include "tos.h"
 #include "../port/lib.h"
 #include "mem.h"
 #include "dat.h"
@@ -5,11 +6,10 @@
 #include "fns.h"
 #include "io.h"
 
-#include "init.h"
 #include <pool.h>
 
 #include "arm.h"
-#include "reboot.h"
+#include "rebootcode.i"
 
 /*
  * Where configuration info is left for the loaded programme.
@@ -40,21 +40,6 @@
  */
 Lowmemcache *cacheconf;
 
-/*
- * Option arguments from the command line.
- * oargv[0] is the boot file.
- * Optionsinit() is called from multiboot()
- * or some other machine-dependent place
- * to set it all up.
- */
-static int oargc;
-static char* oargv[20];
-static char oargb[128];
-static int oargblen;
-static char oenv[4096];
-
-static uintptr sp;		/* XXX - must go - user stack of init proc */
-
 int vflag;
 int normalprint;
 char debug[256];
@@ -165,45 +150,6 @@
 	}
 }
 
-static void
-optionsinit(char* s)
-{
-	char *o;
-
-	strcpy(oenv, "");
-	o = strecpy(oargb, oargb+sizeof(oargb), s)+1;
-	if(getenv("bootargs", o, o - oargb) != nil)
-		*(o-1) = ' ';
-
-	oargblen = strlen(oargb);
-	oargc = tokenize(oargb, oargv, nelem(oargv)-1);
-	oargv[oargc] = nil;
-}
-
-char*
-getenv(char* name, char* buf, int n)
-{
-	char *e, *p, *q;
-
-	p = oenv;
-	while(*p != 0){
-		if((e = strchr(p, '=')) == nil)
-			break;
-		for(q = name; p < e; p++){
-			if(*p != *q)
-				break;
-			q++;
-		}
-		if(p == e && *q == 0){
-			strecpy(buf, buf+n, e+1);
-			return buf;
-		}
-		p += strlen(p)+1;
-	}
-
-	return nil;
-}
-
 /* enable scheduling of this cpu */
 void
 machon(uint cpu)
@@ -386,7 +332,6 @@
 	l2pageinit();
 	mmuinit();
 
-	optionsinit("/boot/boot boot");
 	quotefmtinstall();
 
 	/* want plan9.ini to be able to affect memory sizing in confinit */
@@ -586,22 +531,9 @@
 void
 init0(void)
 {
+	char buf[2*KNAMELEN], **sp;
 	int i;
-	char buf[2*KNAMELEN];
 
-	up->nerrlab = 0;
-	coherence();
-	spllo();
-
-	/*
-	 * These are o.k. because rootinit is null.
-	 * Then early kproc's will have a root and dot.
-	 */
-	up->slash = namec("#/", Atodir, 0, 0);
-	pathclose(up->slash->path);
-	up->slash->path = newpath("/");
-	up->dot = cclone(up->slash);
-
 	chandevinit();
 	i8250console();		/* might be redundant, but harmless */
 	if(serialoq == nil)
@@ -626,112 +558,10 @@
 	}
 	kproc("alarm", alarmkproc, 0);
 
-	touser(sp);
-}
-
-static void
-bootargs(uintptr base)
-{
-	int i;
-	ulong ssize;
-	char **av, *p;
-
-	/*
-	 * Push the boot args onto the stack.
-	 * The initial value of the user stack must be such
-	 * that the total used is larger than the maximum size
-	 * of the argument list checked in syscall.
-	 */
-	i = oargblen+1;
-	p = (void*)(STACKALIGN(base + BY2PG - sizeof(up->s.args) - i));
-	memmove(p, oargb, i);
-
-	/*
-	 * Now push argc and the argv pointers.
-	 * This isn't strictly correct as the code jumped to by
-	 * touser in init9.s calls startboot (port/initcode.c) which
-	 * expects arguments
-	 * 	startboot(char *argv0, char **argv)
-	 * not the usual (int argc, char* argv[]), but argv0 is
-	 * unused so it doesn't matter (at the moment...).
-	 */
-	av = (char**)(p - (oargc+2)*sizeof(char*));
-	ssize = base + BY2PG - (uintptr)av;
-	*av++ = (char*)oargc;
-	for(i = 0; i < oargc; i++)
-		*av++ = (oargv[i] - oargb) + (p - base) + (USTKTOP - BY2PG);
-	*av = nil;
-
-	/*
-	 * Leave space for the return PC of the
-	 * caller of initcode.
-	 */
-	sp = USTKTOP - ssize - sizeof(void*);
-}
-
-/*
- *  create the first process
- */
-void
-userinit(void)
-{
-	Proc *p;
-	Segment *s;
-	KMap *k;
-	Page *pg;
-
-	/* no processes yet */
-	up = nil;
-
-	p = newproc();
-	p->pgrp = newpgrp();
-	p->egrp = smalloc(sizeof(Egrp));
-	p->egrp->ref = 1;
-	p->fgrp = dupfgrp(nil);
-	p->rgrp = newrgrp();
-	p->procmode = 0640;
-
-	kstrdup(&eve, "");
-	kstrdup(&p->text, "*init*");
-	kstrdup(&p->user, eve);
-
-	/*
-	 * Kernel Stack
-	 */
-	p->sched.pc = (uintptr)init0;
-	p->sched.sp = (uintptr)p->kstack+KSTACK-sizeof(up->s.args)-sizeof(uintptr);
-	p->sched.sp = STACKALIGN(p->sched.sp);
-
-	/*
-	 * User Stack
-	 *
-	 * Technically, newpage can't be called here because it
-	 * should only be called when in a user context as it may
-	 * try to sleep if there are no pages available, but that
-	 * shouldn't be the case here.
-	 */
-	s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG);
-	s->flushme++;
-	p->seg[SSEG] = s;
-	pg = newpage(1, 0, USTKTOP-BY2PG);
-	segpage(s, pg);
-	k = kmap(pg);
-	bootargs(VA(k));
-	kunmap(k);
-
-	/*
-	 * Text
-	 */
-	s = newseg(SG_TEXT, UTZERO, 1);
-	p->seg[TSEG] = s;
-	pg = newpage(1, 0, UTZERO);
-	pg->txtflush = ~0;
-	segpage(s, pg);
-	k = kmap(s->map[0]->pages[0]);
-	memmove((void*)VA(k), initcode, sizeof initcode);
-	kunmap(k);
-
-	ready(p);
+	sp = (char**)(USTKTOP - sizeof(Tos) - 8 - sizeof(sp[0])*4);
+	sp[3] = sp[2] = sp[1] = nil;
+	strcpy(sp[0] = (char*)&sp[4], "boot");
+	touser((uintptr)sp);
 }
 
 Conf conf;			/* XXX - must go - gag */
--- a/sys/src/9/teg2/mkfile
+++ b/sys/src/9/teg2/mkfile
@@ -40,6 +40,7 @@
 	taslock.$O\
 	tod.$O\
 	xalloc.$O\
+	userinit.$O\
 
 OBJ=\
 	l.$O\
@@ -121,32 +122,17 @@
 archtegra.$O devflash.$O flashtegra.$O flashigep.$O: ../port/flashif.h
 ecc.$O flashtegra.$O flashigep.$O: ../port/nandecc.h io.h
 fpi.$O fpiarm.$O fpimem.$O: fpi.h
-l.$O lexception.$O lproc.$O mmu.$O: arm.s mem.h
+l.$O lexception.$O lproc.$O mmu.$O rebootcode.$O: arm.s mem.h
 l.$O rebootcode.$O: cache.v7.s
-main.$O: errstr.h init.h reboot.h
+main.$O: errstr.h rebootcode.i /sys/include/tos.h
 devusb.$O: ../port/usb.h
 usbehci.$O usbohci.$O usbuhci.$O: ../port/usb.h usbehci.h uncached.h
 
-init.h:D:	../port/initcode.c init9.s
-	$CC ../port/initcode.c
-	$AS init9.s
-	$LD -l -R1 -s -o init.out init9.$O initcode.$O /$objtype/lib/libc.a
-	{echo 'uchar initcode[]={'
-	 xd -1x <init.out |
-		sed -e 's/^[0-9a-f]+ //' -e 's/ ([0-9a-f][0-9a-f])/0x\1,/g'
-	 echo '};'} > init.h
+init9.$O:	../omap/init9.s
+	$AS ../omap/init9.s
 
-reboot.h:D:	rebootcode.s cache.v7.s arm.s arm.h mem.h
-	$AS rebootcode.s
-	# -lc is only for memmove.  -T arg is PADDR(REBOOTADDR)
-#	$LD -l -a -s -T0x100 -R4 -o reboot.out rebootcode.$O -lc >reboot.list
-	$LD -l -s -T0x100 -R4 -o reboot.out rebootcode.$O -lc
-	{echo 'uchar rebootcode[]={'
-	 xd -1x reboot.out |
-		sed -e '1,2d' -e 's/^[0-9a-f]+ //' -e 's/ ([0-9a-f][0-9a-f])/0x\1,/g'
-	 echo '};'} > reboot.h
-errstr.h:D:	../port/mkerrstr ../port/error.h
-	rc ../port/mkerrstr > errstr.h
+initcode.out:		init9.$O initcode.$O /$objtype/lib/libc.a
+	$LD -l -R1 -s -o $target $prereq
 
-$CONF.clean:
-	rm -rf $p$CONF s$p$CONF errstr.h reboot.h $CONF.c boot$CONF.c
+rebootcode.out:		rebootcode.$O
+	$LD -l -R4 -T0x100 -s -o $target $prereq -lc
--- a/sys/src/9/teg2/syscall.c
+++ b/sys/src/9/teg2/syscall.c
@@ -353,8 +353,4 @@
 
 	/* syscall returns 0 for child */
 	cureg->r0 = 0;
-
-	/* Things from bottom of syscall which were never executed */
-	p->psstate = 0;
-	p->insyscall = 0;
 }
--- a/sys/src/9/xen/main.c
+++ b/sys/src/9/xen/main.c
@@ -1,4 +1,5 @@
 #include	"u.h"
+#include	"tos.h"
 #include	"../port/lib.h"
 #include	"mem.h"
 #include	"dat.h"
@@ -5,10 +6,8 @@
 #include	"fns.h"
 #include	"io.h"
 #include	"ureg.h"
-#include	"init.h"
 #include	"pool.h"
-#include	"reboot.h"
-#include	<tos.h>
+#include	"rebootcode.i"
 
 Mach *m;
 
@@ -16,16 +15,10 @@
 #define	BOOTARGSLEN	(sizeof xenstart->cmd_line)
 #define	MAXCONF		64
 
-enum {
-	/* space for syscall args, return PC, top-of-stack struct */
-	Ustkheadroom	= sizeof(Sargs) + sizeof(uintptr) + sizeof(Tos),
-};
-
 Conf conf;
 char *confname[MAXCONF];
 char *confval[MAXCONF];
 int nconf;
-uchar *sp;	/* user stack of init proc */
 int idle_spin;
 
 static void
@@ -152,22 +145,9 @@
 void
 init0(void)
 {
+	char buf[2*KNAMELEN], **sp;
 	int i;
-	char buf[2*KNAMELEN];
 
-	up->nerrlab = 0;
-
-	spllo();
-
-	/*
-	 * These are o.k. because rootinit is null.
-	 * Then early kproc's will have a root and dot.
-	 */
-	up->slash = namec("#/", Atodir, 0, 0);
-	pathclose(up->slash->path);
-	up->slash->path = newpath("/");
-	up->dot = cclone(up->slash);
-
 	chandevinit();
 
 	if(!waserror()){
@@ -186,104 +166,13 @@
 		}
 		poperror();
 	}
-
 	kproc("alarm", alarmkproc, 0);
-	touser(sp);
-}
 
-void
-userinit(void)
-{
-	Proc *p;
-	Segment *s;
-	KMap *k;
-	Page *pg;
-
-	p = newproc();
-	p->pgrp = newpgrp();
-	p->egrp = smalloc(sizeof(Egrp));
-	p->egrp->ref = 1;
-	p->fgrp = dupfgrp(nil);
-	p->rgrp = newrgrp();
-	p->procmode = 0640;
-
-	kstrdup(&eve, "");
-	kstrdup(&p->text, "*init*");
-	kstrdup(&p->user, eve);
-
-	p->fpstate = FPinit;
-	fpoff();
-
-	/*
-	 * Kernel Stack
-	 *
-	 * N.B. make sure there's enough space for syscall to check
-	 *	for valid args and 
-	 *	4 bytes for gotolabel's return PC
-	 */
-	p->sched.pc = (ulong)init0;
-	p->sched.sp = (ulong)p->kstack+KSTACK-(sizeof(Sargs)+BY2WD);
-
-	/*
-	 * User Stack
-	 */
-	s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG);
-	p->seg[SSEG] = s;
-	pg = newpage(1, 0, USTKTOP-BY2PG);
-	segpage(s, pg);
-	k = kmap(pg);
-	bootargs(VA(k));
-	kunmap(k);
-
-	/*
-	 * Text
-	 */
-	s = newseg(SG_TEXT, UTZERO, 1);
-	s->flushme++;
-	p->seg[TSEG] = s;
-	pg = newpage(1, 0, UTZERO);
-	pg->txtflush = ~0;
-	segpage(s, pg);
-	k = kmap(s->map[0]->pages[0]);
-	memmove((ulong*)VA(k), initcode, sizeof initcode);
-	kunmap(k);
-	ready(p);
-}
-
-uchar *
-pusharg(char *p)
-{
-	int n;
-
-	n = strlen(p)+1;
-	sp -= n;
-	memmove(sp, p, n);
-	return sp;
-}
-
-void
-bootargs(ulong base)
-{
- 	int i, ac;
-	uchar *av[32];
-	uchar **lsp;
-
-	sp = (uchar*)base + BY2PG - Ustkheadroom;
-
-	ac = 0;
-	av[ac++] = pusharg("boot");
-	av[ac++] = pusharg("-D");
-
-	/* 4 byte word align stack */
-	sp = (uchar*)((ulong)sp & ~3);
-
-	/* build argc, argv on stack */
-	sp -= (ac+1)*sizeof(sp);
-	lsp = (uchar**)sp;
-	for(i = 0; i < ac; i++)
-		*lsp++ = av[i] + ((USTKTOP - BY2PG) - base);
-	*lsp = 0;
-	sp += (USTKTOP - BY2PG) - base - sizeof(ulong);
+	sp = (char**)(USTKTOP - sizeof(Tos) - 8 - sizeof(sp[0])*4);
+	sp[3] = sp[2] = nil;
+	strcpy(sp[1] = (char*)&sp[4], "boot");
+	sp[0] = nil;
+	touser(sp);
 }
 
 char*
--- a/sys/src/9/xen/mkfile
+++ b/sys/src/9/xen/mkfile
@@ -37,6 +37,7 @@
 	taslock.$O\
 	tod.$O\
 	xalloc.$O\
+	userinit.$O\
 
 XEN=\
 	xengrant.$O\
@@ -131,8 +132,8 @@
 # we inherited these.. revisit.
 $ETHER: 	../port/etherif.h ../port/netif.h
 $SDEV:	../port/sd.h
-main.$O:	init.h reboot.h
-trap.$O:	/sys/include/tos.h
+main.$O:		rebootcode.i
+main.$O trap.$O:	/sys/include/tos.h
 
 %.$O:	/$objtype/include/u.h ../port/lib.h mem.h dat.h fns.h io.h ../port/error.h ../port/portdat.h ../port/portfns.h xendat.h xendefs.h
 
@@ -146,23 +147,15 @@
 	  cat xen-public/^($XENHEADERS) } | \
 	./cppx > $target
 
-init.h:	../port/initcode.c ../pc/init9.c
-	$CC ../port/initcode.c
-	$CC ../pc/init9.c
-	$LD -l -R1 -o init.out init9.$O initcode.$O /386/lib/libc.a
-	{echo 'uchar initcode[]={'
-	 strip -o /fd/1 init.out | xd -1x |
-		sed -e 's/^[0-9a-f]+ //' -e 's/ ([0-9a-f][0-9a-f])/0x\1,/g'
-	 echo '};'} > init.h
+initcode.out:		init9.$O initcode.$O /$objtype/lib/libc.a
+	$LD -l -R1 -s -o $target $prereq
 
-reboot.h:	../pc/rebootcode.s
+rebootcode.$O:	../pc/rebootcode.s mem.h
 	$AS ../pc/rebootcode.s
-	$LD -l -s -T0x1000 -R4 -o reboot.out rebootcode.$O
-	{echo 'uchar rebootcode[]={'
-	 xd -1x reboot.out |
-		sed -e '1,2d' -e 's/^[0-9a-f]+ //' -e 's/ ([0-9a-f][0-9a-f])/0x\1,/g'
-	 echo '};'} > reboot.h
 
+rebootcode.out:		rebootcode.$O
+	$LD -l -R4 -s -o $target -T0x1000 $prereq
+
 acid:V:
 	$CC -a -w main.c>acid
 
@@ -176,6 +169,6 @@
 	mk -f utilmkfile $target
 
 %.clean:V:
-	rm -f $stem.c [9bz]$stem [9bz]$stem.gz 9$stem.elf boot$stem.* reboot.h init.h xendat.h xendefs.h $PCHEADERS dpart xenbin.$cputype xenelf.$cputype xenstore
+	rm -f $stem.c [9bz]$stem [9bz]$stem.gz 9$stem.elf boot$stem.* xendat.h xendefs.h $PCHEADERS dpart xenbin.$cputype xenelf.$cputype xenstore
 
 
--- a/sys/src/9/xen/trap.c
+++ b/sys/src/9/xen/trap.c
@@ -1015,10 +1015,6 @@
 	memmove(cureg, ureg, sizeof(Ureg));
 	/* return value of syscall in child */
 	cureg->ax = 0;
-
-	/* Things from bottom of syscall which were never executed */
-	p->psstate = 0;
-	p->insyscall = 0;
 }
 
 /* Give enough context in the ureg to produce a kernel stack for
--- a/sys/src/9/zynq/main.c
+++ b/sys/src/9/zynq/main.c
@@ -1,13 +1,12 @@
 #include "u.h"
+#include "tos.h"
 #include "../port/lib.h"
 #include "mem.h"
 #include "dat.h"
 #include "fns.h"
-#include "init.h"
 #include "pool.h"
 #include "io.h"
 #include "../port/error.h"
-#include "tos.h"
 
 Conf conf;
 int normalprint, delaylink;
@@ -213,20 +212,12 @@
 	imagmem->maxsize = kmem - (kmem/10);
 }
 
-static void
+void
 init0(void)
 {
 	char buf[ERRMAX], **sp;
 	int i;
 
-	up->nerrlab = 0;
-	spllo();
-	
-	up->slash = namec("#/", Atodir, 0, 0);
-	pathclose(up->slash->path);
-	up->slash->path = newpath("/");
-	up->dot = cclone(up->slash);
-	
 	chandevinit();
 	uartconsole();
 	
@@ -253,54 +244,6 @@
 	strcpy(sp[1] = (char*)&sp[4], "boot");
 	sp[0] = nil;
 	touser(sp);
-}
-
-void
-userinit(void)
-{
-	Proc *p;
-	Segment *s;
-	void *v;
-	Page *pg;
-	
-	p = newproc();
-	p->pgrp = newpgrp();
-	p->egrp = smalloc(sizeof(Egrp));
-	p->egrp->ref = 1;
-	p->fgrp = dupfgrp(nil);
-	p->rgrp = newrgrp();
-	p->procmode = 0640;
-	
-	kstrdup(&eve, "");
-	kstrdup(&p->text, "*init*");
-	kstrdup(&p->user, eve);
-	
-	procsetup(p);
-	
-	p->sched.pc = (ulong)init0;
-	p->sched.sp = (ulong)p->kstack + KSTACK - (sizeof(Sargs) + BY2WD);
-	
-	s = newseg(SG_STACK, USTKTOP - USTKSIZE, USTKSIZE / BY2PG);
-	p->seg[SSEG] = s;
-	pg = newpage(0, 0, USTKTOP - BY2PG);
-	segpage(s, pg);
-	v = tmpmap(pg->pa);
-	memset(v, 0, BY2PG);
-	tmpunmap(v);
-	
-	s = newseg(SG_TEXT, UTZERO, 1);
-	s->flushme++;
-	p->seg[TSEG] = s;
-	pg = newpage(0, 0, UTZERO);
-	pg->txtflush = ~0;
-
-	segpage(s, pg);
-	v = tmpmap(pg->pa);
-	memset(v, 0, BY2PG);
-	memmove(v, initcode, sizeof(initcode));
-	tmpunmap(v);
-	
-	ready(p);
 }
 
 void
--- a/sys/src/9/zynq/mkfile
+++ b/sys/src/9/zynq/mkfile
@@ -39,6 +39,7 @@
 	random.$O\
 	rdb.$O\
 	syscallfmt.$O\
+	userinit.$O\
 
 OBJ=\
 	ltrap.$O\
@@ -71,14 +72,8 @@
 <../port/portmkfile
 <|../port/mkbootrules $CONF
 
-init.h:D: ../port/initcode.c init9.s
-	$CC ../port/initcode.c
-	$AS init9.s
-	$LD -l -R1 -s -o init.out init9.$O initcode.$O /arm/lib/libc.a
-	{echo 'uchar initcode[]={'
-	 xd -1x <init.out |
-		sed -e 's/^[0-9a-f]+ //' -e 's/ ([0-9a-f][0-9a-f])/0x\1,/g'
-	 echo '};'} > init.h
+initcode.out:		init9.$O initcode.$O /$objtype/lib/libc.a
+	$LD -l -R1 -s -o $target $prereq
 
 install:V:	$p$CONF
 	cp $p$CONF /$objtype/
@@ -85,5 +80,6 @@
 	for(i in $EXTRACOPIES)
 		import $i / /n/$i && cp $p$CONF $p$CONF.gz /n/$i/$objtype/
 
+main.$O trap.$O: /sys/include/tos.h
 devusb.$O usbehci.$O usbehcizynq.$O: ../port/usb.h
 usbehci.$O usbehcizynq.$O: usbehci.h
--- a/sys/src/9/zynq/trap.c
+++ b/sys/src/9/zynq/trap.c
@@ -569,9 +569,6 @@
 	cureg = (Ureg*) p->sched.sp;
 	memmove(cureg, ureg, sizeof(Ureg));
 	cureg->r0 = 0;
-
-	p->psstate = 0;
-	p->insyscall = 0;
 }
 
 uintptr