lguest: comment documentation update.
Rusty Russell [Fri, 28 Mar 2008 16:05:53 +0000 (11:05 -0500)]
Took some cycles to re-read the Lguest Journey end-to-end, fix some
rot and tighten some phrases.

Only comments change.  No new jokes, but a couple of recycled old jokes.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>

13 files changed:
Documentation/lguest/lguest.c
arch/x86/lguest/boot.c
arch/x86/lguest/i386_head.S
drivers/lguest/core.c
drivers/lguest/hypercalls.c
drivers/lguest/interrupts_and_traps.c
drivers/lguest/lguest_device.c
drivers/lguest/lguest_user.c
drivers/lguest/page_tables.c
drivers/lguest/x86/core.c
drivers/lguest/x86/switcher_32.S
include/asm-x86/lguest_hcall.h
include/linux/lguest_launcher.h

index d45c7f6..4c1fc65 100644 (file)
@@ -1,7 +1,7 @@
 /*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.
-:*/
+ * "physical" memory for the new Guest by mapping the kernel image and
+ * the virtual devices, then opens /dev/lguest to tell the kernel
+ * about the Guest and control it. :*/
 #define _LARGEFILE64_SOURCE
 #define _GNU_SOURCE
 #include <stdio.h>
@@ -43,7 +43,7 @@
 #include "linux/virtio_console.h"
 #include "linux/virtio_ring.h"
 #include "asm-x86/bootparam.h"
-/*L:110 We can ignore the 38 include files we need for this program, but I do
+/*L:110 We can ignore the 39 include files we need for this program, but I do
  * want to draw attention to the use of kernel-style types.
  *
  * As Linus said, "C is a Spartan language, and so should your naming be."  I
@@ -320,7 +320,7 @@ static unsigned long map_elf(int elf_fd, const Elf32_Ehdr *ehdr)
                err(1, "Reading program headers");
 
        /* Try all the headers: there are usually only three.  A read-only one,
-        * a read-write one, and a "note" section which isn't loadable. */
+        * a read-write one, and a "note" section which we don't load. */
        for (i = 0; i < ehdr->e_phnum; i++) {
                /* If this isn't a loadable segment, we ignore it */
                if (phdr[i].p_type != PT_LOAD)
@@ -387,7 +387,7 @@ static unsigned long load_kernel(int fd)
        if (memcmp(hdr.e_ident, ELFMAG, SELFMAG) == 0)
                return map_elf(fd, &hdr);
 
-       /* Otherwise we assume it's a bzImage, and try to unpack it */
+       /* Otherwise we assume it's a bzImage, and try to load it. */
        return load_bzimage(fd);
 }
 
@@ -433,12 +433,12 @@ static unsigned long load_initrd(const char *name, unsigned long mem)
        return len;
 }
 
-/* Once we know how much memory we have, we can construct simple linear page
+/* Once we know how much memory we have we can construct simple linear page
  * tables which set virtual == physical 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). */
+ * know its size here). */
 static unsigned long setup_pagetables(unsigned long mem,
                                      unsigned long initrd_size)
 {
@@ -850,7 +850,8 @@ static void handle_console_output(int fd, struct virtqueue *vq)
  *
  * Handling output for network is also simple: we get all the output buffers
  * and write them (ignoring the first element) to this device's file descriptor
- * (stdout). */
+ * (/dev/net/tun).
+ */
 static void handle_net_output(int fd, struct virtqueue *vq)
 {
        unsigned int head, out, in;
@@ -924,7 +925,7 @@ static void enable_fd(int fd, struct virtqueue *vq)
        write(waker_fd, &vq->dev->fd, sizeof(vq->dev->fd));
 }
 
-/* Resetting a device is fairly easy. */
+/* When the Guest asks us to reset a device, it's is fairly easy. */
 static void reset_device(struct device *dev)
 {
        struct virtqueue *vq;
@@ -1003,8 +1004,8 @@ static void handle_input(int fd)
                if (select(devices.max_infd+1, &fds, NULL, NULL, &poll) == 0)
                        break;
 
-               /* Otherwise, call the device(s) which have readable
-                * file descriptors and a method of handling them.  */
+               /* Otherwise, call the device(s) which have readable file
+                * descriptors and a method of handling them.  */
                for (i = devices.dev; i; i = i->next) {
                        if (i->handle_input && FD_ISSET(i->fd, &fds)) {
                                int dev_fd;
@@ -1015,8 +1016,7 @@ static void handle_input(int fd)
                                 * should no longer service it.  Networking and
                                 * console do this when there's no input
                                 * buffers to deliver into.  Console also uses
-                                * it when it discovers that stdin is
-                                * closed. */
+                                * it when it discovers that stdin is closed. */
                                FD_CLR(i->fd, &devices.infds);
                                /* Tell waker to ignore it too, by sending a
                                 * negative fd number (-1, since 0 is a valid
@@ -1033,7 +1033,8 @@ static void handle_input(int fd)
  *
  * All devices need a descriptor so the Guest knows it exists, and a "struct
  * device" so the Launcher can keep track of it.  We have common helper
- * routines to allocate and manage them. */
+ * routines to allocate and manage them.
+ */
 
 /* The layout of the device page is a "struct lguest_device_desc" followed by a
  * number of virtqueue descriptors, then two sets of feature bits, then an
@@ -1078,7 +1079,7 @@ static void add_virtqueue(struct device *dev, unsigned int num_descs,
        struct virtqueue **i, *vq = malloc(sizeof(*vq));
        void *p;
 
-       /* First we need some pages for this virtqueue. */
+       /* First we need some memory for this virtqueue. */
        pages = (vring_size(num_descs, getpagesize()) + getpagesize() - 1)
                / getpagesize();
        p = get_pages(pages);
@@ -1122,7 +1123,7 @@ static void add_virtqueue(struct device *dev, unsigned int num_descs,
 }
 
 /* The first half of the feature bitmask is for us to advertise features.  The
- * second half if for the Guest to accept features. */
+ * second half is for the Guest to accept features. */
 static void add_feature(struct device *dev, unsigned bit)
 {
        u8 *features = get_feature_bits(dev);
@@ -1151,7 +1152,9 @@ static void set_config(struct device *dev, unsigned len, const void *conf)
 }
 
 /* This routine does all the creation and setup of a new device, including
- * calling new_dev_desc() to allocate the descriptor and device memory. */
+ * calling new_dev_desc() to allocate the descriptor and device memory.
+ *
+ * See what I mean about userspace being boring? */
 static struct device *new_device(const char *name, u16 type, int fd,
                                 bool (*handle_input)(int, struct device *))
 {
@@ -1492,7 +1495,10 @@ static int io_thread(void *_dev)
        while (read(vblk->workpipe[0], &c, 1) == 1) {
                /* We acknowledge each request immediately to reduce latency,
                 * rather than waiting until we've done them all.  I haven't
-                * measured to see if it makes any difference. */
+                * measured to see if it makes any difference.
+                *
+                * That would be an interesting test, wouldn't it?  You could
+                * also try having more than one I/O thread. */
                while (service_io(dev))
                        write(vblk->done_fd, &c, 1);
        }
@@ -1500,7 +1506,7 @@ static int io_thread(void *_dev)
 }
 
 /* Now we've seen the I/O thread, we return to the Launcher to see what happens
- * when the thread tells us it's completed some I/O. */
+ * when that thread tells us it's completed some I/O. */
 static bool handle_io_finish(int fd, struct device *dev)
 {
        char c;
@@ -1572,11 +1578,12 @@ static void setup_block_file(const char *filename)
         * more work. */
        pipe(vblk->workpipe);
 
-       /* Create stack for thread and run it */
+       /* Create stack for thread and run it.  Since stack grows upwards, we
+        * point the stack pointer to the end of this region. */
        stack = malloc(32768);
        /* SIGCHLD - We dont "wait" for our cloned thread, so prevent it from
         * becoming a zombie. */
-       if (clone(io_thread, stack + 32768,  CLONE_VM | SIGCHLD, dev) == -1)
+       if (clone(io_thread, stack + 32768, CLONE_VM | SIGCHLD, dev) == -1)
                err(1, "Creating clone");
 
        /* We don't need to keep the I/O thread's end of the pipes open. */
@@ -1586,14 +1593,14 @@ static void setup_block_file(const char *filename)
        verbose("device %u: virtblock %llu sectors\n",
                devices.device_num, le64_to_cpu(conf.capacity));
 }
-/* That's the end of device setup. :*/
+/* That's the end of device setup. */
 
-/* Reboot */
+/*L:230 Reboot is pretty easy: clean up and exec() the Launcher afresh. */
 static void __attribute__((noreturn)) restart_guest(void)
 {
        unsigned int i;
 
-       /* Closing pipes causes the waker thread and io_threads to die, and
+       /* Closing pipes causes the Waker thread and io_threads to die, and
         * closing /dev/lguest cleans up the Guest.  Since we don't track all
         * open fds, we simply close everything beyond stderr. */
        for (i = 3; i < FD_SETSIZE; i++)
@@ -1602,7 +1609,7 @@ static void __attribute__((noreturn)) restart_guest(void)
        err(1, "Could not exec %s", main_args[0]);
 }
 
-/*L:220 Finally we reach the core of the Launcher, which runs the Guest, serves
+/*L:220 Finally we reach the core of the Launcher which runs the Guest, serves
  * its input and output, and finally, lays it to rest. */
 static void __attribute__((noreturn)) run_guest(int lguest_fd)
 {
@@ -1643,7 +1650,7 @@ static void __attribute__((noreturn)) run_guest(int lguest_fd)
                        err(1, "Resetting break");
        }
 }
-/*
+/*L:240
  * This is the end of the Launcher.  The good news: we are over halfway
  * through!  The bad news: the most fiendish part of the code still lies ahead
  * of us.
@@ -1690,8 +1697,8 @@ int main(int argc, char *argv[])
         * device receive input from a file descriptor, we keep an fdset
         * (infds) and the maximum fd number (max_infd) with the head of the
         * list.  We also keep a pointer to the last device.  Finally, we keep
-        * the next interrupt number to hand out (1: remember that 0 is used by
-        * the timer). */
+        * the next interrupt number to use for devices (1: remember that 0 is
+        * used by the timer). */
        FD_ZERO(&devices.infds);
        devices.max_infd = -1;
        devices.lastdev = NULL;
@@ -1792,8 +1799,8 @@ int main(int argc, char *argv[])
        lguest_fd = tell_kernel(pgdir, start);
 
        /* We fork off a child process, which wakes the Launcher whenever one
-        * of the input file descriptors needs attention.  Otherwise we would
-        * run the Guest until it tries to output something. */
+        * of the input file descriptors needs attention.  We call this the
+        * Waker, and we'll cover it in a moment. */
        waker_fd = setup_waker(lguest_fd);
 
        /* Finally, run the Guest.  This doesn't return. */
index a104c53..3335b45 100644 (file)
  * (such as the example in Documentation/lguest/lguest.c) is called the
  * Launcher.
  *
- * Secondly, we only run specially modified Guests, not normal kernels.  When
- * you set CONFIG_LGUEST to 'y' or 'm', this automatically sets
- * CONFIG_LGUEST_GUEST=y, which compiles this file into the kernel so it knows
- * how to be a Guest.  This means that you can use the same kernel you boot
- * normally (ie. as a Host) as a Guest.
+ * Secondly, we only run specially modified Guests, not normal kernels: setting
+ * CONFIG_LGUEST_GUEST to "y" compiles this file into the kernel so it knows
+ * how to be a Guest at boot time.  This means that you can use the same kernel
+ * you boot normally (ie. as a Host) as a Guest.
  *
  * These Guests know that they cannot do privileged operations, such as disable
  * interrupts, and that they have to ask the Host to do such things explicitly.
  * This file consists of all the replacements for such low-level native
  * hardware operations: these special Guest versions call the Host.
  *
- * So how does the kernel know it's a Guest?  The Guest starts at a special
- * entry point marked with a magic string, which sets up a few things then
- * calls here.  We replace the native functions various "paravirt" structures
- * with our Guest versions, then boot like normal. :*/
+ * So how does the kernel know it's a Guest?  We'll see that later, but let's
+ * just say that we end up here where we replace the native functions various
+ * "paravirt" structures with our Guest versions, then boot like normal. :*/
 
 /*
  * Copyright (C) 2006, Rusty Russell <rusty@rustcorp.com.au> IBM Corporation.
@@ -134,7 +132,7 @@ static void async_hcall(unsigned long call, unsigned long arg1,
  * lguest_leave_lazy_mode().
  *
  * So, when we're in lazy mode, we call async_hcall() to store the call for
- * future processing. */
+ * future processing: */
 static void lazy_hcall(unsigned long call,
                       unsigned long arg1,
                       unsigned long arg2,
@@ -147,7 +145,7 @@ static void lazy_hcall(unsigned long call,
 }
 
 /* When lazy mode is turned off reset the per-cpu lazy mode variable and then
- * issue a hypercall to flush any stored calls. */
+ * issue the do-nothing hypercall to flush any stored calls. */
 static void lguest_leave_lazy_mode(void)
 {
        paravirt_leave_lazy(paravirt_get_lazy_mode());
@@ -164,7 +162,7 @@ static void lguest_leave_lazy_mode(void)
  *
  * So instead we keep an "irq_enabled" field inside our "struct lguest_data",
  * which the Guest can update with a single instruction.  The Host knows to
- * check there when it wants to deliver an interrupt.
+ * check there before it tries to deliver an interrupt.
  */
 
 /* save_flags() is expected to return the processor state (ie. "flags").  The
@@ -196,10 +194,15 @@ static void irq_enable(void)
 /*M:003 Note that we don't check for outstanding interrupts when we re-enable
  * them (or when we unmask an interrupt).  This seems to work for the moment,
  * since interrupts are rare and we'll just get the interrupt on the next timer
- * tick, but when we turn on CONFIG_NO_HZ, we should revisit this.  One way
+ * tick, but now we can run with CONFIG_NO_HZ, we should revisit this.  One way
  * would be to put the "irq_enabled" field in a page by itself, and have the
  * Host write-protect it when an interrupt comes in when irqs are disabled.
- * There will then be a page fault as soon as interrupts are re-enabled. :*/
+ * There will then be a page fault as soon as interrupts are re-enabled.
+ *
+ * A better method is to implement soft interrupt disable generally for x86:
+ * instead of disabling interrupts, we set a flag.  If an interrupt does come
+ * in, we then disable them for real.  This is uncommon, so we could simply use
+ * a hypercall for interrupt control and not worry about efficiency. :*/
 
 /*G:034
  * The Interrupt Descriptor Table (IDT).
@@ -212,6 +215,10 @@ static void irq_enable(void)
 static void lguest_write_idt_entry(gate_desc *dt,
                                   int entrynum, const gate_desc *g)
 {
+       /* The gate_desc structure is 8 bytes long: we hand it to the Host in
+        * two 32-bit chunks.  The whole 32-bit kernel used to hand descriptors
+        * around like this; typesafety wasn't a big concern in Linux's early
+        * years. */
        u32 *desc = (u32 *)g;
        /* Keep the local copy up to date. */
        native_write_idt_entry(dt, entrynum, g);
@@ -243,7 +250,8 @@ static void lguest_load_idt(const struct desc_ptr *desc)
  *
  * This is the opposite of the IDT code where we have a LOAD_IDT_ENTRY
  * hypercall and use that repeatedly to load a new IDT.  I don't think it
- * really matters, but wouldn't it be nice if they were the same?
+ * really matters, but wouldn't it be nice if they were the same?  Wouldn't
+ * it be even better if you were the one to send the patch to fix it?
  */
 static void lguest_load_gdt(const struct desc_ptr *desc)
 {
@@ -298,9 +306,9 @@ static void lguest_load_tr_desc(void)
 
 /* The "cpuid" instruction is a way of querying both the CPU identity
  * (manufacturer, model, etc) and its features.  It was introduced before the
- * Pentium in 1993 and keeps getting extended by both Intel and AMD.  As you
- * might imagine, after a decade and a half this treatment, it is now a giant
- * ball of hair.  Its entry in the current Intel manual runs to 28 pages.
+ * Pentium in 1993 and keeps getting extended by both Intel, AMD and others.
+ * As you might imagine, after a decade and a half this treatment, it is now a
+ * giant ball of hair.  Its entry in the current Intel manual runs to 28 pages.
  *
  * This instruction even it has its own Wikipedia entry.  The Wikipedia entry
  * has been translated into 4 languages.  I am not making this up!
@@ -594,17 +602,17 @@ static unsigned long lguest_get_wallclock(void)
        return lguest_data.time.tv_sec;
 }
 
-/* The TSC is a Time Stamp Counter.  The Host tells us what speed it runs at,
- * or 0 if it's unusable as a reliable clock source.  This matches what we want
- * here: if we return 0 from this function, the x86 TSC clock will not register
- * itself. */
+/* The TSC is an Intel thing called the Time Stamp Counter.  The Host tells us
+ * what speed it runs at, or 0 if it's unusable as a reliable clock source.
+ * This matches what we want here: if we return 0 from this function, the x86
+ * TSC clock will give up and not register itself. */
 static unsigned long lguest_cpu_khz(void)
 {
        return lguest_data.tsc_khz;
 }
 
-/* If we can't use the TSC, the kernel falls back to our "lguest_clock", where
- * we read the time value given to us by the Host. */
+/* If we can't use the TSC, the kernel falls back to our lower-priority
+ * "lguest_clock", where we read the time value given to us by the Host. */
 static cycle_t lguest_clock_read(void)
 {
        unsigned long sec, nsec;
@@ -648,12 +656,16 @@ static struct clocksource lguest_clock = {
 static int lguest_clockevent_set_next_event(unsigned long delta,
                                            struct clock_event_device *evt)
 {
+       /* FIXME: I don't think this can ever happen, but James tells me he had
+        * to put this code in.  Maybe we should remove it now.  Anyone? */
        if (delta < LG_CLOCK_MIN_DELTA) {
                if (printk_ratelimit())
                        printk(KERN_DEBUG "%s: small delta %lu ns\n",
                               __FUNCTION__, delta);
                return -ETIME;
        }
+
+       /* Please wake us this far in the future. */
        hcall(LHCALL_SET_CLOCKEVENT, delta, 0, 0);
        return 0;
 }
@@ -738,7 +750,7 @@ static void lguest_time_init(void)
  * will not tolerate us trying to use that), the stack pointer, and the number
  * of pages in the stack. */
 static void lguest_load_sp0(struct tss_struct *tss,
-                                    struct thread_struct *thread)
+                           struct thread_struct *thread)
 {
        lazy_hcall(LHCALL_SET_STACK, __KERNEL_DS|0x1, thread->sp0,
                   THREAD_SIZE/PAGE_SIZE);
@@ -786,9 +798,8 @@ static void lguest_safe_halt(void)
        hcall(LHCALL_HALT, 0, 0, 0);
 }
 
-/* Perhaps CRASH isn't the best name for this hypercall, but we use it to get a
- * message out when we're crashing as well as elegant termination like powering
- * off.
+/* The SHUTDOWN hypercall takes a string to describe what's happening, and
+ * an argument which says whether this to restart (reboot) the Guest or not.
  *
  * Note that the Host always prefers that the Guest speak in physical addresses
  * rather than virtual addresses, so we use __pa() here. */
@@ -816,8 +827,9 @@ static struct notifier_block paniced = {
 /* Setting up memory is fairly easy. */
 static __init char *lguest_memory_setup(void)
 {
-       /* We do this here and not earlier because lockcheck barfs if we do it
-        * before start_kernel() */
+       /* We do this here and not earlier because lockcheck used to barf if we
+        * did it before start_kernel().  I think we fixed that, so it'd be
+        * nice to move it back to lguest_init.  Patch welcome... */
        atomic_notifier_chain_register(&panic_notifier_list, &paniced);
 
        /* The Linux bootloader header contains an "e820" memory map: the
@@ -850,12 +862,19 @@ static __init int early_put_chars(u32 vtermno, const char *buf, int count)
        return len;
 }
 
+/* Rebooting also tells the Host we're finished, but the RESTART flag tells the
+ * Launcher to reboot us. */
+static void lguest_restart(char *reason)
+{
+       hcall(LHCALL_SHUTDOWN, __pa(reason), LGUEST_SHUTDOWN_RESTART, 0);
+}
+
 /*G:050
  * Patching (Powerfully Placating Performance Pedants)
  *
- * We have already seen that pv_ops structures let us replace simple
- * native instructions with calls to the appropriate back end all throughout
- * the kernel.  This allows the same kernel to run as a Guest and as a native
+ * We have already seen that pv_ops structures let us replace simple native
+ * instructions with calls to the appropriate back end all throughout the
+ * kernel.  This allows the same kernel to run as a Guest and as a native
  * kernel, but it's slow because of all the indirect branches.
  *
  * Remember that David Wheeler quote about "Any problem in computer science can
@@ -908,14 +927,9 @@ static unsigned lguest_patch(u8 type, u16 clobber, void *ibuf,
        return insn_len;
 }
 
-static void lguest_restart(char *reason)
-{
-       hcall(LHCALL_SHUTDOWN, __pa(reason), LGUEST_SHUTDOWN_RESTART, 0);
-}
-
-/*G:030 Once we get to lguest_init(), we know we're a Guest.  The pv_ops
- * structures in the kernel provide points for (almost) every routine we have
- * to override to avoid privileged instructions. */
+/*G:030 Once we get to lguest_init(), we know we're a Guest.  The various
+ * pv_ops structures in the kernel provide points for (almost) every routine we
+ * have to override to avoid privileged instructions. */
 __init void lguest_init(void)
 {
        /* We're under lguest, paravirt is enabled, and we're running at
@@ -1003,9 +1017,9 @@ __init void lguest_init(void)
         * the normal data segment to get through booting. */
        asm volatile ("mov %0, %%fs" : : "r" (__KERNEL_DS) : "memory");
 
-       /* The Host uses the top of the Guest's virtual address space for the
-        * Host<->Guest Switcher, and it tells us how big that is in
-        * lguest_data.reserve_mem, set up on the LGUEST_INIT hypercall. */
+       /* The Host<->Guest Switcher lives at the top of our address space, and
+        * the Host told us how big it is when we made LGUEST_INIT hypercall:
+        * it put the answer in lguest_data.reserve_mem  */
        reserve_top_address(lguest_data.reserve_mem);
 
        /* If we don't initialize the lock dependency checker now, it crashes
@@ -1027,6 +1041,7 @@ __init void lguest_init(void)
        /* Math is always hard! */
        new_cpu_data.hard_math = 1;
 
+       /* We don't have features.  We have puppies!  Puppies! */
 #ifdef CONFIG_X86_MCE
        mce_disabled = 1;
 #endif
@@ -1044,10 +1059,11 @@ __init void lguest_init(void)
        virtio_cons_early_init(early_put_chars);
 
        /* Last of all, we set the power management poweroff hook to point to
-        * the Guest routine to power off. */
+        * the Guest routine to power off, and the reboot hook to our restart
+        * routine. */
        pm_power_off = lguest_power_off;
-
        machine_ops.restart = lguest_restart;
+
        /* Now we're set up, call start_kernel() in init/main.c and we proceed
         * to boot as normal.  It never returns. */
        start_kernel();
index 95b6fbc..5c7cef3 100644 (file)
@@ -5,13 +5,20 @@
 #include <asm/thread_info.h>
 #include <asm/processor-flags.h>
 
-/*G:020 This is where we begin: head.S notes that the boot header's platform
- * type field is "1" (lguest), so calls us here.
+/*G:020 Our story starts with the kernel booting into startup_32 in
+ * arch/x86/kernel/head_32.S.  It expects a boot header, which is created by
+ * the bootloader (the Launcher in our case).
+ *
+ * The startup_32 function does very little: it clears the uninitialized global
+ * C variables which we expect to be zero (ie. BSS) and then copies the boot
+ * header and kernel command line somewhere safe.  Finally it checks the
+ * 'hardware_subarch' field.  This was introduced in 2.6.24 for lguest and Xen:
+ * if it's set to '1' (lguest's assigned number), then it calls us here.
  *
  * WARNING: be very careful here!  We're running at addresses equal to physical
  * addesses (around 0), not above PAGE_OFFSET as most code expectes
  * (eg. 0xC0000000).  Jumps are relative, so they're OK, but we can't touch any
- * data.
+ * data without remembering to subtract __PAGE_OFFSET!
  *
  * The .section line puts this code in .init.text so it will be discarded after
  * boot. */
@@ -24,7 +31,7 @@ ENTRY(lguest_entry)
        int $LGUEST_TRAP_ENTRY
 
        /* The Host put the toplevel pagetable in lguest_data.pgdir.  The movsl
-        * instruction uses %esi implicitly as the source for the copy we'
+        * instruction uses %esi implicitly as the source for the copy we're
         * about to do. */
        movl lguest_data - __PAGE_OFFSET + LGUEST_DATA_pgdir, %esi
 
index c632c08..5eea435 100644 (file)
@@ -1,8 +1,6 @@
 /*P:400 This contains run_guest() which actually calls into the Host<->Guest
  * Switcher and analyzes the return, such as determining if the Guest wants the
- * Host to do something.  This file also contains useful helper routines, and a
- * couple of non-obvious setup and teardown pieces which were implemented after
- * days of debugging pain. :*/
+ * Host to do something.  This file also contains useful helper routines. :*/
 #include <linux/module.h>
 #include <linux/stringify.h>
 #include <linux/stddef.h>
@@ -49,8 +47,8 @@ static __init int map_switcher(void)
         * easy.
         */
 
-       /* We allocate an array of "struct page"s.  map_vm_area() wants the
-        * pages in this form, rather than just an array of pointers. */
+       /* We allocate an array of struct page pointers.  map_vm_area() wants
+        * this, rather than just an array of pages. */
        switcher_page = kmalloc(sizeof(switcher_page[0])*TOTAL_SWITCHER_PAGES,
                                GFP_KERNEL);
        if (!switcher_page) {
@@ -172,7 +170,7 @@ void __lgread(struct lg_cpu *cpu, void *b, unsigned long addr, unsigned bytes)
        }
 }
 
-/* This is the write (copy into guest) version. */
+/* This is the write (copy into Guest) version. */
 void __lgwrite(struct lg_cpu *cpu, unsigned long addr, const void *b,
               unsigned bytes)
 {
@@ -209,9 +207,9 @@ int run_guest(struct lg_cpu *cpu, unsigned long __user *user)
                if (cpu->break_out)
                        return -EAGAIN;
 
-               /* Check if there are any interrupts which can be delivered
-                * now: if so, this sets up the hander to be executed when we
-                * next run the Guest. */
+               /* Check if there are any interrupts which can be delivered now:
+                * if so, this sets up the hander to be executed when we next
+                * run the Guest. */
                maybe_do_interrupt(cpu);
 
                /* All long-lived kernel loops need to check with this horrible
@@ -246,8 +244,10 @@ int run_guest(struct lg_cpu *cpu, unsigned long __user *user)
                lguest_arch_handle_trap(cpu);
        }
 
+       /* Special case: Guest is 'dead' but wants a reboot. */
        if (cpu->lg->dead == ERR_PTR(-ERESTART))
                return -ERESTART;
+
        /* The Guest is dead => "No such file or directory" */
        return -ENOENT;
 }
index 0f2cb4f..54d66f0 100644 (file)
@@ -29,7 +29,7 @@
 #include "lg.h"
 
 /*H:120 This is the core hypercall routine: where the Guest gets what it wants.
- * Or gets killed.  Or, in the case of LHCALL_CRASH, both. */
+ * Or gets killed.  Or, in the case of LHCALL_SHUTDOWN, both. */
 static void do_hcall(struct lg_cpu *cpu, struct hcall_args *args)
 {
        switch (args->arg0) {
@@ -190,6 +190,13 @@ static void initialize(struct lg_cpu *cpu)
         * pagetable. */
        guest_pagetable_clear_all(cpu);
 }
+/*:*/
+
+/*M:013 If a Guest reads from a page (so creates a mapping) that it has never
+ * written to, and then the Launcher writes to it (ie. the output of a virtual
+ * device), the Guest will still see the old page.  In practice, this never
+ * happens: why would the Guest read a page which it has never written to?  But
+ * a similar scenario might one day bite us, so it's worth mentioning. :*/
 
 /*H:100
  * Hypercalls
@@ -227,7 +234,7 @@ void do_hypercalls(struct lg_cpu *cpu)
                 * However, if we are signalled or the Guest sends I/O to the
                 * Launcher, the run_guest() loop will exit without running the
                 * Guest.  When it comes back it would try to re-run the
-                * hypercall. */
+                * hypercall.  Finding that bug sucked. */
                cpu->hcall = NULL;
        }
 }
index 32e97c1..0414ddf 100644 (file)
@@ -144,7 +144,6 @@ void maybe_do_interrupt(struct lg_cpu *cpu)
        if (copy_from_user(&blk, cpu->lg->lguest_data->blocked_interrupts,
                           sizeof(blk)))
                return;
-
        bitmap_andnot(blk, cpu->irqs_pending, blk, LGUEST_IRQS);
 
        /* Find the first interrupt. */
@@ -237,9 +236,9 @@ void free_interrupts(void)
                clear_bit(syscall_vector, used_vectors);
 }
 
-/*H:220 Now we've got the routines to deliver interrupts, delivering traps
- * like page fault is easy.  The only trick is that Intel decided that some
- * traps should have error codes: */
+/*H:220 Now we've got the routines to deliver interrupts, delivering traps like
+ * page fault is easy.  The only trick is that Intel decided that some traps
+ * should have error codes: */
 static int has_err(unsigned int trap)
 {
        return (trap == 8 || (trap >= 10 && trap <= 14) || trap == 17);
index 1b2ec0b..2bc9bf7 100644 (file)
@@ -1,10 +1,10 @@
 /*P:050 Lguest guests use a very simple method to describe devices.  It's a
- * series of device descriptors contained just above the top of normal
+ * series of device descriptors contained just above the top of normal Guest
  * memory.
  *
  * We use the standard "virtio" device infrastructure, which provides us with a
  * console, a network and a block driver.  Each one expects some configuration
- * information and a "virtqueue" mechanism to send and receive data. :*/
+ * information and a "virtqueue" or two to send and receive data. :*/
 #include <linux/init.h>
 #include <linux/bootmem.h>
 #include <linux/lguest_launcher.h>
@@ -53,7 +53,7 @@ struct lguest_device {
  * Device configurations
  *
  * The configuration information for a device consists of one or more
- * virtqueues, a feature bitmaks, and some configuration bytes.  The
+ * virtqueues, a feature bitmap, and some configuration bytes.  The
  * configuration bytes don't really matter to us: the Launcher sets them up, and
  * the driver will look at them during setup.
  *
@@ -179,7 +179,7 @@ struct lguest_vq_info
 };
 
 /* When the virtio_ring code wants to prod the Host, it calls us here and we
- * make a hypercall.  We hand the page number of the virtqueue so the Host
+ * make a hypercall.  We hand the physical address of the virtqueue so the Host
  * knows which virtqueue we're talking about. */
 static void lg_notify(struct virtqueue *vq)
 {
@@ -199,7 +199,8 @@ static void lg_notify(struct virtqueue *vq)
  * allocate its own pages and tell the Host where they are, but for lguest it's
  * simpler for the Host to simply tell us where the pages are.
  *
- * So we provide devices with a "find virtqueue and set it up" function. */
+ * So we provide drivers with a "find the Nth virtqueue and set it up"
+ * function. */
 static struct virtqueue *lg_find_vq(struct virtio_device *vdev,
                                    unsigned index,
                                    void (*callback)(struct virtqueue *vq))
index 2221485..564e425 100644 (file)
@@ -73,7 +73,7 @@ static ssize_t read(struct file *file, char __user *user, size_t size,loff_t*o)
        if (current != cpu->tsk)
                return -EPERM;
 
-       /* If the guest is already dead, we indicate why */
+       /* If the Guest is already dead, we indicate why */
        if (lg->dead) {
                size_t len;
 
@@ -88,7 +88,7 @@ static ssize_t read(struct file *file, char __user *user, size_t size,loff_t*o)
                return len;
        }
 
-       /* If we returned from read() last time because the Guest notified,
+       /* If we returned from read() last time because the Guest sent I/O,
         * clear the flag. */
        if (cpu->pending_notify)
                cpu->pending_notify = 0;
@@ -97,14 +97,20 @@ static ssize_t read(struct file *file, char __user *user, size_t size,loff_t*o)
        return run_guest(cpu, (unsigned long __user *)user);
 }
 
+/*L:025 This actually initializes a CPU.  For the moment, a Guest is only
+ * uniprocessor, so "id" is always 0. */
 static int lg_cpu_start(struct lg_cpu *cpu, unsigned id, unsigned long start_ip)
 {
+       /* We have a limited number the number of CPUs in the lguest struct. */
        if (id >= NR_CPUS)
                return -EINVAL;
 
+       /* Set up this CPU's id, and pointer back to the lguest struct. */
        cpu->id = id;
        cpu->lg = container_of((cpu - id), struct lguest, cpus[0]);
        cpu->lg->nr_cpus++;
+
+       /* Each CPU has a timer it can set. */
        init_clockdev(cpu);
 
        /* We need a complete page for the Guest registers: they are accessible
@@ -120,11 +126,11 @@ static int lg_cpu_start(struct lg_cpu *cpu, unsigned id, unsigned long start_ip)
         * address. */
        lguest_arch_setup_regs(cpu, start_ip);
 
-       /* Initialize the queue for the waker to wait on */
+       /* Initialize the queue for the Waker to wait on */
        init_waitqueue_head(&cpu->break_wq);
 
        /* We keep a pointer to the Launcher task (ie. current task) for when
-        * other Guests want to wake this one (inter-Guest I/O). */
+        * other Guests want to wake this one (eg. console input). */
        cpu->tsk = current;
 
        /* We need to keep a pointer to the Launcher's memory map, because if
@@ -136,6 +142,7 @@ static int lg_cpu_start(struct lg_cpu *cpu, unsigned id, unsigned long start_ip)
         * when the same Guest runs on the same CPU twice. */
        cpu->last_pages = NULL;
 
+       /* No error == success. */
        return 0;
 }
 
@@ -185,14 +192,13 @@ static int initialize(struct file *file, const unsigned long __user *input)
        lg->mem_base = (void __user *)(long)args[0];
        lg->pfn_limit = args[1];
 
-       /* This is the first cpu */
+       /* This is the first cpu (cpu 0) and it will start booting at args[3] */
        err = lg_cpu_start(&lg->cpus[0], 0, args[3]);
        if (err)
                goto release_guest;
 
        /* Initialize the Guest's shadow page tables, using the toplevel
-        * address the Launcher gave us.  This allocates memory, so can
-        * fail. */
+        * address the Launcher gave us.  This allocates memory, so can fail. */
        err = init_guest_pagetable(lg, args[2]);
        if (err)
                goto free_regs;
@@ -218,11 +224,16 @@ unlock:
 /*L:010 The first operation the Launcher does must be a write.  All writes
  * start with an unsigned long number: for the first write this must be
  * LHREQ_INITIALIZE to set up the Guest.  After that the Launcher can use
- * writes of other values to send interrupts. */
+ * writes of other values to send interrupts.
+ *
+ * Note that we overload the "offset" in the /dev/lguest file to indicate what
+ * CPU number we're dealing with.  Currently this is always 0, since we only
+ * support uniprocessor Guests, but you can see the beginnings of SMP support
+ * here. */
 static ssize_t write(struct file *file, const char __user *in,
                     size_t size, loff_t *off)
 {
-       /* Once the guest is initialized, we hold the "struct lguest" in the
+       /* Once the Guest is initialized, we hold the "struct lguest" in the
         * file private data. */
        struct lguest *lg = file->private_data;
        const unsigned long __user *input = (const unsigned long __user *)in;
@@ -230,6 +241,7 @@ static ssize_t write(struct file *file, const char __user *in,
        struct lg_cpu *uninitialized_var(cpu);
        unsigned int cpu_id = *off;
 
+       /* The first value tells us what this request is. */
        if (get_user(req, input) != 0)
                return -EFAULT;
        input++;
index a7f64a9..d93500f 100644 (file)
@@ -2,8 +2,8 @@
  * previous encounters.  It's functional, and as neat as it can be in the
  * circumstances, but be wary, for these things are subtle and break easily.
  * The Guest provides a virtual to physical mapping, but we can neither trust
- * it nor use it: we verify and convert it here to point the hardware to the
- * actual Guest pages when running the Guest. :*/
+ * it nor use it: we verify and convert it here then point the CPU to the
+ * converted Guest pages when running the Guest. :*/
 
 /* Copyright (C) Rusty Russell IBM Corporation 2006.
  * GPL v2 and any later version */
@@ -106,6 +106,11 @@ static unsigned long gpte_addr(pgd_t gpgd, unsigned long vaddr)
        BUG_ON(!(pgd_flags(gpgd) & _PAGE_PRESENT));
        return gpage + ((vaddr>>PAGE_SHIFT) % PTRS_PER_PTE) * sizeof(pte_t);
 }
+/*:*/
+
+/*M:014 get_pfn is slow; it takes the mmap sem and calls get_user_pages.  We
+ * could probably try to grab batches of pages here as an optimization
+ * (ie. pre-faulting). :*/
 
 /*H:350 This routine takes a page number given by the Guest and converts it to
  * an actual, physical page number.  It can fail for several reasons: the
@@ -113,8 +118,8 @@ static unsigned long gpte_addr(pgd_t gpgd, unsigned long vaddr)
  * and the page is read-only, or the write flag was set and the page was
  * shared so had to be copied, but we ran out of memory.
  *
- * This holds a reference to the page, so release_pte() is careful to
- * put that back. */
+ * This holds a reference to the page, so release_pte() is careful to put that
+ * back. */
 static unsigned long get_pfn(unsigned long virtpfn, int write)
 {
        struct page *page;
@@ -532,13 +537,13 @@ static void do_set_pte(struct lg_cpu *cpu, int idx,
  * all processes.  So when the page table above that address changes, we update
  * all the page tables, not just the current one.  This is rare.
  *
- * The benefit is that when we have to track a new page table, we can copy keep
- * all the kernel mappings.  This speeds up context switch immensely. */
+ * The benefit is that when we have to track a new page table, we can keep all
+ * the kernel mappings.  This speeds up context switch immensely. */
 void guest_set_pte(struct lg_cpu *cpu,
                   unsigned long gpgdir, unsigned long vaddr, pte_t gpte)
 {
-       /* Kernel mappings must be changed on all top levels.  Slow, but
-        * doesn't happen often. */
+       /* Kernel mappings must be changed on all top levels.  Slow, but doesn't
+        * happen often. */
        if (vaddr >= cpu->lg->kernel_address) {
                unsigned int i;
                for (i = 0; i < ARRAY_SIZE(cpu->lg->pgdirs); i++)
@@ -704,12 +709,11 @@ static __init void populate_switcher_pte_page(unsigned int cpu,
 /* We've made it through the page table code.  Perhaps our tired brains are
  * still processing the details, or perhaps we're simply glad it's over.
  *
- * If nothing else, note that all this complexity in juggling shadow page
- * tables in sync with the Guest's page tables is for one reason: for most
- * Guests this page table dance determines how bad performance will be.  This
- * is why Xen uses exotic direct Guest pagetable manipulation, and why both
- * Intel and AMD have implemented shadow page table support directly into
- * hardware.
+ * If nothing else, note that all this complexity in juggling shadow page tables
+ * in sync with the Guest's page tables is for one reason: for most Guests this
+ * page table dance determines how bad performance will be.  This is why Xen
+ * uses exotic direct Guest pagetable manipulation, and why both Intel and AMD
+ * have implemented shadow page table support directly into hardware.
  *
  * There is just one file remaining in the Host. */
 
index 6351878..5126d5d 100644 (file)
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
+/*P:450 This file contains the x86-specific lguest code.  It used to be all
+ * mixed in with drivers/lguest/core.c but several foolhardy code slashers
+ * wrestled most of the dependencies out to here in preparation for porting
+ * lguest to other architectures (see what I mean by foolhardy?).
+ *
+ * This also contains a couple of non-obvious setup and teardown pieces which
+ * were implemented after days of debugging pain. :*/
 #include <linux/kernel.h>
 #include <linux/start_kernel.h>
 #include <linux/string.h>
@@ -157,6 +164,8 @@ static void run_guest_once(struct lg_cpu *cpu, struct lguest_pages *pages)
  * also simplify copy_in_guest_info().  Note that we'd still need to restore
  * things when we exit to Launcher userspace, but that's fairly easy.
  *
+ * We could also try using this hooks for PGE, but that might be too expensive.
+ *
  * The hooks were designed for KVM, but we can also put them to good use. :*/
 
 /*H:040 This is the i386-specific code to setup and run the Guest.  Interrupts
@@ -182,7 +191,7 @@ void lguest_arch_run_guest(struct lg_cpu *cpu)
         * was doing. */
        run_guest_once(cpu, lguest_pages(raw_smp_processor_id()));
 
-       /* Note that the "regs" pointer contains two extra entries which are
+       /* Note that the "regs" structure contains two extra entries which are
         * not really registers: a trap number which says what interrupt or
         * trap made the switcher code come back, and an error code which some
         * traps set.  */
@@ -293,11 +302,10 @@ void lguest_arch_handle_trap(struct lg_cpu *cpu)
                break;
        case 14: /* We've intercepted a Page Fault. */
                /* The Guest accessed a virtual address that wasn't mapped.
-                * This happens a lot: we don't actually set up most of the
-                * page tables for the Guest at all when we start: as it runs
-                * it asks for more and more, and we set them up as
-                * required. In this case, we don't even tell the Guest that
-                * the fault happened.
+                * This happens a lot: we don't actually set up most of the page
+                * tables for the Guest at all when we start: as it runs it asks
+                * for more and more, and we set them up as required. In this
+                * case, we don't even tell the Guest that the fault happened.
                 *
                 * The errcode tells whether this was a read or a write, and
                 * whether kernel or userspace code. */
@@ -342,7 +350,7 @@ void lguest_arch_handle_trap(struct lg_cpu *cpu)
        if (!deliver_trap(cpu, cpu->regs->trapnum))
                /* If the Guest doesn't have a handler (either it hasn't
                 * registered any yet, or it's one of the faults we don't let
-                * it handle), it dies with a cryptic error message. */
+                * it handle), it dies with this cryptic error message. */
                kill_guest(cpu, "unhandled trap %li at %#lx (%#lx)",
                           cpu->regs->trapnum, cpu->regs->eip,
                           cpu->regs->trapnum == 14 ? cpu->arch.last_pagefault
@@ -375,8 +383,8 @@ void __init lguest_arch_host_init(void)
         * The only exception is the interrupt handlers in switcher.S: their
         * addresses are placed in a table (default_idt_entries), so we need to
         * update the table with the new addresses.  switcher_offset() is a
-        * convenience function which returns the distance between the builtin
-        * switcher code and the high-mapped copy we just made. */
+        * convenience function which returns the distance between the
+        * compiled-in switcher code and the high-mapped copy we just made. */
        for (i = 0; i < IDT_ENTRIES; i++)
                default_idt_entries[i] += switcher_offset();
 
@@ -416,7 +424,7 @@ void __init lguest_arch_host_init(void)
                state->guest_gdt_desc.address = (long)&state->guest_gdt;
 
                /* We know where we want the stack to be when the Guest enters
-                * the switcher: in pages->regs.  The stack grows upwards, so
+                * the Switcher: in pages->regs.  The stack grows upwards, so
                 * we start it at the end of that structure. */
                state->guest_tss.sp0 = (long)(&pages->regs + 1);
                /* And this is the GDT entry to use for the stack: we keep a
@@ -513,8 +521,8 @@ int lguest_arch_init_hypercalls(struct lg_cpu *cpu)
 {
        u32 tsc_speed;
 
-       /* The pointer to the Guest's "struct lguest_data" is the only
-        * argument.  We check that address now. */
+       /* The pointer to the Guest's "struct lguest_data" is the only argument.
+        * We check that address now. */
        if (!lguest_address_ok(cpu->lg, cpu->hcall->arg1,
                               sizeof(*cpu->lg->lguest_data)))
                return -EFAULT;
@@ -546,6 +554,7 @@ int lguest_arch_init_hypercalls(struct lg_cpu *cpu)
 
        return 0;
 }
+/*:*/
 
 /*L:030 lguest_arch_setup_regs()
  *
index 0af8baa..3fc1531 100644 (file)
@@ -1,6 +1,6 @@
-/*P:900 This is the Switcher: code which sits at 0xFFC00000 to do the low-level
- * Guest<->Host switch.  It is as simple as it can be made, but it's naturally
- * very specific to x86.
+/*P:900 This is the Switcher: code which sits at 0xFFC00000 astride both the
+ * Host and Guest to do the low-level Guest<->Host switch.  It is as simple as
+ * it can be made, but it's naturally very specific to x86.
  *
  * You have now completed Preparation.  If this has whet your appetite; if you
  * are feeling invigorated and refreshed then the next, more challenging stage
@@ -189,7 +189,7 @@ ENTRY(switch_to_guest)
        // Interrupts are turned back on: we are Guest.
        iret
 
-// We treat two paths to switch back to the Host
+// We tread two paths to switch back to the Host
 // Yet both must save Guest state and restore Host
 // So we put the routine in a macro.
 #define SWITCH_TO_HOST                                                 \
index 758b9a5..f239e70 100644 (file)
@@ -27,7 +27,7 @@
 #ifndef __ASSEMBLY__
 #include <asm/hw_irq.h>
 
-/*G:031 First, how does our Guest contact the Host to ask for privileged
+/*G:031 But first, how does our Guest contact the Host to ask for privileged
  * operations?  There are two ways: the direct way is to make a "hypercall",
  * to make requests of the Host Itself.
  *
index 589be3e..e7217dc 100644 (file)
  * a new device, we simply need to write a new virtio driver and create support
  * for it in the Launcher: this code won't need to change.
  *
+ * Virtio devices are also used by kvm, so we can simply reuse their optimized
+ * device drivers.  And one day when everyone uses virtio, my plan will be
+ * complete.  Bwahahahah!
+ *
  * Devices are described by a simplified ID, a status byte, and some "config"
  * bytes which describe this device's configuration.  This is placed by the
  * Launcher just above the top of physical memory:
@@ -26,7 +30,7 @@ struct lguest_device_desc {
        /* The number of virtqueues (first in config array) */
        __u8 num_vq;
        /* The number of bytes of feature bits.  Multiply by 2: one for host
-        * features and one for guest acknowledgements. */
+        * features and one for Guest acknowledgements. */
        __u8 feature_len;
        /* The number of bytes of the config array after virtqueues. */
        __u8 config_len;