Change map_memory and setup_paging to use virtual_machine struct The virtual machine struct now contains guest minphys and maxphys addresses. Map_memory can be called multiple times. Setup_page is called with a pointer to the virtual_machine, which sets up the early 1:1 mapping for the entire range of minphys to maxphys. This is essentially what we already did, but now we can call map_memory more than once. While it may seem odd to to map the whole range from minphys to maxphys, it's basically ok: - you rarely call map_memory more than once - the real check is done in the EPT, not the GPT - GPT is replaced by most kernels - in the vthreads case, we will typically start the thread memory at 4G, and there will be no holes in that space So it's probably fine. Change-Id: I48311bea6f7ae102959247ccad3234a85665b187 Signed-off-by: Ronald G. Minnich <rminnich@gmail.com> [ 80 char line fix ] Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
diff --git a/tests/dune/dune.c b/tests/dune/dune.c index 808c90f..78ee960 100644 --- a/tests/dune/dune.c +++ b/tests/dune/dune.c
@@ -436,7 +436,7 @@ exit(1); } - mmap_memory(memstart, memsize); + mmap_memory(&vm, memstart, memsize); if (debug) fprintf(stderr, "mmap guest physical memory at %p for 0x%lx bytes\n",
diff --git a/tests/vmm/vmrunkernel.c b/tests/vmm/vmrunkernel.c index 9680793..ceaa200 100644 --- a/tests/vmm/vmrunkernel.c +++ b/tests/vmm/vmrunkernel.c
@@ -545,7 +545,7 @@ exit(1); } - mmap_memory(memstart, memsize); + mmap_memory(vm, memstart, memsize); entry = load_elf(argv[0], 0); if (entry == 0) { @@ -641,7 +641,7 @@ ret = vmm_init(vm, vmmflags); assert(!ret); - cr3 = setup_paging(memstart, memsize, debug); + cr3 = setup_paging(vm, debug); init_timer_alarms(); vm_tf = gth_to_vmtf(vm->gths[0]);
diff --git a/user/vmm/include/vmm/vmm.h b/user/vmm/include/vmm/vmm.h index 388c2e5..13c673e 100644 --- a/user/vmm/include/vmm/vmm.h +++ b/user/vmm/include/vmm/vmm.h
@@ -62,6 +62,13 @@ uint8_t *low4k; struct virtio_mmio_dev *virtio_mmio_devices[VIRTIO_MMIO_MAX_NUM_DEV]; + /* minimum and maximum physical memory addresses. When we set up the initial + * default page tables we use this range. Note that even if the "physical" + * memory has holes, we'll create PTEs for it. This seems enough for now but + * we shall see. */ + uintptr_t minphys; + uintptr_t maxphys; + /* Default root pointer to use if one is not set in a * guest thread. We expect this to be the common case, * where all guests share a page table. It's not required @@ -118,9 +125,9 @@ 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); -void *setup_paging(unsigned long long memstart, unsigned long long memsize, - bool debug); +void checkmemaligned(uintptr_t memstart, size_t memsize); +void mmap_memory(struct virtual_machine *vm, uintptr_t memstart, + size_t memsize); +void *setup_paging(struct virtual_machine *vm, bool debug); void *setup_biostables(struct virtual_machine *vm, void *a, void *smbiostable);
diff --git a/user/vmm/memory.c b/user/vmm/memory.c index 7469c98..b8593e5 100644 --- a/user/vmm/memory.c +++ b/user/vmm/memory.c
@@ -88,7 +88,7 @@ /* 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) +void checkmemaligned(uintptr_t memstart, size_t memsize) { if (!ALIGNED(memstart, PML1_REACH)) errx(1, "memstart (%#x) wrong: must be aligned to %#x", @@ -103,8 +103,9 @@ // RESERVED to _4GiB for that. The memory is either split, all low, or all // 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) +// however, by setting memstart to 4 GiB. This code can be called multiple +// times with more ranges. It does not check for overlaps. +void mmap_memory(struct virtual_machine *vm, uintptr_t memstart, size_t memsize) { void *r1, *r2; unsigned long r1size = memsize; @@ -135,7 +136,7 @@ exit(1); } if (memstart >= _4GiB) - return; + goto done; } r1 = mmap((void *)memstart, r1size, @@ -146,4 +147,11 @@ memsize, memstart); exit(1); } + +done: + if ((vm->minphys == 0) || (vm->minphys > memstart)) + vm->minphys = memstart; + + if (vm->maxphys < memstart + memsize - 1) + vm->maxphys = memstart + memsize - 1; }
diff --git a/user/vmm/pagetables.c b/user/vmm/pagetables.c index f7da0c5..6a69f89 100644 --- a/user/vmm/pagetables.c +++ b/user/vmm/pagetables.c
@@ -1,7 +1,7 @@ /* Copyright (c) 2017 Google Inc. * See LICENSE for details. * - * Memory, paging, e820, bootparams and other helpers */ + * Set up paging, using the minphys and maxphys in the vm struct. */ #include <stdio.h> #include <stdlib.h> @@ -13,11 +13,12 @@ uint64_t pte[512]; } ptp; -void *setup_paging(unsigned long long memstart, unsigned long long memsize, - bool debug) +void *setup_paging(struct virtual_machine *vm, bool debug) { ptp *p512, *p1, *p2m; int nptp, npml4, npml3, npml2; + uintptr_t memstart = vm->minphys; + size_t memsize = vm->maxphys - vm->minphys + 1; /* This test is redundant when booting kernels, as it is also * performed in memory(), but not all users call that function,