diff --git a/sys/src/cmd/5e/5e.c b/sys/src/cmd/5e/5e.c new file mode 100644 index 000000000..3aac578d1 --- /dev/null +++ b/sys/src/cmd/5e/5e.c @@ -0,0 +1,76 @@ +#include +#include +#include +#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(); + } +} diff --git a/sys/src/cmd/5e/arm.c b/sys/src/cmd/5e/arm.c new file mode 100644 index 000000000..fcaab3fb4 --- /dev/null +++ b/sys/src/cmd/5e/arm.c @@ -0,0 +1,472 @@ +#include +#include +#include +#include +#include +#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<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<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); +} diff --git a/sys/src/cmd/5e/dat.h b/sys/src/cmd/5e/dat.h new file mode 100644 index 000000000..d8356f07d --- /dev/null +++ b/sys/src/cmd/5e/dat.h @@ -0,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 + diff --git a/sys/src/cmd/5e/fns.h b/sys/src/cmd/5e/fns.h new file mode 100644 index 000000000..7ae97eae8 --- /dev/null +++ b/sys/src/cmd/5e/fns.h @@ -0,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 diff --git a/sys/src/cmd/5e/mkfile b/sys/src/cmd/5e/mkfile new file mode 100644 index 000000000..b3a10fa81 --- /dev/null +++ b/sys/src/cmd/5e/mkfile @@ -0,0 +1,7 @@ + +#include +#include +#include +#include +#include +#include +#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); +} diff --git a/sys/src/cmd/5e/seg.c b/sys/src/cmd/5e/seg.c new file mode 100644 index 000000000..caa4002ac --- /dev/null +++ b/sys/src/cmd/5e/seg.c @@ -0,0 +1,129 @@ +#include +#include +#include +#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); +} diff --git a/sys/src/cmd/5e/sys.c b/sys/src/cmd/5e/sys.c new file mode 100644 index 000000000..e88f8f1e0 --- /dev/null +++ b/sys/src/cmd/5e/sys.c @@ -0,0 +1,576 @@ +#include +#include +#include +#include "dat.h" +#include "fns.h" +#include + +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](); +} diff --git a/sys/src/cmd/5e/util.c b/sys/src/cmd/5e/util.c new file mode 100644 index 000000000..dc9efa424 --- /dev/null +++ b/sys/src/cmd/5e/util.c @@ -0,0 +1,37 @@ +#include +#include +#include +#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; +}