lguest: Encapsulate Guest memory ready for dealing with other Guests.

We currently keep Guest memory pointer and size in globals.  We move
this into a structure and explicitly hand that to to_guest_phys() and
from_guest_phys() so we can deal with other Guests' memory.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
---
 Documentation/lguest/lguest.c |   92 ++++++++++++++++++++++--------------------
 1 file changed, 50 insertions(+), 42 deletions(-)

diff -r f4116cabcded Documentation/lguest/lguest.c
--- a/Documentation/lguest/lguest.c	Wed Aug 13 11:49:24 2008 +1000
+++ b/Documentation/lguest/lguest.c	Wed Aug 13 11:49:31 2008 +1000
@@ -83,10 +83,19 @@ struct {
 	int lguest_fd;
 } waker_fds;
 
-/* The pointer to the start of guest memory. */
-static void *guest_base;
-/* The maximum guest physical address allowed, and maximum possible. */
-static unsigned long guest_limit, guest_max;
+struct guest_memory {
+	/* The pointer to the start of guest memory. */
+	void *base;
+	/* The maximum guest physical address allowed. */
+	unsigned long limit;
+};
+
+/* The maximum possible page for the guest. */
+static unsigned long guest_max;
+
+/* This Guest's memory. */
+static struct guest_memory gmem;
+
 /* The pipe for signal hander to write to. */
 static int timeoutpipe[2];
 static unsigned int timeout_usec = 500;
@@ -259,20 +268,19 @@ static u8 *get_feature_bits(struct devic
  * will get you through this section.  Or, maybe not.
  *
  * The Launcher sets up a big chunk of memory to be the Guest's "physical"
- * memory and stores it in "guest_base".  In other words, Guest physical ==
- * Launcher virtual with an offset.
+ * memory.  In other words, Guest physical == Launcher virtual with an offset.
  *
  * This can be tough to get your head around, but usually it just means that we
  * use these trivial conversion functions when the Guest gives us it's
  * "physical" addresses: */
-static void *from_guest_phys(unsigned long addr)
+static void *from_guest_phys(struct guest_memory *mem, unsigned long addr)
 {
-	return guest_base + addr;
+	return mem->base + addr;
 }
 
-static unsigned long to_guest_phys(const void *addr)
+static unsigned long to_guest_phys(struct guest_memory *mem, const void *addr)
 {
-	return (addr - guest_base);
+	return (addr - mem->base);
 }
 
 /*L:130
@@ -308,10 +316,10 @@ static void *map_zeroed_pages(unsigned i
 /* Get some more pages for a device. */
 static void *get_pages(unsigned int num)
 {
-	void *addr = from_guest_phys(guest_limit);
+	void *addr = from_guest_phys(&gmem, gmem.limit);
 
-	guest_limit += num * getpagesize();
-	if (guest_limit > guest_max)
+	gmem.limit += num * getpagesize();
+	if (gmem.limit > guest_max)
 		errx(1, "Not enough memory for devices");
 	return addr;
 }
@@ -383,7 +391,7 @@ static unsigned long map_elf(int elf_fd,
 			i, phdr[i].p_memsz, (void *)phdr[i].p_paddr);
 
 		/* We map this section of the file at its physical address. */
-		map_at(elf_fd, from_guest_phys(phdr[i].p_paddr),
+		map_at(elf_fd, from_guest_phys(&gmem, phdr[i].p_paddr),
 		       phdr[i].p_offset, phdr[i].p_filesz);
 	}
 
@@ -403,7 +411,7 @@ static unsigned long load_bzimage(int fd
 	struct boot_params boot;
 	int r;
 	/* Modern bzImages get loaded at 1M. */
-	void *p = from_guest_phys(0x100000);
+	void *p = from_guest_phys(&gmem, 0x100000);
 
 	/* Go back to the start of the file and read the header.  It should be
 	 * a Linux boot header (see Documentation/i386/boot.txt) */
@@ -476,7 +484,7 @@ static unsigned long load_initrd(const c
 	/* We map the initrd at the top of memory, but mmap wants it to be
 	 * page-aligned, so we round the size up for that. */
 	len = page_align(st.st_size);
-	map_at(ifd, from_guest_phys(mem - len), 0, st.st_size);
+	map_at(ifd, from_guest_phys(&gmem, mem - len), 0, st.st_size);
 	/* Once a file is mapped, you can close the file descriptor.  It's a
 	 * little odd, but quite useful. */
 	close(ifd);
@@ -505,7 +513,7 @@ static unsigned long setup_pagetables(un
 	linear_pages = (mapped_pages + ptes_per_page-1)/ptes_per_page;
 
 	/* We put the toplevel page directory page at the top of memory. */
-	pgdir = from_guest_phys(mem) - initrd_size - getpagesize();
+	pgdir = from_guest_phys(&gmem, mem) - initrd_size - getpagesize();
 
 	/* Now we use the next linear_pages pages as pte pages */
 	linear = (void *)pgdir - linear_pages*getpagesize();
@@ -519,16 +527,16 @@ static unsigned long setup_pagetables(un
 	/* The top level points to the linear page table pages above. */
 	for (i = 0; i < mapped_pages; i += ptes_per_page) {
 		pgdir[i/ptes_per_page]
-			= ((to_guest_phys(linear) + i*sizeof(void *))
+			= ((to_guest_phys(&gmem, linear) + i*sizeof(void *))
 			   | PAGE_PRESENT);
 	}
 
 	verbose("Linear mapping of %u pages in %u pte pages at %#lx\n",
-		mapped_pages, linear_pages, to_guest_phys(linear));
+		mapped_pages, linear_pages, to_guest_phys(&gmem, linear));
 
 	/* We return the top level (guest-physical) address: the kernel needs
 	 * to know where it is. */
-	return to_guest_phys(pgdir);
+	return to_guest_phys(&gmem, pgdir);
 }
 /*:*/
 
@@ -557,12 +565,12 @@ static int tell_kernel(unsigned long pgd
 static int tell_kernel(unsigned long pgdir, unsigned long start)
 {
 	unsigned long args[] = { LHREQ_INITIALIZE,
-				 (unsigned long)guest_base,
-				 guest_limit / getpagesize(), pgdir, start };
+				 (unsigned long)gmem.base,
+				 gmem.limit / getpagesize(), pgdir, start };
 	int fd;
 
 	verbose("Guest: %p - %p (%#lx)\n",
-		guest_base, guest_base + guest_limit, guest_limit);
+		gmem.base, gmem.base + gmem.limit, gmem.limit);
 	fd = open_or_die("/dev/lguest", O_RDWR);
 	if (write(fd, args, sizeof(args)) < 0)
 		err(1, "Writing to /dev/lguest");
@@ -656,18 +664,18 @@ static void setup_waker(int lguest_fd)
  * if something funny is going on:
  */
 static void *_check_pointer(unsigned long addr, unsigned int size,
-			    unsigned int line)
+			    struct guest_memory *mem, unsigned int line)
 {
 	/* We have to separately check addr and addr+size, because size could
 	 * be huge and addr + size might wrap around. */
-	if (addr >= guest_limit || addr + size >= guest_limit)
+	if (addr >= mem->limit || addr + size >= mem->limit)
 		errx(1, "%s:%i: Invalid address %#lx", __FILE__, line, addr);
 	/* We return a pointer for the caller's convenience, now we know it's
 	 * safe to use. */
-	return from_guest_phys(addr);
+	return from_guest_phys(mem, addr);
 }
 /* A macro which transparently hands the line number to the real function. */
-#define check_pointer(addr,size) _check_pointer(addr, size, __LINE__)
+#define check_pointer(mem, addr, size) _check_pointer(addr, size, mem, __LINE__)
 
 /* Each buffer in the virtqueues is actually a chain of descriptors.  This
  * function returns the next descriptor in the chain, or vq->vring.num if we're
@@ -732,7 +740,7 @@ static unsigned get_vq_desc(struct virtq
 		/* Grab the first descriptor, and check it's OK. */
 		iov[*out_num + *in_num].iov_len = vq->vring.desc[i].len;
 		iov[*out_num + *in_num].iov_base
-			= check_pointer(vq->vring.desc[i].addr,
+			= check_pointer(&gmem, vq->vring.desc[i].addr,
 					vq->vring.desc[i].len);
 		/* If this is an input descriptor, increment that count. */
 		if (vq->vring.desc[i].flags & VRING_DESC_F_WRITE)
@@ -1125,7 +1133,7 @@ static void handle_output(int fd, unsign
 	/* Check each device and virtqueue. */
 	for (i = devices.dev; i; i = i->next) {
 		/* Notifications to device descriptors update device status. */
-		if (from_guest_phys(addr) == i->desc) {
+		if (from_guest_phys(&gmem, addr) == i->desc) {
 			update_device_status(i);
 			return;
 		}
@@ -1152,11 +1160,11 @@ static void handle_output(int fd, unsign
 
 	/* Early console write is done using notify on a nul-terminated string
 	 * in Guest memory. */
-	if (addr >= guest_limit)
+	if (addr >= gmem.limit)
 		errx(1, "Bad NOTIFY %#lx", addr);
 
-	write(STDOUT_FILENO, from_guest_phys(addr),
-	      strnlen(from_guest_phys(addr), guest_limit - addr));
+	write(STDOUT_FILENO, from_guest_phys(&gmem, addr),
+	      strnlen(from_guest_phys(&gmem, addr), gmem.limit - addr));
 }
 
 static void handle_timeout(int fd)
@@ -1284,7 +1292,7 @@ static void add_virtqueue(struct device 
 	/* Initialize the configuration. */
 	vq->config.num = num_descs;
 	vq->config.irq = devices.next_irq++;
-	vq->config.pfn = to_guest_phys(p) / getpagesize();
+	vq->config.pfn = to_guest_phys(&gmem, p) / getpagesize();
 
 	/* Initialize the vring. */
 	vring_init(&vq->vring, num_descs, p, getpagesize());
@@ -1298,7 +1306,7 @@ static void add_virtqueue(struct device 
 	devices.nextdesc += sizeof(vq->config);
 	dev->desc->num_vq++;
 
-	verbose("Virtqueue page %#lx\n", to_guest_phys(p));
+	verbose("Virtqueue page %#lx\n", to_guest_phys(&gmem, p));
 
 	/* Add to tail of list, so dev->vq is first vq, dev->vq->next is
 	 * second.  */
@@ -1598,8 +1606,8 @@ static int map_vring(struct vring *vr)
 	memset(vr->desc, 0, vring_size(vr->num, getpagesize()));
 
 	/* Set offset & limit. */
-	if (ioctl(fd, VRINGSETBASE, guest_base) != 0
-	    || ioctl(fd, VRINGSETLIMIT, guest_limit) != 0)
+	if (ioctl(fd, VRINGSETBASE, gmem.base) != 0
+	    || ioctl(fd, VRINGSETLIMIT, gmem.limit) != 0)
 		err(1, "Setting vring offset and limit");
 
 	return fd;
@@ -2128,9 +2136,9 @@ int main(int argc, char *argv[])
 			 * guest-physical memory range.  This fills it with 0,
 			 * and ensures that the Guest won't be killed when it
 			 * tries to access it. */
-			guest_base = map_zeroed_pages(mem / getpagesize()
-						      + DEVICE_PAGES);
-			guest_limit = mem;
+			gmem.base = map_zeroed_pages(mem / getpagesize()
+						     + DEVICE_PAGES);
+			gmem.limit = mem;
 			guest_max = mem + DEVICE_PAGES*getpagesize();
 			devices.descpage = devices.nextdesc = get_pages(1);
 			break;
@@ -2168,7 +2176,7 @@ int main(int argc, char *argv[])
 	if (optind + 2 > argc)
 		usage();
 
-	verbose("Guest base is at %p\n", guest_base);
+	verbose("Guest base is at %p\n", gmem.base);
 
 	/* We always have a console device */
 	setup_console();
@@ -2180,7 +2188,7 @@ int main(int argc, char *argv[])
 	start = load_kernel(open_or_die(argv[optind+1], O_RDONLY));
 
 	/* Boot information is stashed at physical address 0 */
-	boot = from_guest_phys(0);
+	boot = from_guest_phys(&gmem, 0);
 
 	/* Map the initrd image if requested (at top of physical memory) */
 	if (initrd_name) {
@@ -2202,7 +2210,7 @@ int main(int argc, char *argv[])
 	boot->e820_map[0] = ((struct e820entry) { 0, mem, E820_RAM });
 	/* The boot header contains a command line pointer: we put the command
 	 * line after the boot header. */
-	boot->hdr.cmd_line_ptr = to_guest_phys(boot + 1);
+	boot->hdr.cmd_line_ptr = to_guest_phys(&gmem, boot + 1);
 	/* We use a simple helper to copy the arguments separated by spaces. */
 	concat((char *)(boot + 1), argv+optind+2);
 
