/*P:100 This is the Launcher code, a simple program which lays out the
  * "physical" memory for the new Guest by mapping the kernel image and the
  * virtual devices, then reads repeatedly from /dev/lguest to run the Guest.
- *
- * The only trick: the Makefile links it at a high address so it will be clear
- * of the guest memory region.  It means that each Guest cannot have more than
- * about 2.5G of memory on a normally configured Host. :*/
+:*/
 #define _LARGEFILE64_SOURCE
 #define _GNU_SOURCE
 #include <stdio.h>
 #ifndef SIOCBRADDIF
 #define SIOCBRADDIF    0x89a2          /* add interface to bridge      */
 #endif
+/* We can have up to 256 pages for devices. */
+#define DEVICE_PAGES 256
 
 /*L:120 verbose is both a global flag and a macro.  The C preprocessor allows
  * this, and although I wouldn't recommend it, it works quite nicely here. */
 
 /* The pipe to send commands to the waker process */
 static int waker_fd;
-/* The top of guest physical memory. */
-static u32 top;
+/* 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;
 
 /* This is our list of devices. */
 struct device_list
        void *priv;
 };
 
+/*L:100 The Launcher code itself takes us out into userspace, that scary place
+ * where pointers run wild and free!  Unfortunately, like most userspace
+ * programs, it's quite boring (which is why everyone likes to hack on the
+ * kernel!).  Perhaps if you make up an Lguest Drinking Game at this point, it
+ * 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.
+ *
+ * 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)
+{
+       return guest_base + addr;
+}
+
+static unsigned long to_guest_phys(const void *addr)
+{
+       return (addr - guest_base);
+}
+
 /*L:130
  * Loading the Kernel.
  *
        return fd;
 }
 
-/* map_zeroed_pages() takes a (page-aligned) address and a number of pages. */
-static void *map_zeroed_pages(unsigned long addr, unsigned int num)
+/* map_zeroed_pages() takes a number of pages. */
+static void *map_zeroed_pages(unsigned int num)
 {
-       /* We cache the /dev/zero file-descriptor so we only open it once. */
-       static int fd = -1;
-
-       if (fd == -1)
-               fd = open_or_die("/dev/zero", O_RDONLY);
+       int fd = open_or_die("/dev/zero", O_RDONLY);
+       void *addr;
 
        /* We use a private mapping (ie. if we write to the page, it will be
-        * copied), and obviously we insist that it be mapped where we ask. */
-       if (mmap((void *)addr, getpagesize() * num,
-                PROT_READ|PROT_WRITE|PROT_EXEC, MAP_FIXED|MAP_PRIVATE, fd, 0)
-           != (void *)addr)
-               err(1, "Mmaping %u pages of /dev/zero @%p", num, (void *)addr);
-
-       /* Returning the address is just a courtesy: can simplify callers. */
-       return (void *)addr;
+        * copied). */
+       addr = mmap(NULL, getpagesize() * num,
+                   PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE, fd, 0);
+       if (addr == MAP_FAILED)
+               err(1, "Mmaping %u pages of /dev/zero", num);
+
+       return addr;
+}
+
+/* Get some more pages for a device. */
+static void *get_pages(unsigned int num)
+{
+       void *addr = from_guest_phys(guest_limit);
+
+       guest_limit += num * getpagesize();
+       if (guest_limit > guest_max)
+               errx(1, "Not enough memory for devices");
+       return addr;
 }
 
 /* To find out where to start we look for the magic Guest string, which marks
  * the code we see in lguest_asm.S.  This is a hack which we are currently
  * plotting to replace with the normal Linux entry point. */
-static unsigned long entry_point(void *start, void *end,
+static unsigned long entry_point(const void *start, const void *end,
                                 unsigned long page_offset)
 {
-       void *p;
+       const void *p;
 
        /* The scan gives us the physical starting address.  We want the
         * virtual address in this case, and fortunately, we already figured
         * "page_offset". */
        for (p = start; p < end; p++)
                if (memcmp(p, "GenuineLguest", strlen("GenuineLguest")) == 0)
-                       return (long)p + strlen("GenuineLguest") + page_offset;
+                       return to_guest_phys(p + strlen("GenuineLguest"))
+                               + page_offset;
 
        errx(1, "Is this image a genuine lguest?");
 }
 static unsigned long map_elf(int elf_fd, const Elf32_Ehdr *ehdr,
                             unsigned long *page_offset)
 {
+       void *start = (void *)-1, *end = NULL;
        Elf32_Phdr phdr[ehdr->e_phnum];
        unsigned int i;
-       unsigned long start = -1UL, end = 0;
 
        /* Sanity checks on the main ELF header: an x86 executable with a
         * reasonable number of correctly-sized program headers. */
 
                /* We track the first and last address we mapped, so we can
                 * tell entry_point() where to scan. */
-               if (phdr[i].p_paddr < start)
-                       start = phdr[i].p_paddr;
-               if (phdr[i].p_paddr + phdr[i].p_filesz > end)
-                       end = phdr[i].p_paddr + phdr[i].p_filesz;
+               if (from_guest_phys(phdr[i].p_paddr) < start)
+                       start = from_guest_phys(phdr[i].p_paddr);
+               if (from_guest_phys(phdr[i].p_paddr) + phdr[i].p_filesz > end)
+                       end=from_guest_phys(phdr[i].p_paddr)+phdr[i].p_filesz;
 
                /* We map this section of the file at its physical address. */
-               map_at(elf_fd, (void *)phdr[i].p_paddr,
+               map_at(elf_fd, from_guest_phys(phdr[i].p_paddr),
                       phdr[i].p_offset, phdr[i].p_filesz);
        }
 
-       return entry_point((void *)start, (void *)end, *page_offset);
+       return entry_point(start, end, *page_offset);
 }
 
 /*L:170 Prepare to be SHOCKED and AMAZED.  And possibly a trifle nauseated.
         * actually configurable as CONFIG_PHYSICAL_START, but as the comment
         * there says, "Don't change this unless you know what you are doing".
         * Indeed. */
-       void *img = (void *)0x100000;
+       void *img = from_guest_phys(0x100000);
 
        /* gzdopen takes our file descriptor (carefully placed at the start of
         * the GZIP header we found) and returns a gzFile. */
        /* 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, (void *)mem - len, 0, st.st_size);
+       map_at(ifd, from_guest_phys(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);
        return len;
 }
 
-/* Once we know how much memory we have, and the address the Guest kernel
- * expects, we can construct simple linear page tables which will get the Guest
- * far enough into the boot to create its own.
+/* Once we know the address the Guest kernel expects, we can construct simple
+ * linear page tables for all of memory which will get the Guest far enough
+ * into the boot to create its own.
  *
  * We lay them out of the way, just below the initrd (which is why we need to
  * know its size). */
        linear_pages = (mapped_pages + ptes_per_page-1)/ptes_per_page;
 
        /* We put the toplevel page directory page at the top of memory. */
-       pgdir = (void *)mem - initrd_size - getpagesize();
+       pgdir = from_guest_phys(mem) - initrd_size - getpagesize();
 
        /* Now we use the next linear_pages pages as pte pages */
        linear = (void *)pgdir - linear_pages*getpagesize();
         * continue from there. */
        for (i = 0; i < mapped_pages; i += ptes_per_page) {
                pgdir[(i + page_offset/getpagesize())/ptes_per_page]
-                       = (((u32)linear + i*sizeof(u32)) | PAGE_PRESENT);
+                       = ((to_guest_phys(linear) + i*sizeof(u32))
+                          | PAGE_PRESENT);
        }
 
-       verbose("Linear mapping of %u pages in %u pte pages at %p\n",
-               mapped_pages, linear_pages, linear);
+       verbose("Linear mapping of %u pages in %u pte pages at %#lx\n",
+               mapped_pages, linear_pages, to_guest_phys(linear));
 
        /* We return the top level (guest-physical) address: the kernel needs
         * to know where it is. */
-       return (unsigned long)pgdir;
+       return to_guest_phys(pgdir);
 }
 
 /* Simple routine to roll all the commandline arguments together with spaces
 
 /* This is where we actually tell the kernel to initialize the Guest.  We saw
  * the arguments it expects when we looked at initialize() in lguest_user.c:
- * the top physical page to allow, the top level pagetable, the entry point and
- * the page_offset constant for the Guest. */
+ * the base of guest "physical" memory, the top physical page to allow, the
+ * top level pagetable, the entry point and the page_offset constant for the
+ * Guest. */
 static int tell_kernel(u32 pgdir, u32 start, u32 page_offset)
 {
        u32 args[] = { LHREQ_INITIALIZE,
-                      top/getpagesize(), pgdir, start, page_offset };
+                      (unsigned long)guest_base,
+                      guest_limit / getpagesize(),
+                      pgdir, start, page_offset };
        int fd;
 
+       verbose("Guest: %p - %p (%#lx)\n",
+               guest_base, guest_base + guest_limit, guest_limit);
        fd = open_or_die("/dev/lguest", O_RDWR);
        if (write(fd, args, sizeof(args)) < 0)
                err(1, "Writing to /dev/lguest");
 {
        /* We have to separately check addr and addr+size, because size could
         * be huge and addr + size might wrap around. */
-       if (addr >= top || addr + size >= top)
+       if (addr >= guest_limit || addr + size >= guest_limit)
                errx(1, "%s:%i: Invalid address %li", __FILE__, line, addr);
        /* We return a pointer for the caller's convenience, now we know it's
         * safe to use. */
-       return (void *)addr;
+       return from_guest_phys(addr);
 }
 /* A macro which transparently hands the line number to the real function. */
 #define check_pointer(addr,size) _check_pointer(addr, size, __LINE__)
 static u32 *get_dma_buffer(int fd, void *key,
                           struct iovec iov[], unsigned int *num, u32 *irq)
 {
-       u32 buf[] = { LHREQ_GETDMA, (u32)key };
+       u32 buf[] = { LHREQ_GETDMA, to_guest_phys(key) };
        unsigned long udma;
        u32 *res;
 
                        descs[i].features = features;
                        descs[i].num_pages = num_pages;
                        /* If they said the device needs memory, we allocate
-                        * that now, bumping up the top of Guest memory. */
+                        * that now. */
                        if (num_pages) {
-                               map_zeroed_pages(top, num_pages);
-                               descs[i].pfn = top/getpagesize();
-                               top += num_pages*getpagesize();
+                               unsigned long pa;
+                               pa = to_guest_phys(get_pages(num_pages));
+                               descs[i].pfn = pa / getpagesize();
                        }
                        return &descs[i];
                }
        if (handle_input)
                set_fd(dev->fd, devices);
        dev->desc = new_dev_desc(devices->descs, type, features, num_pages);
-       dev->mem = (void *)(dev->desc->pfn * getpagesize());
+       dev->mem = from_guest_phys(dev->desc->pfn * getpagesize());
        dev->handle_input = handle_input;
-       dev->watch_key = (unsigned long)dev->mem + watch_off;
+       dev->watch_key = to_guest_phys(dev->mem) + watch_off;
        dev->handle_output = handle_output;
        return dev;
 }
             "<mem-in-mb> vmlinux [args...]");
 }
 
-/*L:100 The Launcher code itself takes us out into userspace, that scary place
- * where pointers run wild and free!  Unfortunately, like most userspace
- * programs, it's quite boring (which is why everyone like to hack on the
- * kernel!).  Perhaps if you make up an Lguest Drinking Game at this point, it
- * will get you through this section.  Or, maybe not.
- *
- * The Launcher binary sits up high, usually starting at address 0xB8000000.
- * Everything below this is the "physical" memory for the Guest.  For example,
- * if the Guest were to write a "1" at physical address 0, we would see a "1"
- * in the Launcher at "(int *)0".  Guest physical == Launcher virtual.
- *
- * This can be tough to get your head around, but usually it just means that we
- * don't need to do any conversion when the Guest gives us it's "physical"
- * addresses.
- */
+/*L:105 The main routine is where the real work begins: */
 int main(int argc, char *argv[])
 {
        /* Memory, top-level pagetable, code startpoint, PAGE_OFFSET and size
        int i, c, lguest_fd;
        /* The list of Guest devices, based on command line arguments. */
        struct device_list device_list;
-       /* The boot information for the Guest: at guest-physical address 0. */
-       void *boot = (void *)0;
+       /* The boot information for the Guest. */
+       void *boot;
        /* If they specify an initrd file to load. */
        const char *initrd_name = NULL;
 
         * of memory now. */
        for (i = 1; i < argc; i++) {
                if (argv[i][0] != '-') {
-                       mem = top = atoi(argv[i]) * 1024 * 1024;
-                       device_list.descs = map_zeroed_pages(top, 1);
-                       top += getpagesize();
+                       mem = atoi(argv[i]) * 1024 * 1024;
+                       /* We start by mapping anonymous pages over all of
+                        * 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;
+                       guest_max = mem + DEVICE_PAGES*getpagesize();
+                       device_list.descs = get_pages(1);
                        break;
                }
        }
        if (optind + 2 > argc)
                usage();
 
+       verbose("Guest base is at %p\n", guest_base);
+
        /* We always have a console device */
        setup_console(&device_list);
 
-       /* We start by mapping anonymous pages over all of guest-physical
-        * memory range.  This fills it with 0, and ensures that the Guest
-        * won't be killed when it tries to access it. */
-       map_zeroed_pages(0, mem / getpagesize());
-
        /* Now we load the kernel */
        start = load_kernel(open_or_die(argv[optind+1], O_RDONLY),
                            &page_offset);
 
+       /* Boot information is stashed at physical address 0 */
+       boot = from_guest_phys(0);
+
        /* Map the initrd image if requested (at top of physical memory) */
        if (initrd_name) {
                initrd_size = load_initrd(initrd_name, mem);
                = ((struct e820entry) { 0, mem, E820_RAM });
        /* The boot header contains a command line pointer: we put the command
         * line after the boot header (at address 4096) */
-       *(void **)(boot + 0x228) = boot + 4096;
+       *(u32 *)(boot + 0x228) = 4096;
        concat(boot + 4096, argv+optind+2);
 
        /* The guest type value of "1" tells the Guest it's under lguest. */
 
  * Dealing With Guest Memory.
  *
  * When the Guest gives us (what it thinks is) a physical address, we can use
- * the normal copy_from_user() & copy_to_user() on that address: remember,
- * Guest physical == Launcher virtual.
+ * the normal copy_from_user() & copy_to_user() on the corresponding place in
+ * the memory region allocated by the Launcher.
  *
  * But we can't trust the Guest: it might be trying to access the Launcher
  * code.  We have to check that the range is below the pfn_limit the Launcher
 
        /* Don't let them access lguest binary. */
        if (!lguest_address_ok(lg, addr, sizeof(val))
-           || get_user(val, (u32 __user *)addr) != 0)
-               kill_guest(lg, "bad read address %#lx", addr);
+           || get_user(val, (u32 *)(lg->mem_base + addr)) != 0)
+               kill_guest(lg, "bad read address %#lx: pfn_limit=%u membase=%p", addr, lg->pfn_limit, lg->mem_base);
        return val;
 }
 
 void lgwrite_u32(struct lguest *lg, unsigned long addr, u32 val)
 {
        if (!lguest_address_ok(lg, addr, sizeof(val))
-           || put_user(val, (u32 __user *)addr) != 0)
+           || put_user(val, (u32 *)(lg->mem_base + addr)) != 0)
                kill_guest(lg, "bad write address %#lx", addr);
 }
 
 void lgread(struct lguest *lg, void *b, unsigned long addr, unsigned bytes)
 {
        if (!lguest_address_ok(lg, addr, bytes)
-           || copy_from_user(b, (void __user *)addr, bytes) != 0) {
+           || copy_from_user(b, lg->mem_base + addr, bytes) != 0) {
                /* copy_from_user should do this, but as we rely on it... */
                memset(b, 0, bytes);
                kill_guest(lg, "bad read address %#lx len %u", addr, bytes);
             unsigned bytes)
 {
        if (!lguest_address_ok(lg, addr, bytes)
-           || copy_to_user((void __user *)addr, b, bytes) != 0)
+           || copy_to_user(lg->mem_base + addr, b, bytes) != 0)
                kill_guest(lg, "bad write address %#lx len %u", addr, bytes);
 }
 /* (end of memory access helper routines) :*/
                         *
                         * Note that if the Guest were really messed up, this
                         * could happen before it's done the INITIALIZE
-                        * hypercall, so lg->lguest_data will be NULL, so
-                        * &lg->lguest_data->cr2 will be address 8.  Writing
-                        * into that address won't hurt the Host at all,
-                        * though. */
-                       if (put_user(cr2, &lg->lguest_data->cr2))
+                        * hypercall, so lg->lguest_data will be NULL */
+                       if (lg->lguest_data
+                           && put_user(cr2, &lg->lguest_data->cr2))
                                kill_guest(lg, "Writing cr2");
                        break;
                case 7: /* We've intercepted a Device Not Available fault. */
 
         * we're doing this. */
        mutex_lock(&lguest_lock);
        down_read(fshared);
-       if (get_futex_key((u32 __user *)ukey, fshared, &key) != 0) {
+       if (get_futex_key(lg->mem_base + ukey, fshared, &key) != 0) {
                kill_guest(lg, "bad dma key %#lx", ukey);
                goto unlock;
        }
                        void *buf, u32 addr, unsigned bytes)
 {
        if (!lguest_address_ok(lg, addr, bytes)
-           || access_process_vm(lg->tsk, addr, buf, bytes, 0) != bytes) {
+           || access_process_vm(lg->tsk, (unsigned long)lg->mem_base + addr,
+                                buf, bytes, 0) != bytes) {
                memset(buf, 0, bytes);
                kill_guest(lg, "bad address in registered DMA struct");
                return 0;
                         const void *buf, unsigned bytes)
 {
        if (!lguest_address_ok(lg, addr, bytes)
-           || (access_process_vm(lg->tsk, addr, (void *)buf, bytes, 1)
-               != bytes)) {
+           || access_process_vm(lg->tsk, (unsigned long)lg->mem_base + addr,
+                                (void *)buf, bytes, 1) != bytes) {
                kill_guest(lg, "bad address writing to registered DMA");
                return 0;
        }
                 * copy_to_user_page(), and some arch's seem to need special
                 * flushes.  x86 is fine. */
                if (copy_from_user(maddr + (dst->addr[di] + dstoff)%PAGE_SIZE,
-                                  (void __user *)src->addr[si], len) != 0) {
+                                  srclg->mem_base+src->addr[si], len) != 0) {
                        /* If a copy failed, it's the source's fault. */
                        kill_guest(srclg, "bad address in sending DMA");
                        totlen = 0;
                 * number of pages.  Note that we're holding the destination's
                 * mmap_sem, as get_user_pages() requires. */
                if (get_user_pages(dstlg->tsk, dstlg->mm,
-                                  dst->addr[i], 1, 1, 1, pages+i, NULL)
+                                  (unsigned long)dstlg->mem_base+dst->addr[i],
+                                  1, 1, 1, pages+i, NULL)
                    != 1) {
                        /* This means the destination gave us a bogus buffer */
                        kill_guest(dstlg, "Error mapping DMA pages");
        mutex_lock(&lguest_lock);
        down_read(fshared);
        /* Get the futex key for the key the Guest gave us */
-       if (get_futex_key((u32 __user *)ukey, fshared, &key) != 0) {
+       if (get_futex_key(lg->mem_base + ukey, fshared, &key) != 0) {
                kill_guest(lg, "bad sending DMA key");
                goto unlock;
        }
 
        /* This can fail if it's not a valid address, or if the address is not
         * divisible by 4 (the futex code needs that, we don't really). */
-       if (get_futex_key((u32 __user *)ukey, fshared, &key) != 0) {
+       if (get_futex_key(lg->mem_base + ukey, fshared, &key) != 0) {
                kill_guest(lg, "bad registered DMA buffer");
                goto unlock;
        }