ref: 43bae2b8369b034af304863d22d8cc238982a7c4
parent: 5fa804d69fe1c1db6954217bca19637656e579b4
parent: 2acb5433d8008012d7208a7bfcb9c6a1544f218f
author: aiju <[email protected]>
date: Thu Jun 16 13:52:56 EDT 2011
merge
--- /dev/null
+++ b/sys/src/cmd/5e/5e.c
@@ -1,0 +1,76 @@
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include "dat.h"
+#include "fns.h"
+
+Process **PP;
+
+static int nflag;
+
+void
+dump(void)
+{
+ int i;
+
+ for(i = 0; i < 16; i++) {
+ print("R%2d %.8ux", i, P->R[i]);
+ if((i % 4) == 3) print("\n");
+ else print("\t");
+ }
+}
+
+static void
+adjustns(void)
+{
+ if(bind("/arm/bin", "/bin", MREPL) < 0)
+ sysfatal("bind: %r");
+ if(bind("/rc/bin", "/bin", MAFTER) < 0)
+ sysfatal("bind: %r");
+ putenv("cputype", "arm");
+ putenv("objtype", "arm");
+}
+
+void
+cleanup(void)
+{
+ if(P == nil)
+ return;
+
+ freesegs();
+ fddecref(P->fd);
+ free(P);
+}
+
+static void
+usage(void)
+{
+ fprint(2, "usage: 5e [ -n ] text [ args ]\n");
+ exits(nil);
+}
+
+void
+main(int argc, char **argv)
+{
+ ARGBEGIN {
+ case 'n': nflag++; break;
+ default: usage();
+ } ARGEND;
+ if(argc < 1)
+ usage();
+ if(_nprivates < 1)
+ sysfatal("we don't have privates");
+ if(rfork(RFREND | RFNAMEG | RFENVG) < 0)
+ sysfatal("rfork: %r");
+ atexit(cleanup);
+ if(nflag)
+ adjustns();
+ initproc();
+ if(loadtext(argv[0], argc, argv) < 0)
+ sysfatal("%r");
+ for(;;) {
+ if(ultraverbose)
+ dump();
+ step();
+ }
+}
--- /dev/null
+++ b/sys/src/cmd/5e/arm.c
@@ -1,0 +1,472 @@
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include <bio.h>
+#include <mach.h>
+#include "dat.h"
+#include "fns.h"
+
+enum {
+ fI = 1<<25,
+ fP = 1<<24,
+ fLi = 1<<24,
+ fU = 1<<23,
+ fB = 1<<22,
+ fW = 1<<21,
+ fL = 1<<20,
+ fS = 1<<20,
+ fSg = 1<<6,
+ fH = 1<<5,
+};
+
+static void
+invalid(u32int instr)
+{
+ sysfatal("undefined instruction %8ux @ %8ux", instr, P->R[15] - 4);
+}
+
+static u32int
+doshift(u32int instr)
+{
+ ulong amount, val;
+
+ if((instr & (1<<4)) && (instr & (1<<7)))
+ invalid(instr);
+
+ if(instr & (1<<4))
+ amount = P->R[(instr >> 8) & 15];
+ else
+ amount = (instr >> 7) & 31;
+ val = P->R[instr & 15];
+ switch((instr >> 5) & 3) {
+ case 0:
+ return val << amount;
+ case 1:
+ return val >> amount;
+ case 2:
+ return ((long) val) >> amount;
+ case 3:
+ return (val >> amount) | (val << (32 - amount));
+ }
+ return 0;
+}
+
+static void
+single(u32int instr)
+{
+ long offset;
+ u32int addr;
+ u32int *Rn, *Rd;
+ void *targ;
+ Segment *seg;
+
+ if(instr & fI) {
+ if(instr & (1<<4))
+ invalid(instr);
+ offset = doshift(instr);
+ } else
+ offset = instr & ((1<<12) - 1);
+ if(!(instr & fU))
+ offset = - offset;
+ Rn = P->R + ((instr >> 16) & 15);
+ Rd = P->R + ((instr >> 12) & 15);
+ if((instr & (fW | fP)) == fW)
+ invalid(instr);
+ if(Rn == P->R + 15) {
+ if(instr & fW)
+ invalid(instr);
+ addr = P->R[15] + 4;
+ }
+ else
+ addr = *Rn;
+ if(instr & fP)
+ addr += offset;
+ targ = vaddr(addr, &seg);
+ switch(instr & (fB | fL)) {
+ case 0:
+ *(u32int*) targ = *Rd;
+ break;
+ case fB:
+ *(u8int*) targ = *Rd;
+ break;
+ case fL:
+ *Rd = *(u32int*) targ;
+ break;
+ case fB | fL:
+ *Rd = *(u8int*) targ;
+ break;
+ }
+ if(Rd == P->R + 15 && !(instr & fL)) {
+ if(instr & fB)
+ *(u8int*) targ += 8;
+ else
+ *(u32int*) targ += 8;
+ }
+ segunlock(seg);
+ if(!(instr & fP))
+ addr += offset;
+ if((instr & fW) || !(instr & fP))
+ *Rn = addr;
+}
+
+static void
+swap(u32int instr)
+{
+ u32int *Rm, *Rn, *Rd, *targ, tmp;
+ Segment *seg;
+
+ Rm = P->R + (instr & 15);
+ Rd = P->R + ((instr >> 12) & 15);
+ Rn = P->R + ((instr >> 16) & 15);
+ if(Rm == P->R + 15 || Rd == P->R + 15 || Rn == P->R + 15)
+ invalid(instr);
+ targ = (u32int *) vaddr(*Rn, &seg);
+ lock(&seg->lock);
+ if(instr & fB) {
+ tmp = *(u8int*) targ;
+ *(u8int*) targ = *Rm;
+ *Rd = tmp;
+ } else {
+ tmp = *targ;
+ *targ = *Rm;
+ *Rd = tmp;
+ }
+ unlock(&seg->lock);
+ segunlock(seg);
+}
+
+static u32int
+add(u32int a, u32int b, u8int type, u8int *carry, u8int *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;
+ 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;
+ if(res2 & 0x100000000LL) *carry = 1;
+ else *carry = 0;
+ }
+ return res1;
+}
+
+static void
+alu(u32int instr)
+{
+ u32int Rn, *Rd, operand, shift, result, op;
+ u8int carry, overflow;
+
+ Rn = P->R[(instr >> 16) & 15];
+ Rd = P->R + ((instr >> 12) & 15);
+ if(((instr >> 16) & 15) == 15) {
+ Rn += 4;
+ if(!(instr & fI) && (instr & (1<<4)))
+ Rn += 4;
+ }
+ if(Rd == P->R + 15 && (instr & fS))
+ invalid(instr);
+ if(instr & fI) {
+ operand = instr & 0xFF;
+ shift = ((instr >> 8) & 15) << 1;
+ operand = (operand >> shift) | (operand << (32 - shift));
+ } else
+ operand = doshift(instr);
+ op = (instr >> 21) & 15;
+ carry = 0;
+ if(op >= 8 && op <= 11 && !(instr & fS))
+ sysfatal("no PSR transfers plz");
+ if(op >= 5 && op < 8) {
+ if(P->CPSR & flC)
+ carry = 1;
+ } else {
+ if(op != 4 && op != 5 && op != 11)
+ carry = 1;
+ }
+ overflow = 0;
+ switch(op) {
+ case 0: case 8: result = Rn & operand; break;
+ case 1: case 9: result = Rn ^ operand; break;
+ case 2: case 6: case 10: result = add(Rn, operand, 1, &carry, &overflow); break;
+ case 3: case 7: result = add(operand, Rn, 1, &carry, &overflow); break;
+ case 4: case 5: case 11: result = add(operand, Rn, 0, &carry, &overflow); break;
+ case 12: result = Rn | operand; break;
+ case 13: result = operand; break;
+ case 14: result = Rn & ~operand; break;
+ case 15: result = ~operand; break;
+ default: result = 0; /* never happens */
+ }
+ if(instr & fS) {
+ P->CPSR &= ~FLAGS;
+ if(result == 0)
+ P->CPSR |= flZ;
+ if(result & (1<<31))
+ P->CPSR |= flN;
+ if(carry && op > 1 && op < 12)
+ P->CPSR |= flC;
+ if(overflow)
+ P->CPSR |= flV;
+ }
+ if(op < 8 || op >= 12)
+ *Rd = result;
+}
+
+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)
+ P->R[14] = P->R[15];
+ P->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 = P->R[instr & 15];
+ }
+ if(!(instr & fU))
+ offset = - offset;
+ if(!(instr & fP) && (instr & fW))
+ invalid(instr);
+ Rn = P->R + ((instr >> 16) & 15);
+ Rd = P->R + ((instr >> 12) & 15);
+ if(Rn == P->R + 15 || Rd == P->R + 15)
+ sysfatal("R15 in halfword");
+ target = *Rn;
+ if(instr & fP)
+ target += offset;
+ switch(instr & (fSg | fH | fL)) {
+ case fSg: *(u8int*) vaddr(target, &seg) = *Rd; break;
+ case fSg | fL: *Rd = (long) *(char*) vaddr(target, &seg); break;
+ case fH: case fSg | fH: *(u16int*) vaddr(target, &seg) = *Rd; break;
+ case fH | fL: *Rd = *(u16int*) vaddr(target, &seg); break;
+ case fH | fL | fSg: *Rd = (long) *(short*) vaddr(target, &seg); break;
+ }
+ 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;
+
+ if(instr & (1<<22))
+ invalid(instr);
+ Rn = P->R + ((instr >> 16) & 15);
+ if(Rn == P->R + 15 || instr & (1<<15))
+ sysfatal("R15 block");
+ targ = *Rn;
+ if(instr & fU) {
+ for(i = 0; i < 16; i++) {
+ if(!(instr & (1<<i)))
+ continue;
+ if(instr & fP)
+ targ += 4;
+ if(instr & fL)
+ P->R[i] = *(u32int*) vaddr(targ, &seg);
+ else
+ *(u32int*) vaddr(targ, &seg) = P->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)
+ P->R[i] = *(u32int*) vaddr(targ, &seg);
+ else
+ *(u32int*) vaddr(targ, &seg) = P->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 = P->R + (instr & 15);
+ Rs = P->R + ((instr >> 8) & 15);
+ Rn = P->R + ((instr >> 12) & 15);
+ Rd = P->R + ((instr >> 16) & 15);
+ if(Rd == Rm || Rm == P->R + 15 || Rs == P->R + 15 || Rn == P->R + 15 || Rd == P->R + 15)
+ invalid(instr);
+ res = *Rm * *Rs;
+ if(instr & (1<<21))
+ res += *Rn;
+ *Rd = res;
+ if(instr & (1<<20)) {
+ P->CPSR &= ~(flN | flZ);
+ if(res & (1<<31))
+ P->CPSR |= flN;
+ if(res == 0)
+ P->CPSR |= flZ;
+ }
+}
+
+static void
+multiplylong(u32int instr)
+{
+ u32int *RdH, *RdL, *Rs, *Rm;
+ u64int res;
+
+ Rm = P->R + (instr & 15);
+ Rs = P->R + ((instr >> 8) & 15);
+ RdL = P->R + ((instr >> 12) & 15);
+ RdH = P->R + ((instr >> 16) & 15);
+ if(RdL == RdH || RdH == Rm || RdL == Rm || Rm == P->R + 15 || Rs == P->R + 15 || RdL == P->R + 15 || RdH == P->R + 15)
+ invalid(instr);
+ if(instr & (1<<22)) {
+ res = *Rs;
+ res *= *Rm;
+ } else
+ res = ((vlong)*(int*)Rs) * *(int*)Rm;
+ if(instr & (1<<21)) {
+ res += *RdL;
+ res += ((uvlong)*RdH) << 32;
+ }
+ *RdL = res;
+ *RdH = res >> 32;
+ if(instr & (1<<20)) {
+ P->CPSR &= ~FLAGS;
+ if(res == 0)
+ P->CPSR |= flN;
+ if(res & (1LL<<63))
+ P->CPSR |= flV;
+ }
+}
+
+static void
+singleex(u32int instr)
+{
+ u32int *Rn, *Rd, *Rm, *targ;
+ Segment *seg;
+
+ Rd = P->R + ((instr >> 12) & 15);
+ Rn = P->R + ((instr >> 16) & 15);
+ if(Rd == P->R + 15 || Rn == P->R + 15)
+ invalid(instr);
+ if(instr & fS) {
+ targ = vaddr(*Rn, &seg);
+ lock(&seg->lock);
+ *Rd = *targ;
+ segunlock(seg);
+ } else {
+ Rm = P->R + (instr & 15);
+ if(Rm == P->R + 15)
+ invalid(instr);
+ targ = vaddr(*Rn, &seg);
+ if(canlock(&seg->lock)) {
+ *Rd = 1;
+ } else {
+ *targ = *Rd;
+ unlock(&seg->lock);
+ *Rd = 0;
+ }
+ segunlock(seg);
+ }
+}
+
+void
+step(void)
+{
+ u32int instr;
+ Segment *seg;
+
+ instr = *(u32int*) vaddr(P->R[15], &seg);
+ segunlock(seg);
+ if(fulltrace) {
+ print("%d ", P->pid);
+ if(havesymbols) {
+ Symbol s;
+ char buf[512];
+
+ if(findsym(P->R[15], CTEXT, &s) >= 0)
+ print("%s ", s.name);
+ if(fileline(buf, 512, P->R[15]) >= 0)
+ print("%s ", buf);
+ }
+ print("%.8ux %.8ux %c%c%c%c\n", P->R[15], instr,
+ (P->CPSR & flZ) ? 'Z' : ' ',
+ (P->CPSR & flC) ? 'C' : ' ',
+ (P->CPSR & flN) ? 'N' : ' ',
+ (P->CPSR & flV) ? 'V' : ' '
+ );
+ }
+ P->R[15] += 4;
+ switch(instr >> 28) {
+ case 0x0: if(!(P->CPSR & flZ)) return; break;
+ case 0x1: if(P->CPSR & flZ) return; break;
+ case 0x2: if(!(P->CPSR & flC)) return; break;
+ case 0x3: if(P->CPSR & flC) return; break;
+ case 0x4: if(!(P->CPSR & flN)) return; break;
+ case 0x5: if(P->CPSR & flN) return; break;
+ case 0x6: if(!(P->CPSR & flV)) return; break;
+ case 0x7: if(P->CPSR & flV) return; break;
+ case 0x8: if(!(P->CPSR & flC) || (P->CPSR & flZ)) return; break;
+ case 0x9: if((P->CPSR & flC) && !(P->CPSR & flZ)) return; break;
+ case 0xA: if(!(P->CPSR & flN) != !(P->CPSR & flV)) return; break;
+ case 0xB: if(!(P->CPSR & flN) == !(P->CPSR & flV)) return; break;
+ case 0xC: if((P->CPSR & flZ) || !(P->CPSR & flN) != !(P->CPSR & flV)) return; break;
+ case 0xD: if(!(P->CPSR & flZ) && !(P->CPSR & flN) == !(P->CPSR & flV)) return; break;
+ case 0xE: break;
+ default: sysfatal("condition code %x not implemented", instr >> 28);
+ }
+ 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
+ invalid(instr);
+}
--- /dev/null
+++ b/sys/src/cmd/5e/dat.h
@@ -1,0 +1,65 @@
+typedef struct Process Process;
+typedef struct Segment Segment;
+typedef struct Fdtable Fdtable;
+typedef struct Fd Fd;
+
+enum {
+ STACKTOP = 0x80000000UL,
+ STACKSIZE = 0x10000,
+
+ FDBLOCK = 16,
+ SEGNUM = 8,
+
+ flN = 1<<31,
+ flZ = 1<<30,
+ flC = 1<<29,
+ flV = 1<<28,
+ FLAGS = flN | flZ | flC | flV,
+};
+
+enum {
+ SEGTEXT,
+ SEGDATA,
+ SEGBSS,
+ SEGSTACK,
+};
+
+struct Process {
+ Segment* S[SEGNUM];
+ u32int R[16]; /* general purpose registers / PC (R15) */
+ u32int CPSR; /* status register */
+ char errbuf[ERRMAX];
+ Fd *fd;
+ int pid;
+};
+
+extern void **_privates;
+extern int _nprivates;
+#define P (*(Process**)_privates)
+
+enum {
+ SEGFLLOCK = 1,
+};
+
+struct Segment {
+ Ref;
+ int flags;
+ RWLock rw; /* lock for SEGLOCK segments */
+ Lock lock; /* atomic accesses */
+ u32int start, size;
+ void *data;
+ Ref *ref;
+};
+
+struct Fd {
+ RWLock;
+ Ref ref;
+ u8int *fds;
+ int nfds;
+};
+
+#define fulltrace 0
+#define havesymbols 0
+#define ultraverbose 0
+#define systrace 0
+
--- /dev/null
+++ b/sys/src/cmd/5e/fns.h
@@ -1,0 +1,23 @@
+void *emalloc(u32int);
+void *emallocz(u32int);
+void *erealloc(void *, u32int);
+void initproc(void);
+int loadtext(char *, int, char **);
+Segment *newseg(u32int, u32int, int);
+void *vaddr(u32int, Segment **);
+void *vaddrnol(u32int);
+void step(void);
+void syscall(void);
+void cherrstr(char *, ...);
+u32int noteerr(u32int, u32int);
+void freesegs(void);
+Fd *newfd(void);
+Fd *copyfd(Fd *);
+void fddecref(Fd *);
+int iscexec(Fd *, int);
+void setcexec(Fd *, int, int);
+void cleanup(void);
+void segunlock(Segment *);
+void *copyifnec(u32int, int, int *);
+void *bufifnec(u32int, int, int *);
+void copyback(u32int, int, void *);
\ No newline at end of file
--- /dev/null
+++ b/sys/src/cmd/5e/mkfile
@@ -1,0 +1,7 @@
+</$objtype/mkfile
+
+TARG=5e
+OFILES=5e.$O seg.$O proc.$O util.$O arm.$O sys.$O
+HFILES=dat.h fns.h
+
+</sys/src/cmd/mkone
--- /dev/null
+++ b/sys/src/cmd/5e/proc.c
@@ -1,0 +1,244 @@
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include <bio.h>
+#include <mach.h>
+#include <ctype.h>
+#include <tos.h>
+#include "dat.h"
+#include "fns.h"
+
+void
+initproc(void)
+{
+ P = emallocz(sizeof(Process));
+ P->pid = getpid();
+ P->fd = newfd();
+}
+
+static void
+initstack(int argc, char **argv)
+{
+ ulong tos, sp, ap, size, i, len;
+
+ tos = STACKTOP - sizeof(Tos) * 2;
+ sp = tos;
+
+ size = 8;
+ for(i = 0; i < argc; i++)
+ size += strlen(argv[i]) + 5;
+
+ sp -= size;
+ sp &= ~7;
+ P->R[0] = tos;
+ P->R[1] = STACKTOP - 4;
+ P->R[13] = sp;
+
+ *(ulong *) vaddrnol(sp) = argc;
+ sp += 4;
+ ap = sp + (argc + 1) * 4;
+ for(i = 0; i < argc; i++) {
+ *(ulong *) vaddrnol(sp) = ap;
+ sp += 4;
+ len = strlen(argv[i]) + 1;
+ memcpy(vaddrnol(ap), argv[i], len);
+ ap += len;
+ }
+ *(ulong *) vaddrnol(sp) = 0;
+
+ ((Tos *) vaddrnol(tos))->pid = getpid();
+}
+
+static int
+loadscript(int fd, 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;
+
+invalid:
+ werrstr("exec header invalid");
+ return -1;
+}
+
+int
+loadtext(char *file, int argc, char **argv)
+{
+ int fd, i;
+ Fhdr fp;
+ Segment *text, *data, *bss, *stack;
+ char buf[2];
+
+ fd = open(file, OREAD);
+ if(fd < 0) return -1;
+ if(pread(fd, buf, 2, 0) == 2 && buf[0] == '#' && buf[1] == '!')
+ return loadscript(fd, file, argc, argv);
+ seek(fd, 0, 0);
+ if(crackhdr(fd, &fp) == 0) {
+ werrstr("exec header invalid");
+ return -1;
+ }
+ if(fp.magic != E_MAGIC) {
+ werrstr("exec header invalid");
+ return -1;
+ }
+ freesegs();
+ memset(P->R, 0, sizeof(P->R));
+ P->CPSR = 0;
+ text = newseg(fp.txtaddr - fp.hdrsz, fp.txtsz + fp.hdrsz, SEGTEXT);
+ data = newseg(fp.dataddr, fp.datsz, SEGDATA);
+ bss = newseg(fp.dataddr + fp.datsz, fp.bsssz, SEGBSS);
+ stack = newseg(STACKTOP - STACKSIZE, STACKSIZE, SEGSTACK);
+ 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);
+ memset(stack->data, 0, stack->size);
+ P->R[15] = fp.entry;
+ if(havesymbols && syminit(fd, &fp) < 0)
+ fprint(2, "initializing symbol table: %r\n");
+ close(fd);
+ for(i = 0; i < P->fd->nfds * 8; i++)
+ if(iscexec(P->fd, i))
+ close(i);
+ wlock(P->fd);
+ free(P->fd->fds);
+ P->fd->fds = nil;
+ P->fd->nfds = 0;
+ wunlock(P->fd);
+ initstack(argc, argv);
+ return 0;
+}
+
+void
+cherrstr(char *str, ...)
+{
+ va_list va;
+
+ va_start(va, str);
+ vsnprint(P->errbuf, ERRMAX, str, va);
+ va_end(va);
+}
+
+u32int
+noteerr(u32int x, u32int y)
+{
+ if(((int)x) >= ((int)y))
+ return x;
+ rerrstr(P->errbuf, ERRMAX);
+ return x;
+}
+
+Fd *
+newfd(void)
+{
+ Fd *fd;
+
+ fd = emallocz(sizeof(*fd));
+ incref(&fd->ref);
+ return fd;
+}
+
+Fd *
+copyfd(Fd *old)
+{
+ Fd *new;
+
+ rlock(old);
+ new = newfd();
+ if(old->nfds > 0) {
+ new->nfds = old->nfds;
+ new->fds = emalloc(old->nfds);
+ memcpy(new->fds, old->fds, old->nfds);
+ }
+ runlock(old);
+ return new;
+}
+
+void
+fddecref(Fd *fd)
+{
+ if(decref(&fd->ref) == 0) {
+ free(fd->fds);
+ free(fd);
+ }
+}
+
+int
+iscexec(Fd *fd, int n)
+{
+ int r;
+
+ r = 0;
+ rlock(fd);
+ if(n / 8 < fd->nfds)
+ r = (fd->fds[n / 8] & (1 << (n % 8))) != 0;
+ runlock(fd);
+ return r;
+}
+
+void
+setcexec(Fd *fd, int n, int status)
+{
+ int old;
+
+ wlock(fd);
+ if(n / 8 >= fd->nfds) {
+ if(status == 0) {
+ wunlock(fd);
+ return;
+ }
+ old = fd->nfds;
+ fd->nfds = (n / 8) + 1;
+ fd->fds = erealloc(fd->fds, fd->nfds);
+ memset(fd->fds + old, 0, fd->nfds - old);
+ }
+ if(status == 0)
+ fd->fds[n / 8] &= ~(1 << (n % 8));
+ else
+ fd->fds[n / 8] |= (1 << (n % 8));
+ wunlock(fd);
+}
--- /dev/null
+++ b/sys/src/cmd/5e/seg.c
@@ -1,0 +1,129 @@
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include "dat.h"
+#include "fns.h"
+
+Segment *
+newseg(u32int start, u32int size, int idx)
+{
+ Segment *s;
+
+ s = emallocz(sizeof *s);
+ incref(s);
+ s->start = start;
+ s->size = size;
+ s->ref = emalloc(size + sizeof(Ref));
+ memset(s->ref, 0, sizeof(Ref));
+ incref(s->ref);
+ s->data = s->ref + 1;
+ if(idx == SEGBSS)
+ s->flags = SEGFLLOCK;
+ P->S[idx] = s;
+ return s;
+}
+
+void
+freesegs(void)
+{
+ Segment **s;
+
+ for(s = P->S; s < P->S + SEGNUM; s++) {
+ if(*s == nil)
+ continue;
+ if(decref((*s)->ref) == 0)
+ free((*s)->ref);
+ if(decref(*s) == 0)
+ free(*s);
+ *s = nil;
+ }
+}
+
+void *
+vaddr(u32int addr, Segment **seg)
+{
+ Segment **ss, *s;
+
+ for(ss = P->S; ss < P->S + SEGNUM; ss++) {
+ if(*ss == nil)
+ continue;
+ s = *ss;
+ if(addr >= s->start && addr < s->start + s->size) {
+ if(s->flags & SEGFLLOCK)
+ rlock(&s->rw);
+ *seg = s;
+ return (char *)s->data + (addr - s->start);
+ }
+ }
+ sysfatal("fault %.8ux @ %.8ux", addr, P->R[15]);
+ return nil;
+}
+
+void *
+vaddrnol(u32int addr)
+{
+ Segment *seg;
+ void *ret;
+
+ ret = vaddr(addr, &seg);
+ segunlock(seg);
+ return ret;
+}
+
+/* might be made a macro for hurr durr performance */
+void
+segunlock(Segment *s)
+{
+ if(s->flags & SEGFLLOCK)
+ runlock(&s->rw);
+}
+
+void *
+copyifnec(u32int addr, int len, int *copied)
+{
+ void *targ, *ret;
+ Segment *seg;
+
+ targ = vaddr(addr, &seg);
+ if((seg->flags & SEGFLLOCK) == 0) {
+ *copied = 0;
+ return targ;
+ }
+ if(len < 0)
+ len = strlen(targ) + 1;
+ ret = emalloc(len);
+ memcpy(ret, targ, len);
+ segunlock(seg);
+ *copied = 1;
+ return ret;
+}
+
+void *
+bufifnec(u32int addr, int len, int *buffered)
+{
+ void *targ;
+ Segment *seg;
+
+ targ = vaddr(addr, &seg);
+ if((seg->flags & SEGFLLOCK) == 0) {
+ *buffered = 0;
+ return targ;
+ }
+ segunlock(seg);
+ *buffered = 1;
+ return emalloc(len);
+}
+
+void
+copyback(u32int addr, int len, void *data)
+{
+ void *targ;
+ Segment *seg;
+
+ if(len <= 0)
+ return;
+ targ = vaddr(addr, &seg);
+ memmove(targ, data, len);
+ segunlock(seg);
+ free(data);
+}
--- /dev/null
+++ b/sys/src/cmd/5e/sys.c
@@ -1,0 +1,576 @@
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include "dat.h"
+#include "fns.h"
+#include </sys/src/libc/9syscall/sys.h>
+
+static u32int
+arg(int n)
+{
+ /* no locking necessary, since we're on the stack */
+ return *(u32int*) vaddrnol(P->R[13] + 4 + 4 * n);
+}
+
+static u64int
+argv(int n)
+{
+ return arg(n) | ((u64int)arg(n+1) << 32);
+}
+
+static void
+sysopen(void)
+{
+ u32int name, flags;
+ char *namet;
+ int fd, copied;
+
+ name = arg(0);
+ flags = arg(1);
+ namet = copyifnec(name, -1, &copied);
+ if(systrace)
+ fprint(2, "open(%#ux=\"%s\", %#o)\n", name, namet, flags);
+ fd = open(namet, flags);
+ if(copied)
+ free(namet);
+ if(fd < 0) {
+ noteerr(0, 1);
+ P->R[0] = fd;
+ return;
+ }
+ setcexec(P->fd, fd, flags & OCEXEC);
+ P->R[0] = fd;
+}
+
+static void
+syscreate(void)
+{
+ u32int name, flags, perm;
+ char *namet;
+ int fd, copied;
+
+ name = arg(0);
+ flags = arg(1);
+ perm = arg(2);
+ namet = copyifnec(name, -1, &copied);
+ if(systrace)
+ fprint(2, "create(%#ux=\"%s\", %#o, %o)\n", name, namet, flags, perm);
+ fd = create(namet, flags, perm);
+ if(copied)
+ free(namet);
+ if(fd < 0) {
+ noteerr(0, 1);
+ P->R[0] = fd;
+ return;
+ }
+ setcexec(P->fd, fd, flags & OCEXEC);
+ P->R[0] = fd;
+}
+
+static void
+sysclose(void)
+{
+ u32int fd;
+
+ fd = arg(0);
+ if(systrace)
+ fprint(2, "close(%d)\n", fd);
+ P->R[0] = noteerr(close(fd), 0);
+ if((fd & (1<<31)) == 0)
+ setcexec(P->fd, fd, 0);
+}
+
+static void
+syspread(void)
+{
+ int buffered;
+ u32int fd, size, buf;
+ u64int off;
+ void *targ;
+
+ fd = arg(0);
+ buf = arg(1);
+ size = arg(2);
+ off = argv(3);
+ if(systrace)
+ fprint(2, "pread(%d, %#ux, %ud, %#ullx)\n", fd, buf, size, off);
+ targ = bufifnec(buf, size, &buffered);
+ P->R[0] = noteerr(pread(fd, targ, size, off), size);
+ if(buffered)
+ copyback(buf, P->R[0], targ);
+}
+
+static void
+syspwrite(void)
+{
+ u32int fd, size, buf;
+ u64int off;
+ int copied;
+ void *buft;
+
+ fd = arg(0);
+ buf = arg(1);
+ size = arg(2);
+ off = argv(3);
+ buft = copyifnec(buf, size, &copied);
+ if(systrace)
+ fprint(2, "pwrite(%d, %#ux, %ud, %#ullx)\n", fd, buf, size, off);
+ P->R[0] = noteerr(pwrite(fd, buft, size, off), size);
+ if(copied)
+ free(buft);
+}
+
+static void
+sysseek(void)
+{
+ u32int fd, type;
+ vlong n, *ret;
+ Segment *seg;
+
+ ret = vaddr(arg(0), &seg);
+ fd = arg(1);
+ n = argv(2);
+ type = arg(4);
+ if(systrace)
+ fprint(2, "seek(%d, %lld, %d)\n", fd, n, type);
+ *ret = seek(fd, n, type);
+ if(*ret < 0) noteerr(0, 1);
+ segunlock(seg);
+}
+
+static void
+sysfd2path(void)
+{
+ u32int fd, buf, nbuf;
+ void *buft;
+ int buffered;
+
+ fd = arg(0);
+ buf = arg(1);
+ nbuf = arg(2);
+ buft = bufifnec(buf, nbuf, &buffered);
+ if(systrace)
+ fprint(2, "fd2path(%d, %#ux, %d)\n", fd, buf, nbuf);
+ P->R[0] = noteerr(fd2path(fd, buft, nbuf), 0);
+ if(buffered)
+ copyback(buf, nbuf, buft);
+}
+
+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);
+ if(systrace)
+ fprint(2, "stat(%#ux=\"%s\", %#ux, %ud)\n", name, namet, edir, nedir);
+ P->R[0] = noteerr(stat(namet, edirt, nedir), nedir);
+ if(copied)
+ free(namet);
+ if(buffered)
+ copyback(edir, P->R[0], edirt);
+}
+
+static void
+sysfstat(void)
+{
+ u32int fd, edir, nedir;
+ void *edirt;
+ int buffered;
+
+ fd = arg(0);
+ edir = arg(1);
+ nedir = arg(2);
+ edirt = bufifnec(edir, nedir, &buffered);
+ if(systrace)
+ fprint(2, "fstat(%d, %#ux, %d)\n", fd, edir, nedir);
+ P->R[0] = noteerr(fstat(fd, edirt, nedir), nedir);
+ if(buffered)
+ copyback(edir, P->R[0], edirt);
+}
+
+static void
+sysexits(void)
+{
+ if(arg(0) == 0)
+ exits(nil);
+ else
+ exits(vaddrnol(arg(0)));
+}
+
+static void
+sysbrk(void)
+{
+ ulong v;
+ Segment *s;
+
+ v = arg(0);
+ if(v >= P->S[SEGSTACK]->start)
+ sysfatal("bss > stack, wtf?");
+ if(v < P->S[SEGBSS]->start)
+ sysfatal("bss length < 0, wtf?");
+ s = P->S[SEGBSS];
+ wlock(&s->rw);
+ s->ref = realloc(s->ref, v - s->start + 4);
+ if(s->ref == nil)
+ sysfatal("error reallocating");
+ s->data = s->ref + 1;
+ if(s->size < v - s->start)
+ memset((char*)s->data + s->size, 0, v - s->start - s->size);
+ s->size = v - s->start;
+ P->R[0] = 0;
+ wunlock(&s->rw);
+}
+
+static void
+syserrstr(void)
+{
+ char buf[ERRMAX], *srct;
+ u32int src, len;
+ int copied;
+
+ src = arg(0);
+ len = arg(1);
+ srct = copyifnec(src, len, &copied);
+ strcpy(buf, P->errbuf);
+ utfecpy(P->errbuf, P->errbuf + ERRMAX, srct);
+ utfecpy(srct, srct + len, buf);
+ if(copied)
+ copyback(src, len, srct);
+ P->R[0] = 0;
+}
+
+static void
+syschdir(void)
+{
+ u32int dir;
+ char *dirt;
+ int copied;
+
+ dir = arg(0);
+ dirt = copyifnec(dir, -1, &copied);
+ if(systrace)
+ fprint(2, "chdir(%#ux=\"%s\")\n", dir, dirt);
+ P->R[0] = noteerr(chdir(dirt), 0);
+ if(copied)
+ free(dirt);
+}
+
+static void
+sysnotify(void)
+{
+}
+
+static void
+sysrfork(void)
+{
+ u32int flags;
+ int rc, i;
+ Process *p;
+ Segment *s, *t;
+ Fd *old;
+ enum {
+ RFORKPASS = RFENVG | RFCENVG | RFNOTEG | RFNOMNT | RFNAMEG | RFCNAMEG | RFNOWAIT | RFREND | RFFDG | RFCFDG,
+ RFORKHANDLED = RFPROC | RFMEM,
+ };
+
+ flags = arg(0);
+ if(systrace)
+ fprint(2, "rfork(%#o)\n", flags);
+ if(flags & ~(RFORKPASS | RFORKHANDLED))
+ sysfatal("rfork with unhandled flags %#o", flags & ~(RFORKPASS | RFORKHANDLED));
+ if((flags & RFPROC) == 0) {
+ if(flags & RFFDG) {
+ old = P->fd;
+ P->fd = copyfd(P->fd);
+ fddecref(old);
+ }
+ if(flags & RFCFDG) {
+ old = P->fd;
+ P->fd = newfd();
+ fddecref(old);
+ }
+ P->R[0] = noteerr(rfork(flags & RFORKPASS), 0);
+ return;
+ }
+ p = emallocz(sizeof(Process));
+ memcpy(p, P, sizeof(Process));
+ for(i = 0; i < SEGNUM; i++) {
+ s = p->S[i];
+ 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->ref = emalloc(sizeof(Ref) + s->size);
+ memset(t->ref, 0, sizeof(Ref));
+ incref(t->ref);
+ t->data = t->ref + 1;
+ memcpy(t->data, s->data, s->size);
+ p->S[i] = t;
+ } else {
+ incref(s);
+ incref(s->ref);
+ }
+ }
+
+ if(flags & RFFDG)
+ p->fd = copyfd(P->fd);
+ else if(flags & RFCFDG)
+ p->fd = newfd();
+ else
+ incref(&P->fd->ref);
+
+ rc = rfork(RFPROC | RFMEM | (flags & RFORKPASS));
+ if(rc < 0)
+ sysfatal("rfork: %r");
+ if(rc == 0) {
+ P = p;
+ atexit(cleanup);
+ P->pid = getpid();
+ }
+ P->R[0] = rc;
+}
+
+static void
+sysexec(void)
+{
+ u32int name, argv, *argvt;
+ char *namet, **argvv;
+ int i, argc, rc;
+ Segment *seg1, *seg2;
+
+ name = arg(0);
+ argv = arg(1);
+ namet = strdup(vaddr(name, &seg1));
+ segunlock(seg1);
+ argvt = vaddr(argv, &seg1);
+ if(systrace)
+ fprint(2, "exec(%#ux=\"%s\", %#ux)\n", name, namet, argv);
+ for(argc = 0; argvt[argc]; argc++)
+ ;
+ argvv = emalloc(sizeof(char *) * argc);
+ for(i = 0; i < argc; i++) {
+ argvv[i] = strdup(vaddr(argvt[i], &seg2));
+ segunlock(seg2);
+ }
+ segunlock(seg1);
+ rc = loadtext(namet, argc, argvv);
+ for(i = 0; i < argc; i++)
+ free(argvv[i]);
+ free(argvv);
+ if(rc < 0)
+ P->R[0] = noteerr(rc, 0);
+ free(namet);
+}
+
+static void
+sysawait(void)
+{
+ u32int s, n;
+ void *st;
+ int buffered;
+
+ s = arg(0);
+ n = arg(1);
+ st = bufifnec(s, n, &buffered);
+ if(systrace)
+ fprint(2, "await(%#ux, %d)\n", s, n);
+ P->R[0] = noteerr(await(st, n), 0);
+ if(buffered)
+ copyback(s, P->R[0], st);
+}
+
+static void
+syspipe(void)
+{
+ u32int fd, *fdt;
+ int buffered;
+
+ fd = arg(0);
+ if(systrace)
+ fprint(2, "pipe(%#ux)\n", fd);
+ fdt = bufifnec(fd, 8, &buffered);
+ P->R[0] = noteerr(pipe((int *) fdt), 0);
+ if(buffered)
+ copyback(fd, 8, fdt);
+}
+
+static void
+sysdup(void)
+{
+ u32int oldfd, newfd;
+
+ oldfd = arg(0);
+ newfd = arg(1);
+ if(systrace)
+ fprint(2, "dup(%d, %d)\n", oldfd, newfd);
+ P->R[0] = noteerr(dup(oldfd, newfd), 0);
+}
+
+static void
+syssleep(void)
+{
+ u32int n;
+
+ n = arg(0);
+ if(systrace)
+ fprint(2, "sleep(%d)\n", n);
+ P->R[0] = noteerr(sleep(n), 0);
+}
+
+static void
+sysrendezvous(void)
+{
+ u32int tag, value;
+
+ tag = arg(0);
+ value = arg(1);
+ if(systrace)
+ fprint(2, "rendezvous(%#ux, %#ux)\n", tag, value);
+ P->R[0] = (u32int) rendezvous((void *) tag, (void *) value);
+ if(P->R[0] == ~0)
+ noteerr(0, 1);
+}
+
+static void
+sysmount(void)
+{
+ u32int fd, afd, old, flag, aname;
+ char *oldt, *anamet;
+ int copiedold, copiedaname;
+
+ fd = arg(0);
+ afd = arg(1);
+ old = arg(2);
+ flag = arg(3);
+ aname = arg(4);
+ oldt = copyifnec(old, -1, &copiedold);
+ if(aname) {
+ anamet = copyifnec(aname, -1, &copiedaname);
+ if(systrace)
+ fprint(2, "mount(%d, %d, %#x=\"%s\", %#o, %#x=\"%s\")\n", fd, afd, old, oldt, flag, aname, anamet);
+ } else {
+ anamet = nil;
+ copiedaname = 0;
+ if(systrace)
+ fprint(2, "mount(%d, %d, %#x=\"%s\", %#o, nil)\n", fd, afd, old, oldt, flag);
+ }
+ P->R[0] = noteerr(mount(fd, afd, oldt, flag, anamet), 0);
+ if(copiedold)
+ free(oldt);
+ if(copiedaname)
+ free(anamet);
+}
+
+static void
+sysbind(void)
+{
+ u32int name, old, flags;
+ char *namet, *oldt;
+ int copiedname, copiedold;
+
+ name = arg(0);
+ old = arg(1);
+ flags = arg(2);
+ namet = copyifnec(name, -1, &copiedname);
+ oldt = copyifnec(old, -1, &copiedold);
+ if(systrace)
+ fprint(2, "bind(%#ux=\"%s\", %#ux=\"%s\", %#o)\n", name, namet, old, oldt, flags);
+ P->R[0] = noteerr(bind(namet, oldt, flags), 0);
+ if(copiedname)
+ free(namet);
+ if(copiedold)
+ free(oldt);
+}
+
+static void
+sysunmount(void)
+{
+ u32int name, old;
+ char *namet, *oldt;
+ int copiedname, copiedold;
+
+ name = arg(0);
+ old = arg(1);
+ oldt = copyifnec(old, -1, &copiedold);
+ if(name == 0) {
+ namet = nil;
+ copiedname = 0;
+ if(systrace)
+ fprint(2, "unmount(nil, %#ux=\"%s\")\n", old, oldt);
+ P->R[0] = noteerr(unmount(nil, oldt), 0);
+ } else {
+ namet = copyifnec(name, -1, &copiedname);
+ if(systrace)
+ fprint(2, "unmount(%#ux=\"%s\", %#ux=\"%s\")\n", name, namet, old, oldt);
+ P->R[0] = noteerr(unmount(namet, oldt), 0);
+ }
+ if(copiedold)
+ free(oldt);
+ if(copiedname)
+ free(namet);
+}
+
+static void
+sysremove(void)
+{
+ u32int file;
+ char *filet;
+ int copied;
+
+ file = arg(0);
+ filet = copyifnec(file, -1, &copied);
+ if(systrace)
+ fprint(2, "remove(%#ux=\"%s\")\n", file, filet);
+ P->R[0] = noteerr(remove(filet), 0);
+ if(copied)
+ free(filet);
+}
+
+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,
+ [SEEK] sysseek,
+ [CHDIR] syschdir,
+ [FD2PATH] sysfd2path,
+ [NOTIFY] sysnotify,
+ [RFORK] sysrfork,
+ [EXEC] sysexec,
+ [AWAIT] sysawait,
+ [PIPE] syspipe,
+ [SLEEP] syssleep,
+ [RENDEZVOUS] sysrendezvous,
+ [BIND] sysbind,
+ [UNMOUNT] sysunmount,
+ [DUP] sysdup,
+ [MOUNT] sysmount,
+ [REMOVE] sysremove,
+ };
+
+ n = P->R[0];
+ if(n >= nelem(calls) || calls[n] == nil)
+ sysfatal("no such syscall %d @ %#ux", n, P->R[15] - 4);
+ calls[n]();
+}
--- /dev/null
+++ b/sys/src/cmd/5e/util.c
@@ -1,0 +1,37 @@
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include "dat.h"
+#include "fns.h"
+
+void *
+emalloc(u32int size)
+{
+ void *v;
+
+ v = malloc(size);
+ if(v == nil)
+ sysfatal("%r");
+ return v;
+}
+
+void *
+emallocz(u32int size)
+{
+ void *v;
+
+ v = emalloc(size);
+ memset(v, 0, size);
+ return v;
+}
+
+void *
+erealloc(void *old, u32int size)
+{
+ void *v;
+
+ v = realloc(old, size);
+ if(v == nil)
+ sysfatal("%r");
+ return v;
+}