Update to linuxemu syscall structure

Changed linuxemu to use array of function pointers
Changed dune test to use linuxemu by default
Modified linuxemu to use a shared library for syscall extensions

Signed-off-by: Zach Zimmerman <zpzimmerman@gmail.com>
Change-Id: Id4b7d86b5f9cc95b224ebe9e282a3973e80b9130
[ checkpatch warning ]
Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
diff --git a/tests/dune/Makefrag b/tests/dune/Makefrag
index 5cce02c..1d3801e 100644
--- a/tests/dune/Makefrag
+++ b/tests/dune/Makefrag
@@ -4,11 +4,11 @@
 
 ALL_DUNE_TEST_FILES := $(wildcard $(DUNE_TESTS_DIR)/*.c)
 
-DUNE_TESTS_LDLIBS := $(TESTS_LDLIBS) -lelf -liplib
+DUNE_TESTS_LDLIBS := $(TESTS_LDLIBS) -lelf -liplib -ldl
 
 DUNE_TESTS_SRCS := $(ALL_DUNE_TEST_FILES)
 
-DUNE_TESTS_LDDEPENDS := $(DUNE_TESTS_DIR)/%.c 
+DUNE_TESTS_LDDEPENDS := $(DUNE_TESTS_DIR)/%.c
 
 TESTS_EXECS_C  += $(patsubst $(DUNE_TESTS_DIR)/%.c, \
                       $(OBJDIR)/$(DUNE_TESTS_DIR)/%, \
diff --git a/tests/dune/dune.c b/tests/dune/dune.c
index 78ee960..785b414 100644
--- a/tests/dune/dune.c
+++ b/tests/dune/dune.c
@@ -28,7 +28,7 @@
 #include <sys/eventfd.h>
 #include <sys/uio.h>
 #include <err.h>
-
+#include <vmm/linuxemu.h>
 struct vmm_gpcore_init gpci;
 bool linuxemu(struct guest_thread *gth, struct vm_trapframe *tf);
 
@@ -51,10 +51,14 @@
 	__asm__ __volatile__("\thlt\n\t");
 }
 
-static int pc(uint16_t c)
+static int pc(char *c)
 {
-	__asm__ __volatile__("movw $0, %%rax\nmovw %0, %%di\n\tvmcall\n" ::
-	                     "m"(c) : "rdi", "rax");
+	__asm__ __volatile__("movq $1, %%rax\n"
+	                     "movq $1, %%rdi\n"
+	                     "movq %0, %%rsi\n"
+	                     "movq $1, %%rdx\n"
+	                     "vmcall\n" ::
+	                     "m"(c) : "rdi", "rax", "rsi", "rdx");
 	return 0;
 }
 
@@ -64,9 +68,8 @@
 
 	for (int i = 0; i < 8; i++) {
 		uint8_t v = ((uint8_t*)&x)[7 - i];
-
-		pc(hex[v >> 4]);
-		pc(hex[v & 0xf]);
+		pc(&hex[v >> 4]);
+		pc(&hex[v & 0xf]);
 	}
 }
 
@@ -79,8 +82,7 @@
 		return;
 	}
 	while (*s) {
-	//	xnum((uint64_t)s);pc(';');
-		pc(*s);
+		pc(s);
 		s++;
 	}
 }
@@ -88,8 +90,11 @@
 /* This is a small test that runs in gr0 and tests our argument setup.
  * This test can grow in capability as we find more broken bits in our
  * dune-like environment. */
+
 void dune_test(void *stack)
 {
+	show("Hello this is dune's test\n");
+
 	int argc;
 	char **argv;
 	struct elf_aux *auxv;
@@ -122,9 +127,6 @@
 		xnum(auxv[i].v[1]); show("\n");
 	}
 	show("Done dumping [argv, env, auxv]\n");
-	__asm__ __volatile__("movl $0xdeadbeef, %eax\nmovq $1, %rdi\nmov $2,"
-	                     "%rsi\nmovq $3, %rdx\n"
-	                     "movq $4,%rcx\nmovq $5, %r8\nmovq $6,%r9\nvmcall\n");
 	hlt();
 }
 
@@ -341,28 +343,6 @@
 	return ret;
 }
 
-static bool
-testvmcall(struct guest_thread *gth, struct vm_trapframe *tf)
-{
-	uintptr_t rax = tf->tf_rax;
-
-	switch (rax) {
-	default:
-		fprintf(stderr, "testvmcall: gth %p tf %p\n", gth, tf);
-		fprintf(stderr, "args should be 1, 2, 3, 4, 5, 6:\n");
-		fprintf(stderr, "%p %p %p %p %p %p\n",
-		        tf->tf_rdi, tf->tf_rsi, tf->tf_rdx,
-		        tf->tf_rcx, tf->tf_r8, tf->tf_r9);
-		fprintf(stderr, "RAX should be deadbeef: 0x%x\n", rax);
-		break;
-	case 0:
-		write(1, &tf->tf_rdi, 1);
-		break;
-	}
-	tf->tf_rip += 3;
-	return true;
-}
-
 int main(int argc, char **argv)
 {
 	void *tos;
@@ -429,6 +409,8 @@
 		usage();
 	}
 
+	init_syscall_table();
+
 	if ((uintptr_t)(memstart + memsize) >= (uintptr_t)BRK_START) {
 		fprintf(stderr,
 		        "memstart 0x%lx memsize 0x%lx -> 0x%lx is too large; overlaps BRK_START at %p\n",
@@ -480,7 +462,7 @@
 		exit(1);
 	}
 
-	vm.gths[0]->vmcall = test ? testvmcall : linuxemu;
+	vm.gths[0]->vmcall = linuxemu;
 	vm_tf = gth_to_vmtf(vm.gths[0]);
 
 	/* we can't use the default stack since we set one up
diff --git a/user/vmm/include/vmm/linux_syscalls.h b/user/vmm/include/vmm/linux_syscalls.h
index 045c756..99c45ce 100644
--- a/user/vmm/include/vmm/linux_syscalls.h
+++ b/user/vmm/include/vmm/linux_syscalls.h
@@ -1,3 +1,7 @@
+#pragma once
+
+#define linux_max_syscall 311
+
 char *syscalls[] = {
 [0]	"DUNE_SYS_READ",
 [1]	"DUNE_SYS_WRITE",
diff --git a/user/vmm/include/vmm/linuxemu.h b/user/vmm/include/vmm/linuxemu.h
new file mode 100644
index 0000000..79b7062
--- /dev/null
+++ b/user/vmm/include/vmm/linuxemu.h
@@ -0,0 +1,16 @@
+#pragma once
+
+typedef bool (*dune_syscall_t)(struct vm_trapframe *);
+
+struct dune_sys_table_entry {
+	dune_syscall_t call;
+	const char *name;
+};
+
+#define dune_max_syscall 1024
+
+struct dune_sys_table_entry dune_syscall_table[dune_max_syscall];
+
+void init_syscall_table(void);
+bool dune_sys_write(struct vm_trapframe *tf);
+bool dune_sys_read(struct vm_trapframe *tf);
diff --git a/user/vmm/linuxemu.c b/user/vmm/linuxemu.c
index bd217e8..e6ac53c 100644
--- a/user/vmm/linuxemu.c
+++ b/user/vmm/linuxemu.c
@@ -14,6 +14,76 @@
 #include <sys/syscall.h>
 #include <vmm/linux_syscalls.h>
 #include <sys/time.h>
+#include <vmm/linuxemu.h>
+#include <dlfcn.h>
+
+bool dune_sys_read(struct vm_trapframe *tf)
+{
+	int retval = read(tf->tf_rdi, (void *)tf->tf_rsi, (size_t)tf->tf_rdx);
+
+	if (retval == -1)
+		tf->tf_rax = -errno;
+	else
+		tf->tf_rax = retval;
+
+	return true;
+}
+
+bool dune_sys_write(struct vm_trapframe *tf)
+{
+	int retval = write(tf->tf_rdi, (void *)tf->tf_rsi, (size_t)tf->tf_rdx);
+
+	if (retval == -1)
+		tf->tf_rax = -errno;
+	else
+		tf->tf_rax = retval;
+
+	return true;
+}
+
+bool dune_sys_gettid(struct vm_trapframe *tf)
+{
+	tf->tf_rax = tf->tf_guest_pcoreid;
+	return true;
+}
+
+bool dune_sys_gettimeofday(struct vm_trapframe *tf)
+{
+	int retval = gettimeofday((struct timeval*)tf->tf_rdi,
+	                          (struct timezone*)tf->tf_rsi);
+	if (retval == -1)
+		tf->tf_rax = -errno;
+	else
+		tf->tf_rax = retval;
+
+	return true;
+}
+
+void init_syscall_table(void)
+{
+	int i;
+
+	for (i = 0; i < dune_max_syscall ; ++i) {
+		dune_syscall_table[i].call = NULL;
+		dune_syscall_table[i].name = "nosyscall";
+	}
+	// For now setup the syscalls here,
+	// there is probably a better way to do this.
+	dune_syscall_table[DUNE_SYS_WRITE].call = dune_sys_write;
+	dune_syscall_table[DUNE_SYS_WRITE].name = syscalls[DUNE_SYS_WRITE];
+	dune_syscall_table[DUNE_SYS_GETTID].call = dune_sys_gettid;
+	dune_syscall_table[DUNE_SYS_GETTID].name = syscalls[DUNE_SYS_GETTID];
+	dune_syscall_table[DUNE_SYS_GETTIMEOFDAY].call = dune_sys_gettimeofday;
+	dune_syscall_table[DUNE_SYS_GETTIMEOFDAY].name =
+		syscalls[DUNE_SYS_GETTIMEOFDAY];
+	dune_syscall_table[DUNE_SYS_READ].call = dune_sys_read;
+	dune_syscall_table[DUNE_SYS_READ].name = syscalls[DUNE_SYS_READ];
+	if (dlopen("liblinuxemu_extend.so", RTLD_NOW) == NULL)
+		fprintf(stderr, "Not using any syscall extensions\n Reason: %s\n",
+		        dlerror());
+
+}
+
 
 /* TODO: have an array which classifies syscall args
  * and "special" system calls (ones with weird return
@@ -32,29 +102,17 @@
 	        tf->tf_rcx, tf->tf_r8, tf->tf_r9);
 
 	tf->tf_rip += 3;
-	/* we don't do tic/tou checking here yet. */
-	switch (tf->tf_rax) {
-	default:
-		/* TODO: just return the error to the guest once we are done
-		 * debugging this. */
-		fprintf(stderr, "System call %d is not implemented\n", tf->tf_rax);
-		//tf->tf_rax = -ENOSYS;
-		break;
-	case DUNE_SYS_GETTIMEOFDAY:
-		tf->tf_rax = gettimeofday((struct timeval*)tf->tf_rdi,
-		                          (struct timezone*)tf->tf_rsi);
-		ret = true;
-		break;
-	case DUNE_SYS_GETTID:
-		tf->tf_rax = 1;
-		ret = true;
-		break;
-	case DUNE_SYS_WRITE:
-		/* debug: write to stdout too for now. */
-		write(2, (void *)tf->tf_rsi, (size_t)tf->tf_rdx);
-		tf->tf_rax = write(tf->tf_rdi, (void *)tf->tf_rsi, (size_t)tf->tf_rdx);
-		ret = true;
-		break;
+
+	if (tf->tf_rax >= dune_max_syscall) {
+		fprintf(stderr, "System call %d is out of range\n", tf->tf_rax);
+		return false;
 	}
-	return ret;
+
+
+	if (dune_syscall_table[tf->tf_rax].call == NULL) {
+		fprintf(stderr, "System call %d is not implemented\n", tf->tf_rax);
+		return false;
+	}
+
+	return (dune_syscall_table[tf->tf_rax].call)(tf);
 }