[RFC PATCH 2/5] lguest: Encapsulate Guest memory ready for dealing with other Guests.

Rusty Russell
2008-03-20T06:22:53Z

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-8n+1lVoiYb80n/F98K4Iww@public.gmane.org>
---
Documentation/lguest/lguest.c | 89 +++++++++++++++++++++++-------------------
1 file changed, 49 insertions(+), 40 deletions(-)

diff -r 95558c7d210e Documentation/lguest/lguest.c
--- a/Documentation/lguest/lguest.c Thu Mar 13 14:11:40 2008 +1100
+++ b/Documentation/lguest/lguest.c Thu Mar 13 23:05:35 2008 +1100
@@ -76,10 +76,20 @@ static bool verbose;

/* The pipe to send commands to the waker process */
static int waker_fd;
-/* 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;

/* a per-cpu variable indicating whose vcpu is currently running */
static unsigned int __thread cpu_id;
@@ -207,20 +217,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
@@ -287,10 +296,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;
}
@@ -351,7 +360,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);
}

@@ -371,7 +380,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) */
@@ -444,7 +453,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);
@@ -473,7 +482,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();
@@ -487,16 +496,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);
}
/*:*/

@@ -525,12 +534,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");
@@ -629,18 +638,18 @@ static int 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(&gmem, 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
@@ -702,7 +711,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)
@@ -975,7 +984,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 reset the device. */
- if (from_guest_phys(addr) == i->desc) {
+ if (from_guest_phys(&gmem, addr) == i->desc) {
reset_device(i);
return;
}
@@ -1002,11 +1011,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));
}

/* This is called when the Waker wakes us up: check for incoming file
@@ -1112,7 +1121,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());
@@ -1125,7 +1134,7 @@ static void add_virtqueue(struct device
memcpy(device_config(dev), &vq->config, 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. */
@@ -1731,9 +1740,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 = get_pages(1);
break;
@@ -1765,7 +1774,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();
@@ -1774,7 +1783,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) {
@@ -1796,7 +1805,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);