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,