vmrunkernel: get the page table setup right
authorRonald G. Minnich <rminnich@gmail.com>
Fri, 21 Apr 2017 00:11:55 +0000 (20:11 -0400)
committerBarret Rhoden <brho@cs.berkeley.edu>
Fri, 21 Apr 2017 15:54:46 +0000 (11:54 -0400)
I screwed this up so many times, maybe this time it's right.
Tested on 3 different memory sizes with weird alignments.

I've added a new check, checkmemaligned, which ensures
that memstart and memsize are 2m aligned.

This check needs to be separate from the memory
function as some environments may not call
memory() but still need to check alignment.

Change-Id: Ie7b8e324683f0415bd8d5d078fe3ff29a04a515e
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

index 45ddb8b..e84b344 100644 (file)
@@ -900,29 +900,32 @@ int main(int argc, char **argv)
         * mappings. */
 
        p2m->pte[PML2(0)] = (uint64_t)0 | PTE_KERN_RW | PTE_PS;
-       memsize = GiB;
+
        fprintf(stderr, "Map %p for %zu bytes\n", memstart, memsize);
-       for (uintptr_t p4 = memstart; p4 < memstart + memsize;
-            p4 += PML4_PTE_REACH, p1++) {
+       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; p3 < memstart + memsize;
-                    p3 += PML3_PTE_REACH, p2m++) {
+                                       &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; p2 < memstart + memsize;
-                            p2 += PML2_PTE_REACH) {
+                                               &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)]);
+                                                       &p2m->pte[PML2(p2)],
+                                                       p2, PML2(p2), p2m->pte[PML2(p2)]);
                        }
                }
 
index d57daaa..000feae 100644 (file)
@@ -114,4 +114,5 @@ static struct virtual_machine *get_my_vm(void)
 void *init_e820map(struct boot_params *bp,
                    unsigned long long memstart,
                    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);
index 40e980f..74c3b3a 100644 (file)
@@ -33,6 +33,8 @@
 #include <sys/param.h>
 #include <parlib/opts.h>
 
+#define ALIGNED(p, a)  (!(((uintptr_t)(p)) & ((a)-1)))
+
 static char *entrynames[] = {
        [E820_RAM] "E820_RAM",
        [E820_RESERVED] "E820_RESERVED",
@@ -105,10 +107,25 @@ void *init_e820map(struct boot_params *bp,
        return (void *)bp + PGSIZE;
 }
 
+/* checkmemaligned verifies alignment attributes of your memory space.
+ * It terminates your process with extreme prejudice if they are
+ * incorrect in some way. */
+void checkmemaligned(unsigned long long memstart, unsigned long long memsize)
+{
+       if (!ALIGNED(memstart, PML1_REACH))
+               errx(1, "memstart (%#x) wrong: must be aligned to %#x",
+                     memstart, PML1_REACH);
+       if (!ALIGNED(memsize, PML1_REACH))
+               errx(1, "memsize (%#x) wrong: must be aligned to %#x",
+                     memsize, PML1_REACH);
+}
+
 // memory allocates memory for the VM. It's a complicated mess because of the
 // break for APIC and other things. We just go ahead and leave the region from
 // RESERVED to _4GiB for that.  The memory is either split, all low, or all
-// high.
+// high. This code is designed for a kernel. Dune-style code does not need it
+// as it does not have the RESERVED restrictions. Dune-style code can use this,
+// however, by setting memstart to 4 GiB.
 void mmap_memory(unsigned long long memstart, unsigned long long memsize)
 {
        void *r1, *r2;
@@ -116,6 +133,7 @@ void mmap_memory(unsigned long long memstart, unsigned long long memsize)
 
        // Let's do some minimal validation, so we don't drive
        // people crazy.
+       checkmemaligned(memstart, memsize);
        if ((memstart >= RESERVED) && (memstart < _4GiB))
                errx(1, "memstart (%#x) wrong: must be < %#x or >= %#x\n",
                     memstart, RESERVED, _4GiB);