5e/ 755 0 0 0 11573700203 72755ustar00aijuaiju5e/5e.c 644 0 0 2101 11573457065 7763ustar00aijuaiju#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(); } } 5e/mkfile 644 0 0 165 11572662660 10466ustar00aijuaiju #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); } 5e/proc.c 644 0 0 10203 11573656124 10434ustar00aijuaiju#include #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); } 5e/util.c 644 0 0 641 11572724317 10412ustar00aijuaiju#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; } 5e/fns.h 644 0 0 1147 11573660320 10244ustar00aijuaijuvoid *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 *);{ 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 5e/arm.c 644 0 0 24030 11573657043 10254ustar00aijuaiju#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); } #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)5e/sys.c 644 0 0 24706 11573673146 10327ustar00aijuaiju#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](); } amet = copyifnec(name, -1, &copied); if(systrace) fprin