shithub: drawcpu

Download patch

ref: eff99e9be0f63c0cc54146e21af5bd423238c226
parent: 8d93ccdbb2a2dee8d2eb1387da1b316fdf84b208
author: halfwit <michaelmisch1985@gmail.com>
date: Sat Jul 19 12:54:05 EDT 2025

updates to embedded 5e

--- a/include/proc.h
+++ b/include/proc.h
@@ -1,2 +1,4 @@
 extern void step(void);
 int loadtext(char *, int, char **);
+void inittos(void);
+void resetvfp(void);
\ No newline at end of file
--- a/kern/Makefile
+++ b/kern/Makefile
@@ -23,6 +23,7 @@
 	devtab.$O\
 	dirread.$O\
 	error.$O\
+	fpa.$O\
 	getwd.$O\
 	memchr.$O\
 	parse.$O\
@@ -44,6 +45,7 @@
 	qlock.$O\
 	wait.$O\
 	waserror.$O\
+	vfp.$O\
 	$(OS).$O
 
 default: $(LIB)
--- a/kern/arm.c
+++ b/kern/arm.c
@@ -20,72 +20,73 @@
 void
 invalid(u32int instr)
 {
-	fprint(2, "undefined instruction %8ux @ %8ux", instr, up->R[15] - 4);
+    panic("undefined instruction %.8ux @ %.8ux\n", instr, up->R[15] - 4);
 }
 
 u32int
 evenaddr(u32int addr, u32int mask)
 {
-	if((addr & mask) == 0)
-		return addr;
-	return addr & ~mask;
+    if((addr & mask) == 0)
+        return addr;
+    panic("unaligned access %8ux @ %8ux", addr, up->R[15] - 4);
+    return addr & ~mask;
 }
 
 static u32int
-doshift(u32int instr, uint *carry)
+doshift(u32int instr, uchar *carry)
 {
-	ulong amount, val;
-
-	val = up->R[instr & 15];
-	if(instr & (1<<4)) {
-		if(instr & (1<<7))
-			invalid(instr);
-		amount = up->R[(instr >> 8) & 15] & 0xFF;
-		if(amount == 0)
-			return val;
-	} else {
-		amount = (instr >> 7) & 31;
-		if(amount == 0 && (instr & (3<<5)) != 0)
-			amount = 32;
-	}
-	switch((instr >> 5) & 3) {
-	default:
-		if(amount == 0)
-			return val;
-		if(amount < 32) {
-			*carry = (val >> (32 - amount)) & 1;
-			return val << amount;
-		}
-		*carry = val & 1;
-		return 0;
-	case 1:
-		if(amount < 32){
-			*carry = (val >> (amount - 1)) & 1;
-			return val >> amount;
-		}
-		*carry = val >> 31;
-		return 0;
-	case 2:
-		if(amount < 32){
-			*carry = (val >> (amount - 1)) & 1;
-			return ((long) val) >> amount;
-		}
-		if((long)val < 0){
-			*carry = 1;
-			return -1;
-		}
-		*carry = 0;
-		return 0;
-	case 3:
-		amount &= 31;
-		if(amount){
-			*carry = (val >> (amount - 1)) & 1;
-			return (val >> amount) | (val << (32 - amount));
-		}
-		amount = *carry & 1;
-		*carry = val & 1;
-		return (val>>1) | (amount<<31);
-	}
+    ulong amount, val;
+print("doshift\n");
+    val = up->R[instr & 15];
+    if(instr & (1<<4)) {
+        if(instr & (1<<7))
+            invalid(instr);
+        amount = up->R[(instr >> 8) & 15] & 0xFF;
+        if(amount == 0)
+            return val;
+    } else {
+        amount = (instr >> 7) & 31;
+        if(amount == 0 && (instr & (3<<5)) != 0)
+            amount = 32;
+    }
+    switch((instr >> 5) & 3) {
+    default:
+        if(amount == 0)
+            return val;
+        if(amount < 32) {
+            *carry = (val >> (32 - amount)) & 1;
+            return val << amount;
+        }
+        *carry = val & 1;
+        return 0;
+    case 1:
+        if(amount < 32){
+            *carry = (val >> (amount - 1)) & 1;
+            return val >> amount;
+        }
+        *carry = val >> 31;
+        return 0;
+    case 2:
+        if(amount < 32){
+            *carry = (val >> (amount - 1)) & 1;
+            return ((long) val) >> amount;
+        }
+        if((long)val < 0){
+            *carry = 1;
+            return -1;
+        }
+        *carry = 0;
+        return 0;
+    case 3:
+        amount &= 31;
+        if(amount){
+            *carry = (val >> (amount - 1)) & 1;
+            return (val >> amount) | (val << (32 - amount));
+        }
+        amount = *carry & 1;
+        *carry = val & 1;
+        return (val>>1) | (amount<<31);
+    }
 }
 
 static void
@@ -96,9 +97,10 @@
 	u32int *Rn, *Rd;
 	void *targ;
 	Segment *seg;
-	
+print("single\n");
+
 	if(instr & fI) {
-		uint carry = 0;
+		uchar carry = 0;
 		if(instr & (1<<4))
 			invalid(instr);
 		offset = doshift(instr, &carry);
@@ -108,6 +110,7 @@
 		offset = - offset;
 	Rn = up->R + ((instr >> 16) & 15);
 	Rd = up->R + ((instr >> 12) & 15);
+
 	if((instr & (fW | fP)) == fW)
 		invalid(instr);
 	if(Rn == up->R + 15) {
@@ -114,8 +117,7 @@
 		if(instr & fW)
 			invalid(instr);
 		addr = up->R[15] + 4;
-	}
-	else
+	} else
 		addr = *Rn;
 	if(instr & fP)
 		addr += offset;
@@ -127,18 +129,18 @@
 		*(u32int*) targ = *Rd;
 		break;
 	case fB:
-		*(uint*) targ = *Rd;
+		*(uchar*) targ = *Rd;
 		break;
 	case fL:
 		*Rd = *(u32int*) targ;
 		break;
 	case fB | fL:
-		*Rd = *(uint*) targ;
+		*Rd = *(uchar*) targ;
 		break;
 	}
 	if(Rd == up->R + 15 && !(instr & fL)) {
 		if(instr & fB)
-			*(uint*) targ += 8;
+			*(uchar*) targ += 8;
 		else
 			*(u32int*) targ += 8;
 	}
@@ -152,67 +154,67 @@
 static void
 swap(u32int instr)
 {
-	u32int *Rm, *Rn, *Rd, *targ, addr, old, new;
-	Segment *seg;
-	
-	Rm = up->R + (instr & 15);
-	Rd = up->R + ((instr >> 12) & 15);
-	Rn = up->R + ((instr >> 16) & 15);
-	if(Rm == up->R + 15 || Rd == up->R + 15 || Rn == up->R + 15)
-		invalid(instr);
-	addr = *Rn;
-	if((instr & fB) == 0)
-		addr = evenaddr(addr, 3);
-	targ = (u32int *) vaddr(addr & ~3, 4, &seg);
-	do {
-		old = *targ;
-		new = *Rm;
-		if(instr & fB){
-			new &= 0xFF;
-			new <<= 8*(addr&3);
-			new |= old & ~(0xFF << 8*(addr&3));
-		}
-	} while(!cas((int*)targ, old, new));
-	if(instr & fB) {
-		old >>= 8*(addr&3);
-		old &= 0xFF;
-	}
-	*Rd = old;
-	segunlock(seg);
+    u32int *Rm, *Rn, *Rd, *targ, addr, old, new;
+    Segment *seg;
+print("swap\n");
+    Rm = up->R + (instr & 15);
+    Rd = up->R + ((instr >> 12) & 15);
+    Rn = up->R + ((instr >> 16) & 15);
+    if(Rm == up->R + 15 || Rd == up->R + 15 || Rn == up->R + 15)
+        invalid(instr);
+    addr = *Rn;
+    if((instr & fB) == 0)
+        addr = evenaddr(addr, 3);
+    targ = (u32int *) vaddr(addr & ~3, 4, &seg);
+    do {
+        old = *targ;
+        new = *Rm;
+        if(instr & fB){
+            new &= 0xFF;
+            new <<= 8*(addr&3);
+            new |= old & ~(0xFF << 8*(addr&3));
+        }
+    } while(!cas((int*)targ, old, new));
+    if(instr & fB) {
+        old >>= 8*(addr&3);
+        old &= 0xFF;
+    }
+    *Rd = old;
+    segunlock(seg);
 }
 
 static u32int
-add(u32int a, u32int b, uint type, uint *carry, uint *overflow)
+add(u32int a, u32int b, uchar type, uchar *carry, uchar *overflow)
 {
-	u32int res1;
-	u64int res2;
-
-	if(type) {
-		res2 = (u64int)a - b + *carry - 1;
-		res1 = res2;
-		if(((a ^ b) & (1<<31)) && !((b ^ res1) & (1<<31))) *overflow = 1;
-		else *overflow = 0;
-		if(res2 & 0x100000000LL) *carry = 0;
-		else *carry = 1;	
-	} else {
-		res2 = (u64int)a + b + *carry;
-		res1 = res2;
-		if(!((a ^ b) & (1<<31)) && ((b ^ res1) & (1<<31))) *overflow = 1;
-		else *overflow = 0;
-		if(res2 & 0x100000000LL) *carry = 1;
-		else *carry = 0;
-	}
-	return res1;
+    u32int res1;
+    u64int res2;
+print("add\n");
+    if(type) {
+        res2 = (u64int)a - b + *carry - 1;
+        res1 = res2;
+        if(((a ^ b) & (1<<31)) && !((b ^ res1) & (1<<31))) *overflow = 1;
+        else *overflow = 0;
+        if(res2 & 0x100000000LL) *carry = 0;
+        else *carry = 1;    
+    } else {
+        res2 = (u64int)a + b + *carry;
+        res1 = res2;
+        if(!((a ^ b) & (1<<31)) && ((b ^ res1) & (1<<31))) *overflow = 1;
+        else *overflow = 0;
+        if(res2 & 0x100000000LL) *carry = 1;
+        else *carry = 0;
+    }
+    return res1;
 }
 
 static void
 alu(u32int instr)
 {
-	u32int Rn, *Rd, operand, shift, result, op;
-	uint carry, overflow;
-	
-	Rn = up->R[(instr >> 16) & 15];
-	Rd = up->R + ((instr >> 12) & 15);
+    u32int Rn, *Rd, operand, shift, result, op;
+    uchar carry, overflow;
+    Rn = up->R[(instr >> 16) & 15];
+    Rd = up->R + ((instr >> 12) & 15);
+print("alu\n");
 	if(((instr >> 16) & 15) == 15) {
 		Rn += 4;
 		if(!(instr & fI) && (instr & (1<<4)))
@@ -235,10 +237,8 @@
 		operand = doshift(instr, &carry);
 
 	op = (instr >> 21) & 15;
-	if(op >= 8 && op <= 11 && !(instr & fS)){
-		fprint(2, "no PSR transfers plz");
-		return;
-	}
+	if(op >= 8 && op <= 11 && !(instr & fS))
+		sysfatal("no PSR transfers plz");
 	if(op >= 5 && op < 8)
 		carry = (up->CPSR & flC) != 0;
 	switch(op) {
@@ -271,310 +271,287 @@
 static void
 branch(u32int instr)
 {
-	long offset;
-	
-	offset = instr & ((1<<24) - 1);
-	if(offset & (1<<23))
-		offset |= ~((1 << 24) - 1);
-	offset *= 4;
-	if(instr & fLi)
-		up->R[14] = up->R[15];
-	up->R[15] += offset + 4;
+    long offset;
+print("branch\n"); 
+    offset = instr & ((1<<24) - 1);
+    if(offset & (1<<23))
+        offset |= ~((1 << 24) - 1);
+    offset *= 4;
+    if(instr & fLi)
+        up->R[14] = up->R[15];
+    up->R[15] += offset + 4;
 }
 
 static void
 halfword(u32int instr)
 {
-	u32int offset, target, *Rn, *Rd;
-	Segment *seg;
-	
-	if(instr & (1<<22)) {
-		offset = (instr & 15) | ((instr >> 4) & 0xF0);
-	} else {
-		if((instr & 15) == 15)
-			invalid(instr);
-		offset = up->R[instr & 15];
-	}
-	if(!(instr & fU))
-		offset = - offset;
-	if(!(instr & fP) && (instr & fW))
-		invalid(instr);
-	Rn = up->R + ((instr >> 16) & 15);
-	Rd = up->R + ((instr >> 12) & 15);
-	if(Rn == up->R + 15 || Rd == up->R + 15)
-		fprint(2, "R15 in halfword");
-	target = *Rn;
-	if(instr & fP)
-		target += offset;
-	if(instr & fH)
-		target = evenaddr(target, 1);
-	switch(instr & (fSg | fH | fL)) {
-	case fSg: *(uint*) vaddr(target, 1, &seg) = *Rd; break;
-	case fSg | fL: *Rd = (long) *(char*) vaddr(target, 1, &seg); break;
-	case fH: case fSg | fH: *(uint16_t*) vaddr(target, 2, &seg) = *Rd; break;
-	case fH | fL: *Rd = *(uint16_t*) vaddr(target, 2, &seg); break;
-	case fH | fL | fSg: *Rd = (long) *(short*) vaddr(target, 2, &seg); break;
-	}
-	segunlock(seg);
-	if(!(instr & fP))
-		target += offset;
-	if(!(instr & fP) || (instr & fW))
-		*Rn = target;
+    u32int offset, target, *Rn, *Rd;
+    Segment *seg;
+print("halfword\n");   
+    if(instr & (1<<22)) {
+        offset = (instr & 15) | ((instr >> 4) & 0xF0);
+    } else {
+        if((instr & 15) == 15)
+            invalid(instr);
+        offset = up->R[instr & 15];
+    }
+    if(!(instr & fU))
+        offset = - offset;
+    if(!(instr & fP) && (instr & fW))
+        invalid(instr);
+    Rn = up->R + ((instr >> 16) & 15);
+    Rd = up->R + ((instr >> 12) & 15);
+    target = *Rn;
+    if(instr & fP)
+        target += offset;
+    if(instr & fH)
+        target = evenaddr(target, 1);
+    switch(instr & (fSg | fH | fL)) {
+    case fSg: *(uchar*) vaddr(target, 1, &seg) = *Rd; break;
+    case fSg | fL: *Rd = (long) *(char*) vaddr(target, 1, &seg); break;
+    case fH: case fSg | fH: *(uint16_t*) vaddr(target, 2, &seg) = *Rd; break;
+    case fH | fL: *Rd = *(uint16_t*) vaddr(target, 2, &seg); break;
+    case fH | fL | fSg: *Rd = (long) *(short*) vaddr(target, 2, &seg); break;
+    }
+    segunlock(seg);
+    if(!(instr & fP))
+        target += offset;
+    if(!(instr & fP) || (instr & fW))
+        *Rn = target;
 }
 
 static void
 block(u32int instr)
 {
-	int i;
-	u32int targ, *Rn;
-	Segment *seg;
+    int i;
+    u32int targ, *Rn;
+    Segment *seg;
 
-	print("Checking invalid\n");
-	if(instr & (1<<22))
-		invalid(instr);
-	
-	Rn = up->R +((instr >> 16) & 15);
-	if(Rn == up->R + 15 || instr & (1<<15))
-		print("R15 in block");
-	targ = evenaddr(*Rn, 3);
-	if(instr & fU) {
-		for(i = 0; i < 16; i++) {
-			if(!(instr & (1<<i)))
-				continue;
-			if(instr & fP)
-				targ += 4;
-			if(instr & fL)
-				up->R[i] = *(u32int*) vaddr(targ, 4, &seg);
-			else
-				*(u32int*) vaddr(targ, 4, &seg) = up->R[i];
-			segunlock(seg);
-			if(!(instr & fP))
-				targ += 4;
-		}
-	} else {
-		for(i = 15; i >= 0; i--) {
-			if(!(instr & (1<<i)))
-				continue;
-			if(instr & fP)
-				targ -= 4;
-			if(instr & fL)
-				up->R[i] = *(u32int*) vaddr(targ, 4, &seg);
-			else
-				*(u32int*) vaddr(targ, 4, &seg) = up->R[i];
-			segunlock(seg);
-			if(!(instr & fP))
-				targ -= 4;
-		}
-	}
-	if(instr & fW)
-		*Rn = targ;
-	print("Farnished\n");
+    if(instr & (1<<22))
+        invalid(instr);
+print("block\n");    
+    Rn = up->R +((instr >> 16) & 15);
+    targ = evenaddr(*Rn, 3);
+    if(instr & fU) {
+        for(i = 0; i < 16; i++) {
+            if(!(instr & (1<<i)))
+                continue;
+print("%d\n", i);
+            if(instr & fP)
+                targ += 4;
+            if(instr & fL)
+                up->R[i] = *(u32int*) vaddr(targ, 4, &seg);
+            else
+                *(u32int*) vaddr(targ, 4, &seg) = up->R[i];
+            segunlock(seg);
+            if(!(instr & fP))
+                targ += 4;
+        }
+    } else {
+        for(i = 15; i >= 0; i--) {
+            if(!(instr & (1<<i)))
+                continue;
+            if(instr & fP)
+                targ -= 4;
+            if(instr & fL)
+                up->R[i] = *(u32int*) vaddr(targ, 4, &seg);
+            else
+                *(u32int*) vaddr(targ, 4, &seg) = up->R[i];
+            segunlock(seg);
+            if(!(instr & fP))
+                targ -= 4;
+        }
+    }
+    if(instr & fW)
+        *Rn = targ;
 }
 
 static void
 multiply(u32int instr)
 {
-	u32int *Rd, *Rn, *Rs, *Rm, res;
-	
-	Rm = up->R + (instr & 15);
-	Rs = up->R + ((instr >> 8) & 15);
-	Rn = up->R + ((instr >> 12) & 15);
-	Rd = up->R + ((instr >> 16) & 15);
-	if(Rd == Rm || Rm == up->R + 15 || Rs == up->R + 15 || Rn == up->R + 15 || Rd == up->R + 15)
-		invalid(instr);
-	res = *Rm * *Rs;
-	if(instr & (1<<21))
-		res += *Rn;
-	*Rd = res;
-	if(instr & (1<<20)) {
-		up->CPSR &= ~(flN | flZ);
-		if(res & (1<<31))
-			up->CPSR |= flN;
-		if(res == 0)
-			up->CPSR |= flZ;
-	}
+    u32int *Rd, *Rn, *Rs, *Rm, res;
+print("multiply\n");
+    Rm = up->R + (instr & 15);
+    Rs = up->R + ((instr >> 8) & 15);
+    Rn = up->R + ((instr >> 12) & 15);
+    Rd = up->R + ((instr >> 16) & 15);
+    if(Rd == Rm || Rm == up->R + 15 || Rs == up->R + 15 || Rn == up->R + 15 || Rd == up->R + 15)
+        invalid(instr);
+    res = *Rm * *Rs;
+    if(instr & (1<<21))
+        res += *Rn;
+    *Rd = res;
+    if(instr & (1<<20)) {
+        up->CPSR &= ~(flN | flZ);
+        if(res & (1<<31))
+            up->CPSR |= flN;
+        if(res == 0)
+            up->CPSR |= flZ;
+    }
 }
 
 static void
 multiplylong(u32int instr)
 {
-	u32int *RdH, *RdL, *Rs, *Rm;
-	u64int res;
-	
-	Rm = up->R + (instr & 15);
-	Rs = up->R + ((instr >> 8) & 15);
-	RdL = up->R + ((instr >> 12) & 15);
-	RdH = up->R + ((instr >> 16) & 15);
-	if(RdL == RdH || RdH == Rm || RdL == Rm || Rm == up->R + 15 || Rs == up->R + 15 || RdL == up->R + 15 || RdH == up->R + 15)
-		invalid(instr);
-	if(instr & (1<<22))
-		res = ((vlong)*(int*)Rs) * *(int*)Rm;
-	else {
-		res = *Rs;
-		res *= *Rm;
-	}
-	if(instr & (1<<21)) {
-		res += *RdL;
-		res += ((uvlong)*RdH) << 32;
-	}
-	*RdL = res;
-	*RdH = res >> 32;
-	if(instr & (1<<20)) {
-		up->CPSR &= ~FLAGS;
-		if(res == 0)
-			up->CPSR |= flN;
-		if(res & (1LL<<63))
-			up->CPSR |= flV;
-	}
+    u32int *RdH, *RdL, *Rs, *Rm;
+    u64int res;
+print("multiplylong\n");
+    Rm = up->R + (instr & 15);
+    Rs = up->R + ((instr >> 8) & 15);
+    RdL = up->R + ((instr >> 12) & 15);
+    RdH = up->R + ((instr >> 16) & 15);
+    if(RdL == RdH || RdH == Rm || RdL == Rm || Rm == up->R + 15 || Rs == up->R + 15 || RdL == up->R + 15 || RdH == up->R + 15)
+        invalid(instr);
+    if(instr & (1<<22))
+        res = ((vlong)*(int*)Rs) * *(int*)Rm;
+    else {
+        res = *Rs;
+        res *= *Rm;
+    }
+    if(instr & (1<<21)) {
+        res += *RdL;
+        res += ((uvlong)*RdH) << 32;
+    }
+    *RdL = res;
+    *RdH = res >> 32;
+    if(instr & (1<<20)) {
+        up->CPSR &= ~FLAGS;
+        if(res == 0)
+            up->CPSR |= flN;
+        if(res & (1LL<<63))
+            up->CPSR |= flV;
+    }
 }
 
 static void
 singleex(u32int instr)
 {
-	u32int *Rn, *Rd, *Rm, *targ, addr;
-	Segment *seg;
-	
-	Rd = up->R + ((instr >> 12) & 15);
-	Rn = up->R + ((instr >> 16) & 15);
-	if(Rd == up->R + 15 || Rn == up->R + 15)
-		invalid(instr);
-	addr = evenaddr(*Rn, 3);
-	if(instr & fS) {
-		targ = vaddr(addr, 4, &seg);
-		*Rd = *targ;
-		up->lladdr = addr;
-		up->llval = *Rd;
-		segunlock(seg);
-	} else {
-		Rm = up->R + (instr & 15);
-		if(Rm == up->R + 15)
-			invalid(instr);
-		targ = vaddr(addr, 4, &seg);
-
-		/*
-		 * this is not quite correct as we will succeed even
-		 * if the value was modified and then restored to its
-		 * original value but good enough approximation for
-		 * libc's _tas(), _cas() and _xinc()/_xdec().
-		 */
-		*Rd = addr != up->lladdr || !cas((int*)targ, up->llval, *Rm);
-		segunlock(seg);
-		clrex();
-	}
+    u32int *Rn, *Rd, *Rm, *targ, addr;
+    Segment *seg; 
+print("singleex\n");
+    Rd = up->R + ((instr >> 12) & 15);
+    Rn = up->R + ((instr >> 16) & 15);
+    if(Rd == up->R + 15 || Rn == up->R + 15)
+        invalid(instr);
+    addr = evenaddr(*Rn, 3);
+    if(instr & fS) {
+        targ = vaddr(addr, 4, &seg);
+        *Rd = *targ;
+        up->lladdr = addr;
+        up->llval = *Rd;
+        segunlock(seg);
+    } else {
+        Rm = up->R + (instr & 15);
+        if(Rm == up->R + 15)
+            invalid(instr);
+        targ = vaddr(addr, 4, &seg);
+        *Rd = addr != up->lladdr || !cas((int*)targ, up->llval, *Rm);
+        segunlock(seg);
+        clrex();
+    }
 }
 
 void
 clrex(void)
 {
-	up->lladdr = 0;
-	up->llval = 0;
+print("clrex\n");
+    up->lladdr = 0;
+    up->llval = 0;
 }
 
 static void
 barrier(void)
 {
-	static Lock l;
-
-	lock(&l);
-	unlock(&l);
+print("barrier\n");
+    static Lock l;
+    lock(&l);
+    unlock(&l);
 }
 
-int
+void
 step(void)
 {
-	u32int instr;
-	Segment *seg;
-print("Grabbing instruction\n");
-	instr = *(u32int*) vaddr(up->R[15], 4, &seg);
-print("Grabbed instruction\n");
-	segunlock(seg);
+    u32int instr;
+    Segment *seg;
 
-	up->R[15] += 4;
+    if (!up->S[SEGTEXT] || up->R[15] < up->S[SEGTEXT]->start || up->R[15] >= up->S[SEGTEXT]->start + up->S[SEGTEXT]->size) {
+        panic("step: invalid PC=%.8ux outside text segment [%.8ux, %.8ux)\n",
+              up->R[15], 
+              up->S[SEGTEXT] ? up->S[SEGTEXT]->start : 0, 
+              up->S[SEGTEXT] ? up->S[SEGTEXT]->start + up->S[SEGTEXT]->size : 0);
+        return;
+    }
+
+    void *targ = vaddr(up->R[15], 4, &seg);
+    instr = *(u32int*)targ;
+    segunlock(seg);
+
+    up->R[15] += 4;
+
 	switch(instr >> 28) {
-	case 0x0: if(!(up->CPSR & flZ)) return 1; break;
-	case 0x1: if(up->CPSR & flZ) return 1; break;
-	case 0x2: if(!(up->CPSR & flC)) return 1; break;
-	case 0x3: if(up->CPSR & flC) return 1; break;
-	case 0x4: if(!(up->CPSR & flN)) return 1; break;
-	case 0x5: if(up->CPSR & flN) return 1; break;
-	case 0x6: if(!(up->CPSR & flV)) return 1; break;
-	case 0x7: if(up->CPSR & flV) return 1; break;
-	case 0x8: if(!(up->CPSR & flC) || (up->CPSR & flZ)) return 1; break;
-	case 0x9: if((up->CPSR & flC) && !(up->CPSR & flZ)) return 1; break;
-	case 0xA: if(!(up->CPSR & flN) != !(up->CPSR & flV)) return 1; break;
-	case 0xB: if(!(up->CPSR & flN) == !(up->CPSR & flV)) return 1; break;
-	case 0xC: if((up->CPSR & flZ) || !(up->CPSR & flN) != !(up->CPSR & flV)) return 1; break;
-	case 0xD: if(!(up->CPSR & flZ) && !(up->CPSR & flN) == !(up->CPSR & flV)) return 1; break;
+	case 0x0: if(!(up->CPSR & flZ)) return; break;
+	case 0x1: if(up->CPSR & flZ) return; break;
+	case 0x2: if(!(up->CPSR & flC)) return; break;
+	case 0x3: if(up->CPSR & flC) return; break;
+	case 0x4: if(!(up->CPSR & flN)) return; break;
+	case 0x5: if(up->CPSR & flN) return; break;
+	case 0x6: if(!(up->CPSR & flV)) return; break;
+	case 0x7: if(up->CPSR & flV) return; break;
+	case 0x8: if(!(up->CPSR & flC) || (up->CPSR & flZ)) return; break;
+	case 0x9: if((up->CPSR & flC) && !(up->CPSR & flZ)) return; break;
+	case 0xA: if(!(up->CPSR & flN) != !(up->CPSR & flV)) return; break;
+	case 0xB: if(!(up->CPSR & flN) == !(up->CPSR & flV)) return; break;
+	case 0xC: if((up->CPSR & flZ) || !(up->CPSR & flN) != !(up->CPSR & flV)) return; break;
+	case 0xD: if(!(up->CPSR & flZ) && !(up->CPSR & flN) == !(up->CPSR & flV)) return; break;
 	case 0xE: break;
 	case 0xF:
 		switch(instr & 0xFFF000F0){
 		case 0xF5700010:	/* CLREX */
-		print("clrex\n");
-			//clrex();
-			return 1;
+			clrex();
+			return;
 		case 0xF5700040:	/* DSB */
 		case 0xF5700050:	/* DMB */
 		case 0xF5700060:	/* ISB */
-		print("barrier\n");
-			//barrier();
-			return 1;
+			barrier();
+			return;
 		}
 	default: 
-		fprint(2, "condition code %x not implemented (instr %ux, ps %ux)", instr >> 28, instr, up->R[15]);
-		return 0;
+        sysfatal("condition code %x not implemented (instr %ux, ps %ux)", instr >> 28, instr, up->R[15]);
 	}
-	if((instr & 0x0FB00FF0) == 0x01000090)
-	print("Swap\n");
-		//swap(instr);
-	else if((instr & 0x0FE000F0) == 0x01800090)
-	print("Singleex\n");
-		//singleex(instr);
-	else if((instr & 0x0FC000F0) == 0x90)
-	print("Multiply\n");
-		//multiply(instr);
-	else if((instr & 0x0F8000F0) == 0x800090)
-	print("Multiplylong\n");
-		//multiplylong(instr);
-	else if((instr & ((1<<26) | (1<<27))) == (1 << 26))
-	print("Single\n");
-		//single(instr);
-	else if((instr & 0x0E000090) == 0x90 && (instr & 0x60))
-	print("Halfword\n");
-		//halfword(instr);
-	else if((instr & ((1<<26) | (1<<27))) == 0)
-	print("Alu\n");
-		//alu(instr);
-	else if((instr & (7<<25)) == (5 << 25))
-	print("Branch\n");
-		//branch(instr);
-	else if((instr & (15<<24)) == (15 << 24))
-	print("Syscall\n");
-		//_syscall();
-	else if((instr & (7<<25)) == (4 << 25))
-	print("Block\n");
-		//block(instr);
-	else if((instr & 0x0E000F00) == 0x0C000100)
-	print("Fpatransfer\n");
-		//fpatransfer(instr);
-	else if((instr & 0x0E000F10) == 0x0E000100)
-	print("Fpaoperation\n");
-		//fpaoperation(instr);
-	else if((instr & 0x0E000F10) == 0x0E000110)
-	print("Fparegtransfer\n");
-		//fparegtransfer(instr);
-	else if((instr & 0x0F000A10) == 0x0E000A00)
-	print("Vfpoperation\n");
-		//vfpoperation(instr);
-	else if((instr & 0x0F000F10) == 0x0E000A10)
-	print("Vfpregtransfer\n");
-		//vfpregtransfer(instr);
-	else if((instr & 0x0F000A00) == 0x0D000A00)
-	print("Vfprmtransfer\n");
-		//vfprmtransfer(instr);
-	else {
-		print("Invalid\n");
-		invalid(instr);
-		return 0;
-	}
-	return 1;
+
+    if ((instr & 0x0FB00FF0) == 0x01000090)
+        swap(instr);
+    else if ((instr & 0x0FE000F0) == 0x01800090)
+        singleex(instr);
+    else if ((instr & 0x0FC000F0) == 0x90)
+        multiply(instr);
+    else if ((instr & 0x0F8000F0) == 0x800090)
+        multiplylong(instr);
+    else if ((instr & ((1<<26) | (1<<27))) == (1 << 26))
+        single(instr);
+    else if ((instr & 0x0E000090) == 0x90 && (instr & 0x60))
+        halfword(instr);
+    else if ((instr & ((1<<26) | (1<<27))) == 0)
+        alu(instr);
+    else if ((instr & (7<<25)) == (5 << 25))
+        branch(instr);
+    else if ((instr & (15<<24)) == (15 << 24))
+        _syscall();
+    else if ((instr & (7<<25)) == (4 << 25))
+        block(instr);
+    else if ((instr & 0x0E000F00) == 0x0C000100)
+        fpatransfer(instr);
+    else if ((instr & 0x0E000F10) == 0x0E000100)
+        fpaoperation(instr);
+    else if ((instr & 0x0E000F10) == 0x0E000110)
+        fparegtransfer(instr);
+    else if ((instr & 0x0F000A10) == 0x0E000A00)
+        vfpoperation(instr);
+    else if ((instr & 0x0F000F10) == 0x0E000A10)
+        vfpregtransfer(instr);
+    else if ((instr & 0x0F000A00) == 0x0D000A00)
+        vfprmtransfer(instr);
+    else {
+        invalid(instr);
+    }
 }
\ No newline at end of file
--- a/kern/dat.h
+++ b/kern/dat.h
@@ -120,7 +120,6 @@
 };
 
 enum {
-	STACKSIZE = 0x100000,
 	NAMEMAX = 27,
 	NSMAX	=	1000,
 	NNOTE = 5,
@@ -376,6 +375,7 @@
 	Pgrp	*pgrp;		/* Process group for namespace */
 	Fgrp	*fgrp;		/* File descriptor group */
 	Rgrp	*rgrp;
+	Egrp    *egrp;
 
 	Lock	rlock;		/* sync sleep/wakeup with postnote */
 	Rendez	*r;		/* rendezvous point slept on */
--- a/kern/fns.h
+++ b/kern/fns.h
@@ -1,5 +1,6 @@
 //#define	ROUND(s, sz)	(((s)+((sz)-1))&~((sz)-1))
 
+void        addnote(char*);
 Block*		adjustblock(Block*, int);
 Block*		allocb(int);
 int		    blocklen(Block*);
@@ -125,6 +126,7 @@
 Mount*		newmount(Chan*, int, char*);
 Path*		newpath(char*);
 Pgrp*		newpgrp(void);
+Egrp*       newegrp(void);
 Rgrp*		newrgrp(void);
 Proc*		newproc(void);
 char*		nextelem(char*, char*);
@@ -219,7 +221,6 @@
 int	    	splhi(void);
 int		    spllo(void);
 void		splx(int);
-int         step(void);
 void        _syscall(void);
 Block*		trimblock(Block*, int, int);
 long		unionread(Chan*, void*, long);
--- /dev/null
+++ b/kern/fpa.c
@@ -1,0 +1,145 @@
+#include "u.h"
+#include "lib.h"
+#include "dat.h"
+#include "fns.h"
+
+void
+resetfpa(void)
+{
+	int i;
+	
+	up->FPSR = 0x81000000;
+	for(i = 0; i < 8; i++)
+		up->F[i] = 0;
+}
+
+void
+fpatransfer(u32int instr)
+{
+	enum {
+		fP = 1<<24,
+		fU = 1<<23,
+		fT1 = 1<<22,
+		fW = 1<<21,
+		fL = 1<<20,
+		fT0 = 1<<15,
+	};
+
+	double *Fd;
+	u32int *Rn, addr;
+	int off;
+	void *targ;
+	Segment *seg;
+
+	Rn = up->R + ((instr >> 16) & 15);
+	Fd = up->F + ((instr >> 12) & 7);
+	if(Rn == up->R + 15)
+		invalid(instr);
+	off = (instr & 255) * 4;
+	if(!(instr  & fU))
+		off = -off;
+	addr = *Rn;
+	if(instr & fP)
+		addr += off;
+	targ = vaddr(addr, 8, &seg);
+	switch(instr & (fT0 | fT1 | fL)) {
+	case 0: *(float *) targ = *Fd; break;
+	case fL: *Fd = *(float *) targ; break;
+	case fT0: *(double *) targ = *Fd; break;
+	case fT0 | fL: *Fd = *(double *) targ; break;
+	default: invalid(instr);
+	}
+	segunlock(seg);
+	if(!(instr & fP))
+		addr += off;
+	if(instr & fW)
+		*Rn = addr;
+}
+
+static double
+fpasecop(u32int instr)
+{
+	switch(instr & 15) {
+	case 8: return 0.0; break;
+	case 9: return 1.0; break;
+	case 10: return 2.0; break;
+	case 11: return 3.0; break;
+	case 12: return 4.0; break;
+	case 13: return 5.0; break;
+	case 14: return 0.5; break;
+	case 15: return 10.0; break;
+	}
+	return up->F[instr & 7];
+}
+
+void
+fpaoperation(u32int instr)
+{
+	double *Fn, *Fd, op, op2, res;
+	int prec, opc;
+	
+	Fn = up->F + ((instr >> 16) & 7);
+	Fd = up->F + ((instr >> 12) & 7);
+	op2 = fpasecop(instr);
+	op = *Fn;
+	prec = ((instr >> 7) & 1) | ((instr >> 18) & 2);
+	opc = ((instr >> 20) & 15) | ((instr >> 11) & 16);
+	switch(opc) {
+	case 0: res = op + op2; break;
+	case 1: res = op * op2; break;
+	case 2: res = op - op2; break;
+	case 3: res = op2 - op; break;
+	case 4: res = op / op2; break;
+	case 5: res = op2 / op; break;
+	case 16: res = op2; break;
+	case 17: res = - op2; break;
+	case 18: res = fabs(op2); break;
+	case 19: res = (vlong) op2; break;
+	case 20: res = sqrt(op2); break;
+	default: sysfatal("unimplemented FPA operation %#x @ %8ux", opc, up->R[15] - 4);
+	}
+	switch(prec) {
+	case 0: *Fd = (float) res; break;
+	case 1: *Fd = (double) res; break;
+	case 2: *Fd = res; break;
+	default: invalid(instr);
+	}
+}
+
+void
+fparegtransfer(u32int instr)
+{
+	u32int *Rd;
+	long tmp;
+	double *Fn, op, op2;
+	
+	Rd = up->R + ((instr >> 12) & 15);
+	Fn = up->F + ((instr >> 16) & 7);
+	op = fpasecop(instr);
+	if(Rd == up->R + 15) {
+		op2 = *Fn;
+		switch((instr >> 21) & 7) {
+		case 4: break;
+		case 5: op = - op; break;
+		default: invalid(instr);
+		}
+		if(op2 < op)
+			up->CPSR = (up->CPSR & ~FLAGS) | flN;
+		else if(op2 >= op) {
+			up->CPSR = (up->CPSR & ~FLAGS) | flC;
+			if(op2 == op)
+				up->CPSR |= flZ;
+		} else
+			up->CPSR = (up->CPSR & ~FLAGS) | flV;
+		return;
+	}
+	if(instr & (1<<3))
+		invalid(instr);
+	switch((instr >> 20) & 15) {
+	case 0: *Fn = *(long *) Rd; break;
+	case 1: tmp = op; *Rd = tmp; break;
+	case 2: up->FPSR = *Rd; break;
+	case 3: *Rd = up->FPSR; break;
+	default: invalid(instr);
+	}
+}
\ No newline at end of file
--- a/kern/notify.c
+++ b/kern/notify.c
@@ -21,7 +21,7 @@
 
 #include <u.h>
 #include <signal.h>
-#include <libc.h>
+#include <lib.h>
 
 extern char *_p9sigstr(int, char*);
 extern int _p9strsig(char*);
--- a/kern/pgrp.c
+++ b/kern/pgrp.c
@@ -16,6 +16,15 @@
 	return p;
 }
 
+Egrp*
+newegrp(void)
+{
+	Egrp *e;
+	e = smalloc(sizeof(Egrp));
+	e->ref.ref = 1;
+	return e;
+}
+
 Rgrp*
 newrgrp(void)
 {
--- a/kern/seg.c
+++ b/kern/seg.c
@@ -3,17 +3,21 @@
 #include "dat.h"
 #include "fns.h"
 
-// TODO: Update to 64 bit
 Segment *
 newseg(u32int start, u32int size, int idx)
 {
 	Segment *s;
 	
-	s = mallocz(sizeof *s, 1);
+	s = malloc(sizeof *s);
+	if(s == nil)
+		panic("%r");
+	memset(s, 0, sizeof *s);
 	incref(&s->ref);
 	s->start = start;
 	s->size = size;
 	s->dref = malloc(size + sizeof(Ref));
+	if(s->dref == nil)
+		panic("%r");
 	memset(s->dref, 0, sizeof(Ref));
 	incref(s->dref);
 	s->data = s->dref + 1;
@@ -43,31 +47,30 @@
 void *
 vaddr(u32int addr, u32int len, Segment **seg)
 {
-	Segment **ss, *s;
-	for(ss = up->S; ss < up->S + SEGNUM; ss++) {
-		if(*ss == nil)
-			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;
-			return (char *)s->data + (addr - s->start);
-		}
-	}
-	fprint(2, "fault %.8ux (%d) @ %.8ux", addr, len, up->R[15]);
-	return nil;
+    Segment **ss, *s;
+    for (ss = up->S; ss < up->S + SEGNUM; ss++) {
+        if (*ss == nil)
+            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;
+            return (char *)s->data + (addr - s->start);
+        }
+    }
+    panic("fault addr=%.8ux, (%d), PC=%.8ux\n", addr, len, up->R[15]);
+    return nil;
 }
 
-void *
+void*
 vaddrnol(u32int addr, u32int len)
 {
-	Segment *seg;
+    Segment *seg;
 	void *ret;
-	
-	ret = vaddr(addr, len, &seg);
+    ret = vaddr(addr, len, &seg);
 	segunlock(seg);
 	return ret;
 }
@@ -94,6 +97,8 @@
 	if(len < 0)
 		len = strlen(targ) + 1;
 	ret = malloc(len);
+	if (ret == nil)
+		panic("%r");
 	setmalloctag(ret, getcallerpc(&addr));
 	memcpy(ret, targ, len);
 	segunlock(seg);
@@ -115,6 +120,8 @@
 	segunlock(seg);
 	*buffered = 1;
 	v = malloc(len);
+	if (v == nil)
+		panic("%r");
 	setmalloctag(v, getcallerpc(&addr));
 	return v;
 }
--- a/kern/syscall.c
+++ b/kern/syscall.c
@@ -5,6 +5,7 @@
 #include "error.h"
 #include "user.h"
 #include "sys.h"
+#include "proc.h"
 
 static u32int
 arg(int n)
@@ -161,21 +162,39 @@
 static void
 _sysstat(void)
 {
-	u32int name, edir, nedir;
-	char *namet;
-	void *edirt;
-	int copied, buffered;
-	
-	name = arg(0);
-	namet = copyifnec(name, -1, &copied);
-	edir = arg(1);
-	nedir = arg(2);
-	edirt = bufifnec(edir, nedir, &buffered);
-	up->R[0] = noteerr(sysstat(namet, edirt, nedir), nedir);
-	if(copied)
-		free(namet);
-	if(buffered)
-		copyback(edir, up->R[0], edirt);
+    u32int name, edir, nedir;
+    char *namet;
+    void *edirt;
+    int copied, buffered;
+    Segment *seg;
+	print("sysstat\n");
+
+    name = arg(0); // R0
+    print("sysstat: name=%.8ux, R13=%.8ux\n", name, up->R[13]);
+    if (!vaddr(name, 1, &seg)) {
+        print("sysstat: invalid name pointer %.8ux\n", name);
+        cherrstr("invalid name pointer");
+        up->R[0] = -1;
+        return;
+    }
+    namet = copyifnec(name, -1, &copied);
+    edir = arg(1); // R1
+    nedir = arg(2); // R2
+    print("sysstat: edir=%.8ux, nedir=%d\n", edir, nedir);
+    if (nedir > 0 && !vaddr(edir, nedir, &seg)) {
+        print("sysstat: invalid edir pointer %.8ux\n", edir);
+        cherrstr("invalid edir pointer");
+        if (copied)
+            free(namet);
+        up->R[0] = -1;
+        return;
+    }
+    edirt = bufifnec(edir, nedir, &buffered);
+    up->R[0] = noteerr(stat(namet, edirt, nedir), nedir);
+    if (copied)
+        free(namet);
+    if (buffered)
+        copyback(edir, up->R[0], edirt);
 }
 
 static void
@@ -184,7 +203,7 @@
 	u32int fd, edir, nedir;
 	void *edirt;
 	int buffered;
-	
+	print("sysfstat\n");
 	fd = arg(0);
 	edir = arg(1);
 	nedir = arg(2);
@@ -230,10 +249,10 @@
 		free(edirt);
 }
 
-// TODO: This may be better done as a longjmp back
 static void
 _sysexits(void)
 {
+	print("Exiting\n");
 	if(arg(0) == 0)
 		exits(nil);
 	else
@@ -271,7 +290,7 @@
 	char buf[ERRMAX], *srct;
 	u32int src, len;
 	int copied;
-	
+	print("We're in syserrstr\n");
 	src = arg(0);
 	len = arg(1);
 	srct = copyifnec(src, len, &copied);
@@ -319,7 +338,6 @@
 	up->R[0] = -1;
 }
 
-
 static void
 _sysrfork(void)
 {
@@ -327,33 +345,37 @@
 	int rc, i;
 	Segment *s, *t;
 	Proc *p;
-	int old;
 	
 	flags = arg(0);
-
 	if((flags & (RFFDG | RFCFDG)) == (RFFDG | RFCFDG) ||
 	   (flags & (RFNAMEG | RFCNAMEG)) == (RFNAMEG | RFCNAMEG) ||
 	   (flags & (RFENVG | RFCENVG)) == (RFENVG | RFCENVG)) {
+		werrstr("bad arg in rfork");
 		up->R[0] = -1;
-		cherrstr("bad arg in syscall");
 		return;
 	}
 	if((flags & RFPROC) == 0) {
 		if(flags & RFFDG) {
-			old = up->fd;
-			up->fd = copyfd(up->fd);
-			fddecref(old);
+			Fgrp *old = up->fgrp;
+			up->fgrp = dupfgrp(up->fgrp);
+			closefgrp(old);
 		}
 		if(flags & RFCFDG) {
-			old = up->fd;
-			//up->fd = newfd();
-			fddecref(old);
+			Fgrp *old = up->fgrp;
+			up->fgrp = dupfgrp(nil);
+			closefgrp(old);
 		}
-		up->R[0] = noteerr(rfork(flags), 0);
+		up->R[0] = noteerr(sysrfork(flags), 0);
 		return;
 	}
-	//incref(&nproc);
-	p = emallocz(sizeof(Proc));
+	p = newproc();
+	if(p == nil) {
+		fprint(2, "rfork: malloc failed for Proc");
+		werrstr("rfork: malloc failed");
+		up->R[0] = -1;
+		return;
+	}
+	memset(p, 0, sizeof(Proc));
 	memcpy(p, up, sizeof(Proc));
 	for(i = 0; i < SEGNUM; i++) {
 		s = p->S[i];
@@ -360,12 +382,20 @@
 		if(s == nil)
 			continue;
 		if((flags & RFMEM) == 0 && i != SEGTEXT || i == SEGSTACK) {
-			t = emallocz(sizeof(Segment));
-			incref(t);
-			t->size = s->size;
-			t->start = s->start;
-			t->dref = emalloc(sizeof(Ref) + s->size);
-			memset(t->dref, 0, sizeof(Ref));
+			t = newseg(s->start, s->size, s->flags);
+			if(t == nil) {
+				fprint(2, "rfork: newseg failed");
+				werrstr("rfork: newseg failed");
+				up->R[0] = -1;
+				return;
+			}
+			t->dref = mallocz(sizeof(Ref) + s->size, 1);
+			if(t->dref == nil) {
+				fprint(2, "rfork: malloc failed for Segment data");
+				werrstr("rfork: malloc failed");
+				up->R[0] = -1;
+				return;
+			}
 			incref(t->dref);
 			t->data = t->dref + 1;
 			memcpy(t->data, s->data, s->size);
@@ -372,60 +402,76 @@
 			p->S[i] = t;
 		} else {
 			incref(s->dref);
-			incref(s);
+			incref(&s->ref);
 		}
 	}
-	
 	if(flags & RFFDG)
-		p->fd = copyfd(up->fd);
-	//else if(flags & RFCFDG)
-	//	p->fd = newfd();
-	//else
-	//	incref(up->fd);
-
-	//incref(up->path);
-	rc = rfork(RFMEM | flags);
-	if(rc < 0) /* this should NEVER happen */
-		sysfatal("rfork failed wtf: %r");
+		p->fgrp = dupfgrp(up->fgrp);
+	else if(flags & RFCFDG)
+		p->fgrp = dupfgrp(nil);
+	else
+		incref(&up->fgrp->ref);
+	if(flags & RFNAMEG)
+		p->pgrp = newpgrp();
+	else
+		incref(&up->pgrp->ref);
+	if(flags & RFENVG)
+		p->egrp = newegrp();
+	else
+		incref(&up->egrp->ref);
+	rc = sysrfork(flags);
+	if(rc < 0) {
+		fprint(2, "rfork: sysrfork failed: %r");
+		werrstr("rfork: %r");
+		up->R[0] = -1;
+		return;
+	}
 	if(rc == 0) {
-	//	up = p;
-		//atexit(cleanup);
-		up->pid = getpid();
+		_setproc(p);
+		atexit((void(*)(void))pexit);
+		p->pid = getpid();
 		inittos();
-	//	addproc(P);
+		osproc(p);
 	}
 	up->R[0] = rc;
 }
-   
 
 static void
 _sysexec(void)
 {
-	u32int name, argv, *argvt;
-	char *namet, **argvv;
+	u32int name, argv;
+	char *namet;
+	char **argvv;
 	int i, argc, rc;
 	Segment *seg1, *seg2;
+	u32int *argvt;
 	
 	name = arg(0);
 	argv = arg(1);
-	namet = strdup(vaddr(name, 0, &seg1));
-	segunlock(seg1);
+	namet = estrdup((char*)vaddrnol(name, 0));
 	argvt = vaddr(argv, 0, &seg1);
 	for(argc = 0; argvt[argc]; argc++)
 		;
-	argvv = emalloc(sizeof(char *) * argc);
+	argvv = mallocz(sizeof(char *) * (argc + 1), 1);
+	if(argvv == nil) {
+		fprint(2, "exec: malloc failed for argv");
+		werrstr("exec: malloc failed");
+		up->R[0] = -1;
+		free(namet);
+		return;
+	}
 	for(i = 0; i < argc; i++) {
-		argvv[i] = strdup(vaddr(argvt[i], 0, &seg2));
-		segunlock(seg2);
+		argvv[i] = estrdup((char*)vaddrnol(argvt[i], 0));
 	}
+	argvv[argc] = nil;
 	segunlock(seg1);
 	rc = loadtext(namet, argc, argvv);
 	for(i = 0; i < argc; i++)
 		free(argvv[i]);
 	free(argvv);
+	free(namet);
 	if(rc < 0)
 		up->R[0] = noteerr(rc, 0);
-	free(namet);
 }
 
 static void
@@ -589,7 +635,6 @@
 	addr = arg(0);
 	block = arg(1);
 	addrt = vaddrnol(addr, 4);
-	// Still need semaphores
 	up->R[0] = noteerr(semacquire(addrt, block), 0);
 }
 
@@ -603,7 +648,6 @@
 	addr = arg(0);
 	count = arg(1);
 	addrt = vaddr(addr, 4, &seg);
-	// Still need semaphores
 	up->R[0] = noteerr(semrelease(addrt, count), 0);
 	segunlock(seg);
 }
@@ -611,43 +655,44 @@
 void
 _syscall(void)
 {
-	u32int n;
-	static void (*calls[])(void) = {
-		[EXITS] 		= _sysexits,
-		[CLOSE] 		= _sysclose,
-		[OPEN] 			= _sysopen,
-		[CREATE] 		= _syscreate,
-		[PREAD] 		= _syspread,
-		[PWRITE] 		= _syspwrite,
-		[BRK_] 			= _sysbrk,
-		[ERRSTR] 		= _syserrstr,
-		[STAT] 			= _sysstat,
-		[FSTAT] 		= _sysfstat,
-		[WSTAT] 		= _syswstat,
-		[FWSTAT] 		= _sysfwstat,
-		[SEEK] 			= _sysseek,
-		[CHDIR]		 	= _syschdir,
-		[FD2PATH] 		= _sysfd2path,
-		[NOTIFY] 		= _sysnotify,
-		[NOTED] 		= _sysnoted,
-		[RFORK] 		= _sysrfork,
-		[EXEC]	 		= _sysexec,
-		[AWAIT] 		= _sysawait,
-		[PIPE] 			= _syspipe,
-		[SLEEP] 		= _syssleep,
-		[RENDEZVOUS] 	= _sysrendezvous,
-		[BIND] 			= _sysbind,
-		[UNMOUNT] 		= _sysunmount,
-		[DUP] 			= _sysdup,
-		[MOUNT] 		= _sysmount,
-		[REMOVE] 		= _sysremove,
-		[ALARM] 		= _sysalarm,
-		[SEMACQUIRE] 	= _syssemacquire,
-		[SEMRELEASE] 	= _syssemrelease,
-	};
-	
-	n = up->R[0];
-	if(n >= nelem(calls) || calls[n] == nil)
-		fprint(2, "no such syscall %d @ %#ux", n, up->R[15] - 4);
-	calls[n]();
+    u32int n;
+    static void (*calls[])(void) = {
+        [EXITS]     = _sysexits,
+        [CLOSE]     = _sysclose,
+        [OPEN]      = _sysopen,
+        [CREATE]    = _syscreate,
+        [PREAD]     = _syspread,
+        [PWRITE]    = _syspwrite,
+        [BRK_]      = _sysbrk,
+        [ERRSTR]    = _syserrstr,
+        [STAT]      = _sysstat,
+        [FSTAT]     = _sysfstat,
+        [WSTAT]     = _syswstat,
+        [FWSTAT]    = _sysfwstat,
+        [SEEK]      = _sysseek,
+        [CHDIR]     = _syschdir,
+        [FD2PATH]   = _sysfd2path,
+        [NOTIFY]    = _sysnotify,
+        [NOTED]     = _sysnoted,
+        [RFORK]     = _sysrfork,
+        [EXEC]      = _sysexec,
+        [AWAIT]     = _sysawait,
+        [PIPE]      = _syspipe,
+        [SLEEP]     = _syssleep,
+        [RENDEZVOUS]= _sysrendezvous,
+        [BIND]      = _sysbind,
+        [UNMOUNT]   = _sysunmount,
+        [DUP]       = _sysdup,
+        [MOUNT]     = _sysmount,
+        [REMOVE]    = _sysremove,
+        [ALARM]     = _sysalarm,
+        [SEMACQUIRE]= _syssemacquire,
+        [SEMRELEASE]= _syssemrelease,
+    };
+    
+    n = up->R[0];
+
+    print("syscall: calling handler for syscall %d\n", n);
+    calls[n]();
+    print("syscall: handler for syscall %d completed\n", n);
 }
\ No newline at end of file
--- a/kern/sysproc.c
+++ b/kern/sysproc.c
@@ -3,6 +3,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "error.h"
+#include "proc.h"
 #include "user.h"
 #include "mem.h"
 #include "sys.h"
@@ -12,7 +13,7 @@
 #include <setjmp.h>
 
 #undef rfork
-
+#undef read
 jmp_buf exec_jmp;
 
 static void
@@ -93,9 +94,9 @@
                 pid = fork();
                 if(pid){
                     if(pid > 0)
-                        fprint(p[1], "%d", pid);
+                        print("%d\n", pid);
                     else
-                        fprint(p[1], "x %r");
+                        print("x %r\n");
                     close(p[1]);
                     _exit(0);
                 }else{
@@ -193,197 +194,235 @@
     return memchr((void*)a, c, i);
 }
 
-#undef read
-/* Load text and data segments into memory */
+void
+addnote(char *msg)
+{
+	int new;
+	
+	new = up->notein + 1;
+	if((new - up->noteout) % NNOTE == 0)
+		return;
 
+	strncpy(up->notes[up->notein % NNOTE], msg, ERRMAX - 1);
+	up->notein = new;
+}
 
-/* the following code is not for the weak of heart */
 void
 donote(char *msg, ulong type)
 {
-	int rc;
-	u32int *ureg, *sp, uregp, msgp;
-	char *msgb;
+    int rc;
+    u32int *ureg, *sp, uregp, msgp;
+    char *msgb;
 
-        print("In donote\n");
-	if(up->notehandler == 0)
-		exits(msg);
+    if(up->notehandler == 0)
+        exits(msg);
 
-	clrex();
-	uregp = up->R[13] - 18 * 4;
-	ureg = vaddrnol(uregp, 18 * 4);
-	memcpy(ureg, up->R, 15 * 4);
-	ureg[15] = type;
-	ureg[16] = up->CPSR;
-	ureg[17] = up->R[15];
-	up->R[13] = uregp;
-	msgp = up->R[13] -= ERRMAX;
-	msgb = vaddrnol(msgp, ERRMAX);
-	strncpy(msgb, msg, ERRMAX);
-	up->R[13] -= 3 * 4;
-	sp = vaddrnol(up->R[13], 3 * 4);
-	sp[0] = 0;
-	sp[2] = msgp;
-	up->R[0] = uregp;
-	up->R[15] = up->notehandler;
-	up->innote = 1;
-	switch(rc = setjmp(up->notejmp) - 1) {
-	case -1:
-		for(;;) {
-			step();
-		}
-	case NDFLT:
-		exits(msg);
-	case NCONT:
-		break;
-	default:
-		sysfatal("unhandled noted argument %d", rc);
-	}
-	up->innote = 0;
-	ureg = vaddrnol(uregp, 18 * 4); /* just to be sure */
-	memcpy(up->R, ureg, 15 * 4);
-	up->CPSR = ureg[16];
-	up->R[15] = ureg[17];
+    clrex();
+    uregp = up->R[13] - 18 * 4;
+    ureg = vaddrnol(uregp, 18 * 4);
+    memcpy(ureg, up->R, 15 * 4);
+    ureg[15] = type;
+    ureg[16] = up->CPSR;
+    ureg[17] = up->R[15];
+    up->R[13] = uregp;
+    msgp = up->R[13] -= ERRMAX;
+    msgb = vaddrnol(msgp, ERRMAX);
+    strncpy(msgb, msg, ERRMAX);
+    up->R[13] -= 3 * 4;
+    sp = vaddrnol(up->R[13], 3 * 4);
+    sp[0] = 0;
+    sp[2] = msgp;
+    up->R[0] = uregp;
+    up->R[15] = up->notehandler;
+    up->innote = 1;
+    switch(rc = setjmp(up->notejmp) - 1) {
+    case -1:
+        for(;;) {
+            step();
+        }
+    case NDFLT:
+        exits(msg);
+    case NCONT:
+        break;
+    default:
+        sysfatal("unhandled noted argument %d", rc);
+    }
+    up->innote = 0;
+    ureg = vaddrnol(uregp, 18 * 4); /* just to be sure */
+    memcpy(up->R, ureg, 15 * 4);
+    up->CPSR = ureg[16];
+    up->R[15] = ureg[17];
 }
 
-
 static void
 initstack(int argc, char **argv)
 {
-	ulong tos, sp, ap, size, i, len;
-	
-	tos = USTKTOP - sizeof(Tos) * 2;
-	sp = tos;
-	
-	size = 8;
-	for(i = 0; i < argc; i++)
-		size += strlen(argv[i]) + 5;
-	
-	sp -= size;
-	sp &= ~7;
-	up->R[0] = tos;
-	up->R[1] = USTKTOP - 4;
-	up->R[13] = sp;
-	
+    ulong tos, sp, ap, size, i, len;
+    
+    tos = (USTKTOP & ~7) - sizeof(Tos) * 2;
+    sp = tos;
+    
+    size = 8;
+    for(i = 0; i < argc; i++)
+        size += strlen(argv[i]) + 5;
+    
+    sp -= size;
+    sp &= ~7;
+    up->R[0] = tos;
+    up->R[1] = USTKTOP - 4;
+    up->R[13] = sp;
+
 	*(ulong *) vaddrnol(sp, 4) = argc;
-	sp += 4;
-	ap = sp + (argc + 1) * 4;
-	for(i = 0; i < argc; i++) {
-		*(ulong *) vaddrnol(sp, 4) = ap;
-		sp += 4;
-		len = strlen(argv[i]) + 1;
-		memcpy(vaddrnol(ap, len), argv[i], len);
-		ap += len;
-	}
-	*(ulong *) vaddrnol(sp, 4) = 0;
-	inittos();
+    sp += 4;
+    ap = sp + (argc + 1) * 4;
+    for(i = 0; i < argc; i++) {
+        *(ulong *) vaddrnol(sp, 4) = ap;
+        sp += 4;
+        len = strlen(argv[i]) + 1;
+        memcpy(vaddrnol(ap, len), argv[i], len);
+        ap += len;
+    }
+    *(ulong *) vaddrnol(sp, 4) = 0;
+    inittos();
+
 }
 
-
 void
 inittos(void)
 {
-	ulong tos;
+    ulong tos;
 
-	tos = USTKTOP - sizeof(Tos) * 2;
-	((Tos *) vaddrnol(tos, sizeof(Tos)))->pid = up->pid;
+    tos = (USTKTOP & ~7) - sizeof(Tos) * 2;
+    ((Tos *) vaddrnol(tos, sizeof(Tos)))->pid = up->pid;
 }
 
-// TODO: fd has to go away here.
 static int
-loadscript(int fd, char *file, int argc, char **argv)
+loadscript(Chan *tc, char *file, int argc, char **argv)
 {
-	char buf[513], *p, **q, **nargv;
-	int rc, nargc, i;
-	
-	seek(fd, 0, 0);
-	rc = readn(fd, buf, 512);
-	if(rc <= 0)
-		goto invalid;
-	close(fd);
-	buf[rc] = 0;
-	p = strchr(buf, '\n');
-	if(p == nil)
-		goto invalid;
-	*p = 0;
-	while(isspace(*--p))
-		*p = 0;
-	nargc = 0;
-	p = buf + 2;
-	while(*p) {
-		while(*p && isspace(*p))
-			p++;
-		nargc++;
-		while(*p && !isspace(*p))
-			p++;
-	}
-	if(nargc == 0)
-		goto invalid;
-	nargv = emallocz(sizeof(char *) * (nargc + argc));
-	q = nargv;
-	p = buf + 2;
-	while(*p) {
-		while(*p && isspace(*p))
-			p++;
-		*(p-1) = 0;
-		*q++ = p;
-		while(*p && !isspace(*p))
-			p++;
-	}
-	*q++ = file;
-	for(i = 1; i < argc; i++)
-		*q++ = argv[i];
-	rc = loadtext(*nargv, argc + nargc, nargv);
-	free(nargv);
-	return rc;
+    char buf[513], *p, **q, **nargv;
+    int rc, nargc, i;
+    
+	rc = devtab[tc->type]->read(tc, &buf, 512, 0);
+    if(rc <= 0)
+        goto invalid;
 
+    buf[rc] = 0;
+    p = strchr(buf, '\n');
+    if(p == nil)
+        goto invalid;
+    *p = 0;
+    while(isspace(*--p))
+        *p = 0;
+    nargc = 0;
+    p = buf + 2;
+    while(*p) {
+        while(*p && isspace(*p))
+            p++;
+        nargc++;
+        while(*p && !isspace(*p))
+            p++;
+    }
+    if(nargc == 0)
+        goto invalid;
+    nargv = mallocz(sizeof(char *) * (nargc + argc), 1);
+    q = nargv;
+    p = buf + 2;
+    while(*p) {
+        while(*p && isspace(*p))
+            p++;
+        *(p-1) = 0;
+        *q++ = p;
+        while(*p && !isspace(*p))
+            p++;
+    }
+    *q++ = file;
+    for(i = 1; i < argc; i++)
+        *q++ = argv[i];
+    rc = loadtext(*nargv, argc + nargc, nargv);
+    free(nargv);
+    return rc;
+
 invalid:
-	werrstr("exec header invalid");
-	return -1;
+    werrstr("exec header invalid");
+    return -1;
 }
 
 int
 loadtext(char *file, int argc, char **argv)
 {
-	Segment *text, *data, *bss;
-	char buf[2];
     Chan *tc;
+    Segment *text, *data, *bss;
+    Exec hdr;
+	char buf[2];
+    vlong off;
     int n;
-	    union {
-        struct {
-            Exec ex;
-            uvlong hdr[1];
-        } ehdr;
-        char buf[256];
-    } u;
-
+    
+    /* Open the file using namespaced access */
     tc = namec(file, Aopen, OEXEC, 0);
-    n = devtab[tc->type]->read(tc, u.buf, sizeof(u.buf), 0);
+    if(tc == nil) {
+        print("cannot open %s: %r", file);
+        return -1;
+    }
+    
+	/* Peek the first two bytes */
+	devtab[tc->type]->read(tc, &buf, 2, 0);
+	if(buf[0] =='#' && buf[1] == '!') {
+		return loadscript(tc, file, argc, argv);
+	}
 
-	copyname(file);
-	up->notehandler = up->innote = up->notein = up->noteout = 0;
-	freesegs();
-	memset(up->R, 0, sizeof(up->R));
-	up->CPSR = 0;
-    // Read instead with beswav(whatever) 
-	//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);
-	//newseg(USTKTOP - STACKSIZE, STACKSIZE, SEGSTACK);
-    // This also doesn't work, we want to read in the devtab way
-	//seek(fd, fp.txtoff - fp.hdrsz, 0);
-	//if(readn(fd, text->data, fp.txtsz + fp.hdrsz) < fp.txtsz + fp.hdrsz)
-	//	sysfatal("%r");
-	//seek(fd, fp.datoff, 0);
-	//if(readn(fd, data->data, fp.datsz) < fp.datsz)
-	//	sysfatal("%r");
-	//memset(bss->data, 0, bss->size);
-	//up->R[15] = fp.entry;
-	//if(havesymbols && syminit(fd, &fp) < 0)
-	//	fprint(2, "initializing symbol table: %r\n");
-	//close(fd);
-	fdclear(up->fd);
-	initstack(argc, argv);
-	resetfpa();
-	return 0;
-}
+    n = devtab[tc->type]->read(tc, &hdr, sizeof(Exec), 0);
+    if(n != sizeof(Exec)) {
+        print("short read on exec header");
+        cclose(tc);
+        return -1;
+    }
+    
+    if(beswal(hdr.magic) != E_MAGIC) {
+        print("bad magic number in exec header: got 0x%lux, want 0x%lux", beswal(hdr.magic), E_MAGIC);
+        cclose(tc);
+        return -1;
+    }
+
+    freesegs();
+    up->CPSR = 0;
+    
+    /* Create segments: text, data, bss, stack */
+    text = newseg(beswal(hdr.entry), beswal(hdr.text) + sizeof(Exec), SEGTEXT);
+    data = newseg(beswal(hdr.entry) + beswal(hdr.text) + sizeof(Exec), beswal(hdr.data), SEGDATA);
+    bss = newseg(beswal(hdr.entry) + beswal(hdr.text) + sizeof(Exec) + beswal(hdr.data), beswal(hdr.bss), SEGBSS);
+    newseg((USTKTOP & ~7) - USTKSIZE, USTKSIZE, SEGSTACK);
+
+    /* Read text segment (including header) */
+    off = sizeof(Exec);
+    n = devtab[tc->type]->read(tc, text->data, beswal(hdr.text) + sizeof(Exec), off);
+    if(n != beswal(hdr.text) + sizeof(Exec)) {
+        freesegs();
+        werrstr("short read on text segment: got %d, want %lud", n, beswal(hdr.text) + sizeof(Exec));
+        cclose(tc);
+        return -1;
+    }
+    
+    /* Read data segment */
+    off += beswal(hdr.text);
+    n = devtab[tc->type]->read(tc, data->data, beswal(hdr.data), off);
+    if(n != beswal(hdr.data)) {
+        freesegs();
+        werrstr("short read on data segment: got %d, want %lud", n, beswal(hdr.data));
+        cclose(tc);
+        return -1;
+    }
+    
+    memset(bss->data, 0, bss->size);
+    up->R[15] = beswal(hdr.entry);
+
+    initstack(argc, argv);
+
+    //if(debug)
+        print("loadtext: PC=%.8ux, R1=%.8ux, R13=%.8ux\n", up->R[15], up->R[1], up->R[13]);
+    
+    /* Close the channel */
+    cclose(tc);
+    resetvfp();
+    
+    return 0;
+}
\ No newline at end of file
--- /dev/null
+++ b/kern/vfp.c
@@ -1,0 +1,158 @@
+#include <u.h>
+#include <lib.h>
+#include "dat.h"
+#include "fns.h"
+#include "proc.h"
+
+void
+resetvfp(void)
+{
+	int i;
+
+	up->FPSR = 0x00000000;
+	for(i = 0; i < Nfpregs; i++)
+		up->F[i] = 0;
+}
+
+void
+vfpregtransfer(u32int instr)
+{
+	u32int *Rt;
+	double *Fn;
+
+	Rt = up->R + ((instr>>12)&0xF);
+	Fn = up->F + ((instr>>16)&0xF);
+	switch((instr>>20)&0xF){
+	case 0:
+		*((int*)Fn) = *Rt; break;
+	case 1:
+		*Rt = *((int*)Fn); break;
+	case 14:
+		up->FPSR = *Rt; break;
+	case 15:
+		if(Rt == (up->R + 15))
+			up->CPSR = up->FPSR;
+		else
+			*Rt = up->FPSR;
+		break;
+	default:
+		sysfatal("unimplemented VFP instruction %8ux @ %8ux", instr, up->R[15] - 4);
+	}
+}
+
+void
+vfprmtransfer(u32int instr)
+{
+	int n, d, off, sz;
+	void* ea;
+	Segment *seg;
+
+	n = (instr>>16) & 0xF;
+	d = (instr>>12) & 0xF;
+	off = (instr & 0xFF) << 2;
+	sz = instr & (1<<8);
+	if((instr & (1<<23)) == 0)
+		off = -off;
+	ea = vaddr(evenaddr(up->R[n] + off, 3), sz ? 8 : 4, &seg);
+	switch((instr>>20)&0x3){
+	case 0:
+		if(sz)
+			*(double*)ea = up->F[d];
+		else
+			*(float*)ea = up->F[d];
+		break;
+	case 1:
+		if(sz)
+			up->F[d] = *(double*)ea;
+		else
+			up->F[d] = *(float*)ea;
+		break;
+	default:
+		sysfatal("unimplemented VFP instruction %8ux @ %8ux", instr, up->R[15] - 4);
+	}
+	segunlock(seg);
+}
+
+void
+vfparithop(int opc, u32int instr)
+{
+	int o;
+	double *Fd, *Fn, *Fm;
+
+	Fd = up->F + ((instr>>12)&0xF);
+	Fn = up->F + ((instr>>16)&0xF);
+	Fm = up->F + (instr&0xF);
+	o = ((opc&0x3)<<1) | (opc&0x8) | ((instr>>6)&0x1);
+
+	switch(o){
+	case 4:
+		*Fd = *Fn * *Fm; break;
+	case 6:
+		*Fd = *Fn + *Fm; break;
+	case 7:
+		*Fd = *Fn - *Fm; break;
+	case 8:
+		*Fd = *Fn / *Fm; break;
+	default:
+		sysfatal("unimplemented VFP instruction %8ux @ %8ux", instr, up->R[15] - 4);
+	}
+}
+
+void
+vfpotherop(u32int instr)
+{
+	int o2, o3;
+	double *Fd, *Fm, F0;
+
+	Fd = up->F + ((instr>>12)&0xF);
+	Fm = up->F + (instr&0xF);
+	F0 = 0.0;
+	o2 = (instr>>16) & 0xF;
+	o3 = (instr>>6) & 0x3;
+
+	if((o3&1) == 0)
+		sysfatal("unimplemented VFP instruction %8ux @ %8ux", instr, up->R[15] - 4);
+	switch(o2){
+	case 0x5:
+		Fm = &F0;
+	case 0x4:
+		if(*Fd < *Fm)
+			up->FPSR = (up->FPSR & ~FLAGS) | flN;
+		else if(*Fd >= *Fm) {
+			up->FPSR = (up->FPSR & ~FLAGS) | flC;
+			if(*Fd == *Fm)
+				up->FPSR |= flZ;
+		} else
+			up->FPSR = (up->FPSR & ~FLAGS) | flV | flC;
+		break;
+	case 0x8:
+		*Fd = *((int*)Fm); break;
+	case 0xD:
+		*((int*)Fd) = (int)*Fm; break;
+	default:
+		switch((o2<<1)|(o3>>1)){
+		case 0:
+		case 15:
+			*Fd = *Fm; break;
+		case 1:
+			*Fd = fabs(*Fm); break;
+		case 2:
+			*Fd = -*Fm; break;
+		case 3:
+			*Fd = sqrt(*Fm); break;
+		default:
+			sysfatal("unimplemented VFP instruction %8ux @ %8ux", instr, up->R[15] - 4);
+		}
+	}
+}
+
+void
+vfpoperation(u32int instr)
+{
+	int o1;
+	o1 = (instr>>20) & 0xF;
+	if(o1 == 0xB)
+		vfpotherop(instr);
+	else
+		vfparithop(o1, instr);
+}
--- a/main.c
+++ b/main.c
@@ -48,17 +48,30 @@
 	exit(1);
 }
 
-int
-notehandler(void *, char *note)
+void
+dump(void)
 {
+	int i;
+	
+	for(i = 0; i < 16; i++) {
+		print("R%2d %.8ux", i, up->R[i]);
+		if((i % 4) == 3) print("\n");
+		else print("\t");
+	}
+}
+
+void
+notehandler(void *d, char *note)
+{
+	USED(d);
 	if(strncmp(note, "sys:", 4) == 0)
-		return 0;
+		return;
 	
 	if(strncmp(note, "emu:", 4) == 0)
 		exits(note);
 
 	addnote(note);
-	return 1;
+	return;
 }
 
 int
@@ -66,6 +79,7 @@
 {
 	extern ulong kerndate;
 	char *path, *file;
+	int debug = 0;
 
 	path = nil;
 	kerndate = seconds();
@@ -77,6 +91,9 @@
 	case 'p':
 		path = EARGF(usage());
 		break;
+	case 'd':
+		debug++;
+		break;
 	default:
 		usage();
 	} ARGEND;
@@ -111,24 +128,24 @@
 		bind(path, "/bin", MAFTER);
 
 	if(**argv == '/' || **argv == '.' || **argv == '#') {
-		// TODO: Export loadtext from the kernel
 		if(loadtext(*argv, argc, argv) < 0)
-			sysfatal("loadtext: %r");
-		return;
+			panic("loadtext: %r");
+	} else {
+		file = smprint("/bin/%s", *argv);
+		if(loadtext(file, argc, argv) < 0)
+			panic("loadtext: %r");
+		free(file);
 	}
-	file = smprint("/bin/%s", *argv);
-	if(loadtext(file, argc, argv) < 0)
-		sysfatal("loadtext: %r");
-	free(file);
 
-	// TODO: Export step() from the kernel
-	atnotify(notehandler, 1);
+	notify(notehandler);
 	for(;;) {
-		// Kernel step, while this greys kernelspace/userspace this is the cleaner approach
+		if(debug)
+			dump();
 		step();
 		while((up->notein - up->noteout) % NNOTE) {
 			donote(up->notes[up->noteout % NNOTE], 0);
-			ainc(&up->noteout);
+			up->noteout++;
 		}
 	}
+	exits(0);
 }
--