Commit Diff


commit - 5f8048ab7e609ab2283a4a1e9a4e74276ec1f547
commit + 52a430f311f2ce1fe38eb2fb7d5867df29e13e7e
blob - b862efd1a319407c20f8397f6fa3a7b6fd65b9b9
blob + 2739ea77906d91f6c1a52c00b357948a4c7390ef
--- .gitignore
+++ .gitignore
@@ -2,5 +2,7 @@
 *.core
 *.o
 *.elf
+rootfs
+syscalls.h
 rvemu
 
blob - c683707ec93490fb754776ec570d1ce24be25248
blob + 6634c2708ac436e52f5c1fb974b170cf6de574cb
--- Makefile
+++ Makefile
@@ -2,24 +2,41 @@
 .SUFFIXES:
 .SUFFIXES: .c .S .o .elf
 
-CROSS	= riscv32-unknown-linux-musl
-CFLAGS	= -fno-PIC -O3
-LDFLAGS	= -s -Wl,--image-base,0x78000000 -no-pie -static -lpthread -lutil
-OBJ	= rvemu.o syscall.o cpu.o exec.o
+SUDO	= doas
+PREFIX	= /usr/local
+
+CROSS	= riscv64-unknown-linux-musl
+CFLAGS	= -fPIC -O3
+LDFLAGS	= -s -pie -static -lpthread
+OBJ	= rvemu.o ecall.o cpu.o exec.o
 PROGS	= test.elf hello.elf
 
 all: rvemu ${PROGS}
 
 clean:
-	rm -f rvemu *.o *.elf *.core
+	rm -f rvemu *.o *.elf *.core syscalls.h
+	rm -rf rootfs
 
-run: rvemu test.elf
-	./rvemu test.elf
+install: rvemu
+	mkdir -p ${DESTDIR}${PREFIX}/bin
+	cp -f rvemu ${DESTDIR}${PREFIX}/bin/
 
+run: rvemu ${PROGS}
+	mkdir -p rootfs/bin
+	cp -f rvemu rootfs/bin
+	cp -f ${PROGS} rootfs
+	${SUDO} chroot rootfs /bin/rvemu /test.elf
 
+
 rvemu: ${OBJ}
 	${CC} -o $@ ${OBJ} ${LDFLAGS}
 
+ecall.o: syscalls.h
+
+syscalls.h: syscalls.inc
+	sed 's/^\.set \(SYS_[a-z0-9_]*\), \([0-9]*\)$$/#define \1 \2/'	\
+		< syscalls.inc > syscalls.h
+
 .c.o: rvemu.h
 	${CC} -c -o $@ $< ${CFLAGS}
 
blob - be1763527ea5c72f4c66c475b65c59b496befb2e
blob + f12b40ff570310c03a64afafdf2dcb151c7f4878
--- cpu.c
+++ cpu.c
@@ -1,16 +1,15 @@
 #include "rvemu.h"
 
-static u32 regs[31];
-u32 pc;
+static u64 regs[31];
+u64 pc;
 
-
-void cpu_set (size_t reg, u32 val)
+void cpu_set (size_t reg, u64 val)
 {
 	if (reg > 0)
 		regs[reg - 1] = val;
 }
 
-u32 cpu_get (size_t reg)
+u64 cpu_get (size_t reg)
 {
 	return reg > 0 ? regs[reg - 1] : 0;
 }
@@ -23,6 +22,11 @@ u32 cpu_fetch (void)
 	return i;
 }
 
+static i64 extend (i32 x)
+{
+	return x;
+}
+
 void cpu_exec (u32 instr)
 {
 	const char *name;
@@ -31,19 +35,20 @@ void cpu_exec (u32 instr)
 	const u8 rs1 = (instr >> 15) & 0x1f;
 	const u8 rs2 = (instr >> 20) & 0x1f;
 	const u8 funct7 = instr >> 25;
-	const u32 imm_i = (i32)instr >> 20;
-	const u32 imm_s = ((i32)instr >> 25 << 5) | ((instr >> 7) & 0x1f);
-	const u32 imm_b = (instr >> 31 << 12)
+	const u64 imm_i = extend ((i32)instr >> 20);
+	const u64 imm_s = extend (((i32)instr >> 25 << 5) | ((instr >> 7) & 0x1f));
+	const u64 imm_b = extend (((i32)instr >> 31 << 12)
 		| (((instr >> 25) & 0x3f) << 5)
 		| (((instr >> 8) & 0xf) << 1)
-		| (((instr >> 7) & 1) << 11);
-	const u32 imm_u = instr & 0xfffff000;
-	const u32 imm_j = ((i32)instr >> 31 << 20)
+		| (((instr >> 7) & 1) << 11));
+	const u64 imm_u = extend (instr & 0xfffff000);
+	const u64 imm_j = extend (((i32)instr >> 31 << 20)
 		| (((instr >> 21) & 0x3ff) << 1)
 		| (((instr >> 20) & 1) << 11)
-		| (((instr >> 12) & 0xff) << 12);
+		| (((instr >> 12) & 0xff) << 12));
+	const u8 shamt = imm_i & 0x3f;
 
-	u32 a, b, c;
+	u64 a, b, c;
 	switch (instr & 0x7f) {
 	case 0b0110111: // lui rd, uimm
 		eprintf ("lui x%u, %u\n", (uint)rd, imm_u);
@@ -78,11 +83,11 @@ void cpu_exec (u32 instr)
 			c = a != b;
 		case 0b100:
 			name = "blt";
-			c = (i32)a < (i32)b;
+			c = (i64)a < (i64)b;
 			break;
 		case 0b101:
 			name = "bge";
-			c = (i32)a >= (i32)b;
+			c = (i64)a >= (i64)b;
 			break;
 		case 0b110:
 			name = "bltu";
@@ -104,16 +109,20 @@ void cpu_exec (u32 instr)
 		switch (funct3) {
 		case 0b000: // lb
 			name = "lb";
-			b = (i32)read_i8 (a);
+			b = (i64)read_i8 (a);
 			break;
 		case 0b001: // lh
 			name = "lh";
-			b = (i32)read_i16 (a);
+			b = (i64)read_i16 (a);
 			break;
 		case 0b010: // lw
 			name = "lw";
-			b = read_u32 (a);
+			b = (i64)read_i32 (a);
 			break;
+		case 0b011: // ld
+			name = "ld";
+			b = read_u64 (a);
+			break;
 		case 0b100: // lbu
 			name = "lbu";
 			b = read_u8 (a);
@@ -122,6 +131,10 @@ void cpu_exec (u32 instr)
 			name = "lhu";
 			b = read_u16 (a);
 			break;
+		case 0b110: // lwu
+			name = "lwu";
+			b = read_u32 (a);
+			break;
 		default:
 			goto ud;
 		}
@@ -144,6 +157,10 @@ void cpu_exec (u32 instr)
 			name = "sw";
 			write_u32 (b, a);
 			break;
+		case 0b011: // sd
+			 name = "sd";
+			 write_u64 (b, a);
+			 break;
 		default:
 			goto ud;
 		}
@@ -159,11 +176,11 @@ void cpu_exec (u32 instr)
 			break;
 		case 0b001: // slli
 			name = "slli";
-			c = a << (b & 0x1f);
+			c = a << shamt;
 			break;
 		case 0b010: // slti
 			name = "slti";
-			c = (i32)a < (i32)b;
+			c = (i64)a < (i64)b;
 			break;
 		case 0b011: // sltiu
 			name = "sltiu";
@@ -176,10 +193,10 @@ void cpu_exec (u32 instr)
 		case 0b101: // srli/srai
 			if ((instr >> 30) & 1) {
 				name = "srai";
-				c = (i32)a >> b;
+				c = (i64)a >> shamt;
 			} else {
 				name = "srli";
-				c = a >> b;
+				c = a >> shamt;
 			}
 			break;
 		case 0b110: // ori
@@ -193,7 +210,41 @@ void cpu_exec (u32 instr)
 		default:
 			goto ud;
 		}
-		eprintf ("%s x%u, x%u, %d\n", name, (uint)rd, (uint)rs1, (int)imm_i);
+		eprintf ("%s x%u, x%u, %lld\n", name, (uint)rd, (uint)rs1, (i64)imm_i);
+		cpu_set (rd, c);
+		break;
+	case 0b0011011: // aluiw rd, rs1, iimm
+		a = cpu_get (rs1);
+		b = imm_i;
+		c = (instr >> 30) & 1;
+		switch (funct3) {
+		case 0b000: // addiw
+			name = "addiw";
+			c = a + b;
+			break;
+		case 0b001: // slliw
+			if (shamt >> 5)
+				goto ud;
+			name = "slliw";
+			c = a << shamt;
+			break;
+		case 0b101: // srliw/sraiw
+			if (shamt >> 5)
+				goto ud;
+			if (c) {
+				name = "srai";
+				c = (i64)a >> shamt;
+			} else {
+				name = "srli";
+				c = a >> shamt;
+			}
+			break;
+		default:
+			goto ud;
+		}
+		c &= 0x00000000ffffffff;
+		c = extend (c);
+		eprintf ("%s x%u, x%u, %lld\n", name, (uint)rd, (uint)rs1, (i64)imm_i);
 		cpu_set (rd, c);
 		break;
 	case 0b0110011: // alu rd, rs1, rs2
@@ -216,7 +267,7 @@ void cpu_exec (u32 instr)
 			break;
 		case 0b010: // slt
 			name = "slt";
-			a = (i32)a < (i32)b;
+			a = (i64)a < (i64)b;
 			break;
 		case 0b011: // sltu
 			name = "sltu";
@@ -229,10 +280,10 @@ void cpu_exec (u32 instr)
 		case 0b101: // srl/sra
 			if (c) {
 				name = "sra";
-				a = (i32)a >> b;
+				a = (i64)a >> (b & 0x3f);
 			} else {
 				name = "srl";
-				a >>= b;
+				a >>= (b & 0x3f);
 			}
 			break;
 		case 0b110: // or
@@ -247,6 +298,39 @@ void cpu_exec (u32 instr)
 		eprintf ("%s x%u, x%u, x%u\n", name, (uint)rd, (uint)rs1, (uint)rs2);
 		cpu_set (rd, a);
 		break;
+	case 0b0111011: // aluw
+		a = cpu_get (rs1);
+		b = cpu_get (rs2);
+		c = (instr >> 30) & 1;
+		switch (funct3) {
+		case 0b000: // addw/subw
+			if (c) {
+				name = "subw";
+				c = a - b;
+			} else {
+				name = "addw";
+				c = a + b;
+			}
+			break;
+		case 0b001: // sllw
+			name = "sllw";
+			c = a << (b & 0x1f);
+			break;
+		case 0b101: // srlw/sraiw
+			if (c) {
+				name = "sraw";
+				c = (i64)a >> (b & 0x1f);
+			} else {
+				name = "srlw";
+				c = a >> (b & 0x1f);
+			}
+			break;
+		default:
+			goto ud;
+		}
+		eprintf ("%s x%u, x%u, x%u\n", name, (uint)rd, (uint)rs1, (uint)rs2);
+		cpu_set (rd, extend ((i32)a));
+		break;
 	case 0b0001111: // fence/fence.tso/pause
 		eprintf ("fence\n");
 		break;
@@ -265,7 +349,7 @@ void cpu_exec (u32 instr)
 		break;
 	default:
 	ud:
-		errx (1, "%08x: invalid instruction: %08x", pc - 4, instr);
+		errx (1, "%08llx: invalid instruction: %08x", pc - 4, instr);
 	}
 }
 
blob - 7f8efcda3a12cf5aff8ecfa2b29bb63f61b90cd3
blob + 66eb875ea57dc87a40bf8b6cb2d3386f35feeb06
--- exec.c
+++ exec.c
@@ -7,33 +7,19 @@
 #include "rvemu.h"
 
 
-int is_executable (const Elf32_Ehdr *ehdr)
+int is_executable (const Elf64_Ehdr *ehdr)
 {
 	return IS_ELF (*ehdr)
-		&& ehdr->e_ident[EI_CLASS] == ELFCLASS32
+		&& ehdr->e_ident[EI_CLASS] == ELFCLASS64
 		&& ehdr->e_ident[EI_DATA] == ELFDATA2LSB
 		&& ehdr->e_machine == EM_RISCV
 		;
 }
 
-static char **copyv (u32 v)
+int my_execve (const char *path, char **argv, char **envp)
 {
-	char **a;
-	int n;
 
-	for (n = 0; read_u32 (v + n * 4) != 0; ++n);
-
-	a = calloc (n + 1, sizeof (char *));
-	for (int i = 0; i < n; ++i)
-		a[i] = (char *)(size_t)read_u32 (v + i * 4);
-
-	return a;
-}
-
-int my_execve (const char *path, u32 argv, u32 envp)
-{
-
-	Elf32_Ehdr ehdr;
+	Elf64_Ehdr ehdr;
 	char buffer[256], *nl, *s, **args, **env;
 	int fd;
 
@@ -68,13 +54,10 @@ int my_execve (const char *path, u32 argv, u32 envp)
 	read (fd, &ehdr, sizeof (ehdr));
 	close (fd);
 
-	args = copyv (argv);
-	env = copyv (envp);
-
 	if (is_executable (&ehdr)) {
-		path = interpreter;
+		return execvpe ("rvemu", argv, envp);
 	}
 
-	return execve (path, args, env);
+	return execve (path, argv, envp);
 }
 
blob - /dev/null
blob + f2631d600322b6a3bc1d74865ef5cd3f54fe743a (mode 644)
--- /dev/null
+++ ecall.c
@@ -0,0 +1,964 @@
+#include <sys/resource.h>
+#include <sys/utsname.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/msg.h>
+#include <sys/sem.h>
+#include <signal.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sched.h>
+#include <errno.h>
+#include "syscalls.h"
+#include "rvemu.h"
+
+struct linux_stat64 {
+	u64 dev;
+	u64 ino;
+	u32 mode;
+	u32 nlink;
+	u32 uid;
+	u32 gid;
+	u64 rdev;
+	u64 __pad1;
+	u64 size;
+	u32 blksize;
+	u32 __pad2;
+	u64 blocks;
+	u32 atime;
+	u32 atime_ns;
+	u32 mtime;
+	u32 mtime_ns;
+	u32 ctime;
+	u32 ctime_ns;
+	u32 __unused4;
+	u32 __unused5;
+};
+
+struct linux_utsname {
+	char sysname[65];
+	char nodename[65];
+	char release[65];
+	char version[65];
+	char machine[65];
+};
+
+static int map_errno (int err)
+{
+	const int errnos[] = {
+		[EPERM]		= 1,
+		[ENOENT]	= 2,
+		[ESRCH]		= 3,
+		[EINTR]		= 4,
+		[EIO]		= 5,
+		[ENXIO]		= 6,
+		[E2BIG]		= 7,
+		[ENOEXEC]	= 8,
+		[EBADF]		= 9,
+		[ECHILD]	= 10,
+		[EAGAIN]	= 11,
+		[ENOMEM]	= 12,
+		[EACCES]	= 13,
+		[EFAULT]	= 14,
+		[ENOTBLK]	= 15,
+		[EBUSY]		= 16,
+		[EEXIST]	= 17,
+		[EXDEV]		= 18,
+		[ENODEV]	= 19,
+		[ENOTDIR]	= 20,
+		[EISDIR]	= 21,
+		[EINVAL]	= 22,
+		[ENFILE]	= 23,
+		[EMFILE]	= 24,
+		[ENOTTY]	= 25,
+		[ETXTBSY]	= 26,
+		[EFBIG]		= 27,
+		[ENOSPC]	= 28,
+		[ESPIPE]	= 29,
+		[EROFS]		= 30,
+		[EMLINK]	= 31,
+		[EPIPE]		= 32,
+		[EDOM]		= 33,
+		[ERANGE]	= 34,
+		[EDEADLK]	= 35,
+		[ENAMETOOLONG]	= 36,
+		[ENOLCK]	= 37,
+		[ENOSYS]	= 38,
+	};
+	return errnos[err];
+}
+
+static int map (int x) {
+	return x < 0 ? -map_errno (errno) : x;
+}
+
+
+static void stat_to_linux_stat (struct linux_stat64 *lst, const struct stat *st)
+{
+	memset (lst, 0, sizeof (*lst));
+	lst->dev	= st->st_dev;
+	lst->ino	= st->st_dev;
+	lst->mode	= st->st_dev;
+	lst->nlink	= st->st_dev;
+	lst->uid	= st->st_dev;
+	lst->gid	= st->st_dev;
+	lst->rdev	= st->st_dev;
+	lst->size	= st->st_dev;
+	lst->blksize	= st->st_dev;
+	lst->blocks	= st->st_dev;
+	lst->atime	= st->st_atim.tv_sec;
+	lst->atime_ns	= st->st_atim.tv_nsec;
+	lst->mtime	= st->st_mtim.tv_sec;
+	lst->mtime_ns	= st->st_mtim.tv_nsec;
+	lst->ctime	= st->st_ctim.tv_sec;
+	lst->ctime_ns	= st->st_ctim.tv_nsec;
+}
+
+static void utsname_to_linux_utsname (struct linux_utsname *lun, const struct utsname *un)
+{
+	memset (lun, 0, sizeof (*lun));
+	strlcpy (lun->sysname,	un->sysname, 65);
+	strlcpy (lun->nodename,	un->nodename, 65);
+	strlcpy (lun->release,	un->release, 65);
+	strlcpy (lun->version,	un->version, 65);
+	strlcpy (lun->machine,	un->machine, 65);
+}
+
+static int enosys (const char *sys)
+{
+	warnx ("unimplemented syscall: %s", sys);
+	return -map_errno (ENOSYS);
+}
+
+static u64 my_brk (u64 new)
+{
+	void *ptr;
+
+	if (new < brkval)
+		return brkval;
+	if (new >= 0x78000000) {
+		errno = ENOMEM;
+		return -1;
+	}
+
+	new = (new + 4095) & ~0x3ff;
+	ptr = mmap (
+		(void *)brkval,
+		new - brkval,
+		PROT_READ | PROT_WRITE,
+		MAP_PRIVATE | MAP_ANON,
+		-1,
+		0
+	);
+	if (ptr == NULL)
+		return -1;
+	brkval = new;
+	return brkval;
+}
+
+#define ptr(T, x) ((T *)(x))
+#define str(x) ptr (const char, x)
+void ecall (void)
+{
+	struct linux_stat64 lst;
+	struct linux_utsname lun;
+	struct stat st;
+	struct utsname un;
+	void *ptr;
+	const u64 a0 = cpu_get (10);
+	const u64 a1 = cpu_get (11);
+	const u64 a2 = cpu_get (12);
+	const u64 a3 = cpu_get (13);
+	const u64 a4 = cpu_get (14);
+	const u64 a5 = cpu_get (15);
+	const u64 a7 = cpu_get (17);
+	u64 ret;
+	switch (a7) {
+	case SYS_getcwd:
+		ret = enosys ("getcwd");
+		break;
+	case SYS_dup:
+		ret = map (dup ((int)a0));
+		break;
+	case SYS_dup3:
+		ret = map (dup3 ((int)a0, (int)a1, (int)a2));
+		break;
+	case SYS_fcntl:
+		ret = enosys ("fcntl");
+		break;
+	case SYS_ioctl:
+		ret = enosys ("ioctl");
+		break;
+	case SYS_flock:
+		ret = map (flock ((int)a0, (int)a1));
+		break;
+	case SYS_mknodat:
+		ret = map (mknodat ((int)a0, str (a1), (mode_t)a2, (dev_t)a3));
+
+	case SYS_mkdirat:
+		ret = map (mkdirat ((int)a0, str (a1), (mode_t)a2));
+		break;
+	case SYS_unlinkat:
+		ret = map (unlinkat ((int)a0, str (a1), (int)a2));
+		break;
+	case SYS_symlinkat:
+		ret = map (symlinkat (str (a0), (int)a1, str (a2)));
+		break;
+	case SYS_linkat:
+		ret = map (linkat ((int)a0, str (a1), (int)a2, str (a3), (int)a4));
+		break;
+	case SYS_renameat:
+		ret = map (renameat ((int)a0, str (a1), (int)a2, str (a3)));
+		break;
+	case SYS_umount:
+		ret = enosys ("umount");
+		break;
+	case SYS_mount:
+		ret = enosys ("mount");
+		break;
+	case SYS_pivot_root:
+		ret = enosys ("pivot_root");
+		break;
+	case SYS_nfsservctl:
+		ret = enosys ("nfsservctl");
+		break;
+	case SYS_statfs:
+		ret = enosys ("statfs");
+		break;
+	case SYS_fstatfs:
+		ret = enosys ("fstatfs");
+		break;
+	case SYS_truncate:
+		ret = map (truncate (str (a0), (off_t)a1));
+		break;
+		break;
+	case SYS_ftruncate:
+		ret = map (ftruncate ((int)a0, (off_t)a1));
+		break;
+	case SYS_fallocate:
+		ret = enosys ("fallocate");
+		break;
+	case SYS_faccessat:
+		ret = map (faccessat ((int)a0, str (a1), (int)a2, (int)a3));
+		break;
+	case SYS_chdir:
+		ret = map (chdir (str (a0)));
+		break;
+	case SYS_fchdir:
+		ret = map (fchdir ((int)a0));
+		break;
+	case SYS_chroot:
+		ret = map (chroot (str (a0)));
+		break;
+	case SYS_fchmod:
+		ret = map (fchmod ((int)a0, (mode_t)a1));
+		break;
+	case SYS_fchmodat:
+		ret = map (fchmodat ((int)a0, str (a1), (mode_t)a2, (int)a3));
+		break;
+	case SYS_fchownat:
+		ret = map (fchownat ((int)a0, str (a1), (uid_t)a2, (gid_t)a3, (int)a4));
+		break;
+	case SYS_fchown:
+		ret = map (fchown ((int)a0, (uid_t)a1, (gid_t)a2));
+		break;
+	case SYS_openat:
+		ret = map (openat ((int)a0, str (a1), (int)a2, (int)a3));
+		break;
+	case SYS_close:
+		ret = map (close ((int)a0));
+		break;
+	case SYS_vhangup:
+		ret = enosys ("vhangup");
+		break;
+	case SYS_pipe2:
+		ret = map (pipe2 (ptr (int, a0), (int)a1));
+		break;
+	case SYS_quotactl:
+		ret = enosys ("quotactl");
+		break;
+	case SYS_getdents64:
+		ret = enosys ("getdents64");
+		break;
+	case SYS_lseek:
+		ret = map (lseek ((int)a0, (off_t)a1, (int)a2));
+		break;
+	case SYS_read:
+		ret = map (read ((int)a0, ptr (void, a1), (size_t)a2));
+		break;
+	case SYS_write:
+		ret = map (write ((int)a0, ptr (const void, a1), (size_t)a2));
+		break;
+	case SYS_readv:
+		ret = enosys ("readv");
+		break;
+	case SYS_writev:
+		ret = enosys ("writev");
+		break;
+	case SYS_pread:
+		ret = map (pread ((int)a0, ptr (void, a1), (size_t)a2, (off_t)a3));
+		break;
+	case SYS_pwrite:
+		ret = map (pwrite ((int)a0, ptr (const void, a1), (size_t)a2, (off_t)a3));
+		break;
+	case SYS_preadv:
+		ret = enosys ("preadv");
+		break;
+	case SYS_pwritev:
+		ret = enosys ("pwritev");
+		break;
+	case SYS_sendfile:
+		ret = enosys ("sendfile");
+		break;
+	case SYS_pselect6:
+		ret = enosys ("pselect6");
+		break;
+	case SYS_ppoll:
+		ret = enosys ("ppoll");
+		break;
+	case SYS_signalfd4:
+		ret = enosys ("signalfd4");
+		break;
+	case SYS_vmsplice:
+		ret = enosys ("vmsplice");
+		break;
+	case SYS_splice:
+		ret = enosys ("splice");
+		break;
+	case SYS_tee:
+		ret = enosys ("tee");
+		break;
+	case SYS_readlinkat:
+		ret = map (readlinkat ((int)a0, str (a1), ptr (char, a2), (size_t)a3));
+		break;
+	case SYS_fstatat:
+		ret = map (fstatat ((int)a0, str (a1), &st, (int)a3));
+		stat_to_linux_stat (&lst, &st);
+		memcpy (ptr (void, a2), &lst, sizeof (lst));
+		break;
+	case SYS_fstat:
+		ret = map (fstat ((int)a0, &st));
+		stat_to_linux_stat (&lst, &st);
+		memcpy (ptr (void, a1), &lst, sizeof (lst));
+		break;
+	case SYS_sync:
+		sync ();
+		ret = 0;
+		break;
+	case SYS_fsync:
+		ret = map (fsync ((int)a0));
+		break;
+	case SYS_fdatasync:
+		ret = map (fdatasync ((int)a0));
+		break;
+	case SYS_sync_file_range:
+		ret = enosys ("sync_file_range");
+		break;
+	case SYS_timerfd_create:
+		ret = enosys ("timerfd_create");
+		break;
+	case SYS_timerfd_settime:
+		ret = enosys ("timerfd_settime");
+		break;
+	case SYS_timerfd_gettime:
+		ret = enosys ("timerfd_gettime");
+		break;
+	case SYS_utimensat:
+		ret = enosys ("utimensat");
+		break;
+	case SYS_acct:
+		ret = acct (str (a0));
+		break;
+	case SYS_capget:
+		ret = enosys ("capget");
+		break;
+	case SYS_capset:
+		ret = enosys ("capset");
+		break;
+	case SYS_personality:
+		ret = enosys ("personality");
+		break;
+	case SYS_exit:
+		exit (a0);
+		ret = -1;
+		break;
+	case SYS_exit_group:
+		ret = enosys ("exit_group");
+		break;
+	case SYS_waitid:
+		ret = enosys ("waitid");
+		break;
+	case SYS_set_tid_address:
+		ret = enosys ("set_tid_address");
+		break;
+	case SYS_unshare:
+		ret = enosys ("unshare");
+		break;
+	case SYS_futex:
+		ret = enosys ("futex");
+		break;
+	case SYS_set_robust_limit:
+		ret = enosys ("set_robust_limit");
+		break;
+	case SYS_get_robust_limit:
+		ret = enosys ("get_robust_limit");
+		break;
+	case SYS_nanosleep:
+		ret = enosys ("nanosleep");
+		break;
+	case SYS_gettimer:
+		ret = enosys ("gettimer");
+		break;
+	case SYS_settimer:
+		ret = enosys ("settimer");
+		break;
+	case SYS_kexec_load:
+		ret = enosys ("kexec_load");
+		break;
+	case SYS_kexec_init_module:
+		ret = enosys ("kexec_init_module");
+		break;
+	case SYS_kexec_delete_module:
+		ret = enosys ("kexec_delete_module");
+		break;
+	case SYS_timer_create:
+		ret = enosys ("timer_create");
+		break;
+	case SYS_timer_gettime:
+		ret = enosys ("timer_gettime");
+		break;
+	case SYS_timer_getoverrun:
+		ret = enosys ("timer_getoverrun");
+		break;
+	case SYS_timer_settime:
+		ret = enosys ("timer_settime");
+		break;
+	case SYS_timer_delete:
+		ret = enosys ("timer_delete");
+		break;
+	case SYS_clock_settime:
+		ret = enosys ("clock_settime");
+		break;
+	case SYS_clock_gettime:
+		ret = enosys ("clock_gettime");
+		break;
+	case SYS_clock_getres:
+		ret = enosys ("clock_getres");
+		break;
+	case SYS_clock_nanosleep:
+		ret = enosys ("clock_nanosleep");
+		break;
+	case SYS_syslog:
+		ret = enosys ("syslog");
+		break;
+	case SYS_ptrace:
+		ret = enosys ("ptrace");
+		break;
+	case SYS_sched_setparam:
+		ret = enosys ("sched_setparam");
+		break;
+	case SYS_sched_setscheduler:
+		ret = enosys ("sched_setscheduler");
+		break;
+	case SYS_sched_getscheduler:
+		ret = enosys ("sched_getscheduler");
+		break;
+	case SYS_sched_getparam:
+		ret = enosys ("sched_getparam");
+		break;
+	case SYS_sched_setaffinity:
+		ret = enosys ("sched_setaffinity");
+		break;
+	case SYS_sched_getaffinity:
+		ret = enosys ("sched_getaffinity");
+		break;
+	case SYS_sched_yield:
+		ret = map (sched_yield ());
+		break;
+	case SYS_sched_get_priority_max:
+		ret = map (sched_get_priority_max ((int)a0));
+		break;
+	case SYS_sched_get_priority_min:
+		ret = map (sched_get_priority_min ((int)a0));
+		break;
+	case SYS_sched_rr_get_interval:
+		ret = enosys ("sched_rr_get_interval");
+		break;
+	case SYS_restart_syscall:
+		ret = enosys ("restart_syscall");
+		break;
+	case SYS_kill:
+		ret = map (kill ((pid_t)a0, (int)a1));
+		break;
+	case SYS_tkill:
+		ret = enosys ("tkill");
+		break;
+	case SYS_tgkill:
+		ret = enosys ("tgkill");
+		break;
+	case SYS_signalstack:
+		ret = enosys ("signalstack");
+		break;
+	case SYS_sigsuspend:
+		ret = enosys ("sigsuspend");
+		break;
+	case SYS_sigaction:
+		ret = enosys ("sigaction");
+		break;
+	case SYS_rt_sigprocmask:
+		ret = enosys ("rt_sigprocmask");
+		break;
+	case SYS_sigpending:
+		ret = enosys ("sigpending");
+		break;
+	case SYS_sigtimedwait:
+		ret = enosys ("sigtimedwait");
+		break;
+	case SYS_sigqueueinfo:
+		ret = enosys ("sigqueueinfo");
+		break;
+	case SYS_sigreturn:
+		ret = enosys ("sigreturn");
+		break;
+	case SYS_setpriority:
+		ret = map (setpriority ((int)a0, (id_t)a1, (int)a2));
+		break;
+	case SYS_getpriority:
+		ret = map (getpriority ((int)a0, (id_t)a1));
+		break;
+	case SYS_reboot:
+		ret = enosys ("reboot");
+		break;
+	case SYS_setregid:
+		ret = map (setregid ((gid_t)a0, (gid_t)a1));
+		break;
+	case SYS_setgid:
+		ret = map (setgid ((gid_t)a0));
+		break;
+	case SYS_setreuid:
+		ret = map (setreuid ((uid_t)a0, (uid_t)a1));
+		break;
+	case SYS_setuid:
+		ret = map (setuid ((uid_t)a0));
+		break;
+	case SYS_setresuid:
+		ret = map (setresuid ((uid_t)a0, (uid_t)a1, (uid_t)a2));
+		break;
+	case SYS_getresuid:
+		ret = map (getresuid (ptr (uid_t, a0), ptr (uid_t, a1), ptr (uid_t, a2)));
+		break;
+	case SYS_setresgid:
+		ret = map (setresgid ((gid_t)a0, (gid_t)a1, (gid_t)a2));
+		break;
+	case SYS_getresgid:
+		ret = map (getresgid (ptr (gid_t, a0), ptr (gid_t, a1), ptr (gid_t, a2)));
+		break;
+	case SYS_setfsuid:
+		ret = enosys ("setfsuid");
+		break;
+	case SYS_setfsgid:
+		ret = enosys ("setfsgid");
+		break;
+	case SYS_times:
+		ret = enosys ("times");
+		break;
+	case SYS_setpgid:
+		ret = map (setpgid ((pid_t)a0, (pid_t)a1));
+		break;
+	case SYS_getpgid:
+		ret = map (getpgid ((pid_t)a0));
+		break;
+	case SYS_getsid:
+		ret = map (getsid ((pid_t)a0));
+		break;
+	case SYS_setsid:
+		ret = map (setsid ());
+		break;
+	case SYS_setgroups:
+		ret = enosys ("setgroups");
+		break;
+	case SYS_uname:
+		ret = map (uname (&un));
+		utsname_to_linux_utsname (&lun, &un);
+		memcpy (ptr (void, a0), &lun, sizeof (lun));
+		break;
+	case SYS_sethostname:
+		ret = enosys ("sethostname");
+		break;
+	case SYS_setdomainname:
+		ret = enosys ("setdomainname");
+		break;
+	case SYS_getrlimit:
+		ret = enosys ("getrlimit");
+		break;
+	case SYS_setrlimit:
+		ret = enosys ("setrlimit");
+		break;
+	case SYS_getrusage:
+		ret = enosys ("getrusage");
+		break;
+	case SYS_umask:
+		ret = map (umask ((mode_t)a0));
+		break;
+	case SYS_prctl:
+		ret = enosys ("prctl");
+		break;
+	case SYS_getcpu:
+		ret = enosys ("getcpu");
+		break;
+	case SYS_gettimeofday:
+		ret = enosys ("gettimeofday");
+		break;
+	case SYS_settimeofday:
+		ret = enosys ("settimeofday");
+		break;
+	case SYS_adjtimex:
+		ret = enosys ("adjtimex");
+		break;
+	case SYS_getpid:
+		ret = map (getpid ());
+		break;
+	case SYS_getuid:
+		ret = map (getuid ());
+		break;
+	case SYS_geteuid:
+		ret = map (geteuid ());
+		break;
+	case SYS_getgid:
+		ret = map (getgid ());
+		break;
+	case SYS_getegid:
+		ret = map (getegid ());
+		break;
+	case SYS_gettid:
+		ret = enosys ("gettid");
+		break;
+	case SYS_sysinfo:
+		ret = enosys ("sysinfo");
+		break;
+	case 180:
+	case 181:
+	case 182:
+	case 183:
+	case 184:
+	case 185:
+		ret = enosys ("mq_*");
+		break;
+	case SYS_msgget:
+		ret = map(msgget ((key_t)a0, (int)a1));
+		break;
+	case SYS_msgctl:
+		ret = enosys ("msgctl");
+		break;
+	case SYS_msgrcv:
+		ret = map (msgrcv ((int)a0, ptr (void, a1), (size_t)a2, (long)a3, (int)a4));
+		break;
+	case SYS_msgsnd:
+		ret = map (msgsnd ((int)a0, ptr (const void, a1), (size_t)a2, (int)a3));
+		break;
+	case SYS_semget:
+		ret = map (semget ((key_t)a0, (int)a1, (int)a2));
+		break;
+	case SYS_semctl:
+		ret = enosys ("semctl");
+		break;
+	case SYS_semtimedop:
+		ret = enosys ("semtimedop");
+		break;
+	case SYS_semop:
+		ret = enosys ("semop");
+		break;
+	case 194:
+	case 195:
+	case 196:
+	case 197:
+		ret = enosys ("shm*");
+		break;
+	case 198:
+	case 199:
+	case 200:
+	case 201:
+	case 202:
+	case 203:
+	case 204:
+	case 205:
+	case 206:
+	case 207:
+	case 208:
+	case 209:
+	case 210:
+	case 211:
+	case 212:
+		ret = enosys ("socket api");
+		break;
+	case SYS_readahead:
+		ret = enosys ("readahead");
+		break;
+	case SYS_brk:
+		ret = map (my_brk (a0));
+		break;
+	case SYS_munmap:
+		ret = map (munmap (ptr (void, a0), (size_t)a1));
+		break;
+	case SYS_mremap:
+		ret = enosys ("mremap");
+		break;
+	case SYS_add_key:
+		ret = enosys ("add_key");
+		break;
+	case SYS_request_key:
+		ret = enosys ("request_key");
+		break;
+	case SYS_keyctl:
+		ret = enosys ("keyctl");
+		break;
+	case SYS_clone:
+		if (a0 == 17 && a1 == 0) {
+			// fork
+			ret = map (fork ());
+		} else {
+			ret = enosys ("clone");
+		}
+		break;
+	case SYS_execve:
+		ret = map (my_execve (str (a0), ptr (char *, a1), ptr (char *, a2)));
+		break;
+	case SYS_mmap:
+		ptr = mmap (ptr (void, a0), (size_t)a1, (int)a2, (int)a3, (int)a4, (off_t)a5);
+		if (ptr == NULL) {
+			ret = -map_errno (errno);
+		} else {
+			ret = (u64)ptr;
+		}
+		break;
+	case SYS_fadvise64:
+		ret = enosys ("fadvise64");
+		break;
+	case SYS_swapon:
+		ret = enosys ("swapon");
+		break;
+	case SYS_swapoff:
+		ret = enosys ("swapoff");
+		break;
+	case SYS_mprotect:
+		ret = map (mprotect (ptr (void, a0), (size_t)a1, (int)a2));
+		break;
+	case SYS_msync:
+		ret = map (msync (ptr (void, a0), (size_t)a1, (int)a2));
+		break;
+	case SYS_mlock:
+		ret = map (mlock (ptr (void, a0), (size_t)a1));
+		break;
+	case SYS_munlock:
+		ret = map (munlock (ptr (void, a0), (size_t)a1));
+		break;
+	case SYS_mlockall:
+		ret = map (mlockall ((int)a0));
+		break;
+	case SYS_munlockall:
+		ret = map (munlockall ());
+		break;
+	case SYS_mincore:
+		ret = enosys ("mincore");
+		break;
+	case SYS_madvise:
+		ret = map (madvise (ptr (void, a0), (size_t)a1, (int)a2));
+		break;
+	case SYS_remap_file_pages:
+		ret = enosys ("remap_file_pages");
+		break;
+	case SYS_mbind:
+		ret = enosys ("mbind");
+		break;
+	case SYS_get_mempolicy:
+		ret = enosys ("get_mempolicy");
+		break;
+	case SYS_set_mempolicy:
+		ret = enosys ("set_mempolicy");
+		break;
+	case SYS_migrate_pages:
+		ret = enosys ("migrate_pages");
+		break;
+	case SYS_move_pages:
+		ret = enosys ("move_pages");
+		break;
+	case SYS_rt_tgsigqueueinfo:
+		ret = enosys ("rt_tgsigqueueinfo");
+		break;
+	case SYS_perf_event_open:
+		ret = enosys ("perf_event_open");
+		break;
+	case SYS_accept4:
+		ret = enosys ("accept4");
+		break;
+	case SYS_recvmsg:
+		ret = enosys ("recvmsg");
+		break;
+	case 244:
+	case 245:
+	case 246:
+	case 247:
+	case 248:
+	case 249:
+	case 250:
+	case 251:
+	case 252:
+	case 253:
+	case 254:
+	case 255:
+	case 256:
+	case 257:
+	case 258:
+	case 259:
+		ret = enosys ("arch-specific");
+		break;
+	case 260:
+		ret = enosys ("wait4");
+		break;
+	case SYS_prlimit64:
+		ret = enosys ("prlimit64");
+		break;
+	case SYS_fanotify_init:
+		ret = enosys ("fanotify_init");
+		break;
+	case SYS_fanotify_mark:
+		ret = enosys ("fanotify_mark");
+		break;
+	case SYS_name_to_handle_at:
+		ret = enosys ("name_to_handle_at");
+		break;
+	case SYS_open_by_handle_at:
+		ret = enosys ("open_by_handle_at");
+		break;
+	case SYS_clock_adjtime:
+		ret = enosys ("clock_adjtime");
+		break;
+	case SYS_syncfs:
+		ret = enosys ("syncfs");
+		break;
+	case SYS_setns:
+		ret = enosys ("setns");
+		break;
+	case SYS_sendmsg:
+		ret = enosys ("sendmsg");
+		break;
+	case SYS_process_vm_readv:
+		ret = enosys ("process_vm_readv");
+		break;
+	case SYS_process_vm_writev:
+		ret = enosys ("process_vm_writev");
+		break;
+	case SYS_kcmp:
+		ret = enosys ("kcmp");
+		break;
+	case SYS_finit_module:
+		ret = enosys ("finit_module");
+		break;
+	case SYS_sched_setattr:
+		ret = enosys ("sched_setattr");
+		break;
+	case SYS_sched_getattr:
+		ret = enosys ("sched_getattr");
+		break;
+	case SYS_renameat2:
+		ret = enosys ("renameat2");
+		break;
+	case SYS_seccomp:
+		ret = enosys ("seccomp");
+		break;
+	case SYS_getrandom:
+		ret = enosys ("getrandom");
+		break;
+	case SYS_memfd_create:
+		ret = enosys ("seccomp");
+		break;
+	case SYS_bpf:
+		ret = enosys ("bpf");
+		break;
+	case SYS_execveat:
+		ret = enosys ("execveat");
+		break;
+	case SYS_userfaultfd:
+		ret = enosys ("usefaultfd");
+		break;
+	case SYS_membarrier:
+		ret = enosys ("membarrier");
+		break;
+	case SYS_mlock2:
+		ret = enosys ("mlock2");
+		break;
+	case SYS_copy_file_range:
+		ret = enosys ("copy_file_range");
+		break;
+	case SYS_preadv2:
+		ret = enosys ("preadv2");
+		break;
+	case SYS_pwritev2:
+		ret = enosys ("pwritev2");
+		break;
+	case SYS_pkey_mprotect:
+		ret = enosys ("pkey_mprotect");
+		break;
+	case SYS_pkey_alloc:
+		ret = enosys ("pkey_alloc");
+		break;
+	case SYS_pkey_free:
+		ret = enosys ("pkey_free");
+		break;
+	case SYS_statx:
+		ret = enosys ("statx");
+		break;
+	case SYS_io_pgetevents:
+		ret = enosys ("io_pgetevents");
+		break;
+	case SYS_rseq:
+		ret = enosys ("rseq");
+		break;
+	case SYS_kexec_file_load:
+		ret = enosys ("kexec_file_load");
+		break;
+	case SYS_open:
+		ret = map (open ((const char *)(size_t)a0, (int)a1, (int)a2));
+		break;
+	case SYS_link:
+		ret = map (link (str (a0), str (a1)));
+		break;
+	case SYS_unlink:
+		ret = map (unlink (str (a0)));
+		break;
+	case SYS_mkdir:
+		ret = map (mkdir (str (a0), (mode_t)a1));
+		break;
+	case SYS_access:
+		ret = map (access (str (a0), (int)a1));
+		break;
+	case SYS_stat:
+		ret = map (stat (str (a0), &st));
+		stat_to_linux_stat (&lst, &st);
+		memcpy (ptr (void, a1), &lst, sizeof (lst));
+		break;
+	case SYS_lstat:
+		ret = map (lstat (str (a0), &st));
+		stat_to_linux_stat (&lst, &st);
+		memcpy (ptr (void, a1), &lst, sizeof (lst));
+		break;
+	case SYS_time:
+		ret = enosys ("time");
+		break;
+	case SYS_getmainvars:
+		ret = enosys ("getmainvars");
+		break;
+	case SYS_debug:
+		fprintf (stderr, "DEBUG: %llu\n", a0);
+		ret = 0;
+		break;
+	default:
+		warnx ("%08llx: unimplemented syscall %llu", pc - 4, a7);
+		ret = -map_errno (ENOSYS);
+		break;
+	}
+	cpu_set (REG_a0, ret);
+}
+
blob - 10f6646bd6ae37bf7de1a9d35d7eccec7fbf3f7d
blob + f5eebd803603f22e5415e2c2dbd56c756d929182
--- rvemu.c
+++ rvemu.c
@@ -9,12 +9,11 @@
 #include <errno.h>
 #include "rvemu.h"
 
-const char *interpreter = "./rvemu";
-u32 brkval;
+u64 brkval;
 
 static void load_image (const char *filename)
 {
-	Elf32_Ehdr ehdr;
+	Elf64_Ehdr ehdr;
 	int fd;
 
 	fd = open (filename, O_RDONLY);
@@ -30,7 +29,7 @@ static void load_image (const char *filename)
 	pc = ehdr.e_entry;
 
 	for (unsigned i = 0; i < ehdr.e_phnum; ++i) {
-		Elf32_Phdr phdr;
+		Elf64_Phdr phdr;
 		u32 flags = 0, end;
 		void *ptr;
 
@@ -49,11 +48,11 @@ static void load_image (const char *filename)
 		case PT_NULL:
 			break;
 		case PT_LOAD:
-			eprintf ("loading %08x into %08x flags %x memsz %u\n",
+			eprintf ("loading %016llx into %016llx flags %x memsz %u\n",
 				phdr.p_offset, phdr.p_vaddr, phdr.p_flags, phdr.p_memsz);
 			if (phdr.p_filesz == phdr.p_memsz) {
 				ptr = mmap (
-					(void *)(size_t)phdr.p_vaddr,
+					(void *)phdr.p_vaddr,
 					phdr.p_memsz,
 					flags,
 					MAP_PRIVATE | MAP_COPY,
@@ -62,7 +61,7 @@ static void load_image (const char *filename)
 				);
 			} else if (phdr.p_filesz == 0) {
 				ptr = mmap (
-					(void *)(size_t)phdr.p_vaddr,
+					(void *)phdr.p_vaddr,
 					phdr.p_memsz,
 					flags,
 					MAP_ANON | MAP_PRIVATE,
@@ -70,14 +69,14 @@ static void load_image (const char *filename)
 					0
 				);
 			} else {
-				errx (1, "%u: p_filesz: %u, p_memsz: %u",
+				errx (1, "%u: p_filesz: %llu, p_memsz: %llu",
 					i, phdr.p_filesz, phdr.p_memsz);
 			}
 
-			if ((size_t)ptr != (size_t)phdr.p_vaddr)
+			if ((u64)ptr != phdr.p_vaddr)
 				err (1, "%u: failed to map program header", i);
 
-			end = (((u32)(size_t)ptr + phdr.p_memsz) + 4095) & ~0x3ff;
+			end = (((u64)ptr + phdr.p_memsz) + 4095) & ~0x3ff;
 			if (end > brkval)
 				brkval = end;
 			break;
@@ -93,26 +92,14 @@ static void load_image (const char *filename)
 	close (fd);
 }
 
-static void cpu_push (u32 val)
+static void cpu_push (u64 val)
 {
-	cpu_set (2, cpu_get (2) - 4);
-	write_u32 (cpu_get (2), val);
+	cpu_set (REG_sp, cpu_get (REG_sp) - 8);
+	write_u64 (cpu_get (REG_sp), val);
 }
 
-static void cpu_push_str (const char *ptr)
-{
-	if ((size_t)ptr > 0x80000000) {
-		const size_t len = strlen (ptr);
-		char *nptr = sbrk (len + 1);
-		memcpy (nptr, ptr, len + 1);
-		assert ((size_t)nptr < 0x80000000);
-		ptr = nptr;
-	}
-	cpu_push ((u32)(size_t)ptr);
-}
-
 static void setup_stack (
-	u32 stack_size,
+	u64 stack_size,
 	int argc,
 	char **argv,
 	int envc,
@@ -122,9 +109,9 @@ static void setup_stack (
 	void *stack_bottom;
 
 	// set stack pointer
-	cpu_set (2, 0x80000000);
+	cpu_set (REG_sp, 0x80000000);
 
-	stack_bottom = (void *)(size_t)(0x80000000 - stack_size);
+	stack_bottom = (void *)(u64)(0x80000000 - stack_size);
 	ptr = mmap (
 		stack_bottom,
 		stack_size,
@@ -139,10 +126,10 @@ static void setup_stack (
 
 	cpu_push (0);
 	for (int i = envc - 1; i >= 0; --i)
-		cpu_push_str (envp[i]);
+		cpu_push ((u64)envp[i]);
 	cpu_push (0);
 	for (int i = argc; i >= 0; --i)
-		cpu_push_str (argv[i]);
+		cpu_push ((u64)argv[i]);
 	cpu_push (argc);
 }
 
@@ -155,6 +142,8 @@ int main (int argc, char *argv[], char *envp[])
 	char *base;
 	void *ptr;
 
+	eprintf ("&main = %p\n", &main);
+
 	base = basename (argv[0]);
 
 	if (strcmp (base, "rvemu") == 0) {
blob - 982df935a81ad7877a60e5f5f7198413aa9a8819
blob + f1fa870f78600a53528abcc226d280124e392286
--- rvemu.h
+++ rvemu.h
@@ -12,6 +12,41 @@
 # define eprintf(...)
 #endif
 
+enum {
+	REG_zero,
+	REG_ra,
+	REG_sp,
+	REG_gp,
+	REG_tp,
+	REG_t0,
+	REG_t1,
+	REG_t2,
+	REG_s0,
+	REG_s1,
+	REG_a0,
+	REG_a1,
+	REG_a2,
+	REG_a3,
+	REG_a4,
+	REG_a5,
+	REG_a6,
+	REG_a7,
+	REG_s2,
+	REG_s3,
+	REG_s4,
+	REG_s5,
+	REG_s6,
+	REG_s7,
+	REG_s8,
+	REG_s9,
+	REG_s10,
+	REG_s11,
+	REG_t3,
+	REG_t4,
+	REG_t5,
+	REG_t6,
+};
+
 typedef uint8_t  u8;
 typedef uint16_t u16;
 typedef uint32_t u32;
@@ -24,17 +59,17 @@ typedef int64_t  i64;
 
 typedef unsigned int uint;
 
-extern u32 pc;
-extern u32 brkval;
+extern u64 pc;
+extern u64 brkval;
 extern const char *interpreter;
 
 u32 cpu_fetch (void);
-u32 cpu_get (size_t reg);
-void cpu_set (size_t reg, u32 val);
+u64 cpu_get (size_t reg);
+void cpu_set (size_t reg, u64 val);
 void cpu_exec (u32 instr);
 void ecall (void);
-int my_execve (const char *path, u32 argv, u32 envp);
-int is_executable (const Elf32_Ehdr *);
+int my_execve (const char *path, char **argv, char **envp);
+int is_executable (const Elf64_Ehdr *);
 
 #define read_u8(ptr)		(*(const u8 *)(size_t)(ptr))
 #define read_u16(ptr)		(*(const u16 *)(size_t)(ptr))
blob - 687d4a84e1e49fbedc28cb07e931e816c372b093 (mode 644)
blob + /dev/null
--- syscall.c
+++ /dev/null
@@ -1,965 +0,0 @@
-#include <sys/resource.h>
-#include <sys/utsname.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <sys/msg.h>
-#include <sys/sem.h>
-#include <signal.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <sched.h>
-#include <errno.h>
-#include "rvemu.h"
-
-struct linux_stat64 {
-	u64 dev;
-	u64 ino;
-	u32 mode;
-	u32 nlink;
-	u32 uid;
-	u32 gid;
-	u64 rdev;
-	u64 __pad1;
-	u64 size;
-	u32 blksize;
-	u32 __pad2;
-	u64 blocks;
-	u32 atime;
-	u32 atime_ns;
-	u32 mtime;
-	u32 mtime_ns;
-	u32 ctime;
-	u32 ctime_ns;
-	u32 __unused4;
-	u32 __unused5;
-};
-
-struct linux_utsname {
-	char sysname[65];
-	char nodename[65];
-	char release[65];
-	char version[65];
-	char machine[65];
-};
-
-static int map_errno (int err)
-{
-	const int errnos[] = {
-		[EPERM]		= 1,
-		[ENOENT]	= 2,
-		[ESRCH]		= 3,
-		[EINTR]		= 4,
-		[EIO]		= 5,
-		[ENXIO]		= 6,
-		[E2BIG]		= 7,
-		[ENOEXEC]	= 8,
-		[EBADF]		= 9,
-		[ECHILD]	= 10,
-		[EAGAIN]	= 11,
-		[ENOMEM]	= 12,
-		[EACCES]	= 13,
-		[EFAULT]	= 14,
-		[ENOTBLK]	= 15,
-		[EBUSY]		= 16,
-		[EEXIST]	= 17,
-		[EXDEV]		= 18,
-		[ENODEV]	= 19,
-		[ENOTDIR]	= 20,
-		[EISDIR]	= 21,
-		[EINVAL]	= 22,
-		[ENFILE]	= 23,
-		[EMFILE]	= 24,
-		[ENOTTY]	= 25,
-		[ETXTBSY]	= 26,
-		[EFBIG]		= 27,
-		[ENOSPC]	= 28,
-		[ESPIPE]	= 29,
-		[EROFS]		= 30,
-		[EMLINK]	= 31,
-		[EPIPE]		= 32,
-		[EDOM]		= 33,
-		[ERANGE]	= 34,
-		[EDEADLK]	= 35,
-		[ENAMETOOLONG]	= 36,
-		[ENOLCK]	= 37,
-		[ENOSYS]	= 38,
-	};
-	return errnos[err];
-}
-
-static int map (int x) {
-	return x < 0 ? -map_errno (errno) : x;
-}
-
-
-static void stat_to_linux_stat (struct linux_stat64 *lst, const struct stat *st)
-{
-	memset (lst, 0, sizeof (*lst));
-	lst->dev	= st->st_dev;
-	lst->ino	= st->st_dev;
-	lst->mode	= st->st_dev;
-	lst->nlink	= st->st_dev;
-	lst->uid	= st->st_dev;
-	lst->gid	= st->st_dev;
-	lst->rdev	= st->st_dev;
-	lst->size	= st->st_dev;
-	lst->blksize	= st->st_dev;
-	lst->blocks	= st->st_dev;
-	lst->atime	= st->st_atim.tv_sec;
-	lst->atime_ns	= st->st_atim.tv_nsec;
-	lst->mtime	= st->st_mtim.tv_sec;
-	lst->mtime_ns	= st->st_mtim.tv_nsec;
-	lst->ctime	= st->st_ctim.tv_sec;
-	lst->ctime_ns	= st->st_ctim.tv_nsec;
-}
-
-static void utsname_to_linux_utsname (struct linux_utsname *lun, const struct utsname *un)
-{
-	memset (lun, 0, sizeof (*lun));
-	strlcpy (lun->sysname,	un->sysname, 65);
-	strlcpy (lun->nodename,	un->nodename, 65);
-	strlcpy (lun->release,	un->release, 65);
-	strlcpy (lun->version,	un->version, 65);
-	strlcpy (lun->machine,	un->machine, 65);
-}
-
-static int enosys (const char *sys)
-{
-	warnx ("unimplemented syscall: %s", sys);
-	return -map_errno (ENOSYS);
-}
-
-static u32 my_brk (u32 new)
-{
-	void *ptr;
-
-	if (new < brkval)
-		return brkval;
-	if (new >= 0x78000000) {
-		errno = ENOMEM;
-		return -1;
-	}
-
-	new = (new + 4095) & ~0x3ff;
-	ptr = mmap (
-		(void *)(size_t)brkval,
-		new - brkval,
-		PROT_READ | PROT_WRITE,
-		MAP_PRIVATE | MAP_ANON,
-		-1,
-		0
-	);
-	if (ptr == NULL)
-		return -1;
-	brkval = new;
-	return brkval;
-}
-
-#define ptr(T, x) ((T *)(size_t)(x))
-#define str(x) ptr (const char, x)
-void ecall (void)
-{
-	struct linux_stat64 lst;
-	struct linux_utsname lun;
-	struct stat st;
-	struct utsname un;
-	void *ptr;
-	const u32 a0 = cpu_get (10);
-	const u32 a1 = cpu_get (11);
-	const u32 a2 = cpu_get (12);
-	const u32 a3 = cpu_get (13);
-	const u32 a4 = cpu_get (14);
-	const u32 a5 = cpu_get (15);
-	const u32 a7 = cpu_get (17);
-	u32 ret;
-	switch (a7) {
-	case 17: // getcwd
-		ret = enosys ("getcwd");
-		break;
-	case 23: // dup
-		ret = map (dup ((int)a0));
-		break;
-	case 24: // dup3
-		ret = map (dup3 ((int)a0, (int)a1, (int)a2));
-		break;
-	case 25: // fcntl
-		ret = enosys ("fcntl");
-		break;
-	case 29: // ioctl
-		ret = enosys ("ioctl");
-		break;
-	case 32: // flock
-		ret = map (flock ((int)a0, (int)a1));
-		break;
-	case 33: // mknodat
-		ret = map (mknodat ((int)a0, str (a1), (mode_t)a2, (dev_t)a3));
-
-	case 34: // mkdirat
-		ret = map (mkdirat ((int)a0, str (a1), (mode_t)a2));
-		break;
-	case 35: // unlinkat
-		ret = map (unlinkat ((int)a0, str (a1), (int)a2));
-		break;
-	case 36: // symlinkat
-		ret = map (symlinkat (str (a0), (int)a1, str (a2)));
-		break;
-	case 37: // linkat
-		ret = map (linkat ((int)a0, str (a1), (int)a2, str (a3), (int)a4));
-		break;
-	case 38: // renameat
-		ret = map (renameat ((int)a0, str (a1), (int)a2, str (a3)));
-		break;
-	case 39: // umount
-		ret = enosys ("umount");
-		break;
-	case 40: // mount
-		ret = enosys ("mount");
-		break;
-	case 41: // pivot_root
-		ret = enosys ("pivot_root");
-		break;
-	case 42: // nfsservctl
-		ret = enosys ("nfsservctl");
-		break;
-	case 43: // statfs
-		ret = enosys ("statfs");
-		break;
-	case 44: // fstatfs
-		ret = enosys ("fstatfs");
-		break;
-	case 45: // truncate
-		ret = map (truncate (str (a0), (off_t)a1));
-		break;
-		break;
-	case 46: // ftruncate
-		ret = map (ftruncate ((int)a0, (off_t)a1));
-		break;
-	case 47: // fallocate
-		ret = enosys ("fallocate");
-		break;
-	case 48: // faccessat
-		ret = map (faccessat ((int)a0, str (a1), (int)a2, (int)a3));
-		break;
-	case 49: // chdir
-		ret = map (chdir (str (a0)));
-		break;
-	case 50: // fchdir
-		ret = map (fchdir ((int)a0));
-		break;
-	case 51: // chroot
-		ret = map (chroot (str (a0)));
-		break;
-	case 52: // fchmod
-		ret = map (fchmod ((int)a0, (mode_t)a1));
-		break;
-	case 53: // fchmodat
-		ret = map (fchmodat ((int)a0, str (a1), (mode_t)a2, (int)a3));
-		break;
-	case 54: // fchownat
-		ret = map (fchownat ((int)a0, str (a1), (uid_t)a2, (gid_t)a3, (int)a4));
-		break;
-	case 55: // fchown
-		ret = map (fchown ((int)a0, (uid_t)a1, (gid_t)a2));
-		break;
-	case 56: // openat
-		ret = map (openat ((int)a0, str (a1), (int)a2, (int)a3));
-		break;
-	case 57: // close
-		ret = map (close ((int)a0));
-		break;
-	case 58: // vhangup
-		ret = enosys ("vhangup");
-		break;
-	case 59: // pipe2
-		ret = map (pipe2 (ptr (int, a0), (int)a1));
-		break;
-	case 60: // quotactl
-		ret = enosys ("quotactl");
-		break;
-	case 61: // getdents64
-		ret = enosys ("getdents64");
-		break;
-	case 62: // lseek
-		ret = map (lseek ((int)a0, (off_t)a1, (int)a2));
-		break;
-	case 63: // read
-		ret = map (read ((int)a0, ptr (void, a1), (size_t)a2));
-		break;
-	case 64: // write
-		ret = map (write ((int)a0, ptr (const void, a1), (size_t)a2));
-		break;
-	case 65: // readv
-		ret = enosys ("readv");
-		break;
-	case 66: // writev
-		ret = enosys ("writev");
-		break;
-	case 67: // pread
-		ret = map (pread ((int)a0, ptr (void, a1), (size_t)a2, (off_t)a3));
-		break;
-	case 68: // pwrite
-		ret = map (pwrite ((int)a0, ptr (const void, a1), (size_t)a2, (off_t)a3));
-		break;
-	case 69: // preadv
-		ret = enosys ("preadv");
-		break;
-	case 70: // pwritev
-		ret = enosys ("pwritev");
-		break;
-	case 71: // pwritev
-		ret = enosys ("sendfile");
-		break;
-	case 72: // pselect6
-		ret = enosys ("pselect6");
-		break;
-	case 73: // ppoll
-		ret = enosys ("ppoll");
-		break;
-	case 74: // signalfd4
-		ret = enosys ("signalfd4");
-		break;
-	case 75: // vmsplice
-		ret = enosys ("vmsplice");
-		break;
-	case 76: // splice
-		ret = enosys ("splice");
-		break;
-	case 77: // tee
-		ret = enosys ("tee");
-		break;
-	case 78: // readlinkat
-		ret = map (readlinkat ((int)a0, str (a1), ptr (char, a2), (size_t)a3));
-		break;
-	case 79: // fstatat
-		ret = map (fstatat ((int)a0, str (a1), &st, (int)a3));
-		stat_to_linux_stat (&lst, &st);
-		memcpy (ptr (void, a2), &lst, sizeof (lst));
-		break;
-	case 80: // fstat
-		ret = map (fstat ((int)a0, &st));
-		stat_to_linux_stat (&lst, &st);
-		memcpy (ptr (void, a1), &lst, sizeof (lst));
-		break;
-	case 81: // sync
-		sync ();
-		ret = 0;
-		break;
-	case 82: // fsync
-		ret = map (fsync ((int)a0));
-		break;
-	case 83: // fdatasync
-		ret = map (fdatasync ((int)a0));
-		break;
-	case 84: // sync_file_range
-		ret = enosys ("sync_file_range");
-		break;
-	case 85: // timerfd_create
-		ret = enosys ("timerfd_create");
-		break;
-	case 86: // timerfd_settime
-		ret = enosys ("timerfd_settime");
-		break;
-	case 87: // timerfd_gettime
-		ret = enosys ("timerfd_gettime");
-		break;
-	case 88: // utimensat
-		ret = enosys ("utimensat");
-		break;
-	case 89: // acct
-		ret = acct (str (a0));
-		break;
-	case 90: // capget
-		ret = enosys ("capget");
-		break;
-	case 91: // capset
-		ret = enosys ("capset");
-		break;
-	case 92: // personality
-		ret = enosys ("personality");
-		break;
-	case 93: // exit
-		exit (a0);
-		ret = -1;
-		break;
-	case 94: // exit_group
-		ret = enosys ("exit_group");
-		break;
-	case 95: // waitid
-		ret = enosys ("waitid");
-		break;
-	case 96: // set_tid_address
-		ret = enosys ("set_tid_address");
-		break;
-	case 97: // unshare
-		ret = enosys ("unshare");
-		break;
-	case 98: // futex
-		ret = enosys ("futex");
-		break;
-	case 99: // set_robust_limit
-		ret = enosys ("set_robust_limit");
-		break;
-	case 100: // get_robust_limit
-		ret = enosys ("get_robust_limit");
-		break;
-	case 101: // nanosleep
-		ret = enosys ("nanosleep");
-		break;
-	case 102: // gettimer
-		ret = enosys ("gettimer");
-		break;
-	case 103: // settimer
-		ret = enosys ("settimer");
-		break;
-	case 104: // kexec_load
-		ret = enosys ("kexec_load");
-		break;
-	case 105: // kexec_init_module
-		ret = enosys ("kexec_init_module");
-		break;
-	case 106: // kexec_delete_module
-		ret = enosys ("kexec_delete_module");
-		break;
-	case 107: // timer_create
-		ret = enosys ("timer_create");
-		break;
-	case 108: // timer_gettime
-		ret = enosys ("timer_gettime");
-		break;
-	case 109: // timer_getoverrun
-		ret = enosys ("timer_getoverrun");
-		break;
-	case 110: // timer_settime
-		ret = enosys ("timer_settime");
-		break;
-	case 111: // timer_delete
-		ret = enosys ("timer_delete");
-		break;
-	case 112: // clock_settime
-		ret = enosys ("clock_settime");
-		break;
-	case 113: // clock_gettime
-		ret = enosys ("clock_gettime");
-		break;
-	case 114: // clock_getres
-		ret = enosys ("clock_getres");
-		break;
-	case 115: // clock_nanosleep
-		ret = enosys ("clock_nanosleep");
-		break;
-	case 116: // syslog
-		ret = enosys ("syslog");
-		break;
-	case 117: // ptrace
-		ret = enosys ("ptrace");
-		break;
-	case 118: // sched_setparam
-		ret = enosys ("sched_setparam");
-		break;
-	case 119: // sched_setscheduler
-		ret = enosys ("sched_setscheduler");
-		break;
-	case 120: // sched_getscheduler
-		ret = enosys ("sched_getscheduler");
-		break;
-	case 121: // sched_getparam
-		ret = enosys ("sched_getparam");
-		break;
-	case 122: // sched_setaffinity
-		ret = enosys ("sched_setaffinity");
-		break;
-	case 123: // sched_getaffinity
-		ret = enosys ("sched_getaffinity");
-		break;
-	case 124: // sched_yield
-		ret = map (sched_yield ());
-		break;
-	case 125: // sched_get_priority_max
-		ret = map (sched_get_priority_max ((int)a0));
-		break;
-	case 126: // sched_get_priority_min
-		ret = map (sched_get_priority_min ((int)a0));
-		break;
-	case 127: // sched_rr_get_interval
-		ret = enosys ("sched_rr_get_interval");
-		break;
-	case 128: // restart_syscall
-		ret = enosys ("restart_syscall");
-		break;
-	case 129: // kill
-		ret = map (kill ((pid_t)a0, (int)a1));
-		break;
-	case 130: // tkill
-		ret = enosys ("tkill");
-		break;
-	case 131: // tgkill
-		ret = enosys ("tgkill");
-		break;
-	case 132: // signalstack
-		ret = enosys ("signalstack");
-		break;
-	case 133: // sigaction
-		ret = enosys ("sigaction");
-		break;
-	case 134: // sigaction
-		ret = enosys ("sigaction");
-		break;
-	case 135: // rt_sigprocmask
-		ret = enosys ("rt_sigprocmask");
-		break;
-	case 136: // sigpending
-		ret = enosys ("sigpending");
-		break;
-	case 137: // sigtimedwait
-		ret = enosys ("sigtimedwait");
-		break;
-	case 138: // sigqueueinfo
-		ret = enosys ("sigqueueinfo");
-		break;
-	case 139: // sigreturn
-		ret = enosys ("sigreturn");
-		break;
-	case 140: // setpriority
-		ret = map (setpriority ((int)a0, (id_t)a1, (int)a2));
-		break;
-	case 141: // getpriority
-		ret = map (getpriority ((int)a0, (id_t)a1));
-		break;
-	case 142: // reboot
-		ret = enosys ("reboot");
-		break;
-	case 143: // setregid
-		ret = map (setregid ((gid_t)a0, (gid_t)a1));
-		break;
-	case 144: // setgid
-		ret = map (setgid ((gid_t)a0));
-		break;
-	case 145: // setreuid
-		ret = map (setreuid ((uid_t)a0, (uid_t)a1));
-		break;
-	case 146: // setuid
-		ret = map (setuid ((uid_t)a0));
-		break;
-	case 147: // setresuid
-		ret = map (setresuid ((uid_t)a0, (uid_t)a1, (uid_t)a2));
-		break;
-	case 148: // getresuid
-		ret = map (getresuid (ptr (uid_t, a0), ptr (uid_t, a1), ptr (uid_t, a2)));
-		break;
-	case 149: // setresgid
-		ret = map (setresgid ((gid_t)a0, (gid_t)a1, (gid_t)a2));
-		break;
-	case 150: // getresgid
-		ret = map (getresgid (ptr (gid_t, a0), ptr (gid_t, a1), ptr (gid_t, a2)));
-		break;
-	case 151: // setfsuid
-		ret = enosys ("setfsuid");
-		break;
-	case 152: // setfsgid
-		ret = enosys ("setfsgid");
-		break;
-	case 153: // times
-		ret = enosys ("times");
-		break;
-	case 154: // setpgid
-		ret = map (setpgid ((pid_t)a0, (pid_t)a1));
-		break;
-	case 155: // getpgid
-		ret = map (getpgid ((pid_t)a0));
-		break;
-	case 156: // getsid
-		ret = map (getsid ((pid_t)a0));
-		break;
-	case 158: // setsid
-		ret = map (setsid ());
-		break;
-	case 159: // setgroups
-		ret = enosys ("setgroups");
-		break;
-	case 160: // uname
-		ret = map (uname (&un));
-		utsname_to_linux_utsname (&lun, &un);
-		memcpy (ptr (void, a0), &lun, sizeof (lun));
-		break;
-	case 161: // sethostname
-		ret = enosys ("sethostname");
-		break;
-	case 162: // setdomainname
-		ret = enosys ("setdomainname");
-		break;
-	case 163: // getrlimit
-		ret = enosys ("getrlimit");
-		break;
-	case 164: // setrlimit
-		ret = enosys ("setrlimit");
-		break;
-	case 165: // getrusage
-		ret = enosys ("getrusage");
-		break;
-	case 166: // umask
-		ret = map (umask ((mode_t)a0));
-		break;
-	case 167: // prctl
-		ret = enosys ("prctl");
-		break;
-	case 168: // getcpu
-		ret = enosys ("getcpu");
-		break;
-	case 169: // gettimeofday
-		ret = enosys ("gettimeofday");
-		break;
-	case 170: // settimeofday
-		ret = enosys ("settimeofday");
-		break;
-	case 171: // adjtimex
-		ret = enosys ("adjtimex");
-		break;
-	case 172: // getpid
-		ret = map (getpid ());
-		break;
-	case 174: // getuid
-		ret = map (getuid ());
-		break;
-	case 175: // geteuid
-		ret = map (geteuid ());
-		break;
-	case 176: // getgid
-		ret = map (getgid ());
-		break;
-	case 177: // getegid
-		ret = map (getegid ());
-		break;
-	case 178: // gettid
-		ret = enosys ("gettid");
-		break;
-	case 179: // sysinfo
-		ret = enosys ("sysinfo");
-		break;
-	case 180:
-	case 181:
-	case 182:
-	case 183:
-	case 184:
-	case 185:
-		ret = enosys ("mq_*");
-		break;
-	case 186: // msgget
-		ret = map (msgget ((key_t)a0, (int)a1));
-		break;
-	case 187: // msgctl
-		ret = enosys ("msgctl");
-		break;
-	case 188: // msgrcv
-		ret = map (msgrcv ((int)a0, ptr (void, a1), (size_t)a2, (long)a3, (int)a4));
-		break;
-	case 189: // msgsnd
-		ret = map (msgsnd ((int)a0, ptr (const void, a1), (size_t)a2, (int)a3));
-		break;
-	case 190: // semget
-		ret = map (semget ((key_t)a0, (int)a1, (int)a2));
-		break;
-	case 191: // semctl
-		ret = enosys ("semctl");
-		break;
-	case 192: // semtimedop
-		ret = enosys ("semtimedop");
-		break;
-	case 193: // semop
-		ret = enosys ("semop");
-		break;
-	case 194:
-	case 195:
-	case 196:
-	case 197:
-		ret = enosys ("shm*");
-		break;
-	case 198:
-	case 199:
-	case 200:
-	case 201:
-	case 202:
-	case 203:
-	case 204:
-	case 205:
-	case 206:
-	case 207:
-	case 208:
-	case 209:
-	case 210:
-	case 211:
-	case 212:
-		ret = enosys ("socket api");
-		break;
-	case 213: // readahead
-		ret = enosys ("readahead");
-		break;
-	case 214: // brk
-		ret = map (my_brk (a0));
-		break;
-	case 215: // munmap
-		ret = map (munmap (ptr (void, a0), (size_t)a1));
-		break;
-	case 216: // mremap
-		ret = enosys ("mremap");
-		break;
-	case 217: // add_key
-		ret = enosys ("add_key");
-		break;
-	case 218: // request_key
-		ret = enosys ("request_key");
-		break;
-	case 219: // keyctl
-		ret = enosys ("keyctl");
-		break;
-	case 220: // clone
-		if (a0 == 17 && a1 == 0) {
-			// fork
-			ret = map (fork ());
-		} else {
-			ret = enosys ("clone");
-		}
-		break;
-	case 221: // execve
-		ret = map (my_execve (str (a0), a1, a2));
-		break;
-	case 222: // mmap
-		ptr = mmap (ptr (void, a0), (size_t)a1, (int)a2, (int)a3, (int)a4, (off_t)a5);
-		if (ptr == NULL) {
-			ret = -map_errno (errno);
-		} else if ((size_t)ptr > INT32_MAX) {
-			ret = -map_errno (EINVAL);
-		} else {
-			ret = (size_t)ptr;
-		}
-		break;
-	case 223: // fadvise64
-		ret = enosys ("fadvise64");
-		break;
-	case 224: // swapon
-		ret = enosys ("swapon");
-		break;
-	case 225: // swapoff
-		ret = enosys ("swapoff");
-		break;
-	case 226: // mprotect
-		ret = map (mprotect (ptr (void, a0), (size_t)a1, (int)a2));
-		break;
-	case 227: // msync
-		ret = map (msync (ptr (void, a0), (size_t)a1, (int)a2));
-		break;
-	case 228: // mlock
-		ret = map (mlock (ptr (void, a0), (size_t)a1));
-		break;
-	case 229: // munlock
-		ret = map (munlock (ptr (void, a0), (size_t)a1));
-		break;
-	case 230: // mlockall
-		ret = map (mlockall ((int)a0));
-		break;
-	case 231: // munlockall
-		ret = map (munlockall ());
-		break;
-	case 232: // mincore
-		ret = enosys ("mincore");
-		break;
-	case 233: // madvise
-		ret = map (madvise (ptr (void, a0), (size_t)a1, (int)a2));
-		break;
-	case 234: // remap_file_pages
-		ret = enosys ("remap_file_pages");
-		break;
-	case 235: // mbind
-		ret = enosys ("mbind");
-		break;
-	case 236: // get_mempolicy
-		ret = enosys ("get_mempolicy");
-		break;
-	case 237: // set_mempolicy
-		ret = enosys ("set_mempolicy");
-		break;
-	case 238: // migrate_pages
-		ret = enosys ("migrate_pages");
-		break;
-	case 239: // move_pages
-		ret = enosys ("move_pages");
-		break;
-	case 240: // rt_tgsigqueueinfo
-		ret = enosys ("rt_tgsigqueueinfo");
-		break;
-	case 241: // perf_event_open
-		ret = enosys ("perf_event_open");
-		break;
-	case 242: // accept4
-		ret = enosys ("accept4");
-		break;
-	case 243: // recvmsg
-		ret = enosys ("recvmsg");
-		break;
-	case 244:
-	case 245:
-	case 246:
-	case 247:
-	case 248:
-	case 249:
-	case 250:
-	case 251:
-	case 252:
-	case 253:
-	case 254:
-	case 255:
-	case 256:
-	case 257:
-	case 258:
-	case 259:
-		ret = enosys ("arch-specific");
-		break;
-	case 260:
-		ret = enosys ("wait4");
-		break;
-	case 261: // prlimit64
-		ret = enosys ("prlimit64");
-		break;
-	case 262: // fanotify_init
-		ret = enosys ("fanotify_init");
-		break;
-	case 263: // fanotify_mark
-		ret = enosys ("fanotify_mark");
-		break;
-	case 264: // name_to_handle_at
-		ret = enosys ("name_to_handle_at");
-		break;
-	case 265: // open_by_handle_at
-		ret = enosys ("open_by_handle_at");
-		break;
-	case 266: // clock_adjtime
-		ret = enosys ("clock_adjtime");
-		break;
-	case 267: // syncfs
-		ret = enosys ("syncfs");
-		break;
-	case 268: // setns
-		ret = enosys ("setns");
-		break;
-	case 269: // sendmsg
-		ret = enosys ("sendmsg");
-		break;
-	case 270: // process_vm_readv
-		ret = enosys ("process_vm_readv");
-		break;
-	case 271: // process_vm_writev
-		ret = enosys ("process_vm_writev");
-		break;
-	case 272: // kcmp
-		ret = enosys ("kcmp");
-		break;
-	case 273: // finit_module
-		ret = enosys ("finit_module");
-		break;
-	case 274: // sched_setattr
-		ret = enosys ("sched_setattr");
-		break;
-	case 275: // sched_getattr
-		ret = enosys ("sched_getattr");
-		break;
-	case 276: // renameat2
-		ret = enosys ("renameat2");
-		break;
-	case 277: // seccomp
-		ret = enosys ("seccomp");
-		break;
-	case 278: // getrandom
-		ret = enosys ("getrandom");
-		break;
-	case 279: // memfd_create
-		ret = enosys ("seccomp");
-		break;
-	case 280: // bpf
-		ret = enosys ("bpf");
-		break;
-	case 281: // execveat
-		ret = enosys ("execveat");
-		break;
-	case 282: // userfaultfd
-		ret = enosys ("usefaultfd");
-		break;
-	case 283: // membarrier
-		ret = enosys ("membarrier");
-		break;
-	case 284: // mlock2
-		ret = enosys ("mlock2");
-		break;
-	case 285: // copy_file_range
-		ret = enosys ("copy_file_range");
-		break;
-	case 286: // preadv2
-		ret = enosys ("preadv2");
-		break;
-	case 287: // pwritev2
-		ret = enosys ("pwritev2");
-		break;
-	case 288: // pkey_mprotect
-		ret = enosys ("pkey_mprotect");
-		break;
-	case 289: // pkey_alloc
-		ret = enosys ("pkey_alloc");
-		break;
-	case 290: // pkey_free
-		ret = enosys ("pkey_free");
-		break;
-	case 291: // statx
-		ret = enosys ("statx");
-		break;
-	case 292: // io_pgetevents
-		ret = enosys ("io_pgetevents");
-		break;
-	case 293: // rseq
-		ret = enosys ("rseq");
-		break;
-	case 294: // kexec_file_load
-		ret = enosys ("kexec_file_load");
-		break;
-	case 1024: // open
-		ret = map (open ((const char *)(size_t)a0, (int)a1, (int)a2));
-		break;
-	case 1025: // link
-		ret = map (link (str (a0), str (a1)));
-		break;
-	case 1026: // unlink
-		ret = map (unlink (str (a0)));
-		break;
-	case 1030: // mkdir
-		ret = map (mkdir (str (a0), (mode_t)a1));
-		break;
-	case 1033: // access
-		ret = map (access (str (a0), (int)a1));
-		break;
-	case 1038: // stat
-		ret = map (stat (str (a0), &st));
-		stat_to_linux_stat (&lst, &st);
-		memcpy (ptr (void, a1), &lst, sizeof (lst));
-		break;
-	case 1039: // lstat
-		ret = map (lstat (str (a0), &st));
-		stat_to_linux_stat (&lst, &st);
-		memcpy (ptr (void, a1), &lst, sizeof (lst));
-		break;
-	case 1062: // time
-		ret = enosys ("time");
-		break;
-	case 2011: // getmainvars
-		ret = enosys ("getmainvars");
-		break;
-	case 2048:
-		fprintf (stderr, "DEBUG: %u\n", a0);
-		ret = 0;
-		break;
-	default:
-		warnx ("%08x: unimplemented syscall %u", pc - 4, a7);
-		ret = -map_errno (ENOSYS);
-		break;
-	}
-	cpu_set (10, ret);
-}
-
blob - 5df22c2c59aad064533fec3b092b5bd3b62773b7
blob + f107b56f5fe7a8f694784c2a8903a7c54f1e5c14
--- syscalls.inc
+++ syscalls.inc
@@ -42,7 +42,7 @@
 .set SYS_pwrite, 68
 .set SYS_preadv, 69
 .set SYS_pwritev, 70
-.set SYS_pwritev, 71
+.set SYS_sendfile, 71
 .set SYS_pselect6, 72
 .set SYS_ppoll, 73
 .set SYS_signalfd4, 74
@@ -104,7 +104,7 @@
 .set SYS_tkill, 130
 .set SYS_tgkill, 131
 .set SYS_signalstack, 132
-.set SYS_sigaction, 133
+.set SYS_sigsuspend, 133
 .set SYS_sigaction, 134
 .set SYS_rt_sigprocmask, 135
 .set SYS_sigpending, 136
@@ -231,3 +231,4 @@
 .set SYS_lstat, 1039
 .set SYS_time, 1062
 .set SYS_getmainvars, 2011
+.set SYS_debug, 2048
blob - e2cf2fffaab6a3f386b08769438e3f48c8d37b19
blob + 85a84552dd1982a85a006dc9c3b5193fa5b25c11
--- test.S
+++ test.S
@@ -6,11 +6,11 @@ child:	.string "Child\n"
 arg0:
 path:	.string "./hello.elf"
 argv:
-	.int arg0
-	.int 0
+	.dword arg0
+	.dword 0
 
 envp:
-	.int 0
+	.dword 0
 
 .section .text
 .global _start
@@ -50,17 +50,16 @@ _start:
 	li a7, SYS_write
 	ecall
 
-
 	li a0, 0
 	li a7, SYS_exit
 	ecall
 
-# printhex(u32 a0)
+# printhex(u64 a0)
 printhex:
 	addi sp, sp, -12
 	sw s0, 8(sp)
 	sw s1, 4(sp)
-	li s0, 28
+	li s0, 52
 	mv s1, a0
 
 .Loop: