cosmopolitan/tool/build/lib/syscall.c
Justine Tunney f4f4caab0e Add x86_64-linux-gnu emulator
I wanted a tiny scriptable meltdown proof way to run userspace programs
and visualize how program execution impacts memory. It helps to explain
how things like Actually Portable Executable works. It can show you how
the GCC generated code is going about manipulating matrices and more. I
didn't feel fully comfortable with Qemu and Bochs because I'm not smart
enough to understand them. I wanted something like gVisor but with much
stronger levels of assurances. I wanted a single binary that'll run, on
all major operating systems with an embedded GPL barrier ZIP filesystem
that is tiny enough to transpile to JavaScript and run in browsers too.

https://justine.storage.googleapis.com/emulator625.mp4
2020-08-25 04:43:42 -07:00

647 lines
21 KiB
C

/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2020 Justine Alexandra Roberts Tunney │
│ │
│ This program is free software; you can redistribute it and/or modify │
│ it under the terms of the GNU General Public License as published by │
│ the Free Software Foundation; version 2 of the License. │
│ │
│ This program is distributed in the hope that it will be useful, but │
│ WITHOUT ANY WARRANTY; without even the implied warranty of │
│ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU │
│ General Public License for more details. │
│ │
│ You should have received a copy of the GNU General Public License │
│ along with this program; if not, write to the Free Software │
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
│ 02110-1301 USA │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/ioctl.h"
#include "libc/calls/struct/sigaction-linux.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/stat.h"
#include "libc/calls/struct/timespec.h"
#include "libc/calls/struct/timeval.h"
#include "libc/errno.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/macros.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/sock/sock.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/consts/clock.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/msync.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/ok.h"
#include "libc/sysv/consts/sa.h"
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/consts/so.h"
#include "libc/sysv/consts/tcp.h"
#include "libc/sysv/errfuns.h"
#include "libc/time/struct/timezone.h"
#include "libc/time/time.h"
#include "tool/build/lib/case.h"
#include "tool/build/lib/endian.h"
#include "tool/build/lib/machine.h"
#include "tool/build/lib/memory.h"
#include "tool/build/lib/pml4t.h"
#include "tool/build/lib/syscall.h"
#include "tool/build/lib/throw.h"
#include "tool/build/lib/xlaterrno.h"
#define AT_FDCWD_LINUX -100
#define POINTER(x) ((void *)(intptr_t)(x))
#define UNPOINTER(x) ((int64_t)(intptr_t)(x))
#define SYSCALL(x, y) CASE(x, asm("# " #y); ax = y)
#define XLAT(x, y) CASE(x, return y)
#define PNN(x) ResolveAddress(m, x)
#define P(x) ((x) ? PNN(x) : 0)
#define ASSIGN(D, S) memcpy(&D, &S, MIN(sizeof(S), sizeof(D)))
static int XlatSignal(int sig) {
switch (sig) {
XLAT(1, SIGHUP);
XLAT(2, SIGINT);
XLAT(3, SIGQUIT);
XLAT(4, SIGILL);
XLAT(5, SIGTRAP);
XLAT(6, SIGABRT);
XLAT(7, SIGBUS);
XLAT(8, SIGFPE);
XLAT(9, SIGKILL);
XLAT(10, SIGUSR1);
XLAT(11, SIGSEGV);
XLAT(13, SIGPIPE);
XLAT(14, SIGALRM);
XLAT(15, SIGTERM);
XLAT(21, SIGTTIN);
XLAT(22, SIGTTOU);
XLAT(24, SIGXCPU);
XLAT(25, SIGXFSZ);
XLAT(26, SIGVTALRM);
XLAT(27, SIGPROF);
XLAT(28, SIGWINCH);
XLAT(17, SIGCHLD);
XLAT(18, SIGCONT);
XLAT(29, SIGIO);
XLAT(19, SIGSTOP);
XLAT(31, SIGSYS);
XLAT(20, SIGTSTP);
XLAT(23, SIGURG);
XLAT(12, SIGUSR2);
XLAT(0x2000, SIGSTKSZ);
XLAT(30, SIGPWR);
XLAT(0x10, SIGSTKFLT);
default:
return sig;
}
}
static int XlatMapFlags(int x) {
unsigned res = 0;
if (x & 1) res |= MAP_SHARED;
if (x & 2) res |= MAP_PRIVATE;
if (x & 16) res |= MAP_FIXED;
if (x & 32) res |= MAP_ANONYMOUS;
return res;
}
static int XlatAccess(int x) {
unsigned res = F_OK;
if (x & 1) res |= X_OK;
if (x & 2) res |= W_OK;
if (x & 4) res |= R_OK;
return res;
}
static int XlatSigaction(int x) {
unsigned res = 0;
if (x & 0x04000000) res |= SA_RESTORER;
if (x & 0x08000000) res |= SA_ONSTACK;
if (x & 0x10000000) res |= SA_RESTART;
if (x & 1) res |= SA_NOCLDSTOP;
if (x & 2) res |= SA_NOCLDWAIT;
if (x & 4) res |= SA_SIGINFO;
if (x & 0x40000000) res |= SA_NODEFER;
if (x & 0x40000000) res |= SA_NOMASK;
if (x & 0x80000000) res |= SA_RESETHAND;
if (x & 0x80000000) res |= SA_ONESHOT;
return res;
}
static int XlatSo(int x) {
switch (x) {
XLAT(-1, SO_EXCLUSIVEADDRUSE);
XLAT(1, SO_DEBUG);
XLAT(2, SO_REUSEADDR);
XLAT(3, SO_TYPE);
XLAT(4, SO_ERROR);
XLAT(5, SO_DONTROUTE);
XLAT(6, SO_BROADCAST);
XLAT(7, SO_SNDBUF);
XLAT(8, SO_RCVBUF);
XLAT(9, SO_KEEPALIVE);
XLAT(10, SO_OOBINLINE);
XLAT(13, SO_LINGER);
XLAT(15, SO_REUSEPORT);
XLAT(17, SO_PEERCRED);
XLAT(18, SO_RCVLOWAT);
XLAT(19, SO_SNDLOWAT);
XLAT(20, SO_RCVTIMEO);
XLAT(21, SO_SNDTIMEO);
XLAT(29, SO_TIMESTAMP);
XLAT(30, SO_ACCEPTCONN);
XLAT(38, SO_PROTOCOL);
XLAT(39, SO_DOMAIN);
XLAT(47, SO_MAX_PACING_RATE);
default:
return x;
}
}
static int XlatClock(int x) {
switch (x) {
XLAT(0, CLOCK_REALTIME);
XLAT(4, CLOCK_MONOTONIC);
default:
return x;
}
}
static int XlatTcp(int x) {
switch (x) {
XLAT(1, TCP_NODELAY);
XLAT(2, TCP_MAXSEG);
XLAT(23, TCP_FASTOPEN);
XLAT(4, TCP_KEEPIDLE);
XLAT(5, TCP_KEEPINTVL);
XLAT(6, TCP_KEEPCNT);
default:
return x;
}
}
static int XlatAfd(int x) {
if (x == AT_FDCWD_LINUX) x = AT_FDCWD;
return x;
}
static int XlatAtf(int x) {
unsigned res = 0;
if (x & 0x0100) res |= AT_SYMLINK_NOFOLLOW;
if (x & 0x0200) res |= AT_REMOVEDIR;
if (x & 0x0400) res |= AT_SYMLINK_FOLLOW;
if (x & 0x1000) res |= AT_EMPTY_PATH;
return res;
}
static int XlatMsyncFlags(int x) {
unsigned res = 0;
if (x & 1) res |= MS_ASYNC;
if (x & 2) res |= MS_INVALIDATE;
if (x & 4) res |= MS_SYNC;
return res;
}
static unsigned XlatOpenFlags(unsigned flags) {
unsigned res = 0;
if ((flags & 3) == 0) res = O_RDONLY;
if ((flags & 3) == 1) res = O_WRONLY;
if ((flags & 3) == 3) res = O_RDWR;
if (flags & 0x80000) res |= O_CLOEXEC;
if (flags & 0x400) res |= O_APPEND;
if (flags & 0x40) res |= O_CREAT;
if (flags & 0x80) res |= O_EXCL;
if (flags & 0x200) res |= O_TRUNC;
if (flags & 0x0800) res |= O_NDELAY;
if (flags & 0x4000) res |= O_DIRECT;
if (flags & 0x0800) res |= O_NONBLOCK;
if (flags & 0x1000) res |= O_DSYNC;
if (flags & 0x101000) res |= O_RSYNC;
if (flags & 0x040000) res |= O_NOATIME;
return res;
}
static struct sigaction *CoerceSigactionToCosmo(
struct sigaction *dst, const struct sigaction$linux *src) {
if (!src) return NULL;
memset(dst, 0, sizeof(*dst));
ASSIGN(dst->sa_handler, src->sa_handler);
ASSIGN(dst->sa_restorer, src->sa_restorer);
ASSIGN(dst->sa_flags, src->sa_flags);
ASSIGN(dst->sa_mask, src->sa_mask);
return dst;
}
static struct sigaction$linux *CoerceSigactionToLinux(
struct sigaction$linux *dst, const struct sigaction *src) {
if (!dst) return NULL;
memset(dst, 0, sizeof(*dst));
ASSIGN(dst->sa_handler, src->sa_handler);
ASSIGN(dst->sa_restorer, src->sa_restorer);
ASSIGN(dst->sa_flags, src->sa_flags);
ASSIGN(dst->sa_mask, src->sa_mask);
return dst;
}
static int OpMprotect(struct Machine *m, int64_t addr, uint64_t len, int prot) {
return 0;
}
static int OpMadvise(struct Machine *m, int64_t addr, size_t length,
int advice) {
return enosys();
}
static int64_t OpMmap(struct Machine *m, int64_t virt, size_t size, int prot,
int flags, int fd, int64_t off) {
void *real;
flags = XlatMapFlags(flags);
real = mmap(NULL, size, prot, flags & ~MAP_FIXED, fd, off);
if (real == MAP_FAILED) return -1;
if (!(flags & MAP_FIXED)) {
if (0 <= virt && virt < 0x400000) virt = 0x400000;
if ((virt = FindPml4t(m->cr3, virt, size, MallocPage)) == -1) return -1;
}
CHECK_NE(-1, RegisterMemory(m, virt, real, size));
return virt;
}
static int OpMunmap(struct Machine *m, int64_t addr, uint64_t size) {
return FreePml4t(m->cr3, addr, size, free, munmap);
}
static int OpMsync(struct Machine *m, int64_t virt, size_t size, int flags) {
size_t i;
void *page;
virt = ROUNDDOWN(virt, 4096);
flags = XlatMsyncFlags(flags);
for (i = 0; i < size; i += 4096) {
if (!(page = FindReal(m, virt + i))) return efault();
if (msync(page, 4096, flags) == -1) return -1;
}
return 0;
}
static void *GetDirectBuf(struct Machine *m, int64_t addr, size_t *size) {
void *page;
*size = MIN(*size, 0x1000 - (addr & 0xfff));
if (!(page = FindReal(m, addr))) return MAP_FAILED;
return page;
}
static ssize_t OpRead(struct Machine *m, int fd, int64_t addr, size_t size) {
void *data;
ssize_t rc;
if ((data = GetDirectBuf(m, addr, &size)) == MAP_FAILED) return efault();
if ((rc = read(fd, data, size)) != -1) SetWriteAddr(m, addr, rc);
return rc;
}
static ssize_t OpWrite(struct Machine *m, int fd, int64_t addr, size_t size) {
void *data;
ssize_t rc;
if ((data = GetDirectBuf(m, addr, &size)) == MAP_FAILED) return efault();
if ((rc = write(fd, data, size)) != -1) SetReadAddr(m, addr, size);
return rc;
}
static ssize_t OpPread(struct Machine *m, int fd, int64_t addr, size_t size,
int64_t offset) {
void *data;
ssize_t rc;
if ((data = GetDirectBuf(m, addr, &size)) == MAP_FAILED) return efault();
if ((rc = pread(fd, data, size, offset)) != -1) SetWriteAddr(m, addr, rc);
return rc;
}
static ssize_t OpPwrite(struct Machine *m, int fd, int64_t addr, size_t size,
int64_t offset) {
void *data;
ssize_t rc;
if ((data = GetDirectBuf(m, addr, &size)) == MAP_FAILED) return efault();
if ((rc = pwrite(fd, data, size, offset)) != -1) SetReadAddr(m, addr, size);
return rc;
}
static int OpFstatat(struct Machine *m, int dirfd, int64_t path, int64_t st,
int flags) {
int rc;
void *stp[2];
uint8_t *stbuf;
if (!(stbuf = malloc(sizeof(struct stat)))) return enomem();
if ((rc = fstatat(XlatAfd(dirfd), LoadStr(m, path),
BeginStoreNp(m, st, sizeof(stbuf), stp, stbuf),
XlatAtf(flags))) != -1) {
EndStoreNp(m, st, sizeof(stbuf), stp, stbuf);
}
free(stbuf);
return rc;
}
static int OpFstat(struct Machine *m, int fd, int64_t st) {
int rc;
void *stp[2];
uint8_t *stbuf;
if (!(stbuf = malloc(sizeof(struct stat)))) return enomem();
if ((rc = fstat(fd, BeginStoreNp(m, st, sizeof(stbuf), stp, stbuf))) != -1) {
EndStoreNp(m, st, sizeof(stbuf), stp, stbuf);
}
free(stbuf);
return rc;
}
static int OpOpenat(struct Machine *m, int dirfd, int64_t path, int flags,
int mode) {
return openat(XlatAfd(dirfd), LoadStr(m, path), XlatOpenFlags(flags), mode);
}
static int OpFaccessat(struct Machine *m, int dirfd, int64_t path, int mode,
int flags) {
return faccessat(XlatAfd(dirfd), LoadStr(m, path), XlatAccess(mode),
XlatAtf(flags));
}
static int OpChdir(struct Machine *m, int64_t path) {
return chdir(LoadStr(m, path));
}
static int OpMkdir(struct Machine *m, int64_t path, int mode) {
return mkdir(LoadStr(m, path), mode);
}
static int OpMknod(struct Machine *m, int64_t path, uint32_t mode,
uint64_t dev) {
return mknod(LoadStr(m, path), mode, dev);
}
static int OpRmdir(struct Machine *m, int64_t path) {
return rmdir(LoadStr(m, path));
}
static int OpUnlink(struct Machine *m, int64_t path) {
return unlink(LoadStr(m, path));
}
static int OpRename(struct Machine *m, int64_t src, int64_t dst) {
return rename(LoadStr(m, src), LoadStr(m, dst));
}
static int OpTruncate(struct Machine *m, int64_t path, uint64_t length) {
return truncate(LoadStr(m, path), length);
}
static int OpLink(struct Machine *m, int64_t existingpath, int64_t newpath) {
return link(LoadStr(m, existingpath), LoadStr(m, newpath));
}
static int OpSymlink(struct Machine *m, int64_t target, int64_t linkpath) {
return symlink(LoadStr(m, target), LoadStr(m, linkpath));
}
static int OpChmod(struct Machine *m, int64_t path, uint32_t mode) {
return chmod(LoadStr(m, path), mode);
}
static int64_t OpGetcwd(struct Machine *m, int64_t bufaddr, size_t size) {
size_t n;
char *buf;
int64_t res;
size = MIN(size, PATH_MAX);
if (!(buf = malloc(size))) return enomem();
if ((getcwd)(buf, size)) {
n = strlen(buf);
VirtualRecv(m, bufaddr, buf, n);
SetWriteAddr(m, bufaddr, n);
res = bufaddr;
} else {
res = -1;
}
free(buf);
return res;
}
static int OpSigaction(struct Machine *m, int sig, int64_t act, int64_t old) {
int rc;
struct OpSigactionMemory {
struct sigaction act, old;
uint8_t b[sizeof(struct sigaction$linux)];
void *p[2];
} * mem;
if (!(mem = malloc(sizeof(*mem)))) return enomem();
if ((rc = sigaction(
XlatSignal(sig),
CoerceSigactionToCosmo(
&mem->act, LoadBuf(m, act, sizeof(struct sigaction$linux))),
&mem->old)) != -1) {
CoerceSigactionToLinux(BeginStoreNp(m, old, sizeof(mem->b), mem->p, mem->b),
&mem->old);
EndStoreNp(m, old, sizeof(mem->b), mem->p, mem->b);
}
free(mem);
return rc;
}
static int OpPipe(struct Machine *m, int64_t pipefds_addr) {
int rc;
void *p[2];
uint8_t b[8];
if ((rc = pipe(BeginStoreNp(m, pipefds_addr, 8, p, b))) != -1) {
EndStoreNp(m, pipefds_addr, 8, p, b);
}
return rc;
}
static int OpNanosleep(struct Machine *m, int64_t req, int64_t rem) {
int rc;
void *p[2];
uint8_t b[sizeof(struct timespec)];
if ((rc = nanosleep(LoadBuf(m, req, sizeof(b)),
BeginStoreNp(m, rem, sizeof(b), p, b))) != -1) {
EndStoreNp(m, rem, sizeof(b), p, b);
}
return rc;
}
static int OpSigsuspend(struct Machine *m, int64_t maskaddr) {
void *p;
sigset_t mask;
if (!(p = LoadBuf(m, maskaddr, 8))) return efault();
memset(&mask, 0, sizeof(mask));
memcpy(&mask, p, 8);
return sigsuspend(&mask);
}
static int OpClockGettime(struct Machine *m, int clockid, int64_t ts) {
int rc;
void *tsp[2];
uint8_t tsb[sizeof(struct timespec)];
if ((rc = clock_gettime(XlatClock(clockid),
BeginStoreNp(m, ts, sizeof(tsb), tsp, tsb))) != -1) {
EndStoreNp(m, ts, sizeof(tsb), tsp, tsb);
}
return rc;
}
static int OpGettimeofday(struct Machine *m, int64_t tv, int64_t tz) {
int rc;
void *tvp[2], *tzp[2];
uint8_t tvb[sizeof(struct timeval)];
uint8_t tzb[sizeof(struct timezone)];
if ((rc = gettimeofday(BeginStoreNp(m, tv, sizeof(tvb), tvp, tvb),
BeginStoreNp(m, tz, sizeof(tzb), tzp, tzb))) != -1) {
EndStoreNp(m, tv, sizeof(tvb), tvp, tvb);
EndStoreNp(m, tz, sizeof(tzb), tzp, tzb);
}
return rc;
}
static int DoOpen(struct Machine *m, int64_t path, int flags, int mode) {
return OpOpenat(m, AT_FDCWD_LINUX, path, flags, mode);
}
static int DoCreat(struct Machine *m, int64_t file, int mode) {
return DoOpen(m, file, 0x241, mode);
}
static int DoAccess(struct Machine *m, int64_t path, int mode) {
return OpFaccessat(m, AT_FDCWD_LINUX, path, mode, 0);
}
static int DoStat(struct Machine *m, int64_t path, int64_t st) {
return OpFstatat(m, AT_FDCWD_LINUX, path, st, 0);
}
static int DoLstat(struct Machine *m, int64_t path, int64_t st) {
return OpFstatat(m, AT_FDCWD_LINUX, path, st, 0x0400);
}
void OpSyscall(struct Machine *m) {
uint64_t i, ax, di, si, dx, r0, r8, r9;
ax = Read64(m->ax);
di = Read64(m->di);
si = Read64(m->si);
dx = Read64(m->dx);
r0 = Read32(m->r10);
r8 = Read32(m->r8);
r9 = Read32(m->r9);
switch (ax & 0x1ff) {
SYSCALL(0x000, OpRead(m, di, si, dx));
SYSCALL(0x001, OpWrite(m, di, si, dx));
SYSCALL(0x002, DoOpen(m, di, si, dx));
SYSCALL(0x003, close(di));
SYSCALL(0x004, DoStat(m, di, si));
SYSCALL(0x005, OpFstat(m, di, si));
SYSCALL(0x006, DoLstat(m, di, si));
SYSCALL(0x007, poll(PNN(di), si, dx));
SYSCALL(0x008, lseek(di, si, dx));
SYSCALL(0x009, OpMmap(m, di, si, dx, r0, r8, r9));
SYSCALL(0x01A, OpMsync(m, di, si, dx));
SYSCALL(0x00A, OpMprotect(m, di, si, dx));
SYSCALL(0x00B, OpMunmap(m, di, si));
SYSCALL(0x00D, OpSigaction(m, di, si, dx));
SYSCALL(0x00E, sigprocmask(di, P(si), P(dx)));
SYSCALL(0x010, ioctl(di, si, P(dx)));
SYSCALL(0x011, OpPread(m, di, si, dx, r0));
SYSCALL(0x012, OpPwrite(m, di, si, dx, r0));
SYSCALL(0x013, readv(di, P(si), dx));
SYSCALL(0x014, writev(di, P(si), dx));
SYSCALL(0x015, DoAccess(m, di, si));
SYSCALL(0x016, OpPipe(m, di));
SYSCALL(0x017, select(di, P(si), P(dx), P(r0), P(r8)));
SYSCALL(0x018, sched_yield());
SYSCALL(0x01C, OpMadvise(m, di, si, dx));
SYSCALL(0x020, dup(di));
SYSCALL(0x021, dup2(di, si));
SYSCALL(0x022, pause());
SYSCALL(0x023, OpNanosleep(m, di, si));
SYSCALL(0x024, getitimer(di, PNN(si)));
SYSCALL(0x025, alarm(di));
SYSCALL(0x026, setitimer(di, PNN(si), P(dx)));
SYSCALL(0x027, getpid());
SYSCALL(0x028, sendfile(di, si, P(dx), r0));
SYSCALL(0x029, socket(di, si, dx));
SYSCALL(0x02A, connect(di, PNN(si), dx));
SYSCALL(0x02B, accept(di, PNN(di), PNN(dx)));
SYSCALL(0x02C, sendto(di, PNN(si), dx, r0, P(r8), r9));
SYSCALL(0x02D, recvfrom(di, P(si), dx, r0, P(r8), P(r9)));
SYSCALL(0x030, shutdown(di, si));
SYSCALL(0x031, bind(di, PNN(si), dx));
SYSCALL(0x032, listen(di, si));
SYSCALL(0x033, getsockname(di, PNN(si), PNN(dx)));
SYSCALL(0x034, getpeername(di, PNN(si), PNN(dx)));
SYSCALL(0x036, setsockopt(di, si, dx, PNN(r0), r8));
SYSCALL(0x037, getsockopt(di, si, dx, PNN(r0), PNN(r8)));
SYSCALL(0x039, fork());
SYSCALL(0x03B, execve(PNN(r8), PNN(r8), PNN(r8)));
SYSCALL(0x03D, wait4(di, P(si), dx, P(r0)));
SYSCALL(0x03E, kill(di, si));
SYSCALL(0x03F, uname(P(di)));
SYSCALL(0x048, fcntl(di, si, dx));
SYSCALL(0x049, flock(di, si));
SYSCALL(0x04A, fsync(di));
SYSCALL(0x04B, fdatasync(di));
SYSCALL(0x04C, OpTruncate(m, di, si));
SYSCALL(0x04D, ftruncate(di, si));
SYSCALL(0x04F, OpGetcwd(m, di, si));
SYSCALL(0x050, OpChdir(m, di));
SYSCALL(0x052, OpRename(m, di, si));
SYSCALL(0x053, OpMkdir(m, di, si));
SYSCALL(0x054, OpRmdir(m, di));
SYSCALL(0x055, DoCreat(m, di, si));
SYSCALL(0x056, OpLink(m, di, si));
SYSCALL(0x057, OpUnlink(m, di));
SYSCALL(0x058, OpSymlink(m, di, si));
SYSCALL(0x05A, OpChmod(m, di, si));
SYSCALL(0x05B, fchmod(di, si));
SYSCALL(0x060, OpGettimeofday(m, di, si));
SYSCALL(0x061, getrlimit(di, P(si)));
SYSCALL(0x062, getrusage(di, P(si)));
SYSCALL(0x063, sysinfo(PNN(di)));
SYSCALL(0x064, times(PNN(di)));
SYSCALL(0x066, getuid());
SYSCALL(0x068, getgid());
SYSCALL(0x06E, getppid());
SYSCALL(0x075, setresuid(di, si, dx));
SYSCALL(0x077, setresgid(di, si, dx));
SYSCALL(0x082, OpSigsuspend(m, di));
SYSCALL(0x085, OpMknod(m, di, si, dx));
SYSCALL(0x08C, getpriority(di, si));
SYSCALL(0x08D, setpriority(di, si, dx));
SYSCALL(0x0A0, setrlimit(di, P(si)));
SYSCALL(0x084, utime(PNN(di), PNN(si)));
SYSCALL(0x0EB, utimes(P(di), P(si)));
SYSCALL(0x09E, arch_prctl(di, si));
SYSCALL(0x0BA, gettid());
SYSCALL(0x0CB, sched_setaffinity(di, si, P(dx)));
SYSCALL(0x0DD, fadvise(di, si, dx, r0));
SYSCALL(0x0E4, OpClockGettime(m, di, si));
SYSCALL(0x101, OpOpenat(m, di, si, dx, r0));
SYSCALL(0x102, mkdirat(XlatAfd(di), P(si), dx));
SYSCALL(0x104, fchownat(XlatAfd(di), P(si), dx, r0, XlatAtf(r8)));
SYSCALL(0x105, futimesat(XlatAfd(di), P(si), P(dx)));
SYSCALL(0x106, OpFstatat(m, di, si, dx, r0));
SYSCALL(0x107, unlinkat(XlatAfd(di), P(si), XlatAtf(dx)));
SYSCALL(0x108, renameat(XlatAfd(di), P(si), XlatAfd(dx), P(r0)));
SYSCALL(0x10D, OpFaccessat(m, di, si, dx, r0));
SYSCALL(0x113, splice(di, P(si), dx, P(r0), r8, XlatAtf(r9)));
SYSCALL(0x115, sync_file_range(di, si, dx, XlatAtf(r0)));
SYSCALL(0x118, utimensat(XlatAfd(di), P(si), P(dx), XlatAtf(r0)));
SYSCALL(0x177, vmsplice(di, P(si), dx, r0));
CASE(0xE7, HaltMachine(m, di | 0x100));
default:
DEBUGF("missing syscall %03x", ax);
ax = enosys();
break;
}
Write64(m->ax, ax != -1 ? ax : -(XlatErrno(errno) & 0xfff));
for (i = 0; i < m->freelist.i; ++i) free(m->freelist.p[i]);
m->freelist.i = 0;
}