Vmm file mmap ept fault fix (XCC)

Modified vthreads to also check for EAGAIN (like uthreads) in the ept
fault handler. This allows vthreads that mmap with files to correctly
populate memory on an ept fault. Included a test (mmap_file_vmm) that
will check this condition is satisified.

Reinstall your kernel headers.

Change-Id: I09f7b70de98275ed8b9614f89179a0947ca35584
Signed-off-by: Zach Zimmerman <zpzimmerman@gmail.com>
[ XCC warning ]
Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
diff --git a/kern/arch/x86/ros/trapframe64.h b/kern/arch/x86/ros/trapframe64.h
index f7ca1bd..1b3db9e 100644
--- a/kern/arch/x86/ros/trapframe64.h
+++ b/kern/arch/x86/ros/trapframe64.h
@@ -68,6 +68,7 @@
 #define VMCTX_FL_PARTIAL		(1 << 0)
 #define VMCTX_FL_HAS_FAULT		(1 << 1)
 #define VMCTX_FL_VMRESUME		(1 << 2)
+#define VMCTX_FL_EPT_VMR_BACKED	(1 << 3)
 
 struct vm_trapframe {
 	/* Actual processor state */
diff --git a/kern/arch/x86/trap.c b/kern/arch/x86/trap.c
index b1153f9..0c24cad 100644
--- a/kern/arch/x86/trap.c
+++ b/kern/arch/x86/trap.c
@@ -941,11 +941,14 @@
 	prot |= tf->tf_exit_qual & VMX_EPT_FAULT_WRITE ? PROT_WRITE : 0;
 	prot |= tf->tf_exit_qual & VMX_EPT_FAULT_INS ? PROT_EXEC : 0;
 	ret = handle_page_fault(current, tf->tf_guest_pa, prot);
-	if (ret) {
-		/* TODO: maybe put ret in the TF somewhere */
-		return FALSE;
-	}
-	return TRUE;
+	if (ret == 0)
+		return TRUE;
+
+	//Mirror behavior in uthreads, tell userspace to try again.
+	if (ret == -EAGAIN)
+		tf->tf_flags |= VMCTX_FL_EPT_VMR_BACKED;
+
+	return FALSE;
 }
 
 /* Regarding NMI blocking,
diff --git a/tests/mmap_file_vmm.c b/tests/mmap_file_vmm.c
new file mode 100644
index 0000000..81880d5
--- /dev/null
+++ b/tests/mmap_file_vmm.c
@@ -0,0 +1,128 @@
+/* Copyright Google, Inc. 2017
+ * Author: Zach Zimmerman
+ * mmap_vmm_test: tests mmap with fd's with access from
+ * vmthreads */
+
+#include <stdio.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/time.h>
+
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <parlib/parlib.h>
+#include <parlib/timing.h>
+#include <parlib/ros_debug.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <vmm/vmm.h>
+
+static struct virtual_machine vm;
+
+int safe_to_exit;
+void *addr;
+size_t nr_pgs = 1;
+#define STRIDE 1
+#define NUM_ITERS 100
+
+static void mmap_testz(void)
+{
+	assert(addr);
+	for (char *i = addr; (void*)i < addr + nr_pgs * PGSIZE; i += STRIDE)
+		*i = 'z';
+}
+
+static void mmap_testy(void)
+{
+	assert(addr);
+	for (char *i = addr; (void*)i < addr + nr_pgs * PGSIZE; i += STRIDE)
+		*i = 'y';
+}
+
+void *worker_thread(void *arg)
+{
+	int i;
+
+	for (i = 0; i < NUM_ITERS; ++i)
+		mmap_testy();
+
+	safe_to_exit = true;
+	__asm__ __volatile__("hlt\n\t");
+	return 0;
+}
+
+int main(void)
+{
+	int fd, pid, ret;
+	char inputfile[50];
+
+	pid = getpid();
+	sprintf(inputfile, "/tmp/mmap-test-%d", pid);
+
+	fd = open(inputfile, O_RDWR | O_CREAT, 0666);
+	if (fd < 0) {
+		perror("Unable to open file");
+		exit(-1);
+	}
+
+	ret = unlink(inputfile);
+	if (ret == -1) {
+		perror("UNLINK error");
+		exit(-1);
+	}
+
+	//Increase the file size with ftruncate
+	ret = ftruncate(fd, nr_pgs * PGSIZE);
+	if (ret == -1) {
+		perror("FTRUNCATE error");
+		exit(-1);
+	}
+
+	ret = vthread_attr_init(&vm, 0);
+	if (ret) {
+		fprintf(stderr, "vmm_init failed: %r\n");
+		exit(1);
+	}
+
+	fprintf(stderr, "Vthread attr init finished\n");
+	nr_pgs = 1;
+	void *loc = (void*) 0x1000000;
+
+	addr = mmap(loc, nr_pgs * PGSIZE, PROT_WRITE | PROT_READ | PROT_EXEC,
+			    MAP_SHARED, fd, 0);
+	if (addr == MAP_FAILED) {
+		perror("mmap failed");
+		exit(-1);
+	}
+
+	printf("MMap got addr %p\n", addr);
+	printf("Spawning worker vmthread thread, etc...\n");
+	vthread_create(&vm, 0, (void*)&worker_thread, NULL);
+
+	while (!safe_to_exit)
+		cpu_relax();
+
+	for (char *i = addr; (void*)i < addr + nr_pgs * PGSIZE; i += STRIDE)
+		assert(*i == 'y');
+
+	printf("mmap_file_vmm: test finished, doing teardown\n");
+
+	ret = munmap(addr, nr_pgs * PGSIZE);
+	if (ret == -1) {
+		perror("mmap_file_vmm: problem unmapping memory after test\n");
+		exit(-1);
+	}
+
+	ret = close(fd);
+	if (ret == -1) {
+		perror("mmap_file_vmm: problem closing file after test\n");
+		exit(-1);
+	}
+
+	printf("mmap_file_vmm: PASSED\n");
+	return 0;
+}
diff --git a/user/vmm/vmexit.c b/user/vmm/vmexit.c
index 0b97f96..cef0684 100644
--- a/user/vmm/vmexit.c
+++ b/user/vmm/vmexit.c
@@ -109,8 +109,16 @@
 	uint8_t regx;
 	int store, size;
 	int advance;
+	int ret;
 
-	int ret = decode(gth, &gpa, &regx, &regp, &store, &size, &advance);
+	if (vm_tf->tf_flags & VMCTX_FL_EPT_VMR_BACKED) {
+		ret = ros_syscall(SYS_populate_va, vm_tf->tf_guest_pa, 1, 0, 0, 0, 0);
+		if (ret <= 0)
+			panic("[user] handle_ept_fault: populate_va failed: ret = %d\n",
+			      ret);
+		return TRUE;
+	}
+	ret = decode(gth, &gpa, &regx, &regp, &store, &size, &advance);
 
 	if (ret < 0)
 		return FALSE;