vmm: move paging setup to the library
authorRonald G. Minnich <rminnich@gmail.com>
Fri, 21 Apr 2017 15:45:00 +0000 (11:45 -0400)
committerBarret Rhoden <brho@cs.berkeley.edu>
Fri, 21 Apr 2017 19:03:50 +0000 (15:03 -0400)
We create a new function, setup_paging(start, size, debug)
which returns a pointer to the base of page tables (needed
for starting the VM). Since it is just manipulating values
in arrays, and it's almost impossible for it to go wrong,
we print a nice message and bail if anything goes wrong.

Change-Id: I1d5ef0ce1c2a7fed4e21a18bd48ffdac0b3ab0e9
Signed-off-by: Ronald G. Minnich <rminnich@gmail.com>
Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
tests/vmm/vmrunkernel.c
user/vmm/include/vmm/vmm.h
user/vmm/memory.c
user/vmm/pagetables.c [new file with mode: 0644]

index e84b344..e139e10 100644 (file)
@@ -114,10 +114,6 @@ struct acpi_madt_interrupt_override isor[] = {
         */
 };
 
-typedef struct {
-       uint64_t pte[512];
-} ptp;
-
 void vapic_status_dump(FILE *f, void *vapic);
 
 #if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 1)
@@ -478,7 +474,7 @@ void alloc_intr_pages(void)
 
 int main(int argc, char **argv)
 {
-       ptp *p512, *p1, *p2m;
+       void *cr3;
        int debug = 0;
        void *low1m;
        unsigned long long memsize = GiB;
@@ -507,7 +503,6 @@ int main(int argc, char **argv)
        int num_read;
        int option_index;
        char *smbiostable = NULL;
-       int nptp, npml4, npml3, npml2;
        char *net_opts = NULL;
        uint64_t num_pcs = 1;
 
@@ -856,91 +851,17 @@ int main(int argc, char **argv)
        ret = vmm_init(vm, vmmflags);
        assert(!ret);
 
-       /* How many page table pages do we need?  We conservatively
-        * assume that we are in low memory, and hence assume a
-        * 0-based range.  Note that in many cases, kernels will
-        * immediately set up their own map. But for "dune" like
-        * applications, it's necessary. Note also that in most cases,
-        * the total number of pages will be < 16 or so. */
-       npml4 = DIV_ROUND_UP(memstart + memsize, PML4_REACH);
-       nptp = npml4;
-
-       npml3 = DIV_ROUND_UP(memstart + memsize, PML3_REACH);
-       nptp += npml3;
-
-       /* and 1 for each 2 MiB of memory */
-       npml2 = DIV_ROUND_UP(memstart + memsize, PML2_REACH);
-       nptp += npml2;
-
-       fprintf(stderr,
-               "Memstart is %llx, memsize is %llx, memstart + memsize is %llx; ",
-               memstart, memsize, memstart + memsize);
-       fprintf(stderr, " %d pml4 %d pml3 %d pml2\n",
-               npml4, npml3, npml2);
-
-       /* Place these page tables right after VM memory. We
-        * used to use posix_memalign but that puts them
-        * outside EPT-accessible space on some CPUs. */
-       p512 = mmap((void *)memstart + memsize, nptp * 4096, PROT_READ | PROT_WRITE,
-                    MAP_POPULATE | MAP_ANONYMOUS, -1, 0);
-       if (p512 == MAP_FAILED) {
-               perror("page table page alloc");
-               exit(1);
-       }
-       p1 = &p512[npml4];
-       p2m = &p1[npml3];
-
-       /* Set up a 1:1 ("identity") page mapping from guest virtual
-        * to guest physical using the (host virtual)
-        * `kerneladdress`. This mapping may be used for only a short
-        * time, until the guest sets up its own page tables. Be aware
-        * that the values stored in the table are physical addresses.
-        * This is subtle and mistakes are easily disguised due to the
-        * identity mapping, so take care when manipulating these
-        * mappings. */
-
-       p2m->pte[PML2(0)] = (uint64_t)0 | PTE_KERN_RW | PTE_PS;
-
-       fprintf(stderr, "Map %p for %zu bytes\n", memstart, memsize);
-       for (uintptr_t p4 = memstart, i4 = PML4(p4);
-                p4 < memstart + memsize && i4 < NPTENTRIES;
-            p4 = ROUNDUP(p4 + 1, PML4_PTE_REACH), p1++, i4++) {
-               p512->pte[PML4(p4)] = (uint64_t)p1 | PTE_KERN_RW;
-               if (debug)
-                       fprintf(stderr, "l4@%p: %p set index 0x%x to 0x%llx\n",
-                                       &p512->pte[PML4(p4)],
-                                       p4, PML4(p4), p512->pte[PML4(p4)]);
-               for (uintptr_t p3 = p4, i3 = PML3(p3);
-                        p3 < memstart + memsize && i3 < NPTENTRIES;
-                    p3 = ROUNDUP(p3 + 1, PML3_PTE_REACH), p2m++, i3++) {
-                       p1->pte[PML3(p3)] = (uint64_t)p2m | PTE_KERN_RW;
-                       if (debug)
-                               fprintf(stderr, "\tl3@%p: %p set index 0x%x to 0x%llx\n",
-                                               &p1->pte[PML3(p3)],
-                                               p3, PML3(p3), p1->pte[PML3(p3)]);
-                       for (uintptr_t p2 = p3, i2 = PML2(p2);
-                                p2 < memstart + memsize && i2 < NPTENTRIES;
-                            p2 += PML2_PTE_REACH, i2++) {
-                               p2m->pte[PML2(p2)] = (uint64_t)p2 | PTE_KERN_RW | PTE_PS;
-                               if (debug)
-                                       fprintf(stderr, "\t\tl2@%p: %p set index 0x%x to 0x%llx\n",
-                                                       &p2m->pte[PML2(p2)],
-                                                       p2, PML2(p2), p2m->pte[PML2(p2)]);
-                       }
-               }
-
-       }
-
+       cr3 = setup_paging(memstart, memsize, debug);
        vmm_run_task(vm, timer_thread, 0);
 
        vm_tf = gth_to_vmtf(vm->gths[0]);
-       vm_tf->tf_cr3 = (uint64_t) p512;
+       vm_tf->tf_cr3 = (uint64_t) cr3;
        vm_tf->tf_rip = entry;
        vm_tf->tf_rsp = stack;
        vm_tf->tf_rsi = (uint64_t) bp;
        vm->up_gpcs = 1;
        fprintf(stderr, "Start guest: cr3 %p rip %p stack %p\n",
-               p512, entry, stack);
+               cr3, entry, stack);
        start_guest_thread(vm->gths[0]);
 
        uthread_sleep_forever();
index 000feae..47b8c70 100644 (file)
@@ -116,3 +116,5 @@ void *init_e820map(struct boot_params *bp,
                    unsigned long long memsize);
 void checkmemaligned(unsigned long long memstart, unsigned long long memsize);
 void mmap_memory(unsigned long long memstart, unsigned long long memsize);
+void *setup_paging(unsigned long long memstart, unsigned long long memsize,
+                   bool debug);
index 74c3b3a..518f697 100644 (file)
@@ -4,34 +4,11 @@
  * Memory, paging, e820, bootparams and other helpers */
 
 #include <stdio.h>
-#include <pthread.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <parlib/arch/arch.h>
-#include <parlib/ros_debug.h>
-#include <unistd.h>
-#include <errno.h>
-#include <dirent.h>
 #include <stdlib.h>
-#include <string.h>
-#include <ros/syscall.h>
 #include <sys/mman.h>
-#include <vmm/vmm.h>
-#include <vmm/acpi/acpi.h>
 #include <ros/arch/mmu.h>
-#include <ros/arch/membar.h>
-#include <ros/vmm.h>
-#include <parlib/uthread.h>
 #include <vmm/linux_bootparam.h>
-#include <getopt.h>
-
-#include <vmm/sched.h>
-#include <vmm/net.h>
-#include <sys/eventfd.h>
-#include <sys/uio.h>
-#include <sys/param.h>
-#include <parlib/opts.h>
+#include <vmm/vmm.h>
 
 #define ALIGNED(p, a)  (!(((uintptr_t)(p)) & ((a)-1)))
 
diff --git a/user/vmm/pagetables.c b/user/vmm/pagetables.c
new file mode 100644 (file)
index 0000000..2d20ca6
--- /dev/null
@@ -0,0 +1,103 @@
+/* Copyright (c) 2017 Google Inc.
+ * See LICENSE for details.
+ *
+ * Memory, paging, e820, bootparams and other helpers */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <ros/arch/mmu.h>
+#include <vmm/vmm.h>
+
+typedef struct {
+       uint64_t pte[512];
+} ptp;
+
+void *setup_paging(unsigned long long memstart, unsigned long long memsize,
+                                  bool debug)
+{
+       ptp *p512, *p1, *p2m;
+       int nptp, npml4, npml3, npml2;
+
+       /* This test is redundant when booting kernels, as it is also
+        * performed in memory(), but not all users call that function,
+        * hence we must do it here too. */
+       checkmemaligned(memstart, memsize);
+
+       /* How many page table pages do we need?  We conservatively
+        * assume that we are in low memory, and hence assume a
+        * 0-based range.  Note that in many cases, kernels will
+        * immediately set up their own map. But for "dune" like
+        * applications, it's necessary. Note also that in most cases,
+        * the total number of pages will be < 16 or so. */
+       npml4 = DIV_ROUND_UP(memstart + memsize, PML4_REACH);
+       nptp = npml4;
+
+       npml3 = DIV_ROUND_UP(memstart + memsize, PML3_REACH);
+       nptp += npml3;
+
+       /* and 1 for each 2 MiB of memory */
+       npml2 = DIV_ROUND_UP(memstart + memsize, PML2_REACH);
+       nptp += npml2;
+
+       fprintf(stderr,
+               "Memstart is %llx, memsize is %llx, memstart + memsize is %llx; ",
+               memstart, memsize, memstart + memsize);
+       fprintf(stderr, " %d pml4 %d pml3 %d pml2\n",
+               npml4, npml3, npml2);
+
+       /* Place these page tables right after VM memory. We
+        * used to use posix_memalign but that puts them
+        * outside EPT-accessible space on some CPUs. */
+       p512 = mmap((void *)memstart + memsize, nptp * 4096, PROT_READ | PROT_WRITE,
+                    MAP_POPULATE | MAP_ANONYMOUS, -1, 0);
+       if (p512 == MAP_FAILED) {
+               perror("page table page alloc");
+               exit(1);
+       }
+       p1 = &p512[npml4];
+       p2m = &p1[npml3];
+
+       /* Set up a 1:1 ("identity") page mapping from guest virtual
+        * to guest physical using the (host virtual)
+        * `kerneladdress`. This mapping may be used for only a short
+        * time, until the guest sets up its own page tables. Be aware
+        * that the values stored in the table are physical addresses.
+        * This is subtle and mistakes are easily disguised due to the
+        * identity mapping, so take care when manipulating these
+        * mappings. */
+
+       p2m->pte[PML2(0)] = (uint64_t)0 | PTE_KERN_RW | PTE_PS;
+
+       fprintf(stderr, "Map %p for %zu bytes\n", memstart, memsize);
+       for (uintptr_t p4 = memstart, i4 = PML4(p4);
+                p4 < memstart + memsize && i4 < NPTENTRIES;
+            p4 = ROUNDUP(p4 + 1, PML4_PTE_REACH), p1++, i4++) {
+               p512->pte[PML4(p4)] = (uint64_t)p1 | PTE_KERN_RW;
+               if (debug)
+                       fprintf(stderr, "l4@%p: %p set index 0x%x to 0x%llx\n",
+                                       &p512->pte[PML4(p4)],
+                                       p4, PML4(p4), p512->pte[PML4(p4)]);
+               for (uintptr_t p3 = p4, i3 = PML3(p3);
+                        p3 < memstart + memsize && i3 < NPTENTRIES;
+                    p3 = ROUNDUP(p3 + 1, PML3_PTE_REACH), p2m++, i3++) {
+                       p1->pte[PML3(p3)] = (uint64_t)p2m | PTE_KERN_RW;
+                       if (debug)
+                               fprintf(stderr, "\tl3@%p: %p set index 0x%x to 0x%llx\n",
+                                               &p1->pte[PML3(p3)],
+                                               p3, PML3(p3), p1->pte[PML3(p3)]);
+                       for (uintptr_t p2 = p3, i2 = PML2(p2);
+                                p2 < memstart + memsize && i2 < NPTENTRIES;
+                            p2 += PML2_PTE_REACH, i2++) {
+                               p2m->pte[PML2(p2)] = (uint64_t)p2 | PTE_KERN_RW | PTE_PS;
+                               if (debug)
+                                       fprintf(stderr, "\t\tl2@%p: %p set index 0x%x to 0x%llx\n",
+                                                       &p2m->pte[PML2(p2)],
+                                                       p2, PML2(p2), p2m->pte[PML2(p2)]);
+                       }
+               }
+
+       }
+
+       return (void *)p512;
+}