Vmm file mmap ept fault fix (XCC)
authorZach Zimmerman <zpzimmerman@gmail.com>
Tue, 15 Aug 2017 21:27:39 +0000 (14:27 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Tue, 22 Aug 2017 20:12:02 +0000 (16:12 -0400)
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>
kern/arch/x86/ros/trapframe64.h
kern/arch/x86/trap.c
tests/mmap_file_vmm.c [new file with mode: 0644]
user/vmm/vmexit.c

index f7ca1bd..1b3db9e 100644 (file)
@@ -68,6 +68,7 @@ struct sw_trapframe {
 #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 */
index b1153f9..0c24cad 100644 (file)
@@ -941,11 +941,14 @@ static bool handle_vmexit_ept_fault(struct vm_trapframe *tf)
        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 (file)
index 0000000..81880d5
--- /dev/null
@@ -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;
+}
index 0b97f96..cef0684 100644 (file)
@@ -109,8 +109,16 @@ static bool handle_ept_fault(struct guest_thread *gth)
        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;