Merge branch 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc
authorLinus Torvalds <torvalds@woody.linux-foundation.org>
Thu, 26 Jul 2007 21:00:09 +0000 (14:00 -0700)
committerLinus Torvalds <torvalds@woody.linux-foundation.org>
Thu, 26 Jul 2007 21:00:09 +0000 (14:00 -0700)
* 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc: (21 commits)
  [POWERPC] spusched: Fix initial timeslice calculation
  [POWERPC] spufs: Fix incorrect initialization of cbe_spu_info.spus
  [POWERPC] Fix Maple platform ISA bus
  [POWERPC] Make pci_iounmap actually unmap things
  [POWERPC] Add function to check if address is an IO port
  [POWERPC] Fix Pegasos keyboard detection
  [POWERPC] iSeries: Fix section mismatch warning in lpevents
  [POWERPC] iSeries: Fix section mismatch warnings
  [POWERPC] iSeries: We need vio_enable_interrupts
  [POWERPC] Fix RTC and device tree on linkstation machines
  [POWERPC] Add of_register_i2c_devices()
  [POWERPC] Fix loop with unsigned long counter variable
  [POWERPC] Fix register labels on show_regs() message for 4xx/Book-E
  [POWERPC] Only allow building of BootX text support on PPC_MULTIPLATFORM
  [POWERPC] Fix the ability to reset on MPC8544 DS and MPC8568 MDS boards
  [POWERPC] Fix mpc7448hpc2 tsi108 device_type bug
  [POWREPC] Fixup a number of modpost warnings on ppc32
  [POWERPC] Fix ethernet PHY support on MPC8544 DS
  [POWERPC] Don't try to allocate resources for a Freescale POWERPC PHB
  Revert "[POWERPC] Don't complain if size-cells == 0 in prom_parse()"
  ...

155 files changed:
CREDITS
Documentation/lguest/extract [new file with mode: 0644]
Documentation/lguest/lguest.c
Documentation/sched-stats.txt
MAINTAINERS
arch/alpha/kernel/head.S
arch/alpha/kernel/pci.c
arch/alpha/kernel/pci_iommu.c
arch/alpha/kernel/smp.c
arch/alpha/kernel/vmlinux.lds.S
arch/i386/kernel/alternative.c
arch/i386/kernel/cpu/cpufreq/Kconfig
arch/i386/mm/init.c
arch/ia64/kernel/cyclone.c
arch/ia64/kernel/time.c
arch/m32r/kernel/setup_mappi.c
arch/m68knommu/kernel/setup.c
arch/m68knommu/platform/5206/config.c
arch/m68knommu/platform/5206e/config.c
arch/m68knommu/platform/520x/config.c
arch/m68knommu/platform/523x/config.c
arch/m68knommu/platform/5249/config.c
arch/m68knommu/platform/5272/config.c
arch/m68knommu/platform/527x/config.c
arch/m68knommu/platform/528x/config.c
arch/m68knommu/platform/5307/config.c
arch/m68knommu/platform/5307/pit.c
arch/m68knommu/platform/5307/timers.c
arch/m68knommu/platform/532x/config.c
arch/m68knommu/platform/5407/config.c
arch/m68knommu/platform/68328/timers.c
arch/m68knommu/platform/68360/config.c
arch/sparc64/kernel/viohs.c
arch/x86_64/ia32/ia32_binfmt.c
arch/x86_64/ia32/syscall32.c
arch/x86_64/kernel/tce.c
arch/x86_64/kernel/tsc.c
arch/x86_64/mm/init.c
drivers/acpi/Kconfig
drivers/base/power/shutdown.c
drivers/block/lguest_blk.c
drivers/char/Kconfig
drivers/char/hpet.c
drivers/char/hvc_lguest.c
drivers/edac/Kconfig
drivers/edac/edac_mc.c
drivers/edac/edac_mc_sysfs.c
drivers/edac/edac_module.h
drivers/edac/edac_pci.c
drivers/edac/edac_pci_sysfs.c
drivers/edac/i3000_edac.c
drivers/i2c/chips/ds1682.c
drivers/ide/pci/scc_pata.c
drivers/ieee1394/raw1394.c
drivers/lguest/Makefile
drivers/lguest/README [new file with mode: 0644]
drivers/lguest/core.c
drivers/lguest/hypercalls.c
drivers/lguest/interrupts_and_traps.c
drivers/lguest/io.c
drivers/lguest/lg.h
drivers/lguest/lguest.c
drivers/lguest/lguest_asm.S
drivers/lguest/lguest_bus.c
drivers/lguest/lguest_user.c
drivers/lguest/page_tables.c
drivers/lguest/segments.c
drivers/lguest/switcher.S
drivers/media/video/Kconfig
drivers/mtd/maps/Kconfig
drivers/net/ax88796.c
drivers/net/cxgb3/cxgb3_offload.c
drivers/net/lguest_net.c
drivers/net/lib8390.c
drivers/net/pppol2tp.c
drivers/pnp/card.c
drivers/pnp/core.c
drivers/pnp/driver.c
drivers/pnp/interface.c
drivers/pnp/isapnp/compat.c
drivers/pnp/isapnp/core.c
drivers/pnp/isapnp/proc.c
drivers/pnp/manager.c
drivers/pnp/pnpacpi/core.c
drivers/pnp/pnpacpi/rsparser.c
drivers/pnp/pnpbios/bioscalls.c
drivers/pnp/pnpbios/core.c
drivers/pnp/pnpbios/proc.c
drivers/pnp/pnpbios/rsparser.c
drivers/pnp/quirks.c
drivers/pnp/resource.c
drivers/pnp/support.c
drivers/pnp/system.c
drivers/rtc/Makefile
drivers/rtc/rtc-ds1307.c
drivers/rtc/rtc-stk17ta8.c
drivers/spi/spi_s3c24xx.c
drivers/video/chipsfb.c
drivers/video/tgafb.c
drivers/w1/masters/ds1wm.c
drivers/xen/xenbus/xenbus_xs.c
fs/ext2/super.c
fs/ext3/super.c
fs/ext4/super.c
fs/lockd/svclock.c
fs/nfsd/nfs4xdr.c
fs/reiserfs/stree.c
fs/signalfd.c
fs/timerfd.c
fs/xfs/linux-2.6/xfs_ioctl32.c
include/asm-alpha/bitops.h
include/asm-arm/unaligned.h
include/asm-m68k/raw_io.h
include/asm-m68knommu/hardirq.h
include/asm-m68knommu/machdep.h
include/asm-mips/edac.h [new file with mode: 0644]
include/asm-powerpc/bug.h
include/asm-powerpc/page.h
include/asm-x86_64/uaccess.h
include/linux/compiler.h
include/linux/device.h
include/linux/lguest.h
include/linux/lguest_bus.h
include/linux/lguest_launcher.h
include/linux/mm.h
include/linux/netfilter/xt_connlimit.h
include/linux/pnp.h
include/linux/pnpbios.h
include/linux/preempt.h
include/linux/sched.h
include/linux/suspend.h
include/net/netfilter/nf_conntrack_tuple.h
include/xen/page.h
init/initramfs.c
kernel/Kconfig.preempt
kernel/kmod.c
kernel/power/disk.c
kernel/sched.c
kernel/sched_debug.c
kernel/sys.c
mm/migrate.c
mm/page_alloc.c
net/bridge/br_input.c
net/ipv4/netfilter/nf_nat_core.c
net/ipv4/netfilter/nf_nat_rule.c
net/ipv6/ip6_tunnel.c
net/key/af_key.c
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_conntrack_expect.c
net/netfilter/nf_conntrack_helper.c
net/netfilter/xt_connlimit.c
net/netfilter/xt_u32.c
net/rxrpc/ar-connection.c
net/sunrpc/svcsock.c
net/tipc/msg.h

diff --git a/CREDITS b/CREDITS
index 10c214dc95e764865c23834e9ff2ea4fa2bcde73..832436e1dd91c491fdb81efbda723e071c7084f6 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -966,6 +966,7 @@ N: Pekka Enberg
 E: penberg@cs.helsinki.fi
 W: http://www.cs.helsinki.fi/u/penberg/
 D: Various kernel hacks, fixes, and cleanups.
+D: Slab allocators
 S: Finland
 
 N: David Engebretsen
@@ -1939,8 +1940,8 @@ D: for Menuconfig's lxdialog.
 N: Christoph Lameter
 E: christoph@lameter.com
 D: Digiboard PC/Xe and PC/Xi, Digiboard EPCA
-D: Early protocol filter for bridging code
-D: Bug fixes
+D: NUMA support, Slab allocators, Page migration
+D: Scalability, Time subsystem
 
 N: Paul Laufer
 E: paul@laufernet.com
diff --git a/Documentation/lguest/extract b/Documentation/lguest/extract
new file mode 100644 (file)
index 0000000..7730bb6
--- /dev/null
@@ -0,0 +1,58 @@
+#! /bin/sh
+
+set -e
+
+PREFIX=$1
+shift
+
+trap 'rm -r $TMPDIR' 0
+TMPDIR=`mktemp -d`
+
+exec 3>/dev/null
+for f; do
+    while IFS="
+" read -r LINE; do
+       case "$LINE" in
+           *$PREFIX:[0-9]*:\**)
+               NUM=`echo "$LINE" | sed "s/.*$PREFIX:\([0-9]*\).*/\1/"`
+               if [ -f $TMPDIR/$NUM ]; then
+                   echo "$TMPDIR/$NUM already exits prior to $f"
+                   exit 1
+               fi
+               exec 3>>$TMPDIR/$NUM
+               echo $f | sed 's,\.\./,,g' > $TMPDIR/.$NUM
+               /bin/echo "$LINE" | sed -e "s/$PREFIX:[0-9]*//" -e "s/:\*/*/" >&3
+               ;;
+           *$PREFIX:[0-9]*)
+               NUM=`echo "$LINE" | sed "s/.*$PREFIX:\([0-9]*\).*/\1/"`
+               if [ -f $TMPDIR/$NUM ]; then
+                   echo "$TMPDIR/$NUM already exits prior to $f"
+                   exit 1
+               fi
+               exec 3>>$TMPDIR/$NUM
+               echo $f | sed 's,\.\./,,g' > $TMPDIR/.$NUM
+               /bin/echo "$LINE" | sed "s/$PREFIX:[0-9]*//" >&3
+               ;;
+           *:\**)
+               /bin/echo "$LINE" | sed -e "s/:\*/*/" -e "s,/\*\*/,," >&3
+               echo >&3
+               exec 3>/dev/null
+               ;;
+           *)
+               /bin/echo "$LINE" >&3
+               ;;
+       esac
+    done < $f
+    echo >&3
+    exec 3>/dev/null
+done
+
+LASTFILE=""
+for f in $TMPDIR/*; do
+    if [ "$LASTFILE" != $(cat $TMPDIR/.$(basename $f) ) ]; then
+       LASTFILE=$(cat $TMPDIR/.$(basename $f) )
+       echo "[ $LASTFILE ]"
+    fi
+    cat $f
+done
+
index 62a8133393e19d3991781317bc10c834a6ed5939..f7918401a0072c9b08bf81bb07434b66a96f6085 100644 (file)
@@ -1,5 +1,10 @@
-/* Simple program to layout "physical" memory for new lguest guest.
- * Linked high to avoid likely physical memory.  */
+/*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>
 #include <termios.h>
 #include <getopt.h>
 #include <zlib.h>
+/*L:110 We can ignore the 28 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
+ * like these abbreviations and the header we need uses them, so we define them
+ * here.
+ */
 typedef unsigned long long u64;
 typedef uint32_t u32;
 typedef uint16_t u16;
 typedef uint8_t u8;
 #include "../../include/linux/lguest_launcher.h"
 #include "../../include/asm-i386/e820.h"
+/*:*/
 
 #define PAGE_PRESENT 0x7       /* Present, RW, Execute */
 #define NET_PEERNUM 1
@@ -43,33 +56,52 @@ typedef uint8_t u8;
 #define SIOCBRADDIF    0x89a2          /* add interface to bridge      */
 #endif
 
+/*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. */
 static bool verbose;
 #define verbose(args...) \
        do { if (verbose) printf(args); } while(0)
+/*:*/
+
+/* The pipe to send commands to the waker process */
 static int waker_fd;
+/* The top of guest physical memory. */
 static u32 top;
 
+/* This is our list of devices. */
 struct device_list
 {
+       /* Summary information about the devices in our list: ready to pass to
+        * select() to ask which need servicing.*/
        fd_set infds;
        int max_infd;
 
+       /* The descriptor page for the devices. */
        struct lguest_device_desc *descs;
+
+       /* A single linked list of devices. */
        struct device *dev;
+       /* ... And an end pointer so we can easily append new devices */
        struct device **lastdev;
 };
 
+/* The device structure describes a single device. */
 struct device
 {
+       /* The linked-list pointer. */
        struct device *next;
+       /* The descriptor for this device, as mapped into the Guest. */
        struct lguest_device_desc *desc;
+       /* The memory page(s) of this device, if any.  Also mapped in Guest. */
        void *mem;
 
-       /* Watch this fd if handle_input non-NULL. */
+       /* If handle_input is set, it wants to be called when this file
+        * descriptor is ready. */
        int fd;
        bool (*handle_input)(int fd, struct device *me);
 
-       /* Watch DMA to this key if handle_input non-NULL. */
+       /* If handle_output is set, it wants to be called when the Guest sends
+        * DMA to this key. */
        unsigned long watch_key;
        u32 (*handle_output)(int fd, const struct iovec *iov,
                             unsigned int num, struct device *me);
@@ -78,6 +110,11 @@ struct device
        void *priv;
 };
 
+/*L:130
+ * Loading the Kernel.
+ *
+ * We start with couple of simple helper routines.  open_or_die() avoids
+ * error-checking code cluttering the callers: */
 static int open_or_die(const char *name, int flags)
 {
        int fd = open(name, flags);
@@ -86,26 +123,38 @@ static int open_or_die(const char *name, int flags)
        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)
 {
+       /* 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);
 
+       /* 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;
 }
 
-/* Find magic string marking entry point, return entry point. */
+/* 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,
                                 unsigned long page_offset)
 {
        void *p;
 
+       /* The scan gives us the physical starting address.  We want the
+        * virtual address in this case, and fortunately, we already figured
+        * out the physical-virtual difference and passed it here in
+        * "page_offset". */
        for (p = start; p < end; p++)
                if (memcmp(p, "GenuineLguest", strlen("GenuineLguest")) == 0)
                        return (long)p + strlen("GenuineLguest") + page_offset;
@@ -113,7 +162,17 @@ static unsigned long entry_point(void *start, void *end,
        err(1, "Is this image a genuine lguest?");
 }
 
-/* Returns the entry point */
+/* This routine takes an open vmlinux image, which is in ELF, and maps it into
+ * the Guest memory.  ELF = Embedded Linking Format, which is the format used
+ * by all modern binaries on Linux including the kernel.
+ *
+ * The ELF headers give *two* addresses: a physical address, and a virtual
+ * address.  The Guest kernel expects to be placed in memory at the physical
+ * address, and the page tables set up so it will correspond to that virtual
+ * address.  We return the difference between the virtual and physical
+ * addresses in the "page_offset" pointer.
+ *
+ * We return the starting address. */
 static unsigned long map_elf(int elf_fd, const Elf32_Ehdr *ehdr,
                             unsigned long *page_offset)
 {
@@ -122,40 +181,61 @@ static unsigned long map_elf(int elf_fd, const Elf32_Ehdr *ehdr,
        unsigned int i;
        unsigned long start = -1UL, end = 0;
 
-       /* Sanity checks. */
+       /* Sanity checks on the main ELF header: an x86 executable with a
+        * reasonable number of correctly-sized program headers. */
        if (ehdr->e_type != ET_EXEC
            || ehdr->e_machine != EM_386
            || ehdr->e_phentsize != sizeof(Elf32_Phdr)
            || ehdr->e_phnum < 1 || ehdr->e_phnum > 65536U/sizeof(Elf32_Phdr))
                errx(1, "Malformed elf header");
 
+       /* An ELF executable contains an ELF header and a number of "program"
+        * headers which indicate which parts ("segments") of the program to
+        * load where. */
+
+       /* We read in all the program headers at once: */
        if (lseek(elf_fd, ehdr->e_phoff, SEEK_SET) < 0)
                err(1, "Seeking to program headers");
        if (read(elf_fd, phdr, sizeof(phdr)) != sizeof(phdr))
                err(1, "Reading program headers");
 
+       /* We don't know page_offset yet. */
        *page_offset = 0;
-       /* We map the loadable segments at virtual addresses corresponding
-        * to their physical addresses (our virtual == guest physical). */
+
+       /* 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. */
        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)
                        continue;
 
                verbose("Section %i: size %i addr %p\n",
                        i, phdr[i].p_memsz, (void *)phdr[i].p_paddr);
 
-               /* We expect linear address space. */
+               /* We expect a simple linear address space: every segment must
+                * have the same difference between virtual (p_vaddr) and
+                * physical (p_paddr) address. */
                if (!*page_offset)
                        *page_offset = phdr[i].p_vaddr - phdr[i].p_paddr;
                else if (*page_offset != phdr[i].p_vaddr - phdr[i].p_paddr)
                        errx(1, "Page offset of section %i different", i);
 
+               /* 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;
 
-               /* We map everything private, writable. */
+               /* We map this section of the file at its physical address.  We
+                * map it read & write even if the header says this segment is
+                * read-only.  The kernel really wants to be writable: it
+                * patches its own instructions which would normally be
+                * read-only.
+                *
+                * MAP_PRIVATE means that the page won't be copied until a
+                * write is done to it.  This allows us to share much of the
+                * kernel memory between Guests. */
                addr = mmap((void *)phdr[i].p_paddr,
                            phdr[i].p_filesz,
                            PROT_READ|PROT_WRITE|PROT_EXEC,
@@ -169,7 +249,31 @@ static unsigned long map_elf(int elf_fd, const Elf32_Ehdr *ehdr,
        return entry_point((void *)start, (void *)end, *page_offset);
 }
 
-/* This is amazingly reliable. */
+/*L:170 Prepare to be SHOCKED and AMAZED.  And possibly a trifle nauseated.
+ *
+ * We know that CONFIG_PAGE_OFFSET sets what virtual address the kernel expects
+ * to be.  We don't know what that option was, but we can figure it out
+ * approximately by looking at the addresses in the code.  I chose the common
+ * case of reading a memory location into the %eax register:
+ *
+ *  movl <some-address>, %eax
+ *
+ * This gets encoded as five bytes: "0xA1 <4-byte-address>".  For example,
+ * "0xA1 0x18 0x60 0x47 0xC0" reads the address 0xC0476018 into %eax.
+ *
+ * In this example can guess that the kernel was compiled with
+ * CONFIG_PAGE_OFFSET set to 0xC0000000 (it's always a round number).  If the
+ * kernel were larger than 16MB, we might see 0xC1 addresses show up, but our
+ * kernel isn't that bloated yet.
+ *
+ * Unfortunately, x86 has variable-length instructions, so finding this
+ * particular instruction properly involves writing a disassembler.  Instead,
+ * we rely on statistics.  We look for "0xA1" and tally the different bytes
+ * which occur 4 bytes later (the "0xC0" in our example above).  When one of
+ * those bytes appears three times, we can be reasonably confident that it
+ * forms the start of CONFIG_PAGE_OFFSET.
+ *
+ * This is amazingly reliable. */
 static unsigned long intuit_page_offset(unsigned char *img, unsigned long len)
 {
        unsigned int i, possibilities[256] = { 0 };
@@ -182,30 +286,52 @@ static unsigned long intuit_page_offset(unsigned char *img, unsigned long len)
        errx(1, "could not determine page offset");
 }
 
+/*L:160 Unfortunately the entire ELF image isn't compressed: the segments
+ * which need loading are extracted and compressed raw.  This denies us the
+ * information we need to make a fully-general loader. */
 static unsigned long unpack_bzimage(int fd, unsigned long *page_offset)
 {
        gzFile f;
        int ret, len = 0;
+       /* A bzImage always gets loaded at physical address 1M.  This is
+        * 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;
 
+       /* gzdopen takes our file descriptor (carefully placed at the start of
+        * the GZIP header we found) and returns a gzFile. */
        f = gzdopen(fd, "rb");
+       /* We read it into memory in 64k chunks until we hit the end. */
        while ((ret = gzread(f, img + len, 65536)) > 0)
                len += ret;
        if (ret < 0)
                err(1, "reading image from bzImage");
 
        verbose("Unpacked size %i addr %p\n", len, img);
+
+       /* Without the ELF header, we can't tell virtual-physical gap.  This is
+        * CONFIG_PAGE_OFFSET, and people do actually change it.  Fortunately,
+        * I have a clever way of figuring it out from the code itself.  */
        *page_offset = intuit_page_offset(img, len);
 
        return entry_point(img, img + len, *page_offset);
 }
 
+/*L:150 A bzImage, unlike an ELF file, is not meant to be loaded.  You're
+ * supposed to jump into it and it will unpack itself.  We can't do that
+ * because the Guest can't run the unpacking code, and adding features to
+ * lguest kills puppies, so we don't want to.
+ *
+ * The bzImage is formed by putting the decompressing code in front of the
+ * compressed kernel code.  So we can simple scan through it looking for the
+ * first "gzip" header, and start decompressing from there. */
 static unsigned long load_bzimage(int fd, unsigned long *page_offset)
 {
        unsigned char c;
        int state = 0;
 
-       /* Ugly brute force search for gzip header. */
+       /* GZIP header is 0x1F 0x8B <method> <flags>... <compressed-by>. */
        while (read(fd, &c, 1) == 1) {
                switch (state) {
                case 0:
@@ -222,8 +348,10 @@ static unsigned long load_bzimage(int fd, unsigned long *page_offset)
                        state++;
                        break;
                case 9:
+                       /* Seek back to the start of the gzip header. */
                        lseek(fd, -10, SEEK_CUR);
-                       if (c != 0x03) /* Compressed under UNIX. */
+                       /* One final check: "compressed under UNIX". */
+                       if (c != 0x03)
                                state = -1;
                        else
                                return unpack_bzimage(fd, page_offset);
@@ -232,25 +360,43 @@ static unsigned long load_bzimage(int fd, unsigned long *page_offset)
        errx(1, "Could not find kernel in bzImage");
 }
 
+/*L:140 Loading the kernel is easy when it's a "vmlinux", but most kernels
+ * come wrapped up in the self-decompressing "bzImage" format.  With some funky
+ * coding, we can load those, too. */
 static unsigned long load_kernel(int fd, unsigned long *page_offset)
 {
        Elf32_Ehdr hdr;
 
+       /* Read in the first few bytes. */
        if (read(fd, &hdr, sizeof(hdr)) != sizeof(hdr))
                err(1, "Reading kernel");
 
+       /* If it's an ELF file, it starts with "\177ELF" */
        if (memcmp(hdr.e_ident, ELFMAG, SELFMAG) == 0)
                return map_elf(fd, &hdr, page_offset);
 
+       /* Otherwise we assume it's a bzImage, and try to unpack it */
        return load_bzimage(fd, page_offset);
 }
 
+/* This is a trivial little helper to align pages.  Andi Kleen hated it because
+ * it calls getpagesize() twice: "it's dumb code."
+ *
+ * Kernel guys get really het up about optimization, even when it's not
+ * necessary.  I leave this code as a reaction against that. */
 static inline unsigned long page_align(unsigned long addr)
 {
+       /* Add upwards and truncate downwards. */
        return ((addr + getpagesize()-1) & ~(getpagesize()-1));
 }
 
-/* initrd gets loaded at top of memory: return length. */
+/*L:180 An "initial ram disk" is a disk image loaded into memory along with
+ * the kernel which the kernel can use to boot from without needing any
+ * drivers.  Most distributions now use this as standard: the initrd contains
+ * the code to load the appropriate driver modules for the current machine.
+ *
+ * Importantly, James Morris works for RedHat, and Fedora uses initrds for its
+ * kernels.  He sent me this (and tells me when I break it). */
 static unsigned long load_initrd(const char *name, unsigned long mem)
 {
        int ifd;
@@ -259,21 +405,35 @@ static unsigned long load_initrd(const char *name, unsigned long mem)
        void *iaddr;
 
        ifd = open_or_die(name, O_RDONLY);
+       /* fstat() is needed to get the file size. */
        if (fstat(ifd, &st) < 0)
                err(1, "fstat() on initrd '%s'", name);
 
+       /* The length needs to be rounded up to a page size: mmap needs the
+        * address to be page aligned. */
        len = page_align(st.st_size);
+       /* We map the initrd at the top of memory. */
        iaddr = mmap((void *)mem - len, st.st_size,
                     PROT_READ|PROT_EXEC|PROT_WRITE,
                     MAP_FIXED|MAP_PRIVATE, ifd, 0);
        if (iaddr != (void *)mem - len)
                err(1, "Mmaping initrd '%s' returned %p not %p",
                    name, iaddr, (void *)mem - len);
+       /* Once a file is mapped, you can close the file descriptor.  It's a
+        * little odd, but quite useful. */
        close(ifd);
        verbose("mapped initrd %s size=%lu @ %p\n", name, st.st_size, iaddr);
+
+       /* We return the initrd size. */
        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.
+ *
+ * We lay them out of the way, just below the initrd (which is why we need to
+ * know its size). */
 static unsigned long setup_pagetables(unsigned long mem,
                                      unsigned long initrd_size,
                                      unsigned long page_offset)
@@ -282,23 +442,32 @@ static unsigned long setup_pagetables(unsigned long mem,
        unsigned int mapped_pages, i, linear_pages;
        unsigned int ptes_per_page = getpagesize()/sizeof(u32);
 
-       /* If we can map all of memory above page_offset, we do so. */
+       /* Ideally we map all physical memory starting at page_offset.
+        * However, if page_offset is 0xC0000000 we can only map 1G of physical
+        * (0xC0000000 + 1G overflows). */
        if (mem <= -page_offset)
                mapped_pages = mem/getpagesize();
        else
                mapped_pages = -page_offset/getpagesize();
 
-       /* Each linear PTE page can map ptes_per_page pages. */
+       /* Each PTE page can map ptes_per_page pages: how many do we need? */
        linear_pages = (mapped_pages + ptes_per_page-1)/ptes_per_page;
 
-       /* We lay out top-level then linear mapping immediately below initrd */
+       /* We put the toplevel page directory page at the top of memory. */
        pgdir = (void *)mem - initrd_size - getpagesize();
+
+       /* Now we use the next linear_pages pages as pte pages */
        linear = (void *)pgdir - linear_pages*getpagesize();
 
+       /* Linear mapping is easy: put every page's address into the mapping in
+        * order.  PAGE_PRESENT contains the flags Present, Writable and
+        * Executable. */
        for (i = 0; i < mapped_pages; i++)
                linear[i] = ((i * getpagesize()) | PAGE_PRESENT);
 
-       /* Now set up pgd so that this memory is at page_offset */
+       /* The top level points to the linear page table pages above.  The
+        * entry representing page_offset points to the first one, and they
+        * 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);
@@ -307,9 +476,13 @@ static unsigned long setup_pagetables(unsigned long mem,
        verbose("Linear mapping of %u pages in %u pte pages at %p\n",
                mapped_pages, linear_pages, linear);
 
+       /* We return the top level (guest-physical) address: the kernel needs
+        * to know where it is. */
        return (unsigned long)pgdir;
 }
 
+/* Simple routine to roll all the commandline arguments together with spaces
+ * between them. */
 static void concat(char *dst, char *args[])
 {
        unsigned int i, len = 0;
@@ -323,6 +496,10 @@ static void concat(char *dst, char *args[])
        dst[len] = '\0';
 }
 
+/* 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. */
 static int tell_kernel(u32 pgdir, u32 start, u32 page_offset)
 {
        u32 args[] = { LHREQ_INITIALIZE,
@@ -332,8 +509,11 @@ static int tell_kernel(u32 pgdir, u32 start, u32 page_offset)
        fd = open_or_die("/dev/lguest", O_RDWR);
        if (write(fd, args, sizeof(args)) < 0)
                err(1, "Writing to /dev/lguest");
+
+       /* We return the /dev/lguest file descriptor to control this Guest */
        return fd;
 }
+/*:*/
 
 static void set_fd(int fd, struct device_list *devices)
 {
@@ -342,61 +522,108 @@ static void set_fd(int fd, struct device_list *devices)
                devices->max_infd = fd;
 }
 
-/* When input arrives, we tell the kernel to kick lguest out with -EAGAIN. */
+/*L:200
+ * The Waker.
+ *
+ * With a console and network devices, we can have lots of input which we need
+ * to process.  We could try to tell the kernel what file descriptors to watch,
+ * but handing a file descriptor mask through to the kernel is fairly icky.
+ *
+ * Instead, we fork off a process which watches the file descriptors and writes
+ * the LHREQ_BREAK command to the /dev/lguest filedescriptor to tell the Host
+ * loop to stop running the Guest.  This causes it to return from the
+ * /dev/lguest read with -EAGAIN, where it will write to /dev/lguest to reset
+ * the LHREQ_BREAK and wake us up again.
+ *
+ * This, of course, is merely a different *kind* of icky.
+ */
 static void wake_parent(int pipefd, int lguest_fd, struct device_list *devices)
 {
+       /* Add the pipe from the Launcher to the fdset in the device_list, so
+        * we watch it, too. */
        set_fd(pipefd, devices);
 
        for (;;) {
                fd_set rfds = devices->infds;
                u32 args[] = { LHREQ_BREAK, 1 };
 
+               /* Wait until input is ready from one of the devices. */
                select(devices->max_infd+1, &rfds, NULL, NULL, NULL);
+               /* Is it a message from the Launcher? */
                if (FD_ISSET(pipefd, &rfds)) {
                        int ignorefd;
+                       /* If read() returns 0, it means the Launcher has
+                        * exited.  We silently follow. */
                        if (read(pipefd, &ignorefd, sizeof(ignorefd)) == 0)
                                exit(0);
+                       /* Otherwise it's telling us there's a problem with one
+                        * of the devices, and we should ignore that file
+                        * descriptor from now on. */
                        FD_CLR(ignorefd, &devices->infds);
-               } else
+               } else /* Send LHREQ_BREAK command. */
                        write(lguest_fd, args, sizeof(args));
        }
 }
 
+/* This routine just sets up a pipe to the Waker process. */
 static int setup_waker(int lguest_fd, struct device_list *device_list)
 {
        int pipefd[2], child;
 
+       /* We create a pipe to talk to the waker, and also so it knows when the
+        * Launcher dies (and closes pipe). */
        pipe(pipefd);
        child = fork();
        if (child == -1)
                err(1, "forking");
 
        if (child == 0) {
+               /* Close the "writing" end of our copy of the pipe */
                close(pipefd[1]);
                wake_parent(pipefd[0], lguest_fd, device_list);
        }
+       /* Close the reading end of our copy of the pipe. */
        close(pipefd[0]);
 
+       /* Here is the fd used to talk to the waker. */
        return pipefd[1];
 }
 
+/*L:210
+ * Device Handling.
+ *
+ * When the Guest sends DMA to us, it sends us an array of addresses and sizes.
+ * We need to make sure it's not trying to reach into the Launcher itself, so
+ * we have a convenient routine which check it and exits with an error message
+ * if something funny is going on:
+ */
 static void *_check_pointer(unsigned long addr, unsigned int size,
                            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 >= top || addr + size >= top)
                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;
 }
+/* A macro which transparently hands the line number to the real function. */
 #define check_pointer(addr,size) _check_pointer(addr, size, __LINE__)
 
-/* Returns pointer to dma->used_len */
+/* The Guest has given us the address of a "struct lguest_dma".  We check it's
+ * OK and convert it to an iovec (which is a simple array of ptr/size
+ * pairs). */
 static u32 *dma2iov(unsigned long dma, struct iovec iov[], unsigned *num)
 {
        unsigned int i;
        struct lguest_dma *udma;
 
+       /* First we make sure that the array memory itself is valid. */
        udma = check_pointer(dma, sizeof(*udma));
+       /* Now we check each element */
        for (i = 0; i < LGUEST_MAX_DMA_SECTIONS; i++) {
+               /* A zero length ends the array. */
                if (!udma->len[i])
                        break;
 
@@ -404,9 +631,15 @@ static u32 *dma2iov(unsigned long dma, struct iovec iov[], unsigned *num)
                iov[i].iov_len = udma->len[i];
        }
        *num = i;
+
+       /* We return the pointer to where the caller should write the amount of
+        * the buffer used. */
        return &udma->used_len;
 }
 
+/* This routine gets a DMA buffer from the Guest for a given key, and converts
+ * it to an iovec array.  It returns the interrupt the Guest wants when we're
+ * finished, and a pointer to the "used_len" field to fill in. */
 static u32 *get_dma_buffer(int fd, void *key,
                           struct iovec iov[], unsigned int *num, u32 *irq)
 {
@@ -414,16 +647,21 @@ static u32 *get_dma_buffer(int fd, void *key,
        unsigned long udma;
        u32 *res;
 
+       /* Ask the kernel for a DMA buffer corresponding to this key. */
        udma = write(fd, buf, sizeof(buf));
+       /* They haven't registered any, or they're all used? */
        if (udma == (unsigned long)-1)
                return NULL;
 
-       /* Kernel stashes irq in ->used_len. */
+       /* Convert it into our iovec array */
        res = dma2iov(udma, iov, num);
+       /* The kernel stashes irq in ->used_len to get it out to us. */
        *irq = *res;
+       /* Return a pointer to ((struct lguest_dma *)udma)->used_len. */
        return res;
 }
 
+/* This is a convenient routine to send the Guest an interrupt. */
 static void trigger_irq(int fd, u32 irq)
 {
        u32 buf[] = { LHREQ_IRQ, irq };
@@ -431,6 +669,10 @@ static void trigger_irq(int fd, u32 irq)
                err(1, "Triggering irq %i", irq);
 }
 
+/* This simply sets up an iovec array where we can put data to be discarded.
+ * This happens when the Guest doesn't want or can't handle the input: we have
+ * to get rid of it somewhere, and if we bury it in the ceiling space it will
+ * start to smell after a week. */
 static void discard_iovec(struct iovec *iov, unsigned int *num)
 {
        static char discard_buf[1024];
@@ -439,19 +681,24 @@ static void discard_iovec(struct iovec *iov, unsigned int *num)
        iov->iov_len = sizeof(discard_buf);
 }
 
+/* Here is the input terminal setting we save, and the routine to restore them
+ * on exit so the user can see what they type next. */
 static struct termios orig_term;
 static void restore_term(void)
 {
        tcsetattr(STDIN_FILENO, TCSANOW, &orig_term);
 }
 
+/* We associate some data with the console for our exit hack. */
 struct console_abort
 {
+       /* How many times have they hit ^C? */
        int count;
+       /* When did they start? */
        struct timeval start;
 };
 
-/* We DMA input to buffer bound at start of console page. */
+/* This is the routine which handles console input (ie. stdin). */
 static bool handle_console_input(int fd, struct device *dev)
 {
        u32 irq = 0, *lenp;
@@ -460,24 +707,38 @@ static bool handle_console_input(int fd, struct device *dev)
        struct iovec iov[LGUEST_MAX_DMA_SECTIONS];
        struct console_abort *abort = dev->priv;
 
+       /* First we get the console buffer from the Guest.  The key is dev->mem
+        * which was set to 0 in setup_console(). */
        lenp = get_dma_buffer(fd, dev->mem, iov, &num, &irq);
        if (!lenp) {
+               /* If it's not ready for input, warn and set up to discard. */
                warn("console: no dma buffer!");
                discard_iovec(iov, &num);
        }
 
+       /* This is why we convert to iovecs: the readv() call uses them, and so
+        * it reads straight into the Guest's buffer. */
        len = readv(dev->fd, iov, num);
        if (len <= 0) {
+               /* This implies that the console is closed, is /dev/null, or
+                * something went terribly wrong.  We still go through the rest
+                * of the logic, though, especially the exit handling below. */
                warnx("Failed to get console input, ignoring console.");
                len = 0;
        }
 
+       /* If we read the data into the Guest, fill in the length and send the
+        * interrupt. */
        if (lenp) {
                *lenp = len;
                trigger_irq(fd, irq);
        }
 
-       /* Three ^C within one second?  Exit. */
+       /* Three ^C within one second?  Exit.
+        *
+        * This is such a hack, but works surprisingly well.  Each ^C has to be
+        * in a buffer by itself, so they can't be too fast.  But we check that
+        * we get three within about a second, so they can't be too slow. */
        if (len == 1 && ((char *)iov[0].iov_base)[0] == 3) {
                if (!abort->count++)
                        gettimeofday(&abort->start, NULL);
@@ -485,43 +746,60 @@ static bool handle_console_input(int fd, struct device *dev)
                        struct timeval now;
                        gettimeofday(&now, NULL);
                        if (now.tv_sec <= abort->start.tv_sec+1) {
-                               /* Make sure waker is not blocked in BREAK */
                                u32 args[] = { LHREQ_BREAK, 0 };
+                               /* Close the fd so Waker will know it has to
+                                * exit. */
                                close(waker_fd);
+                               /* Just in case waker is blocked in BREAK, send
+                                * unbreak now. */
                                write(fd, args, sizeof(args));
                                exit(2);
                        }
                        abort->count = 0;
                }
        } else
+               /* Any other key resets the abort counter. */
                abort->count = 0;
 
+       /* Now, if we didn't read anything, put the input terminal back and
+        * return failure (meaning, don't call us again). */
        if (!len) {
                restore_term();
                return false;
        }
+       /* Everything went OK! */
        return true;
 }
 
+/* Handling console output is much simpler than input. */
 static u32 handle_console_output(int fd, const struct iovec *iov,
                                 unsigned num, struct device*dev)
 {
+       /* Whatever the Guest sends, write it to standard output.  Return the
+        * number of bytes written. */
        return writev(STDOUT_FILENO, iov, num);
 }
 
+/* Guest->Host network output is also pretty easy. */
 static u32 handle_tun_output(int fd, const struct iovec *iov,
                             unsigned num, struct device *dev)
 {
-       /* Now we've seen output, we should warn if we can't get buffers. */
+       /* We put a flag in the "priv" pointer of the network device, and set
+        * it as soon as we see output.  We'll see why in handle_tun_input() */
        *(bool *)dev->priv = true;
+       /* Whatever packet the Guest sent us, write it out to the tun
+        * device. */
        return writev(dev->fd, iov, num);
 }
 
+/* This matches the peer_key() in lguest_net.c.  The key for any given slot
+ * is the address of the network device's page plus 4 * the slot number. */
 static unsigned long peer_offset(unsigned int peernum)
 {
        return 4 * peernum;
 }
 
+/* This is where we handle a packet coming in from the tun device */
 static bool handle_tun_input(int fd, struct device *dev)
 {
        u32 irq = 0, *lenp;
@@ -529,17 +807,28 @@ static bool handle_tun_input(int fd, struct device *dev)
        unsigned num;
        struct iovec iov[LGUEST_MAX_DMA_SECTIONS];
 
+       /* First we get a buffer the Guest has bound to its key. */
        lenp = get_dma_buffer(fd, dev->mem+peer_offset(NET_PEERNUM), iov, &num,
                              &irq);
        if (!lenp) {
+               /* Now, it's expected that if we try to send a packet too
+                * early, the Guest won't be ready yet.  This is why we set a
+                * flag when the Guest sends its first packet.  If it's sent a
+                * packet we assume it should be ready to receive them.
+                *
+                * Actually, this is what the status bits in the descriptor are
+                * for: we should *use* them.  FIXME! */
                if (*(bool *)dev->priv)
                        warn("network: no dma buffer!");
                discard_iovec(iov, &num);
        }
 
+       /* Read the packet from the device directly into the Guest's buffer. */
        len = readv(dev->fd, iov, num);
        if (len <= 0)
                err(1, "reading network");
+
+       /* Write the used_len, and trigger the interrupt for the Guest */
        if (lenp) {
                *lenp = len;
                trigger_irq(fd, irq);
@@ -547,9 +836,13 @@ static bool handle_tun_input(int fd, struct device *dev)
        verbose("tun input packet len %i [%02x %02x] (%s)\n", len,
                ((u8 *)iov[0].iov_base)[0], ((u8 *)iov[0].iov_base)[1],
                lenp ? "sent" : "discarded");
+       /* All good. */
        return true;
 }
 
+/* The last device handling routine is block output: the Guest has sent a DMA
+ * to the block device.  It will have placed the command it wants in the
+ * "struct lguest_block_page". */
 static u32 handle_block_output(int fd, const struct iovec *iov,
                               unsigned num, struct device *dev)
 {
@@ -559,36 +852,64 @@ static u32 handle_block_output(int fd, const struct iovec *iov,
        struct iovec reply[LGUEST_MAX_DMA_SECTIONS];
        off64_t device_len, off = (off64_t)p->sector * 512;
 
+       /* First we extract the device length from the dev->priv pointer. */
        device_len = *(off64_t *)dev->priv;
 
+       /* We first check that the read or write is within the length of the
+        * block file. */
        if (off >= device_len)
                err(1, "Bad offset %llu vs %llu", off, device_len);
+       /* Move to the right location in the block file.  This shouldn't fail,
+        * but best to check. */
        if (lseek64(dev->fd, off, SEEK_SET) != off)
                err(1, "Bad seek to sector %i", p->sector);
 
        verbose("Block: %s at offset %llu\n", p->type ? "WRITE" : "READ", off);
 
+       /* They were supposed to bind a reply buffer at key equal to the start
+        * of the block device memory.  We need this to tell them when the
+        * request is finished. */
        lenp = get_dma_buffer(fd, dev->mem, reply, &reply_num, &irq);
        if (!lenp)
                err(1, "Block request didn't give us a dma buffer");
 
        if (p->type) {
+               /* A write request.  The DMA they sent contained the data, so
+                * write it out. */
                len = writev(dev->fd, iov, num);
+               /* Grr... Now we know how long the "struct lguest_dma" they
+                * sent was, we make sure they didn't try to write over the end
+                * of the block file (possibly extending it). */
                if (off + len > device_len) {
+                       /* Trim it back to the correct length */
                        ftruncate(dev->fd, device_len);
+                       /* Die, bad Guest, die. */
                        errx(1, "Write past end %llu+%u", off, len);
                }
+               /* The reply length is 0: we just send back an empty DMA to
+                * interrupt them and tell them the write is finished. */
                *lenp = 0;
        } else {
+               /* A read request.  They sent an empty DMA to start the
+                * request, and we put the read contents into the reply
+                * buffer. */
                len = readv(dev->fd, reply, reply_num);
                *lenp = len;
        }
 
+       /* The result is 1 (done), 2 if there was an error (short read or
+        * write). */
        p->result = 1 + (p->bytes != len);
+       /* Now tell them we've used their reply buffer. */
        trigger_irq(fd, irq);
+
+       /* We're supposed to return the number of bytes of the output buffer we
+        * used.  But the block device uses the "result" field instead, so we
+        * don't bother. */
        return 0;
 }
 
+/* This is the generic routine we call when the Guest sends some DMA out. */
 static void handle_output(int fd, unsigned long dma, unsigned long key,
                          struct device_list *devices)
 {
@@ -597,30 +918,53 @@ static void handle_output(int fd, unsigned long dma, unsigned long key,
        struct iovec iov[LGUEST_MAX_DMA_SECTIONS];
        unsigned num = 0;
 
+       /* Convert the "struct lguest_dma" they're sending to a "struct
+        * iovec". */
        lenp = dma2iov(dma, iov, &num);
+
+       /* Check each device: if they expect output to this key, tell them to
+        * handle it. */
        for (i = devices->dev; i; i = i->next) {
                if (i->handle_output && key == i->watch_key) {
+                       /* We write the result straight into the used_len field
+                        * for them. */
                        *lenp = i->handle_output(fd, iov, num, i);
                        return;
                }
        }
+
+       /* This can happen: the kernel sends any SEND_DMA which doesn't match
+        * another Guest to us.  It could be that another Guest just left a
+        * network, for example.  But it's unusual. */
        warnx("Pending dma %p, key %p", (void *)dma, (void *)key);
 }
 
+/* This is called when the waker wakes us up: check for incoming file
+ * descriptors. */
 static void handle_input(int fd, struct device_list *devices)
 {
+       /* select() wants a zeroed timeval to mean "don't wait". */
        struct timeval poll = { .tv_sec = 0, .tv_usec = 0 };
 
        for (;;) {
                struct device *i;
                fd_set fds = devices->infds;
 
+               /* If nothing is ready, we're done. */
                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.  */
                for (i = devices->dev; i; i = i->next) {
                        if (i->handle_input && FD_ISSET(i->fd, &fds)) {
+                               /* If handle_input() returns false, it means we
+                                * should no longer service it.
+                                * handle_console_input() does this. */
                                if (!i->handle_input(fd, i)) {
+                                       /* Clear it from the set of input file
+                                        * descriptors kept at the head of the
+                                        * device list. */
                                        FD_CLR(i->fd, &devices->infds);
                                        /* Tell waker to ignore it too... */
                                        write(waker_fd, &i->fd, sizeof(i->fd));
@@ -630,6 +974,15 @@ static void handle_input(int fd, struct device_list *devices)
        }
 }
 
+/*L:190
+ * Device Setup
+ *
+ * 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 them.
+ *
+ * This routine allocates a new "struct lguest_device_desc" from descriptor
+ * table in the devices array just above the Guest's normal memory. */
 static struct lguest_device_desc *
 new_dev_desc(struct lguest_device_desc *descs,
             u16 type, u16 features, u16 num_pages)
@@ -641,6 +994,8 @@ new_dev_desc(struct lguest_device_desc *descs,
                        descs[i].type = type;
                        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. */
                        if (num_pages) {
                                map_zeroed_pages(top, num_pages);
                                descs[i].pfn = top/getpagesize();
@@ -652,6 +1007,9 @@ new_dev_desc(struct lguest_device_desc *descs,
        errx(1, "too many devices");
 }
 
+/* This monster routine does all the creation and setup of a new device,
+ * including caling new_dev_desc() to allocate the descriptor and device
+ * memory. */
 static struct device *new_device(struct device_list *devices,
                                 u16 type, u16 num_pages, u16 features,
                                 int fd,
@@ -664,12 +1022,18 @@ static struct device *new_device(struct device_list *devices,
 {
        struct device *dev = malloc(sizeof(*dev));
 
-       /* Append to device list. */
+       /* Append to device list.  Prepending to a single-linked list is
+        * easier, but the user expects the devices to be arranged on the bus
+        * in command-line order.  The first network device on the command line
+        * is eth0, the first block device /dev/lgba, etc. */
        *devices->lastdev = dev;
        dev->next = NULL;
        devices->lastdev = &dev->next;
 
+       /* Now we populate the fields one at a time. */
        dev->fd = fd;
+       /* If we have an input handler for this file descriptor, then we add it
+        * to the device_list's fdset and maxfd. */
        if (handle_input)
                set_fd(dev->fd, devices);
        dev->desc = new_dev_desc(devices->descs, type, features, num_pages);
@@ -680,27 +1044,37 @@ static struct device *new_device(struct device_list *devices,
        return dev;
 }
 
+/* Our first setup routine is the console.  It's a fairly simple device, but
+ * UNIX tty handling makes it uglier than it could be. */
 static void setup_console(struct device_list *devices)
 {
        struct device *dev;
 
+       /* If we can save the initial standard input settings... */
        if (tcgetattr(STDIN_FILENO, &orig_term) == 0) {
                struct termios term = orig_term;
+               /* Then we turn off echo, line buffering and ^C etc.  We want a
+                * raw input stream to the Guest. */
                term.c_lflag &= ~(ISIG|ICANON|ECHO);
                tcsetattr(STDIN_FILENO, TCSANOW, &term);
+               /* If we exit gracefully, the original settings will be
+                * restored so the user can see what they're typing. */
                atexit(restore_term);
        }
 
-       /* We don't currently require a page for the console. */
+       /* We don't currently require any memory for the console, so we ask for
+        * 0 pages. */
        dev = new_device(devices, LGUEST_DEVICE_T_CONSOLE, 0, 0,
                         STDIN_FILENO, handle_console_input,
                         LGUEST_CONSOLE_DMA_KEY, handle_console_output);
+       /* We store the console state in dev->priv, and initialize it. */
        dev->priv = malloc(sizeof(struct console_abort));
        ((struct console_abort *)dev->priv)->count = 0;
        verbose("device %p: console\n",
                (void *)(dev->desc->pfn * getpagesize()));
 }
 
+/* Setting up a block file is also fairly straightforward. */
 static void setup_block_file(const char *filename, struct device_list *devices)
 {
        int fd;
@@ -708,20 +1082,47 @@ static void setup_block_file(const char *filename, struct device_list *devices)
        off64_t *device_len;
        struct lguest_block_page *p;
 
+       /* We open with O_LARGEFILE because otherwise we get stuck at 2G.  We
+        * open with O_DIRECT because otherwise our benchmarks go much too
+        * fast. */
        fd = open_or_die(filename, O_RDWR|O_LARGEFILE|O_DIRECT);
+
+       /* We want one page, and have no input handler (the block file never
+        * has anything interesting to say to us).  Our timing will be quite
+        * random, so it should be a reasonable randomness source. */
        dev = new_device(devices, LGUEST_DEVICE_T_BLOCK, 1,
                         LGUEST_DEVICE_F_RANDOMNESS,
                         fd, NULL, 0, handle_block_output);
+
+       /* We store the device size in the private area */
        device_len = dev->priv = malloc(sizeof(*device_len));
+       /* This is the safe way of establishing the size of our device: it
+        * might be a normal file or an actual block device like /dev/hdb. */
        *device_len = lseek64(fd, 0, SEEK_END);
-       p = dev->mem;
 
+       /* The device memory is a "struct lguest_block_page".  It's zeroed
+        * already, we just need to put in the device size.  Block devices
+        * think in sectors (ie. 512 byte chunks), so we translate here. */
+       p = dev->mem;
        p->num_sectors = *device_len/512;
        verbose("device %p: block %i sectors\n",
                (void *)(dev->desc->pfn * getpagesize()), p->num_sectors);
 }
 
-/* We use fnctl locks to reserve network slots (autocleanup!) */
+/*
+ * Network Devices.
+ *
+ * Setting up network devices is quite a pain, because we have three types.
+ * First, we have the inter-Guest network.  This is a file which is mapped into
+ * the address space of the Guests who are on the network.  Because it is a
+ * shared mapping, the same page underlies all the devices, and they can send
+ * DMA to each other.
+ *
+ * Remember from our network driver, the Guest is told what slot in the page it
+ * is to use.  We use exclusive fnctl locks to reserve a slot.  If another
+ * Guest is using a slot, the lock will fail and we try another.  Because fnctl
+ * locks are cleaned up automatically when we die, this cleverly means that our
+ * reservation on the slot will vanish if we crash. */
 static unsigned int find_slot(int netfd, const char *filename)
 {
        struct flock fl;
@@ -729,26 +1130,33 @@ static unsigned int find_slot(int netfd, const char *filename)
        fl.l_type = F_WRLCK;
        fl.l_whence = SEEK_SET;
        fl.l_len = 1;
+       /* Try a 1 byte lock in each possible position number */
        for (fl.l_start = 0;
             fl.l_start < getpagesize()/sizeof(struct lguest_net);
             fl.l_start++) {
+               /* If we succeed, return the slot number. */
                if (fcntl(netfd, F_SETLK, &fl) == 0)
                        return fl.l_start;
        }
        errx(1, "No free slots in network file %s", filename);
 }
 
+/* This function sets up the network file */
 static void setup_net_file(const char *filename,
                           struct device_list *devices)
 {
        int netfd;
        struct device *dev;
 
+       /* We don't use open_or_die() here: for friendliness we create the file
+        * if it doesn't already exist. */
        netfd = open(filename, O_RDWR, 0);
        if (netfd < 0) {
                if (errno == ENOENT) {
                        netfd = open(filename, O_RDWR|O_CREAT, 0600);
                        if (netfd >= 0) {
+                               /* If we succeeded, initialize the file with a
+                                * blank page. */
                                char page[getpagesize()];
                                memset(page, 0, sizeof(page));
                                write(netfd, page, sizeof(page));
@@ -758,11 +1166,15 @@ static void setup_net_file(const char *filename,
                        err(1, "cannot open net file '%s'", filename);
        }
 
+       /* We need 1 page, and the features indicate the slot to use and that
+        * no checksum is needed.  We never touch this device again; it's
+        * between the Guests on the network, so we don't register input or
+        * output handlers. */
        dev = new_device(devices, LGUEST_DEVICE_T_NET, 1,
                         find_slot(netfd, filename)|LGUEST_NET_F_NOCSUM,
                         -1, NULL, 0, NULL);
 
-       /* We overwrite the /dev/zero mapping with the actual file. */
+       /* Map the shared file. */
        if (mmap(dev->mem, getpagesize(), PROT_READ|PROT_WRITE,
                         MAP_FIXED|MAP_SHARED, netfd, 0) != dev->mem)
                        err(1, "could not mmap '%s'", filename);
@@ -770,6 +1182,7 @@ static void setup_net_file(const char *filename,
                (void *)(dev->desc->pfn * getpagesize()), filename,
                dev->desc->features & ~LGUEST_NET_F_NOCSUM);
 }
+/*:*/
 
 static u32 str2ip(const char *ipaddr)
 {
@@ -779,7 +1192,11 @@ static u32 str2ip(const char *ipaddr)
        return (byte[0] << 24) | (byte[1] << 16) | (byte[2] << 8) | byte[3];
 }
 
-/* adapted from libbridge */
+/* This code is "adapted" from libbridge: it attaches the Host end of the
+ * network device to the bridge device specified by the command line.
+ *
+ * This is yet another James Morris contribution (I'm an IP-level guy, so I
+ * dislike bridging), and I just try not to break it. */
 static void add_to_bridge(int fd, const char *if_name, const char *br_name)
 {
        int ifidx;
@@ -798,12 +1215,16 @@ static void add_to_bridge(int fd, const char *if_name, const char *br_name)
                err(1, "can't add %s to bridge %s", if_name, br_name);
 }
 
+/* This sets up the Host end of the network device with an IP address, brings
+ * it up so packets will flow, the copies the MAC address into the hwaddr
+ * pointer (in practice, the Host's slot in the network device's memory). */
 static void configure_device(int fd, const char *devname, u32 ipaddr,
                             unsigned char hwaddr[6])
 {
        struct ifreq ifr;
        struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr;
 
+       /* Don't read these incantations.  Just cut & paste them like I did! */
        memset(&ifr, 0, sizeof(ifr));
        strcpy(ifr.ifr_name, devname);
        sin->sin_family = AF_INET;
@@ -814,12 +1235,19 @@ static void configure_device(int fd, const char *devname, u32 ipaddr,
        if (ioctl(fd, SIOCSIFFLAGS, &ifr) != 0)
                err(1, "Bringing interface %s up", devname);
 
+       /* SIOC stands for Socket I/O Control.  G means Get (vs S for Set
+        * above).  IF means Interface, and HWADDR is hardware address.
+        * Simple! */
        if (ioctl(fd, SIOCGIFHWADDR, &ifr) != 0)
                err(1, "getting hw address for %s", devname);
-
        memcpy(hwaddr, ifr.ifr_hwaddr.sa_data, 6);
 }
 
+/*L:195 The other kind of network is a Host<->Guest network.  This can either
+ * use briding or routing, but the principle is the same: it uses the "tun"
+ * device to inject packets into the Host as if they came in from a normal
+ * network card.  We just shunt packets between the Guest and the tun
+ * device. */
 static void setup_tun_net(const char *arg, struct device_list *devices)
 {
        struct device *dev;
@@ -828,36 +1256,56 @@ static void setup_tun_net(const char *arg, struct device_list *devices)
        u32 ip;
        const char *br_name = NULL;
 
+       /* We open the /dev/net/tun device and tell it we want a tap device.  A
+        * tap device is like a tun device, only somehow different.  To tell
+        * the truth, I completely blundered my way through this code, but it
+        * works now! */
        netfd = open_or_die("/dev/net/tun", O_RDWR);
        memset(&ifr, 0, sizeof(ifr));
        ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
        strcpy(ifr.ifr_name, "tap%d");
        if (ioctl(netfd, TUNSETIFF, &ifr) != 0)
                err(1, "configuring /dev/net/tun");
+       /* We don't need checksums calculated for packets coming in this
+        * device: trust us! */
        ioctl(netfd, TUNSETNOCSUM, 1);
 
-       /* You will be peer 1: we should create enough jitter to randomize */
+       /* We create the net device with 1 page, using the features field of
+        * the descriptor to tell the Guest it is in slot 1 (NET_PEERNUM), and
+        * that the device has fairly random timing.  We do *not* specify
+        * LGUEST_NET_F_NOCSUM: these packets can reach the real world.
+        *
+        * We will put our MAC address is slot 0 for the Guest to see, so
+        * it will send packets to us using the key "peer_offset(0)": */
        dev = new_device(devices, LGUEST_DEVICE_T_NET, 1,
                         NET_PEERNUM|LGUEST_DEVICE_F_RANDOMNESS, netfd,
                         handle_tun_input, peer_offset(0), handle_tun_output);
+
+       /* We keep a flag which says whether we've seen packets come out from
+        * this network device. */
        dev->priv = malloc(sizeof(bool));
        *(bool *)dev->priv = false;
 
+       /* We need a socket to perform the magic network ioctls to bring up the
+        * tap interface, connect to the bridge etc.  Any socket will do! */
        ipfd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP);
        if (ipfd < 0)
                err(1, "opening IP socket");
 
+       /* If the command line was --tunnet=bridge:<name> do bridging. */
        if (!strncmp(BRIDGE_PFX, arg, strlen(BRIDGE_PFX))) {
                ip = INADDR_ANY;
                br_name = arg + strlen(BRIDGE_PFX);
                add_to_bridge(ipfd, ifr.ifr_name, br_name);
-       } else
+       } else /* It is an IP address to set up the device with */
                ip = str2ip(arg);
 
-       /* We are peer 0, ie. first slot. */
+       /* We are peer 0, ie. first slot, so we hand dev->mem to this routine
+        * to write the MAC address at the start of the device memory.  */
        configure_device(ipfd, ifr.ifr_name, ip, dev->mem);
 
-       /* Set "promisc" bit: we want every single packet. */
+       /* Set "promisc" bit: we want every single packet if we're going to
+        * bridge to other machines (and otherwise it doesn't matter). */
        *((u8 *)dev->mem) |= 0x1;
 
        close(ipfd);
@@ -868,7 +1316,10 @@ static void setup_tun_net(const char *arg, struct device_list *devices)
        if (br_name)
                verbose("attached to bridge: %s\n", br_name);
 }
+/* That's the end of device setup. */
 
+/*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, struct device_list *device_list)
 {
@@ -880,20 +1331,37 @@ run_guest(int lguest_fd, struct device_list *device_list)
                /* We read from the /dev/lguest device to run the Guest. */
                readval = read(lguest_fd, arr, sizeof(arr));
 
+               /* The read can only really return sizeof(arr) (the Guest did a
+                * SEND_DMA to us), or an error. */
+
+               /* For a successful read, arr[0] is the address of the "struct
+                * lguest_dma", and arr[1] is the key the Guest sent to. */
                if (readval == sizeof(arr)) {
                        handle_output(lguest_fd, arr[0], arr[1], device_list);
                        continue;
+               /* ENOENT means the Guest died.  Reading tells us why. */
                } else if (errno == ENOENT) {
                        char reason[1024] = { 0 };
                        read(lguest_fd, reason, sizeof(reason)-1);
                        errx(1, "%s", reason);
+               /* EAGAIN means the waker wanted us to look at some input.
+                * Anything else means a bug or incompatible change. */
                } else if (errno != EAGAIN)
                        err(1, "Running guest failed");
+
+               /* Service input, then unset the BREAK which releases
+                * the Waker. */
                handle_input(lguest_fd, device_list);
                if (write(lguest_fd, args, sizeof(args)) < 0)
                        err(1, "Resetting break");
        }
 }
+/*
+ * This is the end of the Launcher.
+ *
+ * But wait!  We've seen I/O from the Launcher, and we've seen I/O from the
+ * Drivers.  If we were to see the Host kernel I/O code, our understanding
+ * would be complete... :*/
 
 static struct option opts[] = {
        { "verbose", 0, NULL, 'v' },
@@ -911,20 +1379,49 @@ static void usage(void)
             "<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.
+ */
 int main(int argc, char *argv[])
 {
+       /* Memory, top-level pagetable, code startpoint, PAGE_OFFSET and size
+        * of the (optional) initrd. */
        unsigned long mem = 0, pgdir, start, page_offset, initrd_size = 0;
+       /* A temporary and the /dev/lguest file descriptor. */
        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;
+       /* If they specify an initrd file to load. */
        const char *initrd_name = NULL;
 
+       /* First we initialize the device list.  Since console and network
+        * 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, for easy appending
+        * to the list. */
        device_list.max_infd = -1;
        device_list.dev = NULL;
        device_list.lastdev = &device_list.dev;
        FD_ZERO(&device_list.infds);
 
-       /* We need to know how much memory so we can allocate devices. */
+       /* We need to know how much memory so we can set up the device
+        * descriptor and memory pages for the devices as we parse the command
+        * line.  So we quickly look through the arguments to find the amount
+        * of memory now. */
        for (i = 1; i < argc; i++) {
                if (argv[i][0] != '-') {
                        mem = top = atoi(argv[i]) * 1024 * 1024;
@@ -933,6 +1430,8 @@ int main(int argc, char *argv[])
                        break;
                }
        }
+
+       /* The options are fairly straight-forward */
        while ((c = getopt_long(argc, argv, "v", opts, NULL)) != EOF) {
                switch (c) {
                case 'v':
@@ -955,42 +1454,71 @@ int main(int argc, char *argv[])
                        usage();
                }
        }
+       /* After the other arguments we expect memory and kernel image name,
+        * followed by command line arguments for the kernel. */
        if (optind + 2 > argc)
                usage();
 
-       /* We need a console device */
+       /* We always have a console device */
        setup_console(&device_list);
 
-       /* First we map /dev/zero over all of guest-physical memory. */
+       /* 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);
 
-       /* Map the initrd image if requested */
+       /* Map the initrd image if requested (at top of physical memory) */
        if (initrd_name) {
                initrd_size = load_initrd(initrd_name, mem);
+               /* These are the location in the Linux boot header where the
+                * start and size of the initrd are expected to be found. */
                *(unsigned long *)(boot+0x218) = mem - initrd_size;
                *(unsigned long *)(boot+0x21c) = initrd_size;
+               /* The bootloader type 0xFF means "unknown"; that's OK. */
                *(unsigned char *)(boot+0x210) = 0xFF;
        }
 
-       /* Set up the initial linar pagetables. */
+       /* Set up the initial linear pagetables, starting below the initrd. */
        pgdir = setup_pagetables(mem, initrd_size, page_offset);
 
-       /* E820 memory map: ours is a simple, single region. */
+       /* The Linux boot header contains an "E820" memory map: ours is a
+        * simple, single region. */
        *(char*)(boot+E820NR) = 1;
        *((struct e820entry *)(boot+E820MAP))
                = ((struct e820entry) { 0, mem, E820_RAM });
-       /* Command line pointer and command line (at 4096) */
+       /* 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;
        concat(boot + 4096, argv+optind+2);
-       /* Paravirt type: 1 == lguest */
+
+       /* The guest type value of "1" tells the Guest it's under lguest. */
        *(int *)(boot + 0x23c) = 1;
 
+       /* We tell the kernel to initialize the Guest: this returns the open
+        * /dev/lguest file descriptor. */
        lguest_fd = tell_kernel(pgdir, start, page_offset);
+
+       /* 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. */
        waker_fd = setup_waker(lguest_fd, &device_list);
 
+       /* Finally, run the Guest.  This doesn't return. */
        run_guest(lguest_fd, &device_list);
 }
+/*:*/
+
+/*M:999
+ * Mastery is done: you now know everything I do.
+ *
+ * But surely you have seen code, features and bugs in your wanderings which
+ * you now yearn to attack?  That is the real game, and I look forward to you
+ * patching and forking lguest into the Your-Name-Here-visor.
+ *
+ * Farewell, and good coding!
+ * Rusty Russell.
+ */
index 6f72021aae51f5e1a015468f342b2b3355315e3b..442e14d35dea272f6906d65723055b82d0566ef3 100644 (file)
@@ -1,10 +1,11 @@
-Version 10 of schedstats includes support for sched_domains, which
-hit the mainline kernel in 2.6.7.  Some counters make more sense to be
-per-runqueue; other to be per-domain.  Note that domains (and their associated
-information) will only be pertinent and available on machines utilizing
-CONFIG_SMP.
-
-In version 10 of schedstat, there is at least one level of domain
+Version 14 of schedstats includes support for sched_domains, which hit the
+mainline kernel in 2.6.20 although it is identical to the stats from version
+12 which was in the kernel from 2.6.13-2.6.19 (version 13 never saw a kernel
+release).  Some counters make more sense to be per-runqueue; other to be
+per-domain.  Note that domains (and their associated information) will only
+be pertinent and available on machines utilizing CONFIG_SMP.
+
+In version 14 of schedstat, there is at least one level of domain
 statistics for each cpu listed, and there may well be more than one
 domain.  Domains have no particular names in this implementation, but
 the highest numbered one typically arbitrates balancing across all the
@@ -27,7 +28,7 @@ to write their own scripts, the fields are described here.
 
 CPU statistics
 --------------
-cpu<N> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
+cpu<N> 1 2 3 4 5 6 7 8 9 10 11 12
 
 NOTE: In the sched_yield() statistics, the active queue is considered empty
     if it has only one process in it, since obviously the process calling
@@ -39,48 +40,20 @@ First four fields are sched_yield() statistics:
      3) # of times just the expired queue was empty
      4) # of times sched_yield() was called
 
-Next four are schedule() statistics:
-     5) # of times the active queue had at least one other process on it
-     6) # of times we switched to the expired queue and reused it
-     7) # of times schedule() was called
-     8) # of times schedule() left the processor idle
-
-Next four are active_load_balance() statistics:
-     9) # of times active_load_balance() was called
-    10) # of times active_load_balance() caused this cpu to gain a task
-    11) # of times active_load_balance() caused this cpu to lose a task
-    12) # of times active_load_balance() tried to move a task and failed
-
-Next three are try_to_wake_up() statistics:
-    13) # of times try_to_wake_up() was called
-    14) # of times try_to_wake_up() successfully moved the awakening task
-    15) # of times try_to_wake_up() attempted to move the awakening task
-
-Next two are wake_up_new_task() statistics:
-    16) # of times wake_up_new_task() was called
-    17) # of times wake_up_new_task() successfully moved the new task
-
-Next one is a sched_migrate_task() statistic:
-    18) # of times sched_migrate_task() was called
+Next three are schedule() statistics:
+     5) # of times we switched to the expired queue and reused it
+     6) # of times schedule() was called
+     7) # of times schedule() left the processor idle
 
-Next one is a sched_balance_exec() statistic:
-    19) # of times sched_balance_exec() was called
+Next two are try_to_wake_up() statistics:
+     8) # of times try_to_wake_up() was called
+     9) # of times try_to_wake_up() was called to wake up the local cpu
 
 Next three are statistics describing scheduling latency:
-    20) sum of all time spent running by tasks on this processor (in ms)
-    21) sum of all time spent waiting to run by tasks on this processor (in ms)
-    22) # of tasks (not necessarily unique) given to the processor
-
-The last six are statistics dealing with pull_task():
-    23) # of times pull_task() moved a task to this cpu when newly idle
-    24) # of times pull_task() stole a task from this cpu when another cpu
-       was newly idle
-    25) # of times pull_task() moved a task to this cpu when idle
-    26) # of times pull_task() stole a task from this cpu when another cpu
-       was idle
-    27) # of times pull_task() moved a task to this cpu when busy
-    28) # of times pull_task() stole a task from this cpu when another cpu
-       was busy
+    10) sum of all time spent running by tasks on this processor (in jiffies)
+    11) sum of all time spent waiting to run by tasks on this processor (in
+        jiffies)
+    12) # of timeslices run on this cpu
 
 
 Domain statistics
@@ -89,65 +62,95 @@ One of these is produced per domain for each cpu described. (Note that if
 CONFIG_SMP is not defined, *no* domains are utilized and these lines
 will not appear in the output.)
 
-domain<N> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
+domain<N> <cpumask> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
 
 The first field is a bit mask indicating what cpus this domain operates over.
 
-The next fifteen are a variety of load_balance() statistics:
-
-     1) # of times in this domain load_balance() was called when the cpu
-       was idle
-     2) # of times in this domain load_balance() was called when the cpu
-       was busy
-     3) # of times in this domain load_balance() was called when the cpu
-       was just becoming idle
-     4) # of times in this domain load_balance() tried to move one or more
-       tasks and failed, when the cpu was idle
-     5) # of times in this domain load_balance() tried to move one or more
-       tasks and failed, when the cpu was busy
-     6) # of times in this domain load_balance() tried to move one or more
-       tasks and failed, when the cpu was just becoming idle
-     7) sum of imbalances discovered (if any) with each call to
-       load_balance() in this domain when the cpu was idle
-     8) sum of imbalances discovered (if any) with each call to
-       load_balance() in this domain when the cpu was busy
-     9) sum of imbalances discovered (if any) with each call to
-       load_balance() in this domain when the cpu was just becoming idle
-    10) # of times in this domain load_balance() was called but did not find
-       a busier queue while the cpu was idle
-    11) # of times in this domain load_balance() was called but did not find
-       a busier queue while the cpu was busy
-    12) # of times in this domain load_balance() was called but did not find
-       a busier queue while the cpu was just becoming idle
-    13) # of times in this domain a busier queue was found while the cpu was
-       idle but no busier group was found
-    14) # of times in this domain a busier queue was found while the cpu was
-       busy but no busier group was found
-    15) # of times in this domain a busier queue was found while the cpu was
-       just becoming idle but no busier group was found
-
-Next two are sched_balance_exec() statistics:
-    17) # of times in this domain sched_balance_exec() successfully pushed
-       a task to a new cpu
-    18) # of times in this domain sched_balance_exec() tried but failed to
-       push a task to a new cpu
-
-Next two are try_to_wake_up() statistics:
-    19) # of times in this domain try_to_wake_up() tried to move a task based
-       on affinity and cache warmth
-    20) # of times in this domain try_to_wake_up() tried to move a task based
-       on load balancing
-
+The next 24 are a variety of load_balance() statistics in grouped into types
+of idleness (idle, busy, and newly idle):
+
+     1) # of times in this domain load_balance() was called when the
+        cpu was idle
+     2) # of times in this domain load_balance() checked but found
+        the load did not require balancing when the cpu was idle
+     3) # of times in this domain load_balance() tried to move one or
+        more tasks and failed, when the cpu was idle
+     4) sum of imbalances discovered (if any) with each call to
+        load_balance() in this domain when the cpu was idle
+     5) # of times in this domain pull_task() was called when the cpu
+        was idle
+     6) # of times in this domain pull_task() was called even though
+        the target task was cache-hot when idle
+     7) # of times in this domain load_balance() was called but did
+        not find a busier queue while the cpu was idle
+     8) # of times in this domain a busier queue was found while the
+        cpu was idle but no busier group was found
+
+     9) # of times in this domain load_balance() was called when the
+        cpu was busy
+    10) # of times in this domain load_balance() checked but found the
+        load did not require balancing when busy
+    11) # of times in this domain load_balance() tried to move one or
+        more tasks and failed, when the cpu was busy
+    12) sum of imbalances discovered (if any) with each call to
+        load_balance() in this domain when the cpu was busy
+    13) # of times in this domain pull_task() was called when busy
+    14) # of times in this domain pull_task() was called even though the
+        target task was cache-hot when busy
+    15) # of times in this domain load_balance() was called but did not
+        find a busier queue while the cpu was busy
+    16) # of times in this domain a busier queue was found while the cpu
+        was busy but no busier group was found
+
+    17) # of times in this domain load_balance() was called when the
+        cpu was just becoming idle
+    18) # of times in this domain load_balance() checked but found the
+        load did not require balancing when the cpu was just becoming idle
+    19) # of times in this domain load_balance() tried to move one or more
+        tasks and failed, when the cpu was just becoming idle
+    20) sum of imbalances discovered (if any) with each call to
+        load_balance() in this domain when the cpu was just becoming idle
+    21) # of times in this domain pull_task() was called when newly idle
+    22) # of times in this domain pull_task() was called even though the
+        target task was cache-hot when just becoming idle
+    23) # of times in this domain load_balance() was called but did not
+        find a busier queue while the cpu was just becoming idle
+    24) # of times in this domain a busier queue was found while the cpu
+        was just becoming idle but no busier group was found
+
+   Next three are active_load_balance() statistics:
+    25) # of times active_load_balance() was called
+    26) # of times active_load_balance() tried to move a task and failed
+    27) # of times active_load_balance() successfully moved a task
+
+   Next three are sched_balance_exec() statistics:
+    28) sbe_cnt is not used
+    29) sbe_balanced is not used
+    30) sbe_pushed is not used
+
+   Next three are sched_balance_fork() statistics:
+    31) sbf_cnt is not used
+    32) sbf_balanced is not used
+    33) sbf_pushed is not used
+
+   Next three are try_to_wake_up() statistics:
+    34) # of times in this domain try_to_wake_up() awoke a task that
+        last ran on a different cpu in this domain
+    35) # of times in this domain try_to_wake_up() moved a task to the
+        waking cpu because it was cache-cold on its own cpu anyway
+    36) # of times in this domain try_to_wake_up() started passive balancing
 
 /proc/<pid>/schedstat
 ----------------
 schedstats also adds a new /proc/<pid/schedstat file to include some of
 the same information on a per-process level.  There are three fields in
-this file correlating to fields 20, 21, and 22 in the CPU fields, but
-they only apply for that process.
+this file correlating for that process to:
+     1) time spent on the cpu
+     2) time spent waiting on a runqueue
+     3) # of timeslices run on this cpu
 
 A program could be easily written to make use of these extra fields to
 report on how well a particular process or set of processes is faring
 under the scheduler's policies.  A simple version of such a program is
 available at
-    http://eaglet.rain.com/rick/linux/schedstat/v10/latency.c
+    http://eaglet.rain.com/rick/linux/schedstat/v12/latency.c
index 01f222e51871ba1ed86465119e2329ba74e7afb1..babd00b0c65cbb10877f30347c731520cc7e0cd1 100644 (file)
@@ -3339,6 +3339,14 @@ M:       thomas@winischhofer.net
 W:     http://www.winischhofer.at/linuxsisusbvga.shtml
 S:     Maintained
 
+SLAB ALLOCATOR
+P:     Christoph Lameter
+M:     clameter@sgi.com
+P:     Pekka Enberg
+M:     penberg@cs.helsinki.fi
+L:     linux-mm@kvack.org
+S:     Maintained
+
 SMC91x ETHERNET DRIVER
 P:     Nicolas Pitre
 M:     nico@cam.org
index e27d23c74ba8172e2b4be60bb21e3880060101fc..7ac1f1372c361648eb4f1d24315b7a10ecf3b984 100644 (file)
@@ -10,6 +10,7 @@
 #include <asm/system.h>
 #include <asm/asm-offsets.h>
 
+.section .text.head, "ax"
 .globl swapper_pg_dir
 .globl _stext
 swapper_pg_dir=SWAPPER_PGD
index ab642a4f08de85eb538077c0261fb9d381d49ae9..9dc1cee43265e206d6863ff40430a2c7a4559e6c 100644 (file)
@@ -195,7 +195,7 @@ pcibios_init(void)
 
 subsys_initcall(pcibios_init);
 
-char * __init
+char * __devinit
 pcibios_setup(char *str)
 {
        return str;
@@ -204,7 +204,7 @@ pcibios_setup(char *str)
 #ifdef ALPHA_RESTORE_SRM_SETUP
 static struct pdev_srm_saved_conf *srm_saved_configs;
 
-void __init
+void __devinit
 pdev_save_srm_config(struct pci_dev *dev)
 {
        struct pdev_srm_saved_conf *tmp;
@@ -247,14 +247,14 @@ pci_restore_srm_config(void)
 }
 #endif
 
-void __init
+void __devinit
 pcibios_fixup_resource(struct resource *res, struct resource *root)
 {
        res->start += root->start;
        res->end += root->start;
 }
 
-void __init
+void __devinit
 pcibios_fixup_device_resources(struct pci_dev *dev, struct pci_bus *bus)
 {
        /* Update device resources.  */
@@ -273,7 +273,7 @@ pcibios_fixup_device_resources(struct pci_dev *dev, struct pci_bus *bus)
        }
 }
 
-void __init
+void __devinit
 pcibios_fixup_bus(struct pci_bus *bus)
 {
        /* Propagate hose info into the subordinate devices.  */
index 6b07f89a72c70af2b4bf11d7ab5eb3653db0102c..e1c470752ebc0db7e146c2d544da50496f3076af 100644 (file)
@@ -58,7 +58,7 @@ size_for_memory(unsigned long max)
        return max;
 }
 \f
-struct pci_iommu_arena *
+struct pci_iommu_arena * __init
 iommu_arena_new_node(int nid, struct pci_controller *hose, dma_addr_t base,
                     unsigned long window_size, unsigned long align)
 {
@@ -117,7 +117,7 @@ iommu_arena_new_node(int nid, struct pci_controller *hose, dma_addr_t base,
        return arena;
 }
 
-struct pci_iommu_arena *
+struct pci_iommu_arena * __init
 iommu_arena_new(struct pci_controller *hose, dma_addr_t base,
                unsigned long window_size, unsigned long align)
 {
index b28731437c31c8e7f66549da67bfd79f54b8060f..0804b6abe20337eb02950d01e3320e4411a528c7 100644 (file)
@@ -358,7 +358,7 @@ secondary_cpu_start(int cpuid, struct task_struct *idle)
 /*
  * Bring one cpu online.
  */
-static int __devinit
+static int __cpuinit
 smp_boot_one_cpu(int cpuid)
 {
        struct task_struct *idle;
@@ -487,7 +487,7 @@ smp_prepare_boot_cpu(void)
 {
 }
 
-int __devinit
+int __cpuinit
 __cpu_up(unsigned int cpu)
 {
        smp_boot_one_cpu(cpu);
@@ -541,7 +541,7 @@ smp_percpu_timer_interrupt(struct pt_regs *regs)
        set_irq_regs(old_regs);
 }
 
-int __init
+int
 setup_profiling_timer(unsigned int multiplier)
 {
        return -EINVAL;
index fe13daa5cb2c17702463cba91ceb7f9d873a3d16..7af07d3ad5f0dc0dcc276763c84d38453cca15dc 100644 (file)
@@ -15,6 +15,7 @@ SECTIONS
 
   _text = .;                                   /* Text and read-only data */
   .text : { 
+       *(.text.head)
        TEXT_TEXT
        SCHED_TEXT
        LOCK_TEXT
index c3750c2c41137a694be9570443f59b379cc4cc4d..c85598acb8fd5854394dd4aa8e16877bd5c01848 100644 (file)
@@ -430,22 +430,12 @@ void __init alternative_instructions(void)
  * And on the local CPU you need to be protected again NMI or MCE handlers
  * seeing an inconsistent instruction while you patch.
  */
-void __kprobes text_poke(void *oaddr, unsigned char *opcode, int len)
+void __kprobes text_poke(void *addr, unsigned char *opcode, int len)
 {
-        u8 *addr = oaddr;
-       if (!pte_write(*lookup_address((unsigned long)addr))) {
-               struct page *p[2] = { virt_to_page(addr), virt_to_page(addr+PAGE_SIZE) };
-               addr = vmap(p, 2, VM_MAP, PAGE_KERNEL);
-               if (!addr)
-                       return;
-               addr += ((unsigned long)oaddr) % PAGE_SIZE;
-       }
        memcpy(addr, opcode, len);
        sync_core();
        /* Not strictly needed, but can speed CPU recovery up. Ignore cross cacheline
           case. */
        if (cpu_has_clflush)
-               asm("clflush (%0) " :: "r" (oaddr) : "memory");
-       if (addr != oaddr)
-               vunmap(addr);
+               asm("clflush (%0) " :: "r" (addr) : "memory");
 }
index 094118ba00da8ee85c5e108db1d0a715564a5b1c..d8c6f132dc7a1f7ca95306e2e15ab2536f5966f1 100644 (file)
@@ -92,7 +92,7 @@ config X86_POWERNOW_K8
 config X86_POWERNOW_K8_ACPI
        bool "ACPI Support"
        select ACPI_PROCESSOR
-       depends on X86_POWERNOW_K8
+       depends on ACPI && X86_POWERNOW_K8
        default y
        help
          This provides access to the K8s Processor Performance States via ACPI.
index 1b1a1e66d099b7c5df78d91d7c4244eb51f06d4b..4c4809f13cb134007cb1c90f567c2e1d367895b3 100644 (file)
@@ -800,9 +800,17 @@ void mark_rodata_ro(void)
        unsigned long start = PFN_ALIGN(_text);
        unsigned long size = PFN_ALIGN(_etext) - start;
 
-       change_page_attr(virt_to_page(start),
-                        size >> PAGE_SHIFT, PAGE_KERNEL_RX);
-       printk("Write protecting the kernel text: %luk\n", size >> 10);
+#ifndef CONFIG_KPROBES
+#ifdef CONFIG_HOTPLUG_CPU
+       /* It must still be possible to apply SMP alternatives. */
+       if (num_possible_cpus() <= 1)
+#endif
+       {
+               change_page_attr(virt_to_page(start),
+                                size >> PAGE_SHIFT, PAGE_KERNEL_RX);
+               printk("Write protecting the kernel text: %luk\n", size >> 10);
+       }
+#endif
        start += size;
        size = (unsigned long)__end_rodata - start;
        change_page_attr(virt_to_page(start),
index 2fd96d9062a1359b41964c3b4e3d90c8879034a3..790ef0d87e129f90b5cd83b617dc2b23000a7219 100644 (file)
@@ -38,11 +38,11 @@ static struct clocksource clocksource_cyclone = {
 
 int __init init_cyclone_clock(void)
 {
-       u64reg;
+       u64 __iomem *reg;
        u64 base;       /* saved cyclone base address */
        u64 offset;     /* offset from pageaddr to cyclone_timer register */
        int i;
-       u32* volatile cyclone_timer;    /* Cyclone MPMC0 register */
+       u32 __iomem *cyclone_timer;     /* Cyclone MPMC0 register */
 
        if (!use_cyclone)
                return 0;
@@ -51,7 +51,7 @@ int __init init_cyclone_clock(void)
 
        /* find base address */
        offset = (CYCLONE_CBAR_ADDR);
-       reg = (u64*)ioremap_nocache(offset, sizeof(u64));
+       reg = ioremap_nocache(offset, sizeof(u64));
        if(!reg){
                printk(KERN_ERR "Summit chipset: Could not find valid CBAR"
                                " register.\n");
@@ -69,7 +69,7 @@ int __init init_cyclone_clock(void)
 
        /* setup PMCC */
        offset = (base + CYCLONE_PMCC_OFFSET);
-       reg = (u64*)ioremap_nocache(offset, sizeof(u64));
+       reg = ioremap_nocache(offset, sizeof(u64));
        if(!reg){
                printk(KERN_ERR "Summit chipset: Could not find valid PMCC"
                                " register.\n");
@@ -81,7 +81,7 @@ int __init init_cyclone_clock(void)
 
        /* setup MPCS */
        offset = (base + CYCLONE_MPCS_OFFSET);
-       reg = (u64*)ioremap_nocache(offset, sizeof(u64));
+       reg = ioremap_nocache(offset, sizeof(u64));
        if(!reg){
                printk(KERN_ERR "Summit chipset: Could not find valid MPCS"
                                " register.\n");
@@ -93,7 +93,7 @@ int __init init_cyclone_clock(void)
 
        /* map in cyclone_timer */
        offset = (base + CYCLONE_MPMC_OFFSET);
-       cyclone_timer = (u32*)ioremap_nocache(offset, sizeof(u32));
+       cyclone_timer = ioremap_nocache(offset, sizeof(u32));
        if(!cyclone_timer){
                printk(KERN_ERR "Summit chipset: Could not find valid MPMC"
                                " register.\n");
@@ -110,7 +110,7 @@ int __init init_cyclone_clock(void)
                        printk(KERN_ERR "Summit chipset: Counter not counting!"
                                        " DISABLED\n");
                        iounmap(cyclone_timer);
-                       cyclone_timer = 0;
+                       cyclone_timer = NULL;
                        use_cyclone = 0;
                        return -ENODEV;
                }
index 627785c48ea95e495389653b5bfdc320967247df..6c0e9e2e1b82004ba8a9ba70586b76fbb1982899 100644 (file)
@@ -52,7 +52,7 @@ static struct clocksource clocksource_itc = {
         .name           = "itc",
         .rating         = 350,
         .read           = itc_get_cycles,
-        .mask           = 0xffffffffffffffff,
+        .mask           = CLOCKSOURCE_MASK(64),
         .mult           = 0, /*to be caluclated*/
         .shift          = 16,
         .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
@@ -255,7 +255,7 @@ ia64_init_itm (void)
        }
 }
 
-static cycle_t itc_get_cycles()
+static cycle_t itc_get_cycles(void)
 {
        u64 lcycle, now, ret;
 
index 6b2d77da06830c734c01d588881694c115e84c53..fe73c9ec611f33fbee6b2e79a554c62205be00b8 100644 (file)
@@ -45,7 +45,8 @@ static void mask_and_ack_mappi(unsigned int irq)
 
 static void end_mappi_irq(unsigned int irq)
 {
-       enable_mappi_irq(irq);
+       if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
+               enable_mappi_irq(irq);
 }
 
 static unsigned int startup_mappi_irq(unsigned int irq)
@@ -88,7 +89,7 @@ void __init init_IRQ(void)
        irq_desc[M32R_IRQ_INT0].chip = &mappi_irq_type;
        irq_desc[M32R_IRQ_INT0].action = NULL;
        irq_desc[M32R_IRQ_INT0].depth = 1;
-       icu_data[M32R_IRQ_INT0].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10;
+       icu_data[M32R_IRQ_INT0].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD11;
        disable_mappi_irq(M32R_IRQ_INT0);
 #endif /* CONFIG_M32R_NE2000 */
 
index a5ac0d40fbec4c83a309b37af115512ca462b93e..3f86ade3a22af15a152d444579858197ddeaaab3 100644 (file)
@@ -42,8 +42,6 @@ EXPORT_SYMBOL(memory_end);
 
 char __initdata command_line[COMMAND_LINE_SIZE];
 
-void (*mach_trap_init)(void);
-
 /* machine dependent timer functions */
 void (*mach_sched_init)(irq_handler_t handler);
 void (*mach_tick)(void);
index d265ed4e5afccdee7a5c389917ac842db089d031..d0f2dc5cb5a17f833f1008c781159f37c18adb0a 100644 (file)
@@ -28,7 +28,6 @@
 void coldfire_tick(void);
 void coldfire_timer_init(irq_handler_t handler);
 unsigned long coldfire_timer_offset(void);
-void coldfire_trap_init(void);
 void coldfire_reset(void);
 
 /***************************************************************************/
@@ -101,7 +100,6 @@ void config_BSP(char *commandp, int size)
        mach_sched_init = coldfire_timer_init;
        mach_tick = coldfire_tick;
        mach_gettimeoffset = coldfire_timer_offset;
-       mach_trap_init = coldfire_trap_init;
        mach_reset = coldfire_reset;
 }
 
index 7fa5e8254c313e83cbe6071b30609589f7f96674..4ab614f1ecdabb82b94e578ea42230e2e02c9776 100644 (file)
@@ -27,7 +27,6 @@
 void coldfire_tick(void);
 void coldfire_timer_init(irq_handler_t handler);
 unsigned long coldfire_timer_offset(void);
-void coldfire_trap_init(void);
 void coldfire_reset(void);
 
 /***************************************************************************/
@@ -107,7 +106,6 @@ void config_BSP(char *commandp, int size)
        mach_sched_init = coldfire_timer_init;
        mach_tick = coldfire_tick;
        mach_gettimeoffset = coldfire_timer_offset;
-       mach_trap_init = coldfire_trap_init;
        mach_reset = coldfire_reset;
 }
 
index 85830f9882f3bfde4e7496fd7ba9701d000b3ab8..a2c95bebd004cf24b25f18d8fed75524b3de9059 100644 (file)
@@ -30,7 +30,6 @@ unsigned int dma_device_address[MAX_M68K_DMA_CHANNELS];
 void coldfire_pit_tick(void);
 void coldfire_pit_init(irq_handler_t handler);
 unsigned long coldfire_pit_offset(void);
-void coldfire_trap_init(void);
 void coldfire_reset(void);
 
 /***************************************************************************/
@@ -51,7 +50,6 @@ void config_BSP(char *commandp, int size)
     mach_sched_init = coldfire_pit_init;
     mach_tick = coldfire_pit_tick;
     mach_gettimeoffset = coldfire_pit_offset;
-    mach_trap_init = coldfire_trap_init;
     mach_reset = coldfire_reset;
 }
 
index c0157e1100356abc0b994bd35a9a8cbf60bf5407..0a3af05a434b415759621b0fc81e7e657b056f46 100644 (file)
@@ -29,7 +29,6 @@
 void coldfire_pit_tick(void);
 void coldfire_pit_init(irq_handler_t handler);
 unsigned long coldfire_pit_offset(void);
-void coldfire_trap_init(void);
 void coldfire_reset(void);
 
 /***************************************************************************/
@@ -66,7 +65,6 @@ void config_BSP(char *commandp, int size)
        mach_sched_init = coldfire_pit_init;
        mach_tick = coldfire_pit_tick;
        mach_gettimeoffset = coldfire_pit_offset;
-       mach_trap_init = coldfire_trap_init;
        mach_reset = coldfire_reset;
 }
 
index 4cdeb719512df8c4e2f5c23f6ac6f8b0740471b3..dc2c362590c229a29a3003b709d2ef75ee53a2e5 100644 (file)
@@ -27,7 +27,6 @@
 void coldfire_tick(void);
 void coldfire_timer_init(irq_handler_t handler);
 unsigned long coldfire_timer_offset(void);
-void coldfire_trap_init(void);
 void coldfire_reset(void);
 
 /***************************************************************************/
@@ -99,7 +98,6 @@ void config_BSP(char *commandp, int size)
        mach_sched_init = coldfire_timer_init;
        mach_tick = coldfire_tick;
        mach_gettimeoffset = coldfire_timer_offset;
-       mach_trap_init = coldfire_trap_init;
        mach_reset = coldfire_reset;
 }
 
index 609b10e4b9b9a049a842147438ba7251330ee6c0..1365a8300d5defbe39be9cc32c89b2ad0689022e 100644 (file)
@@ -28,7 +28,6 @@
 void coldfire_tick(void);
 void coldfire_timer_init(irq_handler_t handler);
 unsigned long coldfire_timer_offset(void);
-void coldfire_trap_init(void);
 void coldfire_reset(void);
 
 extern unsigned int mcf_timervector;
@@ -132,7 +131,6 @@ void config_BSP(char *commandp, int size)
        mach_sched_init = coldfire_timer_init;
        mach_tick = coldfire_tick;
        mach_gettimeoffset = coldfire_timer_offset;
-       mach_trap_init = coldfire_trap_init;
        mach_reset = coldfire_reset;
 }
 
index 126dac06648200c0c38d496a367d51afa35ca2fd..1b820441419aacea972433f166dfeff8b6a9c5a1 100644 (file)
@@ -29,7 +29,6 @@
 void coldfire_pit_tick(void);
 void coldfire_pit_init(irq_handler_t handler);
 unsigned long coldfire_pit_offset(void);
-void coldfire_trap_init(void);
 void coldfire_reset(void);
 
 /***************************************************************************/
@@ -66,7 +65,6 @@ void config_BSP(char *commandp, int size)
        mach_sched_init = coldfire_pit_init;
        mach_tick = coldfire_pit_tick;
        mach_gettimeoffset = coldfire_pit_offset;
-       mach_trap_init = coldfire_trap_init;
        mach_reset = coldfire_reset;
 }
 
index aab1ef0c1f7837f6dbd4fb99becded00c630af07..a089e9513699c1e82c0066576178564eb830ce73 100644 (file)
@@ -29,7 +29,6 @@
 void coldfire_pit_tick(void);
 void coldfire_pit_init(irq_handler_t handler);
 unsigned long coldfire_pit_offset(void);
-void coldfire_trap_init(void);
 void coldfire_reset(void);
 
 /***************************************************************************/
@@ -66,7 +65,6 @@ void config_BSP(char *commandp, int size)
        mach_sched_init = coldfire_pit_init;
        mach_tick = coldfire_pit_tick;
        mach_gettimeoffset = coldfire_pit_offset;
-       mach_trap_init = coldfire_trap_init;
        mach_reset = coldfire_reset;
 }
 
index 1f10e941b87c993babacdb886610e5b3e63b200e..e3461619fd65cb5c23ada8aa109eaa5b1f880caf 100644 (file)
@@ -29,7 +29,6 @@
 void coldfire_tick(void);
 void coldfire_timer_init(irq_handler_t handler);
 unsigned long coldfire_timer_offset(void);
-void coldfire_trap_init(void);
 void coldfire_reset(void);
 
 extern unsigned int mcf_timervector;
@@ -126,7 +125,6 @@ void config_BSP(char *commandp, int size)
        mach_sched_init = coldfire_timer_init;
        mach_tick = coldfire_tick;
        mach_gettimeoffset = coldfire_timer_offset;
-       mach_trap_init = coldfire_trap_init;
        mach_reset = coldfire_reset;
 
 #ifdef MCF_BDM_DISABLE
index aa15beeb36ca8b7676a49894860f66baee32c7e1..e53c446d10e4d9cd2343293b82f0017756a23f58 100644 (file)
@@ -5,9 +5,8 @@
  *              hardware timer only exists in the Freescale ColdFire
  *              5270/5271, 5282 and other CPUs.
  *
- *     Copyright (C) 1999-2006, Greg Ungerer (gerg@snapgear.com)
+ *     Copyright (C) 1999-2007, Greg Ungerer (gerg@snapgear.com)
  *     Copyright (C) 2001-2004, SnapGear Inc. (www.snapgear.com)
- *
  */
 
 /***************************************************************************/
@@ -17,8 +16,8 @@
 #include <linux/param.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <asm/io.h>
-#include <asm/irq.h>
 #include <asm/coldfire.h>
 #include <asm/mcfpit.h>
 #include <asm/mcfsim.h>
@@ -43,13 +42,18 @@ void coldfire_pit_tick(void)
 
 /***************************************************************************/
 
+static struct irqaction coldfire_pit_irq = {
+       .name    = "timer",
+       .flags   = IRQF_DISABLED | IRQF_TIMER,
+};
+
 void coldfire_pit_init(irq_handler_t handler)
 {
        volatile unsigned char *icrp;
        volatile unsigned long *imrp;
 
-       request_irq(MCFINT_VECBASE + MCFINT_PIT1, handler, IRQF_DISABLED,
-               "ColdFire Timer", NULL);
+       coldfire_pit_irq.handler = handler;
+       setup_irq(MCFINT_VECBASE + MCFINT_PIT1, &coldfire_pit_irq);
 
        icrp = (volatile unsigned char *) (MCF_IPSBAR + MCFICM_INTC0 +
                MCFINTC_ICR0 + MCFINT_PIT1);
index fb66eadd589633cf02ecc9e9f89dffe395a808ef..64bd0ff9029e2922dc92b6bde566404c3e0eed79 100644 (file)
@@ -3,7 +3,7 @@
 /*
  *     timers.c -- generic ColdFire hardware timer support.
  *
- *     Copyright (C) 1999-2006, Greg Ungerer (gerg@snapgear.com)
+ *     Copyright (C) 1999-2007, Greg Ungerer (gerg@snapgear.com)
  */
 
 /***************************************************************************/
@@ -13,8 +13,8 @@
 #include <linux/param.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
+#include <linux/irq.h>
 #include <asm/io.h>
-#include <asm/irq.h>
 #include <asm/traps.h>
 #include <asm/machdep.h>
 #include <asm/coldfire.h>
@@ -62,17 +62,24 @@ void coldfire_tick(void)
 
 /***************************************************************************/
 
+static struct irqaction coldfire_timer_irq = {
+        .name    = "timer",
+        .flags   = IRQF_DISABLED | IRQF_TIMER,
+};
+
 static int ticks_per_intr;
 
 void coldfire_timer_init(irq_handler_t handler)
 {
+       coldfire_timer_irq.handler = handler;
+       setup_irq(mcf_timervector, &coldfire_timer_irq);
+
        __raw_writew(MCFTIMER_TMR_DISABLE, TA(MCFTIMER_TMR));
        ticks_per_intr = (MCF_BUSCLK / 16) / HZ;
        __raw_writetrr(ticks_per_intr - 1, TA(MCFTIMER_TRR));
        __raw_writew(MCFTIMER_TMR_ENORI | MCFTIMER_TMR_CLK16 |
                MCFTIMER_TMR_RESTART | MCFTIMER_TMR_ENABLE, TA(MCFTIMER_TMR));
 
-       request_irq(mcf_timervector, handler, IRQF_DISABLED, "timer", NULL);
        mcf_settimericr(1, mcf_timerlevel);
 
 #ifdef CONFIG_HIGHPROFILE
index dc39c466e33f69c7309048a53e78e94f502a4730..b32c6425f8219ea0430de1a8ef3f23c506584648 100644 (file)
@@ -37,7 +37,6 @@
 void coldfire_tick(void);
 void coldfire_timer_init(irq_handler_t handler);
 unsigned long coldfire_timer_offset(void);
-void coldfire_trap_init(void);
 void coldfire_reset(void);
 
 extern unsigned int mcf_timervector;
@@ -108,7 +107,6 @@ void config_BSP(char *commandp, int size)
        mach_sched_init = coldfire_timer_init;
        mach_tick = coldfire_tick;
        mach_gettimeoffset = coldfire_timer_offset;
-       mach_trap_init = coldfire_trap_init;
        mach_reset = coldfire_reset;
 
 #ifdef MCF_BDM_DISABLE
index fde417fdd6504209b108703a5e1a40c6e534719e..e692536817d84fc22f9233360e3f33fd1785eea2 100644 (file)
@@ -28,7 +28,6 @@
 void coldfire_tick(void);
 void coldfire_timer_init(irq_handler_t handler);
 unsigned long coldfire_timer_offset(void);
-void coldfire_trap_init(void);
 void coldfire_reset(void);
 
 extern unsigned int mcf_timervector;
@@ -112,7 +111,6 @@ void config_BSP(char *commandp, int size)
        mach_sched_init = coldfire_timer_init;
        mach_tick = coldfire_tick;
        mach_gettimeoffset = coldfire_timer_offset;
-       mach_trap_init = coldfire_trap_init;
        mach_reset = coldfire_reset;
 }
 
index ef067f4c3cd47b8a241ea364869eda661a469ffc..0396476f955d6de405ba7a62d5c9edb35f3d113a 100644 (file)
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <asm/setup.h>
 #include <asm/system.h>
 #include <asm/pgtable.h>
-#include <asm/irq.h>
 #include <asm/machdep.h>
 #include <asm/MC68VZ328.h>
 
 
 /***************************************************************************/
 
+static struct irqaction m68328_timer_irq = {
+       .name    = "timer",
+       .flags   = IRQF_DISABLED | IRQF_TIMER,
+};
+
 void m68328_timer_init(irq_handler_t timer_routine)
 {
        /* disable timer 1 */
        TCTL = 0;
 
        /* set ISR */
-       if (request_irq(TMR_IRQ_NUM, timer_routine, IRQ_FLG_LOCK, "timer", NULL)) 
-               panic("Unable to attach timer interrupt\n");
+       m68328_timer_irq.handler = timer_routine;
+       setup_irq(TMR_IRQ_NUM, &m68328_timer_irq);
 
        /* Restart mode, Enable int, Set clock source */
        TCTL = TCTL_OM | TCTL_IRQEN | CLOCK_SOURCE;
index 4ff13bd51ffd0e536e06e3f176ad9a18b5c7d2e4..155b72fe2607ac5f179be1c59b734332e4f2b0c0 100644 (file)
 #include <linux/tty.h>
 #include <linux/console.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 
 #include <asm/setup.h>
 #include <asm/system.h>
 #include <asm/pgtable.h>
-#include <asm/irq.h>
 #include <asm/machdep.h>
 #include <asm/m68360.h>
 
@@ -51,11 +51,15 @@ extern unsigned long int system_clock; //In kernel setup.c
 
 extern void config_M68360_irq(void);
 
+static struct irqaction m68360_timer_irq = {
+       .name    = "timer",
+       .flags   = IRQF_DISABLED | IRQF_TIMER,
+};
+
 void BSP_sched_init(irq_handler_t timer_routine)
 {
   unsigned char prescaler;
   unsigned short tgcr_save;
-  int return_value;
 
 #if 0
   /* Restart mode, Enable int, 32KHz, Enable timer */
@@ -86,10 +90,8 @@ void BSP_sched_init(irq_handler_t timer_routine)
   pquicc->timer_ter1 = 0x0003; /* clear timer events */
 
   /* enable timer 1 interrupt in CIMR */
-//  request_irq(IRQ_MACHSPEC | CPMVEC_TIMER1, timer_routine, IRQ_FLG_LOCK, "timer", NULL);
-  //return_value = request_irq( CPMVEC_TIMER1, timer_routine, IRQ_FLG_LOCK, "timer", NULL);
-  return_value = request_irq(CPMVEC_TIMER1 , timer_routine, IRQ_FLG_LOCK,
-          "Timer", NULL);
+  m68360_timer_irq.handler = timer_routine;
+  setup_irq(CPMVEC_TIMER1, &m68360_timer_irq);
 
   /* Start timer 1: */
   tgcr_save = (pquicc->timer_tgcr & 0xfff0) | 0x0001;
index 09126fc338ba70ef28774af051146bebe5f1fa46..708fa1705fbe55fcfdf6b8c9b5d87de96f7653af 100644 (file)
@@ -702,7 +702,7 @@ u32 vio_send_sid(struct vio_driver_state *vio)
 }
 EXPORT_SYMBOL(vio_send_sid);
 
-extern int vio_ldc_alloc(struct vio_driver_state *vio,
+int vio_ldc_alloc(struct vio_driver_state *vio,
                         struct ldc_channel_config *base_cfg,
                         void *event_arg)
 {
index b70f3e7cf06ca7a8943b4d90a7027c6c7e8a42cf..dffd2ac72747b59836de76618f0c74089778424b 100644 (file)
@@ -41,8 +41,9 @@ int sysctl_vsyscall32 = 1;
 #undef ARCH_DLINFO
 #define ARCH_DLINFO do {  \
        if (sysctl_vsyscall32) { \
-       NEW_AUX_ENT(AT_SYSINFO, (u32)(u64)VSYSCALL32_VSYSCALL); \
-       NEW_AUX_ENT(AT_SYSINFO_EHDR, VSYSCALL32_BASE);    \
+               current->mm->context.vdso = (void *)VSYSCALL32_BASE;    \
+               NEW_AUX_ENT(AT_SYSINFO, (u32)(u64)VSYSCALL32_VSYSCALL); \
+               NEW_AUX_ENT(AT_SYSINFO_EHDR, VSYSCALL32_BASE);    \
        }       \
 } while(0)
 
index fc4419ff03558f398cbb5ae22811f5900d39241e..15013bac181c7ed42a9765137f58989d2de6dfa2 100644 (file)
@@ -49,14 +49,6 @@ int syscall32_setup_pages(struct linux_binprm *bprm, int exstack)
        return ret;
 }
 
-const char *arch_vma_name(struct vm_area_struct *vma)
-{
-       if (vma->vm_start == VSYSCALL32_BASE &&
-           vma->vm_mm && vma->vm_mm->task_size == IA32_PAGE_OFFSET)
-               return "[vdso]";
-       return NULL;
-}
-
 static int __init init_syscall32(void)
 { 
        char *syscall32_page = (void *)get_zeroed_page(GFP_KERNEL);
index 3aeae2fa2e240048a8b793db8f9f12c5659c3ca7..821527e7faa327fc85727c0f81120fde453b84e9 100644 (file)
@@ -165,7 +165,7 @@ done:
        return ret;
 }
 
-void* alloc_tce_table(void)
+void * __init alloc_tce_table(void)
 {
        unsigned int size;
 
@@ -175,7 +175,7 @@ void* alloc_tce_table(void)
        return __alloc_bootmem_low(size, size, 0);
 }
 
-void free_tce_table(void *tbl)
+void __init free_tce_table(void *tbl)
 {
        unsigned int size;
 
index 9b76b03d06001209437382b15c6f072c70f7e0dd..2a59bde663f2f1c2b32028f141603bfdab1f38ca 100644 (file)
@@ -118,8 +118,6 @@ core_initcall(cpufreq_tsc);
 
 #endif
 
-static int tsc_unstable = 0;
-
 /*
  * Make an educated guess if the TSC is trustworthy and synchronized
  * over all CPUs.
index 38f5d63680060769a58b7ac607f9085b6acf19d3..458893b376f811fe1e3b0b9f87444a68aeae53c6 100644 (file)
@@ -600,6 +600,16 @@ void mark_rodata_ro(void)
 {
        unsigned long start = (unsigned long)_stext, end;
 
+#ifdef CONFIG_HOTPLUG_CPU
+       /* It must still be possible to apply SMP alternatives. */
+       if (num_possible_cpus() > 1)
+               start = (unsigned long)_etext;
+#endif
+
+#ifdef CONFIG_KPROBES
+       start = (unsigned long)__start_rodata;
+#endif
+       
        end = (unsigned long)__end_rodata;
        start = (start + PAGE_SIZE - 1) & PAGE_MASK;
        end &= PAGE_MASK;
index 251344cb29aea1f04f2e42935b52c68c09103ba3..22b401b2e0884d4a33a3e7a41c9258cc5341bcf7 100644 (file)
@@ -11,9 +11,6 @@ menuconfig ACPI
        depends on PCI
        depends on PM
        select PNP
-       # for sleep
-       select HOTPLUG_CPU if X86 && SMP
-       select SUSPEND_SMP if X86 && SMP
        default y
        ---help---
          Advanced Configuration and Power Interface (ACPI) support for 
index a47ee1b70d2086b76bf41852650dc236fc483e38..56e8eaaac012cd544f69df0823aef84b023cfaaf 100644 (file)
@@ -44,7 +44,5 @@ void device_shutdown(void)
                        dev->driver->shutdown(dev);
                }
        }
-
-       sysdev_shutdown();
 }
 
index 5b79d0724171763ea4950a81d96c282590ab4555..93e3c4001bf51f299a21bf04eff813b88adfaec6 100644 (file)
@@ -1,6 +1,12 @@
-/* A simple block driver for lguest.
+/*D:400
+ * The Guest block driver
  *
- * Copyright 2006 Rusty Russell <rusty@rustcorp.com.au> IBM Corporation
+ * This is a simple block driver, which appears as /dev/lgba, lgbb, lgbc etc.
+ * The mechanism is simple: we place the information about the request in the
+ * device page, then use SEND_DMA (containing the data for a write, or an empty
+ * "ping" DMA for a read).
+ :*/
+/* Copyright 2006 Rusty Russell <rusty@rustcorp.com.au> IBM Corporation
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 
 static char next_block_index = 'a';
 
+/*D:420 Here is the structure which holds all the information we need about
+ * each Guest block device.
+ *
+ * I'm sure at this stage, you're wondering "hey, where was the adventure I was
+ * promised?" and thinking "Rusty sucks, I shall say nasty things about him on
+ * my blog".  I think Real adventures have boring bits, too, and you're in the
+ * middle of one.  But it gets better.  Just not quite yet. */
 struct blockdev
 {
+       /* The block queue infrastructure wants a spinlock: it is held while it
+        * calls our block request function.  We grab it in our interrupt
+        * handler so the responses don't mess with new requests. */
        spinlock_t lock;
 
-       /* The disk structure for the kernel. */
+       /* The disk structure registered with kernel. */
        struct gendisk *disk;
 
-       /* The major number for this disk. */
+       /* The major device number for this disk, and the interrupt.  We only
+        * really keep them here for completeness; we'd need them if we
+        * supported device unplugging. */
        int major;
        int irq;
 
+       /* The physical address of this device's memory page */
        unsigned long phys_addr;
-       /* The mapped block page. */
+       /* The mapped memory page for convenient acces. */
        struct lguest_block_page *lb_page;
 
-       /* We only have a single request outstanding at a time. */
+       /* We only have a single request outstanding at a time: this is it. */
        struct lguest_dma dma;
        struct request *req;
 };
 
-/* Jens gave me this nice helper to end all chunks of a request. */
+/*D:495 We originally used end_request() throughout the driver, but it turns
+ * out that end_request() is deprecated, and doesn't actually end the request
+ * (which seems like a good reason to deprecate it!).  It simply ends the first
+ * bio.  So if we had 3 bios in a "struct request" we would do all 3,
+ * end_request(), do 2, end_request(), do 1 and end_request(): twice as much
+ * work as we needed to do.
+ *
+ * This reinforced to me that I do not understand the block layer.
+ *
+ * Nonetheless, Jens Axboe gave me this nice helper to end all chunks of a
+ * request.  This improved disk speed by 130%. */
 static void end_entire_request(struct request *req, int uptodate)
 {
        if (end_that_request_first(req, uptodate, req->hard_nr_sectors))
@@ -55,30 +84,62 @@ static void end_entire_request(struct request *req, int uptodate)
        end_that_request_last(req, uptodate);
 }
 
+/* I'm told there are only two stories in the world worth telling: love and
+ * hate.  So there used to be a love scene here like this:
+ *
+ *  Launcher:  We could make beautiful I/O together, you and I.
+ *  Guest:     My, that's a big disk!
+ *
+ * Unfortunately, it was just too raunchy for our otherwise-gentle tale. */
+
+/*D:490 This is the interrupt handler, called when a block read or write has
+ * been completed for us. */
 static irqreturn_t lgb_irq(int irq, void *_bd)
 {
+       /* We handed our "struct blockdev" as the argument to request_irq(), so
+        * it is passed through to us here.  This tells us which device we're
+        * dealing with in case we have more than one. */
        struct blockdev *bd = _bd;
        unsigned long flags;
 
+       /* We weren't doing anything?  Strange, but could happen if we shared
+        * interrupts (we don't!). */
        if (!bd->req) {
                pr_debug("No work!\n");
                return IRQ_NONE;
        }
 
+       /* Not done yet?  That's equally strange. */
        if (!bd->lb_page->result) {
                pr_debug("No result!\n");
                return IRQ_NONE;
        }
 
+       /* We have to grab the lock before ending the request. */
        spin_lock_irqsave(&bd->lock, flags);
+       /* "result" is 1 for success, 2 for failure: end_entire_request() wants
+        * to know whether this succeeded or not. */
        end_entire_request(bd->req, bd->lb_page->result == 1);
+       /* Clear out request, it's done. */
        bd->req = NULL;
+       /* Reset incoming DMA for next time. */
        bd->dma.used_len = 0;
+       /* Ready for more reads or writes */
        blk_start_queue(bd->disk->queue);
        spin_unlock_irqrestore(&bd->lock, flags);
+
+       /* The interrupt was for us, we dealt with it. */
        return IRQ_HANDLED;
 }
 
+/*D:480 The block layer's "struct request" contains a number of "struct bio"s,
+ * each of which contains "struct bio_vec"s, each of which contains a page, an
+ * offset and a length.
+ *
+ * Fortunately there are iterators to help us walk through the "struct
+ * request".  Even more fortunately, there were plenty of places to steal the
+ * code from.  We pack the "struct request" into our "struct lguest_dma" and
+ * return the total length. */
 static unsigned int req_to_dma(struct request *req, struct lguest_dma *dma)
 {
        unsigned int i = 0, idx, len = 0;
@@ -87,8 +148,13 @@ static unsigned int req_to_dma(struct request *req, struct lguest_dma *dma)
        rq_for_each_bio(bio, req) {
                struct bio_vec *bvec;
                bio_for_each_segment(bvec, bio, idx) {
+                       /* We told the block layer not to give us too many. */
                        BUG_ON(i == LGUEST_MAX_DMA_SECTIONS);
+                       /* If we had a zero-length segment, it would look like
+                        * the end of the data referred to by the "struct
+                        * lguest_dma", so make sure that doesn't happen. */
                        BUG_ON(!bvec->bv_len);
+                       /* Convert page & offset to a physical address */
                        dma->addr[i] = page_to_phys(bvec->bv_page)
                                + bvec->bv_offset;
                        dma->len[i] = bvec->bv_len;
@@ -96,26 +162,39 @@ static unsigned int req_to_dma(struct request *req, struct lguest_dma *dma)
                        i++;
                }
        }
+       /* If the array isn't full, we mark the end with a 0 length */
        if (i < LGUEST_MAX_DMA_SECTIONS)
                dma->len[i] = 0;
        return len;
 }
 
+/* This creates an empty DMA, useful for prodding the Host without sending data
+ * (ie. when we want to do a read) */
 static void empty_dma(struct lguest_dma *dma)
 {
        dma->len[0] = 0;
 }
 
+/*D:470 Setting up a request is fairly easy: */
 static void setup_req(struct blockdev *bd,
                      int type, struct request *req, struct lguest_dma *dma)
 {
+       /* The type is 1 (write) or 0 (read). */
        bd->lb_page->type = type;
+       /* The sector on disk where the read or write starts. */
        bd->lb_page->sector = req->sector;
+       /* The result is initialized to 0 (unfinished). */
        bd->lb_page->result = 0;
+       /* The current request (so we can end it in the interrupt handler). */
        bd->req = req;
+       /* The number of bytes: returned as a side-effect of req_to_dma(),
+        * which packs the block layer's "struct request" into our "struct
+        * lguest_dma" */
        bd->lb_page->bytes = req_to_dma(req, dma);
 }
 
+/*D:450 Write is pretty straightforward: we pack the request into a "struct
+ * lguest_dma", then use SEND_DMA to send the request. */
 static void do_write(struct blockdev *bd, struct request *req)
 {
        struct lguest_dma send;
@@ -126,6 +205,9 @@ static void do_write(struct blockdev *bd, struct request *req)
        lguest_send_dma(bd->phys_addr, &send);
 }
 
+/* Read is similar to write, except we pack the request into our receive
+ * "struct lguest_dma" and send through an empty DMA just to tell the Host that
+ * there's a request pending. */
 static void do_read(struct blockdev *bd, struct request *req)
 {
        struct lguest_dma ping;
@@ -137,21 +219,30 @@ static void do_read(struct blockdev *bd, struct request *req)
        lguest_send_dma(bd->phys_addr, &ping);
 }
 
+/*D:440 This where requests come in: we get handed the request queue and are
+ * expected to pull a "struct request" off it until we've finished them or
+ * we're waiting for a reply: */
 static void do_lgb_request(struct request_queue *q)
 {
        struct blockdev *bd;
        struct request *req;
 
 again:
+       /* This sometimes returns NULL even on the very first time around.  I
+        * wonder if it's something to do with letting elves handle the request
+        * queue... */
        req = elv_next_request(q);
        if (!req)
                return;
 
+       /* We attached the struct blockdev to the disk: get it back */
        bd = req->rq_disk->private_data;
-       /* Sometimes we get repeated requests after blk_stop_queue. */
+       /* Sometimes we get repeated requests after blk_stop_queue(), but we
+        * can only handle one at a time. */
        if (bd->req)
                return;
 
+       /* We only do reads and writes: no tricky business! */
        if (!blk_fs_request(req)) {
                pr_debug("Got non-command 0x%08x\n", req->cmd_type);
                req->errors++;
@@ -164,20 +255,31 @@ again:
        else
                do_read(bd, req);
 
-       /* Wait for interrupt to tell us it's done. */
+       /* We've put out the request, so stop any more coming in until we get
+        * an interrupt, which takes us to lgb_irq() to re-enable the queue. */
        blk_stop_queue(q);
 }
 
+/*D:430 This is the "struct block_device_operations" we attach to the disk at
+ * the end of lguestblk_probe().  It doesn't seem to want much. */
 static struct block_device_operations lguestblk_fops = {
        .owner = THIS_MODULE,
 };
 
+/*D:425 Setting up a disk device seems to involve a lot of code.  I'm not sure
+ * quite why.  I do know that the IDE code sent two or three of the maintainers
+ * insane, perhaps this is the fringe of the same disease?
+ *
+ * As in the console code, the probe function gets handed the generic
+ * lguest_device from lguest_bus.c: */
 static int lguestblk_probe(struct lguest_device *lgdev)
 {
        struct blockdev *bd;
        int err;
        int irqflags = IRQF_SHARED;
 
+       /* First we allocate our own "struct blockdev" and initialize the easy
+        * fields. */
        bd = kmalloc(sizeof(*bd), GFP_KERNEL);
        if (!bd)
                return -ENOMEM;
@@ -187,59 +289,100 @@ static int lguestblk_probe(struct lguest_device *lgdev)
        bd->req = NULL;
        bd->dma.used_len = 0;
        bd->dma.len[0] = 0;
+       /* The descriptor in the lguest_devices array provided by the Host
+        * gives the Guest the physical page number of the device's page. */
        bd->phys_addr = (lguest_devices[lgdev->index].pfn << PAGE_SHIFT);
 
+       /* We use lguest_map() to get a pointer to the device page */
        bd->lb_page = lguest_map(bd->phys_addr, 1);
        if (!bd->lb_page) {
                err = -ENOMEM;
                goto out_free_bd;
        }
 
+       /* We need a major device number: 0 means "assign one dynamically". */
        bd->major = register_blkdev(0, "lguestblk");
        if (bd->major < 0) {
                err = bd->major;
                goto out_unmap;
        }
 
+       /* This allocates a "struct gendisk" where we pack all the information
+        * about the disk which the rest of Linux sees.  We ask for one minor
+        * number; I do wonder if we should be asking for more. */
        bd->disk = alloc_disk(1);
        if (!bd->disk) {
                err = -ENOMEM;
                goto out_unregister_blkdev;
        }
 
+       /* Every disk needs a queue for requests to come in: we set up the
+        * queue with a callback function (the core of our driver) and the lock
+        * to use. */
        bd->disk->queue = blk_init_queue(do_lgb_request, &bd->lock);
        if (!bd->disk->queue) {
                err = -ENOMEM;
                goto out_put_disk;
        }
 
-       /* We can only handle a certain number of sg entries */
+       /* We can only handle a certain number of pointers in our SEND_DMA
+        * call, so we set that with blk_queue_max_hw_segments().  This is not
+        * to be confused with blk_queue_max_phys_segments() of course!  I
+        * know, who could possibly confuse the two?
+        *
+        * Well, it's simple to tell them apart: this one seems to work and the
+        * other one didn't. */
        blk_queue_max_hw_segments(bd->disk->queue, LGUEST_MAX_DMA_SECTIONS);
-       /* Buffers must not cross page boundaries */
+
+       /* Due to technical limitations of our Host (and simple coding) we
+        * can't have a single buffer which crosses a page boundary.  Tell it
+        * here.  This means that our maximum request size is 16
+        * (LGUEST_MAX_DMA_SECTIONS) pages. */
        blk_queue_segment_boundary(bd->disk->queue, PAGE_SIZE-1);
 
+       /* We name our disk: this becomes the device name when udev does its
+        * magic thing and creates the device node, such as /dev/lgba.
+        * next_block_index is a global which starts at 'a'.  Unfortunately
+        * this simple increment logic means that the 27th disk will be called
+        * "/dev/lgb{".  In that case, I recommend having at least 29 disks, so
+        * your /dev directory will be balanced. */
        sprintf(bd->disk->disk_name, "lgb%c", next_block_index++);
+
+       /* We look to the device descriptor again to see if this device's
+        * interrupts are expected to be random.  If they are, we tell the irq
+        * subsystem.  At the moment this bit is always set. */
        if (lguest_devices[lgdev->index].features & LGUEST_DEVICE_F_RANDOMNESS)
                irqflags |= IRQF_SAMPLE_RANDOM;
+
+       /* Now we have the name and irqflags, we can request the interrupt; we
+        * give it the "struct blockdev" we have set up to pass to lgb_irq()
+        * when there is an interrupt. */
        err = request_irq(bd->irq, lgb_irq, irqflags, bd->disk->disk_name, bd);
        if (err)
                goto out_cleanup_queue;
 
+       /* We bind our one-entry DMA pool to the key for this block device so
+        * the Host can reply to our requests.  The key is equal to the
+        * physical address of the device's page, which is conveniently
+        * unique. */
        err = lguest_bind_dma(bd->phys_addr, &bd->dma, 1, bd->irq);
        if (err)
                goto out_free_irq;
 
+       /* We finish our disk initialization and add the disk to the system. */
        bd->disk->major = bd->major;
        bd->disk->first_minor = 0;
        bd->disk->private_data = bd;
        bd->disk->fops = &lguestblk_fops;
-       /* This is initialized to the disk size by the other end. */
+       /* This is initialized to the disk size by the Launcher. */
        set_capacity(bd->disk, bd->lb_page->num_sectors);
        add_disk(bd->disk);
 
        printk(KERN_INFO "%s: device %i at major %d\n",
               bd->disk->disk_name, lgdev->index, bd->major);
 
+       /* We don't need to keep the "struct blockdev" around, but if we ever
+        * implemented device removal, we'd need this. */
        lgdev->private = bd;
        return 0;
 
@@ -258,6 +401,8 @@ out_free_bd:
        return err;
 }
 
+/*D:410 The boilerplate code for registering the lguest block driver is just
+ * like the console: */
 static struct lguest_driver lguestblk_drv = {
        .name = "lguestblk",
        .owner = THIS_MODULE,
index acdbcdc3e45709e6bd3534537546188c936a380a..b391776e5bf31ca24f45eea0576e63364c2c2c80 100644 (file)
@@ -130,6 +130,7 @@ config ROCKETPORT
 config CYCLADES
        tristate "Cyclades async mux support"
        depends on SERIAL_NONSTANDARD && (PCI || ISA)
+       select FW_LOADER
        ---help---
          This driver supports Cyclades Z and Y multiserial boards.
          You would need something like this to connect more than two modems to
index 9a2694e5f8b98311ff435f3ce4733333c5682266..77bf4aa217a8afcb7e8eb505ed2b0f5d9a0542c0 100644 (file)
@@ -73,7 +73,7 @@ static struct clocksource clocksource_hpet = {
         .name           = "hpet",
         .rating         = 250,
         .read           = read_hpet,
-        .mask           = 0xffffffffffffffff,
+        .mask           = CLOCKSOURCE_MASK(64),
         .mult           = 0, /*to be caluclated*/
         .shift          = 10,
         .flags          = CLOCK_SOURCE_IS_CONTINUOUS,
index e7b889e404a7ec80d498a34f20302dc0ac03d3b8..feeccbaec4382c55c1583fcad49cf73264a407ce 100644 (file)
@@ -1,6 +1,22 @@
-/* Simple console for lguest.
+/*D:300
+ * The Guest console driver
  *
- * Copyright (C) 2006 Rusty Russell, IBM Corporation
+ * This is a trivial console driver: we use lguest's DMA mechanism to send
+ * bytes out, and register a DMA buffer to receive bytes in.  It is assumed to
+ * be present and available from the very beginning of boot.
+ *
+ * Writing console drivers is one of the few remaining Dark Arts in Linux.
+ * Fortunately for us, the path of virtual consoles has been well-trodden by
+ * the PowerPC folks, who wrote "hvc_console.c" to generically support any
+ * virtual console.  We use that infrastructure which only requires us to write
+ * the basic put_chars and get_chars functions and call the right register
+ * functions.
+ :*/
+
+/*M:002 The console can be flooded: while the Guest is processing input the
+ * Host can send more.  Buffering in the Host could alleviate this, but it is a
+ * difficult problem in general. :*/
+/* Copyright (C) 2006 Rusty Russell, IBM Corporation
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 #include <linux/lguest_bus.h>
 #include "hvc_console.h"
 
+/*D:340 This is our single console input buffer, with associated "struct
+ * lguest_dma" referring to it.  Note the 0-terminated length array, and the
+ * use of physical address for the buffer itself. */
 static char inbuf[256];
 static struct lguest_dma cons_input = { .used_len = 0,
                                        .addr[0] = __pa(inbuf),
                                        .len[0] = sizeof(inbuf),
                                        .len[1] = 0 };
 
+/*D:310 The put_chars() callback is pretty straightforward.
+ *
+ * First we put the pointer and length in a "struct lguest_dma": we only have
+ * one pointer, so we set the second length to 0.  Then we use SEND_DMA to send
+ * the data to (Host) buffers attached to the console key.  Usually a device's
+ * key is a physical address within the device's memory, but because the
+ * console device doesn't have any associated physical memory, we use the
+ * LGUEST_CONSOLE_DMA_KEY constant (aka 0). */
 static int put_chars(u32 vtermno, const char *buf, int count)
 {
        struct lguest_dma dma;
 
-       /* FIXME: what if it's over a page boundary? */
+       /* FIXME: DMA buffers in a "struct lguest_dma" are not allowed
+        * to go over page boundaries.  This never seems to happen,
+        * but if it did we'd need to fix this code. */
        dma.len[0] = count;
        dma.len[1] = 0;
        dma.addr[0] = __pa(buf);
 
        lguest_send_dma(LGUEST_CONSOLE_DMA_KEY, &dma);
+       /* We're expected to return the amount of data we wrote: all of it. */
        return count;
 }
 
+/*D:350 get_chars() is the callback from the hvc_console infrastructure when
+ * an interrupt is received.
+ *
+ * Firstly we see if our buffer has been filled: if not, we return.  The rest
+ * of the code deals with the fact that the hvc_console() infrastructure only
+ * asks us for 16 bytes at a time.  We keep a "cons_offset" variable for
+ * partially-read buffers. */
 static int get_chars(u32 vtermno, char *buf, int count)
 {
        static int cons_offset;
 
+       /* Nothing left to see here... */
        if (!cons_input.used_len)
                return 0;
 
+       /* You want more than we have to give?  Well, try wanting less! */
        if (cons_input.used_len - cons_offset < count)
                count = cons_input.used_len - cons_offset;
 
+       /* Copy across to their buffer and increment offset. */
        memcpy(buf, inbuf + cons_offset, count);
        cons_offset += count;
+
+       /* Finished?  Zero offset, and reset cons_input so Host will use it
+        * again. */
        if (cons_offset == cons_input.used_len) {
                cons_offset = 0;
                cons_input.used_len = 0;
        }
        return count;
 }
+/*:*/
 
 static struct hv_ops lguest_cons = {
        .get_chars = get_chars,
        .put_chars = put_chars,
 };
 
+/*D:320 Console drivers are initialized very early so boot messages can go
+ * out.  At this stage, the console is output-only.  Our driver checks we're a
+ * Guest, and if so hands hvc_instantiate() the console number (0), priority
+ * (0), and the struct hv_ops containing the put_chars() function. */
 static int __init cons_init(void)
 {
        if (strcmp(paravirt_ops.name, "lguest") != 0)
@@ -73,21 +121,46 @@ static int __init cons_init(void)
 }
 console_initcall(cons_init);
 
+/*D:370 To set up and manage our virtual console, we call hvc_alloc() and
+ * stash the result in the private pointer of the "struct lguest_device".
+ * Since we never remove the console device we never need this pointer again,
+ * but using ->private is considered good form, and you never know who's going
+ * to copy your driver.
+ *
+ * Once the console is set up, we bind our input buffer ready for input. */
 static int lguestcons_probe(struct lguest_device *lgdev)
 {
        int err;
 
+       /* The first argument of hvc_alloc() is the virtual console number, so
+        * we use zero.  The second argument is the interrupt number.
+        *
+        * The third argument is a "struct hv_ops" containing the put_chars()
+        * and get_chars() pointers.  The final argument is the output buffer
+        * size: we use 256 and expect the Host to have room for us to send
+        * that much. */
        lgdev->private = hvc_alloc(0, lgdev_irq(lgdev), &lguest_cons, 256);
        if (IS_ERR(lgdev->private))
                return PTR_ERR(lgdev->private);
 
+       /* We bind a single DMA buffer at key LGUEST_CONSOLE_DMA_KEY.
+        * "cons_input" is that statically-initialized global DMA buffer we saw
+        * above, and we also give the interrupt we want. */
        err = lguest_bind_dma(LGUEST_CONSOLE_DMA_KEY, &cons_input, 1,
                              lgdev_irq(lgdev));
        if (err)
                printk("lguest console: failed to bind buffer.\n");
        return err;
 }
+/* Note the use of lgdev_irq() for the interrupt number.  We tell hvc_alloc()
+ * to expect input when this interrupt is triggered, and then tell
+ * lguest_bind_dma() that is the interrupt to send us when input comes in. */
 
+/*D:360 From now on the console driver follows standard Guest driver form:
+ * register_lguest_driver() registers the device type and probe function, and
+ * the probe function sets up the device.
+ *
+ * The standard "struct lguest_driver": */
 static struct lguest_driver lguestcons_drv = {
        .name = "lguestcons",
        .owner = THIS_MODULE,
@@ -95,6 +168,7 @@ static struct lguest_driver lguestcons_drv = {
        .probe = lguestcons_probe,
 };
 
+/* The standard init function */
 static int __init hvc_lguest_init(void)
 {
        return register_lguest_driver(&lguestcons_drv);
index 1724c41d2414d8834e1f238df38e51977becebbd..98b6b4fb42577615447648d0cdbb3a3a7a33ca98 100644 (file)
@@ -8,7 +8,7 @@ menuconfig EDAC
        bool "EDAC - error detection and reporting (EXPERIMENTAL)"
        depends on HAS_IOMEM
        depends on EXPERIMENTAL
-       depends on X86 || MIPS || PPC
+       depends on X86 || PPC
        help
          EDAC is designed to report errors in the core system.
          These are low-level errors that are reported in the CPU or
@@ -126,7 +126,7 @@ config EDAC_I5000
 config EDAC_PASEMI
        tristate "PA Semi PWRficient"
        depends on EDAC_MM_EDAC && PCI
-       depends on PPC
+       depends on PPC_PASEMI
        help
          Support for error detection and correction on PA Semi
          PWRficient.
index 4471be3625995e59a8264ca91a3c6737e163e604..063a1bffe38b026ba7005ee0b105a4e956baf6e9 100644 (file)
@@ -214,6 +214,13 @@ void edac_mc_free(struct mem_ctl_info *mci)
 }
 EXPORT_SYMBOL_GPL(edac_mc_free);
 
+
+/*
+ * find_mci_by_dev
+ *
+ *     scan list of controllers looking for the one that manages
+ *     the 'dev' device
+ */
 static struct mem_ctl_info *find_mci_by_dev(struct device *dev)
 {
        struct mem_ctl_info *mci;
@@ -268,12 +275,6 @@ static void edac_mc_workq_function(struct work_struct *work_req)
        if (edac_mc_assert_error_check_and_clear() && (mci->edac_check != NULL))
                mci->edac_check(mci);
 
-       /*
-        * FIXME: temp place holder for PCI checks,
-        * goes away when we break out PCI
-        */
-       edac_pci_do_parity_check();
-
        mutex_unlock(&mem_ctls_mutex);
 
        /* Reschedule */
@@ -314,36 +315,55 @@ static void edac_mc_workq_teardown(struct mem_ctl_info *mci)
 {
        int status;
 
-       /* if not running POLL, leave now */
-       if (mci->op_state == OP_RUNNING_POLL) {
-               status = cancel_delayed_work(&mci->work);
-               if (status == 0) {
-                       debugf0("%s() not canceled, flush the queue\n",
-                               __func__);
+       status = cancel_delayed_work(&mci->work);
+       if (status == 0) {
+               debugf0("%s() not canceled, flush the queue\n",
+                       __func__);
 
-                       /* workq instance might be running, wait for it */
-                       flush_workqueue(edac_workqueue);
-               }
+               /* workq instance might be running, wait for it */
+               flush_workqueue(edac_workqueue);
        }
 }
 
 /*
- * edac_reset_delay_period
+ * edac_mc_reset_delay_period(unsigned long value)
+ *
+ *     user space has updated our poll period value, need to
+ *     reset our workq delays
  */
-static void edac_reset_delay_period(struct mem_ctl_info *mci, unsigned long value)
+void edac_mc_reset_delay_period(int value)
 {
-       /* cancel the current workq request */
-       edac_mc_workq_teardown(mci);
+       struct mem_ctl_info *mci;
+       struct list_head *item;
 
-       /* lock the list of devices for the new setup */
        mutex_lock(&mem_ctls_mutex);
 
-       /* restart the workq request, with new delay value */
-       edac_mc_workq_setup(mci, value);
+       /* scan the list and turn off all workq timers, doing so under lock
+        */
+       list_for_each(item, &mc_devices) {
+               mci = list_entry(item, struct mem_ctl_info, link);
+
+               if (mci->op_state == OP_RUNNING_POLL)
+                       cancel_delayed_work(&mci->work);
+       }
+
+       mutex_unlock(&mem_ctls_mutex);
+
+
+       /* re-walk the list, and reset the poll delay */
+       mutex_lock(&mem_ctls_mutex);
+
+       list_for_each(item, &mc_devices) {
+               mci = list_entry(item, struct mem_ctl_info, link);
+
+               edac_mc_workq_setup(mci, (unsigned long) value);
+       }
 
        mutex_unlock(&mem_ctls_mutex);
 }
 
+
+
 /* Return 0 on success, 1 on failure.
  * Before calling this function, caller must
  * assign a unique value to mci->mc_idx.
index cd090b0677a78b2606f09aa2e694357003f42a2c..4a0576bd06fc93bab9b2028b695ff7907a13f9c4 100644 (file)
@@ -122,6 +122,23 @@ static ssize_t memctrl_int_store(void *ptr, const char *buffer, size_t count)
        return count;
 }
 
+/*
+ * mc poll_msec time value
+ */
+static ssize_t poll_msec_int_store(void *ptr, const char *buffer, size_t count)
+{
+       int *value = (int *)ptr;
+
+       if (isdigit(*buffer)) {
+               *value = simple_strtoul(buffer, NULL, 0);
+
+               /* notify edac_mc engine to reset the poll period */
+               edac_mc_reset_delay_period(*value);
+       }
+
+       return count;
+}
+
 
 /* EDAC sysfs CSROW data structures and methods
  */
@@ -704,7 +721,7 @@ MEMCTRL_ATTR(edac_mc_log_ce,
        S_IRUGO | S_IWUSR, memctrl_int_show, memctrl_int_store);
 
 MEMCTRL_ATTR(edac_mc_poll_msec,
-       S_IRUGO | S_IWUSR, memctrl_int_show, memctrl_int_store);
+       S_IRUGO | S_IWUSR, memctrl_int_show, poll_msec_int_store);
 
 /* Base Attributes of the memory ECC object */
 static struct memctrl_dev_attribute *memctrl_attr[] = {
index a2134dfc3cc691783122cddec1a9906d982b00ef..cbc419c8ebc1b8373c3c5661ce9a449cb3517107 100644 (file)
@@ -52,6 +52,8 @@ extern void edac_device_workq_setup(struct edac_device_ctl_info *edac_dev,
 extern void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev);
 extern void edac_device_reset_delay_period(struct edac_device_ctl_info
                                           *edac_dev, unsigned long value);
+extern void edac_mc_reset_delay_period(int value);
+
 extern void *edac_align_ptr(void *ptr, unsigned size);
 
 /*
@@ -64,6 +66,10 @@ extern int edac_sysfs_pci_setup(void);
 extern void edac_sysfs_pci_teardown(void);
 extern int edac_pci_get_check_errors(void);
 extern int edac_pci_get_poll_msec(void);
+extern void edac_pci_remove_sysfs(struct edac_pci_ctl_info *pci);
+extern void edac_pci_handle_pe(struct edac_pci_ctl_info *pci, const char *msg);
+extern void edac_pci_handle_npe(struct edac_pci_ctl_info *pci,
+                               const char *msg);
 #else                          /* CONFIG_PCI */
 /* pre-process these away */
 #define edac_pci_do_parity_check()
@@ -72,6 +78,8 @@ extern int edac_pci_get_poll_msec(void);
 #define edac_sysfs_pci_teardown()
 #define edac_pci_get_check_errors()
 #define edac_pci_get_poll_msec()
+#define edac_pci_handle_pe()
+#define edac_pci_handle_npe()
 #endif                         /* CONFIG_PCI */
 
 #endif                         /* __EDAC_MODULE_H__ */
index d9cd5e048cee92b520413bef79592e62b6521a73..5dee9f50414bee396fde63895efa6ddcf7f0841c 100644 (file)
 static DEFINE_MUTEX(edac_pci_ctls_mutex);
 static struct list_head edac_pci_list = LIST_HEAD_INIT(edac_pci_list);
 
-static inline void edac_lock_pci_list(void)
-{
-       mutex_lock(&edac_pci_ctls_mutex);
-}
-
-static inline void edac_unlock_pci_list(void)
-{
-       mutex_unlock(&edac_pci_ctls_mutex);
-}
-
 /*
- * The alloc() and free() functions for the 'edac_pci' control info
- * structure. The chip driver will allocate one of these for each
- * edac_pci it is going to control/register with the EDAC CORE.
+ * edac_pci_alloc_ctl_info
+ *
+ *     The alloc() function for the 'edac_pci' control info
+ *     structure. The chip driver will allocate one of these for each
+ *     edac_pci it is going to control/register with the EDAC CORE.
  */
 struct edac_pci_ctl_info *edac_pci_alloc_ctl_info(unsigned int sz_pvt,
                                                const char *edac_pci_name)
@@ -53,47 +45,59 @@ struct edac_pci_ctl_info *edac_pci_alloc_ctl_info(unsigned int sz_pvt,
        void *pvt;
        unsigned int size;
 
+       debugf1("%s()\n", __func__);
+
        pci = (struct edac_pci_ctl_info *)0;
        pvt = edac_align_ptr(&pci[1], sz_pvt);
        size = ((unsigned long)pvt) + sz_pvt;
 
-       if ((pci = kzalloc(size, GFP_KERNEL)) == NULL)
+       /* Alloc the needed control struct memory */
+       pci = kzalloc(size, GFP_KERNEL);
+       if (pci  == NULL)
                return NULL;
 
+       /* Now much private space */
        pvt = sz_pvt ? ((char *)pci) + ((unsigned long)pvt) : NULL;
 
        pci->pvt_info = pvt;
-
        pci->op_state = OP_ALLOC;
 
        snprintf(pci->name, strlen(edac_pci_name) + 1, "%s", edac_pci_name);
 
        return pci;
 }
-
 EXPORT_SYMBOL_GPL(edac_pci_alloc_ctl_info);
 
 /*
  * edac_pci_free_ctl_info()
- *     frees the memory allocated by edac_pci_alloc_ctl_info() function
+ *
+ *     Last action on the pci control structure.
+ *
+ *     call the remove sysfs informaton, which will unregister
+ *     this control struct's kobj. When that kobj's ref count
+ *     goes to zero, its release function will be call and then
+ *     kfree() the memory.
  */
 void edac_pci_free_ctl_info(struct edac_pci_ctl_info *pci)
 {
-       kfree(pci);
-}
+       debugf1("%s()\n", __func__);
 
+       edac_pci_remove_sysfs(pci);
+}
 EXPORT_SYMBOL_GPL(edac_pci_free_ctl_info);
 
 /*
  * find_edac_pci_by_dev()
  *     scans the edac_pci list for a specific 'struct device *'
+ *
+ *     return NULL if not found, or return control struct pointer
  */
 static struct edac_pci_ctl_info *find_edac_pci_by_dev(struct device *dev)
 {
        struct edac_pci_ctl_info *pci;
        struct list_head *item;
 
-       debugf3("%s()\n", __func__);
+       debugf1("%s()\n", __func__);
 
        list_for_each(item, &edac_pci_list) {
                pci = list_entry(item, struct edac_pci_ctl_info, link);
@@ -118,10 +122,13 @@ static int add_edac_pci_to_global_list(struct edac_pci_ctl_info *pci)
        struct list_head *item, *insert_before;
        struct edac_pci_ctl_info *rover;
 
+       debugf1("%s()\n", __func__);
+
        insert_before = &edac_pci_list;
 
        /* Determine if already on the list */
-       if (unlikely((rover = find_edac_pci_by_dev(pci->dev)) != NULL))
+       rover = find_edac_pci_by_dev(pci->dev);
+       if (unlikely(rover != NULL))
                goto fail0;
 
        /* Insert in ascending order by 'pci_idx', so find position */
@@ -157,6 +164,8 @@ fail1:
 
 /*
  * complete_edac_pci_list_del
+ *
+ *     RCU completion callback to indicate item is deleted
  */
 static void complete_edac_pci_list_del(struct rcu_head *head)
 {
@@ -169,6 +178,8 @@ static void complete_edac_pci_list_del(struct rcu_head *head)
 
 /*
  * del_edac_pci_from_global_list
+ *
+ *     remove the PCI control struct from the global list
  */
 static void del_edac_pci_from_global_list(struct edac_pci_ctl_info *pci)
 {
@@ -207,35 +218,52 @@ struct edac_pci_ctl_info *edac_pci_find(int idx)
 
        return NULL;
 }
-
 EXPORT_SYMBOL_GPL(edac_pci_find);
 
 /*
  * edac_pci_workq_function()
- *     performs the operation scheduled by a workq request
+ *
+ *     periodic function that performs the operation
+ *     scheduled by a workq request, for a given PCI control struct
  */
 static void edac_pci_workq_function(struct work_struct *work_req)
 {
        struct delayed_work *d_work = (struct delayed_work *)work_req;
        struct edac_pci_ctl_info *pci = to_edac_pci_ctl_work(d_work);
+       int msec;
+       unsigned long delay;
 
-       edac_lock_pci_list();
+       debugf3("%s() checking\n", __func__);
 
-       if ((pci->op_state == OP_RUNNING_POLL) &&
-               (pci->edac_check != NULL) && (edac_pci_get_check_errors()))
-               pci->edac_check(pci);
+       mutex_lock(&edac_pci_ctls_mutex);
 
-       edac_unlock_pci_list();
+       if (pci->op_state == OP_RUNNING_POLL) {
+               /* we might be in POLL mode, but there may NOT be a poll func
+                */
+               if ((pci->edac_check != NULL) && edac_pci_get_check_errors())
+                       pci->edac_check(pci);
+
+               /* if we are on a one second period, then use round */
+               msec = edac_pci_get_poll_msec();
+               if (msec == 1000)
+                       delay = round_jiffies(msecs_to_jiffies(msec));
+               else
+                       delay = msecs_to_jiffies(msec);
+
+               /* Reschedule only if we are in POLL mode */
+               queue_delayed_work(edac_workqueue, &pci->work, delay);
+       }
 
-       /* Reschedule */
-       queue_delayed_work(edac_workqueue, &pci->work,
-                       msecs_to_jiffies(edac_pci_get_poll_msec()));
+       mutex_unlock(&edac_pci_ctls_mutex);
 }
 
 /*
  * edac_pci_workq_setup()
  *     initialize a workq item for this edac_pci instance
  *     passing in the new delay period in msec
+ *
+ *     locking model:
+ *             called when 'edac_pci_ctls_mutex' is locked
  */
 static void edac_pci_workq_setup(struct edac_pci_ctl_info *pci,
                                 unsigned int msec)
@@ -255,6 +283,8 @@ static void edac_pci_workq_teardown(struct edac_pci_ctl_info *pci)
 {
        int status;
 
+       debugf0("%s()\n", __func__);
+
        status = cancel_delayed_work(&pci->work);
        if (status == 0)
                flush_workqueue(edac_workqueue);
@@ -262,19 +292,25 @@ static void edac_pci_workq_teardown(struct edac_pci_ctl_info *pci)
 
 /*
  * edac_pci_reset_delay_period
+ *
+ *     called with a new period value for the workq period
+ *     a) stop current workq timer
+ *     b) restart workq timer with new value
  */
 void edac_pci_reset_delay_period(struct edac_pci_ctl_info *pci,
                                 unsigned long value)
 {
-       edac_lock_pci_list();
+       debugf0("%s()\n", __func__);
 
        edac_pci_workq_teardown(pci);
 
+       /* need to lock for the setup */
+       mutex_lock(&edac_pci_ctls_mutex);
+
        edac_pci_workq_setup(pci, value);
 
-       edac_unlock_pci_list();
+       mutex_unlock(&edac_pci_ctls_mutex);
 }
-
 EXPORT_SYMBOL_GPL(edac_pci_reset_delay_period);
 
 /*
@@ -294,14 +330,13 @@ int edac_pci_add_device(struct edac_pci_ctl_info *pci, int edac_idx)
        debugf0("%s()\n", __func__);
 
        pci->pci_idx = edac_idx;
+       pci->start_time = jiffies;
 
-       edac_lock_pci_list();
+       mutex_lock(&edac_pci_ctls_mutex);
 
        if (add_edac_pci_to_global_list(pci))
                goto fail0;
 
-       pci->start_time = jiffies;
-
        if (edac_pci_create_sysfs(pci)) {
                edac_pci_printk(pci, KERN_WARNING,
                                "failed to create sysfs pci\n");
@@ -323,16 +358,16 @@ int edac_pci_add_device(struct edac_pci_ctl_info *pci, int edac_idx)
                        pci->ctl_name,
                        dev_name(pci), edac_op_state_to_string(pci->op_state));
 
-       edac_unlock_pci_list();
+       mutex_unlock(&edac_pci_ctls_mutex);
        return 0;
 
+       /* error unwind stack */
 fail1:
        del_edac_pci_from_global_list(pci);
 fail0:
-       edac_unlock_pci_list();
+       mutex_unlock(&edac_pci_ctls_mutex);
        return 1;
 }
-
 EXPORT_SYMBOL_GPL(edac_pci_add_device);
 
 /*
@@ -354,22 +389,25 @@ struct edac_pci_ctl_info *edac_pci_del_device(struct device *dev)
 
        debugf0("%s()\n", __func__);
 
-       edac_lock_pci_list();
+       mutex_lock(&edac_pci_ctls_mutex);
 
-       if ((pci = find_edac_pci_by_dev(dev)) == NULL) {
-               edac_unlock_pci_list();
+       /* ensure the control struct is on the global list
+        * if not, then leave
+        */
+       pci = find_edac_pci_by_dev(dev);
+       if (pci  == NULL) {
+               mutex_unlock(&edac_pci_ctls_mutex);
                return NULL;
        }
 
        pci->op_state = OP_OFFLINE;
 
-       edac_pci_workq_teardown(pci);
-
-       edac_pci_remove_sysfs(pci);
-
        del_edac_pci_from_global_list(pci);
 
-       edac_unlock_pci_list();
+       mutex_unlock(&edac_pci_ctls_mutex);
+
+       /* stop the workq timer */
+       edac_pci_workq_teardown(pci);
 
        edac_printk(KERN_INFO, EDAC_PCI,
                "Removed device %d for %s %s: DEV %s\n",
@@ -377,14 +415,20 @@ struct edac_pci_ctl_info *edac_pci_del_device(struct device *dev)
 
        return pci;
 }
-
 EXPORT_SYMBOL_GPL(edac_pci_del_device);
 
+/*
+ * edac_pci_generic_check
+ *
+ *     a Generic parity check API
+ */
 void edac_pci_generic_check(struct edac_pci_ctl_info *pci)
 {
+       debugf4("%s()\n", __func__);
        edac_pci_do_parity_check();
 }
 
+/* free running instance index counter */
 static int edac_pci_idx;
 #define EDAC_PCI_GENCTL_NAME   "EDAC PCI controller"
 
@@ -392,6 +436,17 @@ struct edac_pci_gen_data {
        int edac_idx;
 };
 
+/*
+ * edac_pci_create_generic_ctl
+ *
+ *     A generic constructor for a PCI parity polling device
+ *     Some systems have more than one domain of PCI busses.
+ *     For systems with one domain, then this API will
+ *     provide for a generic poller.
+ *
+ *     This routine calls the edac_pci_alloc_ctl_info() for
+ *     the generic device, with default values
+ */
 struct edac_pci_ctl_info *edac_pci_create_generic_ctl(struct device *dev,
                                                const char *mod_name)
 {
@@ -421,13 +476,18 @@ struct edac_pci_ctl_info *edac_pci_create_generic_ctl(struct device *dev,
 
        return pci;
 }
-
 EXPORT_SYMBOL_GPL(edac_pci_create_generic_ctl);
 
+/*
+ * edac_pci_release_generic_ctl
+ *
+ *     The release function of a generic EDAC PCI polling device
+ */
 void edac_pci_release_generic_ctl(struct edac_pci_ctl_info *pci)
 {
+       debugf0("%s() pci mod=%s\n", __func__, pci->mod_name);
+
        edac_pci_del_device(pci->dev);
        edac_pci_free_ctl_info(pci);
 }
-
 EXPORT_SYMBOL_GPL(edac_pci_release_generic_ctl);
index fac94cae2c3d5cb126707c3435a5822c9e3cec03..69f5dddabddfcfcb0294e374c42bf70c3104c89f 100644 (file)
 #include "edac_core.h"
 #include "edac_module.h"
 
+/* Turn off this whole feature if PCI is not configured */
 #ifdef CONFIG_PCI
 
 #define EDAC_PCI_SYMLINK       "device"
 
-static int check_pci_errors;   /* default YES check PCI parity */
-static int edac_pci_panic_on_pe;       /* default no panic on PCI Parity */
-static int edac_pci_log_pe = 1;        /* log PCI parity errors */
+/* data variables exported via sysfs */
+static int check_pci_errors;           /* default NO check PCI parity */
+static int edac_pci_panic_on_pe;       /* default NO panic on PCI Parity */
+static int edac_pci_log_pe = 1;                /* log PCI parity errors */
 static int edac_pci_log_npe = 1;       /* log PCI non-parity error errors */
+static int edac_pci_poll_msec = 1000;  /* one second workq period */
+
 static atomic_t pci_parity_count = ATOMIC_INIT(0);
 static atomic_t pci_nonparity_count = ATOMIC_INIT(0);
-static int edac_pci_poll_msec = 1000;
 
-static struct kobject edac_pci_kobj;   /* /sys/devices/system/edac/pci */
-static struct completion edac_pci_kobj_complete;
+static struct kobject edac_pci_top_main_kobj;
 static atomic_t edac_pci_sysfs_refcount = ATOMIC_INIT(0);
 
+/* getter functions for the data variables */
 int edac_pci_get_check_errors(void)
 {
        return check_pci_errors;
@@ -74,17 +77,22 @@ static void edac_pci_instance_release(struct kobject *kobj)
 {
        struct edac_pci_ctl_info *pci;
 
-       debugf1("%s()\n", __func__);
+       debugf0("%s()\n", __func__);
 
+       /* Form pointer to containing struct, the pci control struct */
        pci = to_instance(kobj);
-       complete(&pci->kobj_complete);
+
+       /* decrement reference count on top main kobj */
+       kobject_put(&edac_pci_top_main_kobj);
+
+       kfree(pci);     /* Free the control struct */
 }
 
 /* instance specific attribute structure */
 struct instance_attribute {
        struct attribute attr;
-        ssize_t(*show) (struct edac_pci_ctl_info *, char *);
-        ssize_t(*store) (struct edac_pci_ctl_info *, const char *, size_t);
+       ssize_t(*show) (struct edac_pci_ctl_info *, char *);
+       ssize_t(*store) (struct edac_pci_ctl_info *, const char *, size_t);
 };
 
 /* Function to 'show' fields from the edac_pci 'instance' structure */
@@ -112,6 +120,7 @@ static ssize_t edac_pci_instance_store(struct kobject *kobj,
        return -EIO;
 }
 
+/* fs_ops table */
 static struct sysfs_ops pci_instance_ops = {
        .show = edac_pci_instance_show,
        .store = edac_pci_instance_store
@@ -134,48 +143,82 @@ static struct instance_attribute *pci_instance_attr[] = {
        NULL
 };
 
-/* the ktype for pci instance */
+/* the ktype for pci instance */
 static struct kobj_type ktype_pci_instance = {
        .release = edac_pci_instance_release,
        .sysfs_ops = &pci_instance_ops,
        .default_attrs = (struct attribute **)pci_instance_attr,
 };
 
+/*
+ * edac_pci_create_instance_kobj
+ *
+ *     construct one EDAC PCI instance's kobject for use
+ */
 static int edac_pci_create_instance_kobj(struct edac_pci_ctl_info *pci, int idx)
 {
+       struct kobject *main_kobj;
        int err;
 
-       pci->kobj.parent = &edac_pci_kobj;
+       debugf0("%s()\n", __func__);
+
+       /* Set the parent and the instance's ktype */
+       pci->kobj.parent = &edac_pci_top_main_kobj;
        pci->kobj.ktype = &ktype_pci_instance;
 
        err = kobject_set_name(&pci->kobj, "pci%d", idx);
        if (err)
                return err;
 
+       /* First bump the ref count on the top main kobj, which will
+        * track the number of PCI instances we have, and thus nest
+        * properly on keeping the module loaded
+        */
+       main_kobj = kobject_get(&edac_pci_top_main_kobj);
+       if (!main_kobj) {
+               err = -ENODEV;
+               goto error_out;
+       }
+
+       /* And now register this new kobject under the main kobj */
        err = kobject_register(&pci->kobj);
        if (err != 0) {
                debugf2("%s() failed to register instance pci%d\n",
                        __func__, idx);
-               return err;
+               kobject_put(&edac_pci_top_main_kobj);
+               goto error_out;
        }
 
        debugf1("%s() Register instance 'pci%d' kobject\n", __func__, idx);
 
        return 0;
+
+       /* Error unwind statck */
+error_out:
+       return err;
 }
 
-static void
-edac_pci_delete_instance_kobj(struct edac_pci_ctl_info *pci, int idx)
+/*
+ * edac_pci_unregister_sysfs_instance_kobj
+ *
+ *     unregister the kobj for the EDAC PCI instance
+ */
+void edac_pci_unregister_sysfs_instance_kobj(struct edac_pci_ctl_info *pci)
 {
-       init_completion(&pci->kobj_complete);
+       debugf0("%s()\n", __func__);
+
+       /* Unregister the instance kobject and allow its release
+        * function release the main reference count and then
+        * kfree the memory
+        */
        kobject_unregister(&pci->kobj);
-       wait_for_completion(&pci->kobj_complete);
 }
 
 /***************************** EDAC PCI sysfs root **********************/
 #define to_edacpci(k) container_of(k, struct edac_pci_ctl_info, kobj)
 #define to_edacpci_attr(a) container_of(a, struct edac_pci_attr, attr)
 
+/* simple show/store functions for attributes */
 static ssize_t edac_pci_int_show(void *ptr, char *buffer)
 {
        int *value = ptr;
@@ -267,118 +310,189 @@ static struct edac_pci_dev_attribute *edac_pci_attr[] = {
        NULL,
 };
 
-/* No memory to release */
-static void edac_pci_release(struct kobject *kobj)
+/*
+ * edac_pci_release_main_kobj
+ *
+ *     This release function is called when the reference count to the
+ *     passed kobj goes to zero.
+ *
+ *     This kobj is the 'main' kobject that EDAC PCI instances
+ *     link to, and thus provide for proper nesting counts
+ */
+static void edac_pci_release_main_kobj(struct kobject *kobj)
 {
-       struct edac_pci_ctl_info *pci;
 
-       pci = to_edacpci(kobj);
+       debugf0("%s() here to module_put(THIS_MODULE)\n", __func__);
 
-       debugf1("%s()\n", __func__);
-       complete(&pci->kobj_complete);
+       /* last reference to top EDAC PCI kobject has been removed,
+        * NOW release our ref count on the core module
+        */
+       module_put(THIS_MODULE);
 }
 
-static struct kobj_type ktype_edac_pci = {
-       .release = edac_pci_release,
+/* ktype struct for the EDAC PCI main kobj */
+static struct kobj_type ktype_edac_pci_main_kobj = {
+       .release = edac_pci_release_main_kobj,
        .sysfs_ops = &edac_pci_sysfs_ops,
        .default_attrs = (struct attribute **)edac_pci_attr,
 };
 
 /**
- * edac_sysfs_pci_setup()
+ * edac_pci_main_kobj_setup()
  *
  *     setup the sysfs for EDAC PCI attributes
  *     assumes edac_class has already been initialized
  */
-int edac_pci_register_main_kobj(void)
+int edac_pci_main_kobj_setup(void)
 {
        int err;
        struct sysdev_class *edac_class;
 
-       debugf1("%s()\n", __func__);
+       debugf0("%s()\n", __func__);
+
+       /* check and count if we have already created the main kobject */
+       if (atomic_inc_return(&edac_pci_sysfs_refcount) != 1)
+               return 0;
 
+       /* First time, so create the main kobject and its
+        * controls and atributes
+        */
        edac_class = edac_get_edac_class();
        if (edac_class == NULL) {
                debugf1("%s() no edac_class\n", __func__);
-               return -ENODEV;
+               err = -ENODEV;
+               goto decrement_count_fail;
        }
 
-       edac_pci_kobj.ktype = &ktype_edac_pci;
+       /* Need the kobject hook ups, and name setting */
+       edac_pci_top_main_kobj.ktype = &ktype_edac_pci_main_kobj;
+       edac_pci_top_main_kobj.parent = &edac_class->kset.kobj;
 
-       edac_pci_kobj.parent = &edac_class->kset.kobj;
-
-       err = kobject_set_name(&edac_pci_kobj, "pci");
+       err = kobject_set_name(&edac_pci_top_main_kobj, "pci");
        if (err)
-               return err;
+               goto decrement_count_fail;
+
+       /* Bump the reference count on this module to ensure the
+        * modules isn't unloaded until we deconstruct the top
+        * level main kobj for EDAC PCI
+        */
+       if (!try_module_get(THIS_MODULE)) {
+               debugf1("%s() try_module_get() failed\n", __func__);
+               err = -ENODEV;
+               goto decrement_count_fail;
+       }
 
        /* Instanstiate the pci object */
        /* FIXME: maybe new sysdev_create_subdir() */
-       err = kobject_register(&edac_pci_kobj);
-
+       err = kobject_register(&edac_pci_top_main_kobj);
        if (err) {
                debugf1("Failed to register '.../edac/pci'\n");
-               return err;
+               goto kobject_register_fail;
        }
 
+       /* At this point, to 'release' the top level kobject
+        * for EDAC PCI, then edac_pci_main_kobj_teardown()
+        * must be used, for resources to be cleaned up properly
+        */
        debugf1("Registered '.../edac/pci' kobject\n");
 
        return 0;
+
+       /* Error unwind statck */
+kobject_register_fail:
+       module_put(THIS_MODULE);
+
+decrement_count_fail:
+       /* if are on this error exit, nothing to tear down */
+       atomic_dec(&edac_pci_sysfs_refcount);
+
+       return err;
 }
 
 /*
- * edac_pci_unregister_main_kobj()
+ * edac_pci_main_kobj_teardown()
  *
- *     perform the sysfs teardown for the PCI attributes
+ *     if no longer linked (needed) remove the top level EDAC PCI
+ *     kobject with its controls and attributes
  */
-void edac_pci_unregister_main_kobj(void)
+static void edac_pci_main_kobj_teardown(void)
 {
        debugf0("%s()\n", __func__);
-       init_completion(&edac_pci_kobj_complete);
-       kobject_unregister(&edac_pci_kobj);
-       wait_for_completion(&edac_pci_kobj_complete);
+
+       /* Decrement the count and only if no more controller instances
+        * are connected perform the unregisteration of the top level
+        * main kobj
+        */
+       if (atomic_dec_return(&edac_pci_sysfs_refcount) == 0) {
+               debugf0("%s() called kobject_unregister on main kobj\n",
+                       __func__);
+               kobject_unregister(&edac_pci_top_main_kobj);
+       }
 }
 
+/*
+ *
+ * edac_pci_create_sysfs
+ *
+ *     Create the controls/attributes for the specified EDAC PCI device
+ */
 int edac_pci_create_sysfs(struct edac_pci_ctl_info *pci)
 {
        int err;
        struct kobject *edac_kobj = &pci->kobj;
 
-       if (atomic_inc_return(&edac_pci_sysfs_refcount) == 1) {
-               err = edac_pci_register_main_kobj();
-               if (err) {
-                       atomic_dec(&edac_pci_sysfs_refcount);
-                       return err;
-               }
-       }
+       debugf0("%s() idx=%d\n", __func__, pci->pci_idx);
 
-       err = edac_pci_create_instance_kobj(pci, pci->pci_idx);
-       if (err) {
-               if (atomic_dec_return(&edac_pci_sysfs_refcount) == 0)
-                       edac_pci_unregister_main_kobj();
-       }
+       /* create the top main EDAC PCI kobject, IF needed */
+       err = edac_pci_main_kobj_setup();
+       if (err)
+               return err;
 
-       debugf0("%s() idx=%d\n", __func__, pci->pci_idx);
+       /* Create this instance's kobject under the MAIN kobject */
+       err = edac_pci_create_instance_kobj(pci, pci->pci_idx);
+       if (err)
+               goto unregister_cleanup;
 
        err = sysfs_create_link(edac_kobj, &pci->dev->kobj, EDAC_PCI_SYMLINK);
        if (err) {
                debugf0("%s() sysfs_create_link() returned err= %d\n",
                        __func__, err);
-               return err;
+               goto symlink_fail;
        }
 
        return 0;
+
+       /* Error unwind stack */
+symlink_fail:
+       edac_pci_unregister_sysfs_instance_kobj(pci);
+
+unregister_cleanup:
+       edac_pci_main_kobj_teardown();
+
+       return err;
 }
 
+/*
+ * edac_pci_remove_sysfs
+ *
+ *     remove the controls and attributes for this EDAC PCI device
+ */
 void edac_pci_remove_sysfs(struct edac_pci_ctl_info *pci)
 {
-       debugf0("%s()\n", __func__);
-
-       edac_pci_delete_instance_kobj(pci, pci->pci_idx);
+       debugf0("%s() index=%d\n", __func__, pci->pci_idx);
 
+       /* Remove the symlink */
        sysfs_remove_link(&pci->kobj, EDAC_PCI_SYMLINK);
 
-       if (atomic_dec_return(&edac_pci_sysfs_refcount) == 0)
-               edac_pci_unregister_main_kobj();
+       /* remove this PCI instance's sysfs entries */
+       edac_pci_unregister_sysfs_instance_kobj(pci);
+
+       /* Call the main unregister function, which will determine
+        * if this 'pci' is the last instance.
+        * If it is, the main kobject will be unregistered as a result
+        */
+       debugf0("%s() calling edac_pci_main_kobj_teardown()\n", __func__);
+       edac_pci_main_kobj_teardown();
 }
 
 /************************ PCI error handling *************************/
@@ -414,13 +528,14 @@ static u16 get_pci_parity_status(struct pci_dev *dev, int secondary)
        return status;
 }
 
-typedef void (*pci_parity_check_fn_t) (struct pci_dev * dev);
 
 /* Clear any PCI parity errors logged by this device. */
 static void edac_pci_dev_parity_clear(struct pci_dev *dev)
 {
        u8 header_type;
 
+       debugf0("%s()\n", __func__);
+
        get_pci_parity_status(dev, 0);
 
        /* read the device TYPE, looking for bridges */
@@ -433,17 +548,28 @@ static void edac_pci_dev_parity_clear(struct pci_dev *dev)
 /*
  *  PCI Parity polling
  *
+ *     Fucntion to retrieve the current parity status
+ *     and decode it
+ *
  */
 static void edac_pci_dev_parity_test(struct pci_dev *dev)
 {
+       unsigned long flags;
        u16 status;
        u8 header_type;
 
-       /* read the STATUS register on this device
-        */
+       /* stop any interrupts until we can acquire the status */
+       local_irq_save(flags);
+
+       /* read the STATUS register on this device */
        status = get_pci_parity_status(dev, 0);
 
-       debugf2("PCI STATUS= 0x%04x %s\n", status, dev->dev.bus_id);
+       /* read the device TYPE, looking for bridges */
+       pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type);
+
+       local_irq_restore(flags);
+
+       debugf4("PCI STATUS= 0x%04x %s\n", status, dev->dev.bus_id);
 
        /* check the status reg for errors */
        if (status) {
@@ -471,16 +597,14 @@ static void edac_pci_dev_parity_test(struct pci_dev *dev)
                }
        }
 
-       /* read the device TYPE, looking for bridges */
-       pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type);
 
-       debugf2("PCI HEADER TYPE= 0x%02x %s\n", header_type, dev->dev.bus_id);
+       debugf4("PCI HEADER TYPE= 0x%02x %s\n", header_type, dev->dev.bus_id);
 
        if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) {
                /* On bridges, need to examine secondary status register  */
                status = get_pci_parity_status(dev, 1);
 
-               debugf2("PCI SEC_STATUS= 0x%04x %s\n", status, dev->dev.bus_id);
+               debugf4("PCI SEC_STATUS= 0x%04x %s\n", status, dev->dev.bus_id);
 
                /* check the secondary status reg for errors */
                if (status) {
@@ -510,9 +634,12 @@ static void edac_pci_dev_parity_test(struct pci_dev *dev)
        }
 }
 
+/* reduce some complexity in definition of the iterator */
+typedef void (*pci_parity_check_fn_t) (struct pci_dev *dev);
+
 /*
  * pci_dev parity list iterator
- *     Scan the PCI device list for one iteration, looking for SERRORs
+ *     Scan the PCI device list for one pass, looking for SERRORs
  *     Master Parity ERRORS or Parity ERRORs on primary or secondary devices
  */
 static inline void edac_pci_dev_parity_iterator(pci_parity_check_fn_t fn)
@@ -535,22 +662,22 @@ static inline void edac_pci_dev_parity_iterator(pci_parity_check_fn_t fn)
  */
 void edac_pci_do_parity_check(void)
 {
-       unsigned long flags;
        int before_count;
 
        debugf3("%s()\n", __func__);
 
+       /* if policy has PCI check off, leave now */
        if (!check_pci_errors)
                return;
 
        before_count = atomic_read(&pci_parity_count);
 
        /* scan all PCI devices looking for a Parity Error on devices and
-        * bridges
+        * bridges.
+        * The iterator calls pci_get_device() which might sleep, thus
+        * we cannot disable interrupts in this scan.
         */
-       local_irq_save(flags);
        edac_pci_dev_parity_iterator(edac_pci_dev_parity_test);
-       local_irq_restore(flags);
 
        /* Only if operator has selected panic on PCI Error */
        if (edac_pci_get_panic_on_pe()) {
@@ -560,6 +687,12 @@ void edac_pci_do_parity_check(void)
        }
 }
 
+/*
+ * edac_pci_clear_parity_errors
+ *
+ *     function to perform an iteration over the PCI devices
+ *     and clearn their current status
+ */
 void edac_pci_clear_parity_errors(void)
 {
        /* Clear any PCI bus parity errors that devices initially have logged
@@ -567,6 +700,12 @@ void edac_pci_clear_parity_errors(void)
         */
        edac_pci_dev_parity_iterator(edac_pci_dev_parity_clear);
 }
+
+/*
+ * edac_pci_handle_pe
+ *
+ *     Called to handle a PARITY ERROR event
+ */
 void edac_pci_handle_pe(struct edac_pci_ctl_info *pci, const char *msg)
 {
 
@@ -584,9 +723,14 @@ void edac_pci_handle_pe(struct edac_pci_ctl_info *pci, const char *msg)
         */
        edac_pci_do_parity_check();
 }
-
 EXPORT_SYMBOL_GPL(edac_pci_handle_pe);
 
+
+/*
+ * edac_pci_handle_npe
+ *
+ *     Called to handle a NON-PARITY ERROR event
+ */
 void edac_pci_handle_npe(struct edac_pci_ctl_info *pci, const char *msg)
 {
 
@@ -604,7 +748,6 @@ void edac_pci_handle_npe(struct edac_pci_ctl_info *pci, const char *msg)
         */
        edac_pci_do_parity_check();
 }
-
 EXPORT_SYMBOL_GPL(edac_pci_handle_npe);
 
 /*
index 0ecfdc432f87045588080183f5b96ecbc340e28a..e895f9f887abb8dbda0c45706e649a8cff8fd9c8 100644 (file)
@@ -275,7 +275,7 @@ static int i3000_probe1(struct pci_dev *pdev, int dev_idx)
        unsigned char *c0dra = dra, *c1dra = &dra[I3000_RANKS_PER_CHANNEL / 2];
        unsigned char *c0drb = drb, *c1drb = &drb[I3000_RANKS_PER_CHANNEL];
        unsigned long mchbar;
-       void *window;
+       void __iomem *window;
 
        debugf0("MC: %s()\n", __func__);
 
index 5879f0f25495ae6fe7f0fc04b3dfd4237a95e5ac..9e94542c18a2bc57abd22d05c17c0b04955fe7c3 100644 (file)
@@ -75,7 +75,8 @@ static ssize_t ds1682_show(struct device *dev, struct device_attribute *attr,
        /* Special case: the 32 bit regs are time values with 1/4s
         * resolution, scale them up to milliseconds */
        if (sattr->nr == 4)
-               return sprintf(buf, "%llu\n", ((u64) le32_to_cpu(val)) * 250);
+               return sprintf(buf, "%llu\n",
+                       ((unsigned long long)le32_to_cpu(val)) * 250);
 
        /* Format the output string and return # of bytes */
        return sprintf(buf, "%li\n", (long)le32_to_cpu(val));
index f668d235e6be25a2a91de82dd18d052ad08b1887..bf19ddfa6cda256c3d06f8164087f0a83c3c6e98 100644 (file)
@@ -551,8 +551,8 @@ static int setup_mmio_scc (struct pci_dev *dev, const char *name)
        unsigned long dma_base = pci_resource_start(dev, 1);
        unsigned long ctl_size = pci_resource_len(dev, 0);
        unsigned long dma_size = pci_resource_len(dev, 1);
-       void *ctl_addr;
-       void *dma_addr;
+       void __iomem *ctl_addr;
+       void __iomem *dma_addr;
        int i;
 
        for (i = 0; i < MAX_HWIFS; i++) {
index 336e5ff4cfcf6f111cf5c57d6a043c5767d1513d..cadf0479cce54d7b0150aaa833114d2b9b8f2b7e 100644 (file)
@@ -2677,7 +2677,7 @@ static long raw1394_iso_xmit_recv_packets32(struct file *file, unsigned int cmd,
                                           struct raw1394_iso_packets32 __user *arg)
 {
        compat_uptr_t infos32;
-       void *infos;
+       void __user *infos;
        long err = -EFAULT;
        struct raw1394_iso_packets __user *dst = compat_alloc_user_space(sizeof(struct raw1394_iso_packets));
 
index 55382c7d799c2453c06656507ff8054f29272647..e5047471c334ed0f84081bf594a9ada58f20ba70 100644 (file)
@@ -5,3 +5,15 @@ obj-$(CONFIG_LGUEST_GUEST) += lguest.o lguest_asm.o lguest_bus.o
 obj-$(CONFIG_LGUEST)   += lg.o
 lg-y := core.o hypercalls.o page_tables.o interrupts_and_traps.o \
        segments.o io.o lguest_user.o switcher.o
+
+Preparation Preparation!: PREFIX=P
+Guest: PREFIX=G
+Drivers: PREFIX=D
+Launcher: PREFIX=L
+Host: PREFIX=H
+Switcher: PREFIX=S
+Mastery: PREFIX=M
+Beer:
+       @for f in Preparation Guest Drivers Launcher Host Switcher Mastery; do echo "{==- $$f -==}"; make -s $$f; done; echo "{==-==}"
+Preparation Preparation! Guest Drivers Launcher Host Switcher Mastery:
+       @sh ../../Documentation/lguest/extract $(PREFIX) `find ../../* -name '*.[chS]' -wholename '*lguest*'`
diff --git a/drivers/lguest/README b/drivers/lguest/README
new file mode 100644 (file)
index 0000000..b7db39a
--- /dev/null
@@ -0,0 +1,47 @@
+Welcome, friend reader, to lguest.
+
+Lguest is an adventure, with you, the reader, as Hero.  I can't think of many
+5000-line projects which offer both such capability and glimpses of future
+potential; it is an exciting time to be delving into the source!
+
+But be warned; this is an arduous journey of several hours or more!  And as we
+know, all true Heroes are driven by a Noble Goal.  Thus I offer a Beer (or
+equivalent) to anyone I meet who has completed this documentation.
+
+So get comfortable and keep your wits about you (both quick and humorous).
+Along your way to the Noble Goal, you will also gain masterly insight into
+lguest, and hypervisors and x86 virtualization in general.
+
+Our Quest is in seven parts: (best read with C highlighting turned on)
+
+I) Preparation
+       - In which our potential hero is flown quickly over the landscape for a
+         taste of its scope.  Suitable for the armchair coders and other such
+         persons of faint constitution.
+
+II) Guest
+       - Where we encounter the first tantalising wisps of code, and come to
+         understand the details of the life of a Guest kernel.
+
+III) Drivers
+       - Whereby the Guest finds its voice and become useful, and our
+         understanding of the Guest is completed.
+
+IV) Launcher
+       - Where we trace back to the creation of the Guest, and thus begin our
+         understanding of the Host.
+
+V) Host
+       - Where we master the Host code, through a long and tortuous journey.
+         Indeed, it is here that our hero is tested in the Bit of Despair.
+
+VI) Switcher
+       - Where our understanding of the intertwined nature of Guests and Hosts
+         is completed.
+
+VII) Mastery
+       - Where our fully fledged hero grapples with the Great Question:
+         "What next?"
+
+make Preparation!
+Rusty Russell.
index ce909ec57499729a69694b558eb0320774941105..0a46e8837d9a01629d708db246953a4af3f4600b 100644 (file)
@@ -1,5 +1,8 @@
-/* World's simplest hypervisor, to test paravirt_ops and show
- * unbelievers that virtualization is the future.  Plus, it's fun! */
+/*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. :*/
 #include <linux/module.h>
 #include <linux/stringify.h>
 #include <linux/stddef.h>
@@ -61,11 +64,33 @@ static struct lguest_pages *lguest_pages(unsigned int cpu)
                  (SWITCHER_ADDR + SHARED_SWITCHER_PAGES*PAGE_SIZE))[cpu]);
 }
 
+/*H:010 We need to set up the Switcher at a high virtual address.  Remember the
+ * Switcher is a few hundred bytes of assembler code which actually changes the
+ * CPU to run the Guest, and then changes back to the Host when a trap or
+ * interrupt happens.
+ *
+ * The Switcher code must be at the same virtual address in the Guest as the
+ * Host since it will be running as the switchover occurs.
+ *
+ * Trying to map memory at a particular address is an unusual thing to do, so
+ * it's not a simple one-liner.  We also set up the per-cpu parts of the
+ * Switcher here.
+ */
 static __init int map_switcher(void)
 {
        int i, err;
        struct page **pagep;
 
+       /*
+        * Map the Switcher in to high memory.
+        *
+        * It turns out that if we choose the address 0xFFC00000 (4MB under the
+        * top virtual address), it makes setting up the page tables really
+        * 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. */
        switcher_page = kmalloc(sizeof(switcher_page[0])*TOTAL_SWITCHER_PAGES,
                                GFP_KERNEL);
        if (!switcher_page) {
@@ -73,6 +98,8 @@ static __init int map_switcher(void)
                goto out;
        }
 
+       /* Now we actually allocate the pages.  The Guest will see these pages,
+        * so we make sure they're zeroed. */
        for (i = 0; i < TOTAL_SWITCHER_PAGES; i++) {
                unsigned long addr = get_zeroed_page(GFP_KERNEL);
                if (!addr) {
@@ -82,6 +109,9 @@ static __init int map_switcher(void)
                switcher_page[i] = virt_to_page(addr);
        }
 
+       /* Now we reserve the "virtual memory area" we want: 0xFFC00000
+        * (SWITCHER_ADDR).  We might not get it in theory, but in practice
+        * it's worked so far. */
        switcher_vma = __get_vm_area(TOTAL_SWITCHER_PAGES * PAGE_SIZE,
                                       VM_ALLOC, SWITCHER_ADDR, VMALLOC_END);
        if (!switcher_vma) {
@@ -90,49 +120,105 @@ static __init int map_switcher(void)
                goto free_pages;
        }
 
+       /* This code actually sets up the pages we've allocated to appear at
+        * SWITCHER_ADDR.  map_vm_area() takes the vma we allocated above, the
+        * kind of pages we're mapping (kernel pages), and a pointer to our
+        * array of struct pages.  It increments that pointer, but we don't
+        * care. */
        pagep = switcher_page;
        err = map_vm_area(switcher_vma, PAGE_KERNEL, &pagep);
        if (err) {
                printk("lguest: map_vm_area failed: %i\n", err);
                goto free_vma;
        }
+
+       /* Now the switcher is mapped at the right address, we can't fail!
+        * Copy in the compiled-in Switcher code (from switcher.S). */
        memcpy(switcher_vma->addr, start_switcher_text,
               end_switcher_text - start_switcher_text);
 
-       /* Fix up IDT entries to point into copied text. */
+       /* Most of the switcher.S doesn't care that it's been moved; on Intel,
+        * jumps are relative, and it doesn't access any references to external
+        * code or data.
+        *
+        * 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. */
        for (i = 0; i < IDT_ENTRIES; i++)
                default_idt_entries[i] += switcher_offset();
 
+       /*
+        * Set up the Switcher's per-cpu areas.
+        *
+        * Each CPU gets two pages of its own within the high-mapped region
+        * (aka. "struct lguest_pages").  Much of this can be initialized now,
+        * but some depends on what Guest we are running (which is set up in
+        * copy_in_guest_info()).
+        */
        for_each_possible_cpu(i) {
+               /* lguest_pages() returns this CPU's two pages. */
                struct lguest_pages *pages = lguest_pages(i);
+               /* This is a convenience pointer to make the code fit one
+                * statement to a line. */
                struct lguest_ro_state *state = &pages->state;
 
-               /* These fields are static: rest done in copy_in_guest_info */
+               /* The Global Descriptor Table: the Host has a different one
+                * for each CPU.  We keep a descriptor for the GDT which says
+                * where it is and how big it is (the size is actually the last
+                * byte, not the size, hence the "-1"). */
                state->host_gdt_desc.size = GDT_SIZE-1;
                state->host_gdt_desc.address = (long)get_cpu_gdt_table(i);
+
+               /* All CPUs on the Host use the same Interrupt Descriptor
+                * Table, so we just use store_idt(), which gets this CPU's IDT
+                * descriptor. */
                store_idt(&state->host_idt_desc);
+
+               /* The descriptors for the Guest's GDT and IDT can be filled
+                * out now, too.  We copy the GDT & IDT into ->guest_gdt and
+                * ->guest_idt before actually running the Guest. */
                state->guest_idt_desc.size = sizeof(state->guest_idt)-1;
                state->guest_idt_desc.address = (long)&state->guest_idt;
                state->guest_gdt_desc.size = sizeof(state->guest_gdt)-1;
                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
+                * we start it at the end of that structure. */
                state->guest_tss.esp0 = (long)(&pages->regs + 1);
+               /* And this is the GDT entry to use for the stack: we keep a
+                * couple of special LGUEST entries. */
                state->guest_tss.ss0 = LGUEST_DS;
-               /* No I/O for you! */
+
+               /* x86 can have a finegrained bitmap which indicates what I/O
+                * ports the process can use.  We set it to the end of our
+                * structure, meaning "none". */
                state->guest_tss.io_bitmap_base = sizeof(state->guest_tss);
+
+               /* Some GDT entries are the same across all Guests, so we can
+                * set them up now. */
                setup_default_gdt_entries(state);
+               /* Most IDT entries are the same for all Guests, too.*/
                setup_default_idt_entries(state, default_idt_entries);
 
-               /* Setup LGUEST segments on all cpus */
+               /* The Host needs to be able to use the LGUEST segments on this
+                * CPU, too, so put them in the Host GDT. */
                get_cpu_gdt_table(i)[GDT_ENTRY_LGUEST_CS] = FULL_EXEC_SEGMENT;
                get_cpu_gdt_table(i)[GDT_ENTRY_LGUEST_DS] = FULL_SEGMENT;
        }
 
-       /* Initialize entry point into switcher. */
+       /* In the Switcher, we want the %cs segment register to use the
+        * LGUEST_CS GDT entry: we've put that in the Host and Guest GDTs, so
+        * it will be undisturbed when we switch.  To change %cs and jump we
+        * need this structure to feed to Intel's "lcall" instruction. */
        lguest_entry.offset = (long)switch_to_guest + switcher_offset();
        lguest_entry.segment = LGUEST_CS;
 
        printk(KERN_INFO "lguest: mapped switcher at %p\n",
               switcher_vma->addr);
+       /* And we succeeded... */
        return 0;
 
 free_vma:
@@ -146,35 +232,58 @@ free_some_pages:
 out:
        return err;
 }
+/*:*/
 
+/* Cleaning up the mapping when the module is unloaded is almost...
+ * too easy. */
 static void unmap_switcher(void)
 {
        unsigned int i;
 
+       /* vunmap() undoes *both* map_vm_area() and __get_vm_area(). */
        vunmap(switcher_vma->addr);
+       /* Now we just need to free the pages we copied the switcher into */
        for (i = 0; i < TOTAL_SWITCHER_PAGES; i++)
                __free_pages(switcher_page[i], 0);
 }
 
-/* IN/OUT insns: enough to get us past boot-time probing. */
+/*H:130 Our Guest is usually so well behaved; it never tries to do things it
+ * isn't allowed to.  Unfortunately, "struct paravirt_ops" isn't quite
+ * complete, because it doesn't contain replacements for the Intel I/O
+ * instructions.  As a result, the Guest sometimes fumbles across one during
+ * the boot process as it probes for various things which are usually attached
+ * to a PC.
+ *
+ * When the Guest uses one of these instructions, we get trap #13 (General
+ * Protection Fault) and come here.  We see if it's one of those troublesome
+ * instructions and skip over it.  We return true if we did. */
 static int emulate_insn(struct lguest *lg)
 {
        u8 insn;
        unsigned int insnlen = 0, in = 0, shift = 0;
+       /* The eip contains the *virtual* address of the Guest's instruction:
+        * guest_pa just subtracts the Guest's page_offset. */
        unsigned long physaddr = guest_pa(lg, lg->regs->eip);
 
-       /* This only works for addresses in linear mapping... */
+       /* The guest_pa() function only works for Guest kernel addresses, but
+        * that's all we're trying to do anyway. */
        if (lg->regs->eip < lg->page_offset)
                return 0;
+
+       /* Decoding x86 instructions is icky. */
        lgread(lg, &insn, physaddr, 1);
 
-       /* Operand size prefix means it's actually for ax. */
+       /* 0x66 is an "operand prefix".  It means it's using the upper 16 bits
+          of the eax register. */
        if (insn == 0x66) {
                shift = 16;
+               /* The instruction is 1 byte so far, read the next byte. */
                insnlen = 1;
                lgread(lg, &insn, physaddr + insnlen, 1);
        }
 
+       /* We can ignore the lower bit for the moment and decode the 4 opcodes
+        * we need to emulate. */
        switch (insn & 0xFE) {
        case 0xE4: /* in     <next byte>,%al */
                insnlen += 2;
@@ -191,9 +300,13 @@ static int emulate_insn(struct lguest *lg)
                insnlen += 1;
                break;
        default:
+               /* OK, we don't know what this is, can't emulate. */
                return 0;
        }
 
+       /* If it was an "IN" instruction, they expect the result to be read
+        * into %eax, so we change %eax.  We always return all-ones, which
+        * traditionally means "there's nothing there". */
        if (in) {
                /* Lower bit tells is whether it's a 16 or 32 bit access */
                if (insn & 0x1)
@@ -201,28 +314,46 @@ static int emulate_insn(struct lguest *lg)
                else
                        lg->regs->eax |= (0xFFFF << shift);
        }
+       /* Finally, we've "done" the instruction, so move past it. */
        lg->regs->eip += insnlen;
+       /* Success! */
        return 1;
 }
-
+/*:*/
+
+/*L:305
+ * 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.
+ *
+ * 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
+ * gave us.  We have to make sure that addr + len doesn't give us a false
+ * positive by overflowing, too. */
 int lguest_address_ok(const struct lguest *lg,
                      unsigned long addr, unsigned long len)
 {
        return (addr+len) / PAGE_SIZE < lg->pfn_limit && (addr+len >= addr);
 }
 
-/* Just like get_user, but don't let guest access lguest binary. */
+/* This is a convenient routine to get a 32-bit value from the Guest (a very
+ * common operation).  Here we can see how useful the kill_lguest() routine we
+ * met in the Launcher can be: we return a random value (0) instead of needing
+ * to return an error. */
 u32 lgread_u32(struct lguest *lg, unsigned long addr)
 {
        u32 val = 0;
 
-       /* Don't let them access lguest binary */
+       /* 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);
        return val;
 }
 
+/* Same thing for writing a value. */
 void lgwrite_u32(struct lguest *lg, unsigned long addr, u32 val)
 {
        if (!lguest_address_ok(lg, addr, sizeof(val))
@@ -230,6 +361,9 @@ void lgwrite_u32(struct lguest *lg, unsigned long addr, u32 val)
                kill_guest(lg, "bad write address %#lx", addr);
 }
 
+/* This routine is more generic, and copies a range of Guest bytes into a
+ * buffer.  If the copy_from_user() fails, we fill the buffer with zeroes, so
+ * the caller doesn't end up using uninitialized kernel memory. */
 void lgread(struct lguest *lg, void *b, unsigned long addr, unsigned bytes)
 {
        if (!lguest_address_ok(lg, addr, bytes)
@@ -240,6 +374,7 @@ void lgread(struct lguest *lg, void *b, unsigned long addr, unsigned bytes)
        }
 }
 
+/* Similarly, our generic routine to copy into a range of Guest bytes. */
 void lgwrite(struct lguest *lg, unsigned long addr, const void *b,
             unsigned bytes)
 {
@@ -247,6 +382,7 @@ void lgwrite(struct lguest *lg, unsigned long addr, const void *b,
            || copy_to_user((void __user *)addr, b, bytes) != 0)
                kill_guest(lg, "bad write address %#lx len %u", addr, bytes);
 }
+/* (end of memory access helper routines) :*/
 
 static void set_ts(void)
 {
@@ -257,54 +393,108 @@ static void set_ts(void)
                write_cr0(cr0|8);
 }
 
+/*S:010
+ * We are getting close to the Switcher.
+ *
+ * Remember that each CPU has two pages which are visible to the Guest when it
+ * runs on that CPU.  This has to contain the state for that Guest: we copy the
+ * state in just before we run the Guest.
+ *
+ * Each Guest has "changed" flags which indicate what has changed in the Guest
+ * since it last ran.  We saw this set in interrupts_and_traps.c and
+ * segments.c.
+ */
 static void copy_in_guest_info(struct lguest *lg, struct lguest_pages *pages)
 {
+       /* Copying all this data can be quite expensive.  We usually run the
+        * same Guest we ran last time (and that Guest hasn't run anywhere else
+        * meanwhile).  If that's not the case, we pretend everything in the
+        * Guest has changed. */
        if (__get_cpu_var(last_guest) != lg || lg->last_pages != pages) {
                __get_cpu_var(last_guest) = lg;
                lg->last_pages = pages;
                lg->changed = CHANGED_ALL;
        }
 
-       /* These are pretty cheap, so we do them unconditionally. */
+       /* These copies are pretty cheap, so we do them unconditionally: */
+       /* Save the current Host top-level page directory. */
        pages->state.host_cr3 = __pa(current->mm->pgd);
+       /* Set up the Guest's page tables to see this CPU's pages (and no
+        * other CPU's pages). */
        map_switcher_in_guest(lg, pages);
+       /* Set up the two "TSS" members which tell the CPU what stack to use
+        * for traps which do directly into the Guest (ie. traps at privilege
+        * level 1). */
        pages->state.guest_tss.esp1 = lg->esp1;
        pages->state.guest_tss.ss1 = lg->ss1;
 
-       /* Copy direct trap entries. */
+       /* Copy direct-to-Guest trap entries. */
        if (lg->changed & CHANGED_IDT)
                copy_traps(lg, pages->state.guest_idt, default_idt_entries);
 
-       /* Copy all GDT entries but the TSS. */
+       /* Copy all GDT entries which the Guest can change. */
        if (lg->changed & CHANGED_GDT)
                copy_gdt(lg, pages->state.guest_gdt);
        /* If only the TLS entries have changed, copy them. */
        else if (lg->changed & CHANGED_GDT_TLS)
                copy_gdt_tls(lg, pages->state.guest_gdt);
 
+       /* Mark the Guest as unchanged for next time. */
        lg->changed = 0;
 }
 
+/* Finally: the code to actually call into the Switcher to run the Guest. */
 static void run_guest_once(struct lguest *lg, struct lguest_pages *pages)
 {
+       /* This is a dummy value we need for GCC's sake. */
        unsigned int clobber;
 
+       /* Copy the guest-specific information into this CPU's "struct
+        * lguest_pages". */
        copy_in_guest_info(lg, pages);
 
-       /* Put eflags on stack, lcall does rest: suitable for iret return. */
+       /* Now: we push the "eflags" register on the stack, then do an "lcall".
+        * This is how we change from using the kernel code segment to using
+        * the dedicated lguest code segment, as well as jumping into the
+        * Switcher.
+        *
+        * The lcall also pushes the old code segment (KERNEL_CS) onto the
+        * stack, then the address of this call.  This stack layout happens to
+        * exactly match the stack of an interrupt... */
        asm volatile("pushf; lcall *lguest_entry"
+                    /* This is how we tell GCC that %eax ("a") and %ebx ("b")
+                     * are changed by this routine.  The "=" means output. */
                     : "=a"(clobber), "=b"(clobber)
+                    /* %eax contains the pages pointer.  ("0" refers to the
+                     * 0-th argument above, ie "a").  %ebx contains the
+                     * physical address of the Guest's top-level page
+                     * directory. */
                     : "0"(pages), "1"(__pa(lg->pgdirs[lg->pgdidx].pgdir))
+                    /* We tell gcc that all these registers could change,
+                     * which means we don't have to save and restore them in
+                     * the Switcher. */
                     : "memory", "%edx", "%ecx", "%edi", "%esi");
 }
+/*:*/
 
+/*H:030 Let's jump straight to the the main loop which runs the Guest.
+ * Remember, this is called by the Launcher reading /dev/lguest, and we keep
+ * going around and around until something interesting happens. */
 int run_guest(struct lguest *lg, unsigned long __user *user)
 {
+       /* We stop running once the Guest is dead. */
        while (!lg->dead) {
+               /* We need to initialize this, otherwise gcc complains.  It's
+                * not (yet) clever enough to see that it's initialized when we
+                * need it. */
                unsigned int cr2 = 0; /* Damn gcc */
 
-               /* Hypercalls first: we might have been out to userspace */
+               /* First we run any hypercalls the Guest wants done: either in
+                * the hypercall ring in "struct lguest_data", or directly by
+                * using int 31 (LGUEST_TRAP_ENTRY). */
                do_hypercalls(lg);
+               /* It's possible the Guest did a SEND_DMA hypercall to the
+                * Launcher, in which case we return from the read() now. */
                if (lg->dma_is_pending) {
                        if (put_user(lg->pending_dma, user) ||
                            put_user(lg->pending_key, user+1))
@@ -312,6 +502,7 @@ int run_guest(struct lguest *lg, unsigned long __user *user)
                        return sizeof(unsigned long)*2;
                }
 
+               /* Check for signals */
                if (signal_pending(current))
                        return -ERESTARTSYS;
 
@@ -319,77 +510,154 @@ int run_guest(struct lguest *lg, unsigned long __user *user)
                if (lg->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. */
                maybe_do_interrupt(lg);
 
+               /* All long-lived kernel loops need to check with this horrible
+                * thing called the freezer.  If the Host is trying to suspend,
+                * it stops us. */
                try_to_freeze();
 
+               /* Just make absolutely sure the Guest is still alive.  One of
+                * those hypercalls could have been fatal, for example. */
                if (lg->dead)
                        break;
 
+               /* If the Guest asked to be stopped, we sleep.  The Guest's
+                * clock timer or LHCALL_BREAK from the Waker will wake us. */
                if (lg->halted) {
                        set_current_state(TASK_INTERRUPTIBLE);
                        schedule();
                        continue;
                }
 
+               /* OK, now we're ready to jump into the Guest.  First we put up
+                * the "Do Not Disturb" sign: */
                local_irq_disable();
 
-               /* Even if *we* don't want FPU trap, guest might... */
+               /* Remember the awfully-named TS bit?  If the Guest has asked
+                * to set it we set it now, so we can trap and pass that trap
+                * to the Guest if it uses the FPU. */
                if (lg->ts)
                        set_ts();
 
-               /* Don't let Guest do SYSENTER: we can't handle it. */
+               /* SYSENTER is an optimized way of doing system calls.  We
+                * can't allow it because it always jumps to privilege level 0.
+                * A normal Guest won't try it because we don't advertise it in
+                * CPUID, but a malicious Guest (or malicious Guest userspace
+                * program) could, so we tell the CPU to disable it before
+                * running the Guest. */
                if (boot_cpu_has(X86_FEATURE_SEP))
                        wrmsr(MSR_IA32_SYSENTER_CS, 0, 0);
 
+               /* Now we actually run the Guest.  It will pop back out when
+                * something interesting happens, and we can examine its
+                * registers to see what it was doing. */
                run_guest_once(lg, lguest_pages(raw_smp_processor_id()));
 
-               /* Save cr2 now if we page-faulted. */
+               /* The "regs" pointer 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.  */
+
+               /* If the Guest page faulted, then the cr2 register will tell
+                * us the bad virtual address.  We have to grab this now,
+                * because once we re-enable interrupts an interrupt could
+                * fault and thus overwrite cr2, or we could even move off to a
+                * different CPU. */
                if (lg->regs->trapnum == 14)
                        cr2 = read_cr2();
+               /* Similarly, if we took a trap because the Guest used the FPU,
+                * we have to restore the FPU it expects to see. */
                else if (lg->regs->trapnum == 7)
                        math_state_restore();
 
+               /* Restore SYSENTER if it's supposed to be on. */
                if (boot_cpu_has(X86_FEATURE_SEP))
                        wrmsr(MSR_IA32_SYSENTER_CS, __KERNEL_CS, 0);
+
+               /* Now we're ready to be interrupted or moved to other CPUs */
                local_irq_enable();
 
+               /* OK, so what happened? */
                switch (lg->regs->trapnum) {
                case 13: /* We've intercepted a GPF. */
+                       /* Check if this was one of those annoying IN or OUT
+                        * instructions which we need to emulate.  If so, we
+                        * just go back into the Guest after we've done it. */
                        if (lg->regs->errcode == 0) {
                                if (emulate_insn(lg))
                                        continue;
                        }
                        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.
+                        *
+                        * The errcode tells whether this was a read or a
+                        * write, and whether kernel or userspace code. */
                        if (demand_page(lg, cr2, lg->regs->errcode))
                                continue;
 
-                       /* If lguest_data is NULL, this won't hurt. */
+                       /* OK, it's really not there (or not OK): the Guest
+                        * needs to know.  We write out the cr2 value so it
+                        * knows where the fault occurred.
+                        *
+                        * 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))
                                kill_guest(lg, "Writing cr2");
                        break;
                case 7: /* We've intercepted a Device Not Available fault. */
-                       /* If they don't want to know, just absorb it. */
+                       /* If the Guest doesn't want to know, we already
+                        * restored the Floating Point Unit, so we just
+                        * continue without telling it. */
                        if (!lg->ts)
                                continue;
                        break;
-               case 32 ... 255: /* Real interrupt, fall thru */
+               case 32 ... 255:
+                       /* These values mean a real interrupt occurred, in
+                        * which case the Host handler has already been run.
+                        * We just do a friendly check if another process
+                        * should now be run, then fall through to loop
+                        * around: */
                        cond_resched();
                case LGUEST_TRAP_ENTRY: /* Handled at top of loop */
                        continue;
                }
 
+               /* If we get here, it's a trap the Guest wants to know
+                * about. */
                if (deliver_trap(lg, lg->regs->trapnum))
                        continue;
 
+               /* 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. */
                kill_guest(lg, "unhandled trap %li at %#lx (%#lx)",
                           lg->regs->trapnum, lg->regs->eip,
                           lg->regs->trapnum == 14 ? cr2 : lg->regs->errcode);
        }
+       /* The Guest is dead => "No such file or directory" */
        return -ENOENT;
 }
 
+/* Now we can look at each of the routines this calls, in increasing order of
+ * complexity: do_hypercalls(), emulate_insn(), maybe_do_interrupt(),
+ * deliver_trap() and demand_page().  After all those, we'll be ready to
+ * examine the Switcher, and our philosophical understanding of the Host/Guest
+ * duality will be complete. :*/
+
 int find_free_guest(void)
 {
        unsigned int i;
@@ -407,55 +675,96 @@ static void adjust_pge(void *on)
                write_cr4(read_cr4() & ~X86_CR4_PGE);
 }
 
+/*H:000
+ * Welcome to the Host!
+ *
+ * By this point your brain has been tickled by the Guest code and numbed by
+ * the Launcher code; prepare for it to be stretched by the Host code.  This is
+ * the heart.  Let's begin at the initialization routine for the Host's lg
+ * module.
+ */
 static int __init init(void)
 {
        int err;
 
+       /* Lguest can't run under Xen, VMI or itself.  It does Tricky Stuff. */
        if (paravirt_enabled()) {
                printk("lguest is afraid of %s\n", paravirt_ops.name);
                return -EPERM;
        }
 
+       /* First we put the Switcher up in very high virtual memory. */
        err = map_switcher();
        if (err)
                return err;
 
+       /* Now we set up the pagetable implementation for the Guests. */
        err = init_pagetables(switcher_page, SHARED_SWITCHER_PAGES);
        if (err) {
                unmap_switcher();
                return err;
        }
+
+       /* The I/O subsystem needs some things initialized. */
        lguest_io_init();
 
+       /* /dev/lguest needs to be registered. */
        err = lguest_device_init();
        if (err) {
                free_pagetables();
                unmap_switcher();
                return err;
        }
+
+       /* Finally, we need to turn off "Page Global Enable".  PGE is an
+        * optimization where page table entries are specially marked to show
+        * they never change.  The Host kernel marks all the kernel pages this
+        * way because it's always present, even when userspace is running.
+        *
+        * Lguest breaks this: unbeknownst to the rest of the Host kernel, we
+        * switch to the Guest kernel.  If you don't disable this on all CPUs,
+        * you'll get really weird bugs that you'll chase for two days.
+        *
+        * I used to turn PGE off every time we switched to the Guest and back
+        * on when we return, but that slowed the Switcher down noticibly. */
+
+       /* We don't need the complexity of CPUs coming and going while we're
+        * doing this. */
        lock_cpu_hotplug();
        if (cpu_has_pge) { /* We have a broader idea of "global". */
+               /* Remember that this was originally set (for cleanup). */
                cpu_had_pge = 1;
+               /* adjust_pge is a helper function which sets or unsets the PGE
+                * bit on its CPU, depending on the argument (0 == unset). */
                on_each_cpu(adjust_pge, (void *)0, 0, 1);
+               /* Turn off the feature in the global feature set. */
                clear_bit(X86_FEATURE_PGE, boot_cpu_data.x86_capability);
        }
        unlock_cpu_hotplug();
+
+       /* All good! */
        return 0;
 }
 
+/* Cleaning up is just the same code, backwards.  With a little French. */
 static void __exit fini(void)
 {
        lguest_device_remove();
        free_pagetables();
        unmap_switcher();
+
+       /* If we had PGE before we started, turn it back on now. */
        lock_cpu_hotplug();
        if (cpu_had_pge) {
                set_bit(X86_FEATURE_PGE, boot_cpu_data.x86_capability);
+               /* adjust_pge's argument "1" means set PGE. */
                on_each_cpu(adjust_pge, (void *)1, 0, 1);
        }
        unlock_cpu_hotplug();
 }
 
+/* The Host side of lguest can be a module.  This is a nice way for people to
+ * play with it.  */
 module_init(init);
 module_exit(fini);
 MODULE_LICENSE("GPL");
index ea52ca451f74f78dce4dec85f1e0b39551615fd9..7a5299f9679ddcbe083cb7b16657ecc22cf1e2aa 100644 (file)
@@ -1,5 +1,10 @@
-/*  Actual hypercalls, which allow guests to actually do something.
-    Copyright (C) 2006 Rusty Russell IBM Corporation
+/*P:500 Just as userspace programs request kernel operations through a system
+ * call, the Guest requests Host operations through a "hypercall".  You might
+ * notice this nomenclature doesn't really follow any logic, but the name has
+ * been around for long enough that we're stuck with it.  As you'd expect, this
+ * code is basically a one big switch statement. :*/
+
+/*  Copyright (C) 2006 Rusty Russell IBM Corporation
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
 #include <irq_vectors.h>
 #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.
+ *
+ * Remember from the Guest: %eax == which call to make, and the arguments are
+ * packed into %edx, %ebx and %ecx if needed. */
 static void do_hcall(struct lguest *lg, struct lguest_regs *regs)
 {
        switch (regs->eax) {
        case LHCALL_FLUSH_ASYNC:
+               /* This call does nothing, except by breaking out of the Guest
+                * it makes us process all the asynchronous hypercalls. */
                break;
        case LHCALL_LGUEST_INIT:
+               /* You can't get here unless you're already initialized.  Don't
+                * do that. */
                kill_guest(lg, "already have lguest_data");
                break;
        case LHCALL_CRASH: {
+               /* Crash is such a trivial hypercall that we do it in four
+                * lines right here. */
                char msg[128];
+               /* If the lgread fails, it will call kill_guest() itself; the
+                * kill_guest() with the message will be ignored. */
                lgread(lg, msg, regs->edx, sizeof(msg));
                msg[sizeof(msg)-1] = '\0';
                kill_guest(lg, "CRASH: %s", msg);
                break;
        }
        case LHCALL_FLUSH_TLB:
+               /* FLUSH_TLB comes in two flavors, depending on the
+                * argument: */
                if (regs->edx)
                        guest_pagetable_clear_all(lg);
                else
                        guest_pagetable_flush_user(lg);
                break;
        case LHCALL_GET_WALLCLOCK: {
+               /* The Guest wants to know the real time in seconds since 1970,
+                * in good Unix tradition. */
                struct timespec ts;
                ktime_get_real_ts(&ts);
                regs->eax = ts.tv_sec;
                break;
        }
        case LHCALL_BIND_DMA:
+               /* BIND_DMA really wants four arguments, but it's the only call
+                * which does.  So the Guest packs the number of buffers and
+                * the interrupt number into the final argument, and we decode
+                * it here.  This can legitimately fail, since we currently
+                * place a limit on the number of DMA pools a Guest can have.
+                * So we return true or false from this call. */
                regs->eax = bind_dma(lg, regs->edx, regs->ebx,
                                     regs->ecx >> 8, regs->ecx & 0xFF);
                break;
+
+       /* All these calls simply pass the arguments through to the right
+        * routines. */
        case LHCALL_SEND_DMA:
                send_dma(lg, regs->edx, regs->ebx);
                break;
@@ -81,10 +112,13 @@ static void do_hcall(struct lguest *lg, struct lguest_regs *regs)
        case LHCALL_SET_CLOCKEVENT:
                guest_set_clockevent(lg, regs->edx);
                break;
+
        case LHCALL_TS:
+               /* This sets the TS flag, as we saw used in run_guest(). */
                lg->ts = regs->edx;
                break;
        case LHCALL_HALT:
+               /* Similarly, this sets the halted flag for run_guest(). */
                lg->halted = 1;
                break;
        default:
@@ -92,25 +126,42 @@ static void do_hcall(struct lguest *lg, struct lguest_regs *regs)
        }
 }
 
-/* We always do queued calls before actual hypercall. */
+/* Asynchronous hypercalls are easy: we just look in the array in the Guest's
+ * "struct lguest_data" and see if there are any new ones marked "ready".
+ *
+ * We are careful to do these in order: obviously we respect the order the
+ * Guest put them in the ring, but we also promise the Guest that they will
+ * happen before any normal hypercall (which is why we check this before
+ * checking for a normal hcall). */
 static void do_async_hcalls(struct lguest *lg)
 {
        unsigned int i;
        u8 st[LHCALL_RING_SIZE];
 
+       /* For simplicity, we copy the entire call status array in at once. */
        if (copy_from_user(&st, &lg->lguest_data->hcall_status, sizeof(st)))
                return;
 
+
+       /* We process "struct lguest_data"s hcalls[] ring once. */
        for (i = 0; i < ARRAY_SIZE(st); i++) {
                struct lguest_regs regs;
+               /* We remember where we were up to from last time.  This makes
+                * sure that the hypercalls are done in the order the Guest
+                * places them in the ring. */
                unsigned int n = lg->next_hcall;
 
+               /* 0xFF means there's no call here (yet). */
                if (st[n] == 0xFF)
                        break;
 
+               /* OK, we have hypercall.  Increment the "next_hcall" cursor,
+                * and wrap back to 0 if we reach the end. */
                if (++lg->next_hcall == LHCALL_RING_SIZE)
                        lg->next_hcall = 0;
 
+               /* We copy the hypercall arguments into a fake register
+                * structure.  This makes life simple for do_hcall(). */
                if (get_user(regs.eax, &lg->lguest_data->hcalls[n].eax)
                    || get_user(regs.edx, &lg->lguest_data->hcalls[n].edx)
                    || get_user(regs.ecx, &lg->lguest_data->hcalls[n].ecx)
@@ -119,74 +170,126 @@ static void do_async_hcalls(struct lguest *lg)
                        break;
                }
 
+               /* Do the hypercall, same as a normal one. */
                do_hcall(lg, &regs);
+
+               /* Mark the hypercall done. */
                if (put_user(0xFF, &lg->lguest_data->hcall_status[n])) {
                        kill_guest(lg, "Writing result for async hypercall");
                        break;
                }
 
+               /* Stop doing hypercalls if we've just done a DMA to the
+                * Launcher: it needs to service this first. */
                if (lg->dma_is_pending)
                        break;
        }
 }
 
+/* Last of all, we look at what happens first of all.  The very first time the
+ * Guest makes a hypercall, we end up here to set things up: */
 static void initialize(struct lguest *lg)
 {
        u32 tsc_speed;
 
+       /* You can't do anything until you're initialized.  The Guest knows the
+        * rules, so we're unforgiving here. */
        if (lg->regs->eax != LHCALL_LGUEST_INIT) {
                kill_guest(lg, "hypercall %li before LGUEST_INIT",
                           lg->regs->eax);
                return;
        }
 
-       /* We only tell the guest to use the TSC if it's reliable. */
+       /* We insist that the Time Stamp Counter exist and doesn't change with
+        * cpu frequency.  Some devious chip manufacturers decided that TSC
+        * changes could be handled in software.  I decided that time going
+        * backwards might be good for benchmarks, but it's bad for users.
+        *
+        * We also insist that the TSC be stable: the kernel detects unreliable
+        * TSCs for its own purposes, and we use that here. */
        if (boot_cpu_has(X86_FEATURE_CONSTANT_TSC) && !check_tsc_unstable())
                tsc_speed = tsc_khz;
        else
                tsc_speed = 0;
 
+       /* The pointer to the Guest's "struct lguest_data" is the only
+        * argument. */
        lg->lguest_data = (struct lguest_data __user *)lg->regs->edx;
-       /* We check here so we can simply copy_to_user/from_user */
+       /* If we check the address they gave is OK now, we can simply
+        * copy_to_user/from_user from now on rather than using lgread/lgwrite.
+        * I put this in to show that I'm not immune to writing stupid
+        * optimizations. */
        if (!lguest_address_ok(lg, lg->regs->edx, sizeof(*lg->lguest_data))) {
                kill_guest(lg, "bad guest page %p", lg->lguest_data);
                return;
        }
+       /* The Guest tells us where we're not to deliver interrupts by putting
+        * the range of addresses into "struct lguest_data". */
        if (get_user(lg->noirq_start, &lg->lguest_data->noirq_start)
            || get_user(lg->noirq_end, &lg->lguest_data->noirq_end)
-           /* We reserve the top pgd entry. */
+           /* We tell the Guest that it can't use the top 4MB of virtual
+            * addresses used by the Switcher. */
            || put_user(4U*1024*1024, &lg->lguest_data->reserve_mem)
            || put_user(tsc_speed, &lg->lguest_data->tsc_khz)
+           /* We also give the Guest a unique id, as used in lguest_net.c. */
            || put_user(lg->guestid, &lg->lguest_data->guestid))
                kill_guest(lg, "bad guest page %p", lg->lguest_data);
 
-       /* This is the one case where the above accesses might have
-        * been the first write to a Guest page.  This may have caused
-        * a copy-on-write fault, but the Guest might be referring to
-        * the old (read-only) page. */
+       /* This is the one case where the above accesses might have been the
+        * first write to a Guest page.  This may have caused a copy-on-write
+        * fault, but the Guest might be referring to the old (read-only)
+        * page. */
        guest_pagetable_clear_all(lg);
 }
+/* Now we've examined the hypercall code; our Guest can make requests.  There
+ * is one other way we can do things for the Guest, as we see in
+ * emulate_insn(). */
 
-/* Even if we go out to userspace and come back, we don't want to do
- * the hypercall again. */
+/*H:110 Tricky point: we mark the hypercall as "done" once we've done it.
+ * Normally we don't need to do this: the Guest will run again and update the
+ * trap number before we come back around the run_guest() loop to
+ * do_hypercalls().
+ *
+ * However, if we are signalled or the Guest sends DMA to the Launcher, that
+ * loop will exit without running the Guest.  When it comes back it would try
+ * to re-run the hypercall. */
 static void clear_hcall(struct lguest *lg)
 {
        lg->regs->trapnum = 255;
 }
 
+/*H:100
+ * Hypercalls
+ *
+ * Remember from the Guest, hypercalls come in two flavors: normal and
+ * asynchronous.  This file handles both of types.
+ */
 void do_hypercalls(struct lguest *lg)
 {
+       /* Not initialized yet? */
        if (unlikely(!lg->lguest_data)) {
+               /* Did the Guest make a hypercall?  We might have come back for
+                * some other reason (an interrupt, a different trap). */
                if (lg->regs->trapnum == LGUEST_TRAP_ENTRY) {
+                       /* Set up the "struct lguest_data" */
                        initialize(lg);
+                       /* The hypercall is done. */
                        clear_hcall(lg);
                }
                return;
        }
 
+       /* The Guest has initialized.
+        *
+        * Look in the hypercall ring for the async hypercalls: */
        do_async_hcalls(lg);
+
+       /* If we stopped reading the hypercall ring because the Guest did a
+        * SEND_DMA to the Launcher, we want to return now.  Otherwise if the
+        * Guest asked us to do a hypercall, we do it. */
        if (!lg->dma_is_pending && lg->regs->trapnum == LGUEST_TRAP_ENTRY) {
                do_hcall(lg, lg->regs);
+               /* The hypercall is done. */
                clear_hcall(lg);
        }
 }
index bee029bb2c7bf543912f97d1fa798739569e2606..bd0091bf79ec485edacedcdaf47194e429a35cb3 100644 (file)
+/*P:800 Interrupts (traps) are complicated enough to earn their own file.
+ * There are three classes of interrupts:
+ *
+ * 1) Real hardware interrupts which occur while we're running the Guest,
+ * 2) Interrupts for virtual devices attached to the Guest, and
+ * 3) Traps and faults from the Guest.
+ *
+ * Real hardware interrupts must be delivered to the Host, not the Guest.
+ * Virtual interrupts must be delivered to the Guest, but we make them look
+ * just like real hardware would deliver them.  Traps from the Guest can be set
+ * up to go directly back into the Guest, but sometimes the Host wants to see
+ * them first, so we also have a way of "reflecting" them into the Guest as if
+ * they had been delivered to it directly. :*/
 #include <linux/uaccess.h>
 #include "lg.h"
 
+/* The address of the interrupt handler is split into two bits: */
 static unsigned long idt_address(u32 lo, u32 hi)
 {
        return (lo & 0x0000FFFF) | (hi & 0xFFFF0000);
 }
 
+/* The "type" of the interrupt handler is a 4 bit field: we only support a
+ * couple of types. */
 static int idt_type(u32 lo, u32 hi)
 {
        return (hi >> 8) & 0xF;
 }
 
+/* An IDT entry can't be used unless the "present" bit is set. */
 static int idt_present(u32 lo, u32 hi)
 {
        return (hi & 0x8000);
 }
 
+/* We need a helper to "push" a value onto the Guest's stack, since that's a
+ * big part of what delivering an interrupt does. */
 static void push_guest_stack(struct lguest *lg, unsigned long *gstack, u32 val)
 {
+       /* Stack grows upwards: move stack then write value. */
        *gstack -= 4;
        lgwrite_u32(lg, *gstack, val);
 }
 
+/*H:210 The set_guest_interrupt() routine actually delivers the interrupt or
+ * trap.  The mechanics of delivering traps and interrupts to the Guest are the
+ * same, except some traps have an "error code" which gets pushed onto the
+ * stack as well: the caller tells us if this is one.
+ *
+ * "lo" and "hi" are the two parts of the Interrupt Descriptor Table for this
+ * interrupt or trap.  It's split into two parts for traditional reasons: gcc
+ * on i386 used to be frightened by 64 bit numbers.
+ *
+ * We set up the stack just like the CPU does for a real interrupt, so it's
+ * identical for the Guest (and the standard "iret" instruction will undo
+ * it). */
 static void set_guest_interrupt(struct lguest *lg, u32 lo, u32 hi, int has_err)
 {
        unsigned long gstack;
        u32 eflags, ss, irq_enable;
 
-       /* If they want a ring change, we use new stack and push old ss/esp */
+       /* There are two cases for interrupts: one where the Guest is already
+        * in the kernel, and a more complex one where the Guest is in
+        * userspace.  We check the privilege level to find out. */
        if ((lg->regs->ss&0x3) != GUEST_PL) {
+               /* The Guest told us their kernel stack with the SET_STACK
+                * hypercall: both the virtual address and the segment */
                gstack = guest_pa(lg, lg->esp1);
                ss = lg->ss1;
+               /* We push the old stack segment and pointer onto the new
+                * stack: when the Guest does an "iret" back from the interrupt
+                * handler the CPU will notice they're dropping privilege
+                * levels and expect these here. */
                push_guest_stack(lg, &gstack, lg->regs->ss);
                push_guest_stack(lg, &gstack, lg->regs->esp);
        } else {
+               /* We're staying on the same Guest (kernel) stack. */
                gstack = guest_pa(lg, lg->regs->esp);
                ss = lg->regs->ss;
        }
 
-       /* We use IF bit in eflags to indicate whether irqs were enabled
-          (it's always 1, since irqs are enabled when guest is running). */
+       /* Remember that we never let the Guest actually disable interrupts, so
+        * the "Interrupt Flag" bit is always set.  We copy that bit from the
+        * Guest's "irq_enabled" field into the eflags word: the Guest copies
+        * it back in "lguest_iret". */
        eflags = lg->regs->eflags;
        if (get_user(irq_enable, &lg->lguest_data->irq_enabled) == 0
            && !(irq_enable & X86_EFLAGS_IF))
                eflags &= ~X86_EFLAGS_IF;
 
+       /* An interrupt is expected to push three things on the stack: the old
+        * "eflags" word, the old code segment, and the old instruction
+        * pointer. */
        push_guest_stack(lg, &gstack, eflags);
        push_guest_stack(lg, &gstack, lg->regs->cs);
        push_guest_stack(lg, &gstack, lg->regs->eip);
 
+       /* For the six traps which supply an error code, we push that, too. */
        if (has_err)
                push_guest_stack(lg, &gstack, lg->regs->errcode);
 
-       /* Change the real stack so switcher returns to trap handler */
+       /* Now we've pushed all the old state, we change the stack, the code
+        * segment and the address to execute. */
        lg->regs->ss = ss;
        lg->regs->esp = gstack + lg->page_offset;
        lg->regs->cs = (__KERNEL_CS|GUEST_PL);
        lg->regs->eip = idt_address(lo, hi);
 
-       /* Disable interrupts for an interrupt gate. */
+       /* There are two kinds of interrupt handlers: 0xE is an "interrupt
+        * gate" which expects interrupts to be disabled on entry. */
        if (idt_type(lo, hi) == 0xE)
                if (put_user(0, &lg->lguest_data->irq_enabled))
                        kill_guest(lg, "Disabling interrupts");
 }
 
+/*H:200
+ * Virtual Interrupts.
+ *
+ * maybe_do_interrupt() gets called before every entry to the Guest, to see if
+ * we should divert the Guest to running an interrupt handler. */
 void maybe_do_interrupt(struct lguest *lg)
 {
        unsigned int irq;
        DECLARE_BITMAP(blk, LGUEST_IRQS);
        struct desc_struct *idt;
 
+       /* If the Guest hasn't even initialized yet, we can do nothing. */
        if (!lg->lguest_data)
                return;
 
-       /* Mask out any interrupts they have blocked. */
+       /* Take our "irqs_pending" array and remove any interrupts the Guest
+        * wants blocked: the result ends up in "blk". */
        if (copy_from_user(&blk, lg->lguest_data->blocked_interrupts,
                           sizeof(blk)))
                return;
 
        bitmap_andnot(blk, lg->irqs_pending, blk, LGUEST_IRQS);
 
+       /* Find the first interrupt. */
        irq = find_first_bit(blk, LGUEST_IRQS);
+       /* None?  Nothing to do */
        if (irq >= LGUEST_IRQS)
                return;
 
+       /* They may be in the middle of an iret, where they asked us never to
+        * deliver interrupts. */
        if (lg->regs->eip >= lg->noirq_start && lg->regs->eip < lg->noirq_end)
                return;
 
-       /* If they're halted, we re-enable interrupts. */
+       /* If they're halted, interrupts restart them. */
        if (lg->halted) {
                /* Re-enable interrupts. */
                if (put_user(X86_EFLAGS_IF, &lg->lguest_data->irq_enabled))
                        kill_guest(lg, "Re-enabling interrupts");
                lg->halted = 0;
        } else {
-               /* Maybe they have interrupts disabled? */
+               /* Otherwise we check if they have interrupts disabled. */
                u32 irq_enabled;
                if (get_user(irq_enabled, &lg->lguest_data->irq_enabled))
                        irq_enabled = 0;
@@ -102,112 +162,211 @@ void maybe_do_interrupt(struct lguest *lg)
                        return;
        }
 
+       /* Look at the IDT entry the Guest gave us for this interrupt.  The
+        * first 32 (FIRST_EXTERNAL_VECTOR) entries are for traps, so we skip
+        * over them. */
        idt = &lg->idt[FIRST_EXTERNAL_VECTOR+irq];
+       /* If they don't have a handler (yet?), we just ignore it */
        if (idt_present(idt->a, idt->b)) {
+               /* OK, mark it no longer pending and deliver it. */
                clear_bit(irq, lg->irqs_pending);
+               /* set_guest_interrupt() takes the interrupt descriptor and a
+                * flag to say whether this interrupt pushes an error code onto
+                * the stack as well: virtual interrupts never do. */
                set_guest_interrupt(lg, idt->a, idt->b, 0);
        }
 }
 
+/*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);
 }
 
+/* deliver_trap() returns true if it could deliver the trap. */
 int deliver_trap(struct lguest *lg, unsigned int num)
 {
        u32 lo = lg->idt[num].a, hi = lg->idt[num].b;
 
+       /* Early on the Guest hasn't set the IDT entries (or maybe it put a
+        * bogus one in): if we fail here, the Guest will be killed. */
        if (!idt_present(lo, hi))
                return 0;
        set_guest_interrupt(lg, lo, hi, has_err(num));
        return 1;
 }
 
+/*H:250 Here's the hard part: returning to the Host every time a trap happens
+ * and then calling deliver_trap() and re-entering the Guest is slow.
+ * Particularly because Guest userspace system calls are traps (trap 128).
+ *
+ * So we'd like to set up the IDT to tell the CPU to deliver traps directly
+ * into the Guest.  This is possible, but the complexities cause the size of
+ * this file to double!  However, 150 lines of code is worth writing for taking
+ * system calls down from 1750ns to 270ns.  Plus, if lguest didn't do it, all
+ * the other hypervisors would tease it.
+ *
+ * This routine determines if a trap can be delivered directly. */
 static int direct_trap(const struct lguest *lg,
                       const struct desc_struct *trap,
                       unsigned int num)
 {
-       /* Hardware interrupts don't go to guest (except syscall). */
+       /* Hardware interrupts don't go to the Guest at all (except system
+        * call). */
        if (num >= FIRST_EXTERNAL_VECTOR && num != SYSCALL_VECTOR)
                return 0;
 
-       /* We intercept page fault (demand shadow paging & cr2 saving)
-          protection fault (in/out emulation) and device not
-          available (TS handling), and hypercall */
+       /* The Host needs to see page faults (for shadow paging and to save the
+        * fault address), general protection faults (in/out emulation) and
+        * device not available (TS handling), and of course, the hypercall
+        * trap. */
        if (num == 14 || num == 13 || num == 7 || num == LGUEST_TRAP_ENTRY)
                return 0;
 
-       /* Interrupt gates (0xE) or not present (0x0) can't go direct. */
+       /* Only trap gates (type 15) can go direct to the Guest.  Interrupt
+        * gates (type 14) disable interrupts as they are entered, which we
+        * never let the Guest do.  Not present entries (type 0x0) also can't
+        * go direct, of course 8) */
        return idt_type(trap->a, trap->b) == 0xF;
 }
-
+/*:*/
+
+/*M:005 The Guest has the ability to turn its interrupt gates into trap gates,
+ * if it is careful.  The Host will let trap gates can go directly to the
+ * Guest, but the Guest needs the interrupts atomically disabled for an
+ * interrupt gate.  It can do this by pointing the trap gate at instructions
+ * within noirq_start and noirq_end, where it can safely disable interrupts. */
+
+/*M:006 The Guests do not use the sysenter (fast system call) instruction,
+ * because it's hardcoded to enter privilege level 0 and so can't go direct.
+ * It's about twice as fast as the older "int 0x80" system call, so it might
+ * still be worthwhile to handle it in the Switcher and lcall down to the
+ * Guest.  The sysenter semantics are hairy tho: search for that keyword in
+ * entry.S :*/
+
+/*H:260 When we make traps go directly into the Guest, we need to make sure
+ * the kernel stack is valid (ie. mapped in the page tables).  Otherwise, the
+ * CPU trying to deliver the trap will fault while trying to push the interrupt
+ * words on the stack: this is called a double fault, and it forces us to kill
+ * the Guest.
+ *
+ * Which is deeply unfair, because (literally!) it wasn't the Guests' fault. */
 void pin_stack_pages(struct lguest *lg)
 {
        unsigned int i;
 
+       /* Depending on the CONFIG_4KSTACKS option, the Guest can have one or
+        * two pages of stack space. */
        for (i = 0; i < lg->stack_pages; i++)
+               /* The stack grows *upwards*, hence the subtraction */
                pin_page(lg, lg->esp1 - i * PAGE_SIZE);
 }
 
+/* Direct traps also mean that we need to know whenever the Guest wants to use
+ * a different kernel stack, so we can change the IDT entries to use that
+ * stack.  The IDT entries expect a virtual address, so unlike most addresses
+ * the Guest gives us, the "esp" (stack pointer) value here is virtual, not
+ * physical.
+ *
+ * In Linux each process has its own kernel stack, so this happens a lot: we
+ * change stacks on each context switch. */
 void guest_set_stack(struct lguest *lg, u32 seg, u32 esp, unsigned int pages)
 {
-       /* You cannot have a stack segment with priv level 0. */
+       /* You are not allowd have a stack segment with privilege level 0: bad
+        * Guest! */
        if ((seg & 0x3) != GUEST_PL)
                kill_guest(lg, "bad stack segment %i", seg);
+       /* We only expect one or two stack pages. */
        if (pages > 2)
                kill_guest(lg, "bad stack pages %u", pages);
+       /* Save where the stack is, and how many pages */
        lg->ss1 = seg;
        lg->esp1 = esp;
        lg->stack_pages = pages;
+       /* Make sure the new stack pages are mapped */
        pin_stack_pages(lg);
 }
 
-/* Set up trap in IDT. */
+/* All this reference to mapping stacks leads us neatly into the other complex
+ * part of the Host: page table handling. */
+
+/*H:235 This is the routine which actually checks the Guest's IDT entry and
+ * transfers it into our entry in "struct lguest": */
 static void set_trap(struct lguest *lg, struct desc_struct *trap,
                     unsigned int num, u32 lo, u32 hi)
 {
        u8 type = idt_type(lo, hi);
 
+       /* We zero-out a not-present entry */
        if (!idt_present(lo, hi)) {
                trap->a = trap->b = 0;
                return;
        }
 
+       /* We only support interrupt and trap gates. */
        if (type != 0xE && type != 0xF)
                kill_guest(lg, "bad IDT type %i", type);
 
+       /* We only copy the handler address, present bit, privilege level and
+        * type.  The privilege level controls where the trap can be triggered
+        * manually with an "int" instruction.  This is usually GUEST_PL,
+        * except for system calls which userspace can use. */
        trap->a = ((__KERNEL_CS|GUEST_PL)<<16) | (lo&0x0000FFFF);
        trap->b = (hi&0xFFFFEF00);
 }
 
+/*H:230 While we're here, dealing with delivering traps and interrupts to the
+ * Guest, we might as well complete the picture: how the Guest tells us where
+ * it wants them to go.  This would be simple, except making traps fast
+ * requires some tricks.
+ *
+ * We saw the Guest setting Interrupt Descriptor Table (IDT) entries with the
+ * LHCALL_LOAD_IDT_ENTRY hypercall before: that comes here. */
 void load_guest_idt_entry(struct lguest *lg, unsigned int num, u32 lo, u32 hi)
 {
-       /* Guest never handles: NMI, doublefault, hypercall, spurious irq. */
+       /* Guest never handles: NMI, doublefault, spurious interrupt or
+        * hypercall.  We ignore when it tries to set them. */
        if (num == 2 || num == 8 || num == 15 || num == LGUEST_TRAP_ENTRY)
                return;
 
+       /* Mark the IDT as changed: next time the Guest runs we'll know we have
+        * to copy this again. */
        lg->changed |= CHANGED_IDT;
+
+       /* The IDT which we keep in "struct lguest" only contains 32 entries
+        * for the traps and LGUEST_IRQS (32) entries for interrupts.  We
+        * ignore attempts to set handlers for higher interrupt numbers, except
+        * for the system call "interrupt" at 128: we have a special IDT entry
+        * for that. */
        if (num < ARRAY_SIZE(lg->idt))
                set_trap(lg, &lg->idt[num], num, lo, hi);
        else if (num == SYSCALL_VECTOR)
                set_trap(lg, &lg->syscall_idt, num, lo, hi);
 }
 
+/* The default entry for each interrupt points into the Switcher routines which
+ * simply return to the Host.  The run_guest() loop will then call
+ * deliver_trap() to bounce it back into the Guest. */
 static void default_idt_entry(struct desc_struct *idt,
                              int trap,
                              const unsigned long handler)
 {
+       /* A present interrupt gate. */
        u32 flags = 0x8e00;
 
-       /* They can't "int" into any of them except hypercall. */
+       /* Set the privilege level on the entry for the hypercall: this allows
+        * the Guest to use the "int" instruction to trigger it. */
        if (trap == LGUEST_TRAP_ENTRY)
                flags |= (GUEST_PL << 13);
 
+       /* Now pack it into the IDT entry in its weird format. */
        idt->a = (LGUEST_CS<<16) | (handler&0x0000FFFF);
        idt->b = (handler&0xFFFF0000) | flags;
 }
 
+/* When the Guest first starts, we put default entries into the IDT. */
 void setup_default_idt_entries(struct lguest_ro_state *state,
                               const unsigned long *def)
 {
@@ -217,19 +376,25 @@ void setup_default_idt_entries(struct lguest_ro_state *state,
                default_idt_entry(&state->guest_idt[i], i, def[i]);
 }
 
+/*H:240 We don't use the IDT entries in the "struct lguest" directly, instead
+ * we copy them into the IDT which we've set up for Guests on this CPU, just
+ * before we run the Guest.  This routine does that copy. */
 void copy_traps(const struct lguest *lg, struct desc_struct *idt,
                const unsigned long *def)
 {
        unsigned int i;
 
-       /* All hardware interrupts are same whatever the guest: only the
-        * traps might be different. */
+       /* We can simply copy the direct traps, otherwise we use the default
+        * ones in the Switcher: they will return to the Host. */
        for (i = 0; i < FIRST_EXTERNAL_VECTOR; i++) {
                if (direct_trap(lg, &lg->idt[i], i))
                        idt[i] = lg->idt[i];
                else
                        default_idt_entry(&idt[i], i, def[i]);
        }
+
+       /* Don't forget the system call trap!  The IDT entries for other
+        * interupts never change, so no need to copy them. */
        i = SYSCALL_VECTOR;
        if (direct_trap(lg, &lg->syscall_idt, i))
                idt[i] = lg->syscall_idt;
index c8eb79266991efb68d34e077de859295e8f8edcb..ea68613b43f6282fb922d19a5af30b0e2073b870 100644 (file)
@@ -1,5 +1,9 @@
-/* Simple I/O model for guests, based on shared memory.
- * Copyright (C) 2006 Rusty Russell IBM Corporation
+/*P:300 The I/O mechanism in lguest is simple yet flexible, allowing the Guest
+ * to talk to the Launcher or directly to another Guest.  It uses familiar
+ * concepts of DMA and interrupts, plus some neat code stolen from
+ * futexes... :*/
+
+/* Copyright (C) 2006 Rusty Russell IBM Corporation
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
 #include <linux/uaccess.h>
 #include "lg.h"
 
+/*L:300
+ * I/O
+ *
+ * Getting data in and out of the Guest is quite an art.  There are numerous
+ * ways to do it, and they all suck differently.  We try to keep things fairly
+ * close to "real" hardware so our Guest's drivers don't look like an alien
+ * visitation in the middle of the Linux code, and yet make sure that Guests
+ * can talk directly to other Guests, not just the Launcher.
+ *
+ * To do this, the Guest gives us a key when it binds or sends DMA buffers.
+ * The key corresponds to a "physical" address inside the Guest (ie. a virtual
+ * address inside the Launcher process).  We don't, however, use this key
+ * directly.
+ *
+ * We want Guests which share memory to be able to DMA to each other: two
+ * Launchers can mmap memory the same file, then the Guests can communicate.
+ * Fortunately, the futex code provides us with a way to get a "union
+ * futex_key" corresponding to the memory lying at a virtual address: if the
+ * two processes share memory, the "union futex_key" for that memory will match
+ * even if the memory is mapped at different addresses in each.  So we always
+ * convert the keys to "union futex_key"s to compare them.
+ *
+ * Before we dive into this though, we need to look at another set of helper
+ * routines used throughout the Host kernel code to access Guest memory.
+ :*/
 static struct list_head dma_hash[61];
 
+/* An unfortunate side effect of the Linux double-linked list implementation is
+ * that there's no good way to statically initialize an array of linked
+ * lists. */
 void lguest_io_init(void)
 {
        unsigned int i;
@@ -56,6 +88,19 @@ kill:
        return 0;
 }
 
+/*L:330 This is our hash function, using the wonderful Jenkins hash.
+ *
+ * The futex key is a union with three parts: an unsigned long word, a pointer,
+ * and an int "offset".  We could use jhash_2words() which takes three u32s.
+ * (Ok, the hash functions are great: the naming sucks though).
+ *
+ * It's nice to be portable to 64-bit platforms, so we use the more generic
+ * jhash2(), which takes an array of u32, the number of u32s, and an initial
+ * u32 to roll in.  This is uglier, but breaks down to almost the same code on
+ * 32-bit platforms like this one.
+ *
+ * We want a position in the array, so we modulo ARRAY_SIZE(dma_hash) (ie. 61).
+ */
 static unsigned int hash(const union futex_key *key)
 {
        return jhash2((u32*)&key->both.word,
@@ -64,6 +109,9 @@ static unsigned int hash(const union futex_key *key)
                % ARRAY_SIZE(dma_hash);
 }
 
+/* This is a convenience routine to compare two keys.  It's a much bemoaned C
+ * weakness that it doesn't allow '==' on structures or unions, so we have to
+ * open-code it like this. */
 static inline int key_eq(const union futex_key *a, const union futex_key *b)
 {
        return (a->both.word == b->both.word
@@ -71,22 +119,36 @@ static inline int key_eq(const union futex_key *a, const union futex_key *b)
                && a->both.offset == b->both.offset);
 }
 
-/* Must hold read lock on dmainfo owner's current->mm->mmap_sem */
+/*L:360 OK, when we need to actually free up a Guest's DMA array we do several
+ * things, so we have a convenient function to do it.
+ *
+ * The caller must hold a read lock on dmainfo owner's current->mm->mmap_sem
+ * for the drop_futex_key_refs(). */
 static void unlink_dma(struct lguest_dma_info *dmainfo)
 {
+       /* You locked this too, right? */
        BUG_ON(!mutex_is_locked(&lguest_lock));
+       /* This is how we know that the entry is free. */
        dmainfo->interrupt = 0;
+       /* Remove it from the hash table. */
        list_del(&dmainfo->list);
+       /* Drop the references we were holding (to the inode or mm). */
        drop_futex_key_refs(&dmainfo->key);
 }
 
+/*L:350 This is the routine which we call when the Guest asks to unregister a
+ * DMA array attached to a given key.  Returns true if the array was found. */
 static int unbind_dma(struct lguest *lg,
                      const union futex_key *key,
                      unsigned long dmas)
 {
        int i, ret = 0;
 
+       /* We don't bother with the hash table, just look through all this
+        * Guest's DMA arrays. */
        for (i = 0; i < LGUEST_MAX_DMA; i++) {
+               /* In theory it could have more than one array on the same key,
+                * or one array on multiple keys, so we check both */
                if (key_eq(key, &lg->dma[i].key) && dmas == lg->dma[i].dmas) {
                        unlink_dma(&lg->dma[i]);
                        ret = 1;
@@ -96,51 +158,91 @@ static int unbind_dma(struct lguest *lg,
        return ret;
 }
 
+/*L:340 BIND_DMA: this is the hypercall which sets up an array of "struct
+ * lguest_dma" for receiving I/O.
+ *
+ * The Guest wants to bind an array of "struct lguest_dma"s to a particular key
+ * to receive input.  This only happens when the Guest is setting up a new
+ * device, so it doesn't have to be very fast.
+ *
+ * It returns 1 on a successful registration (it can fail if we hit the limit
+ * of registrations for this Guest).
+ */
 int bind_dma(struct lguest *lg,
             unsigned long ukey, unsigned long dmas, u16 numdmas, u8 interrupt)
 {
        unsigned int i;
        int ret = 0;
        union futex_key key;
+       /* Futex code needs the mmap_sem. */
        struct rw_semaphore *fshared = &current->mm->mmap_sem;
 
+       /* Invalid interrupt?  (We could kill the guest here). */
        if (interrupt >= LGUEST_IRQS)
                return 0;
 
+       /* We need to grab the Big Lguest Lock, because other Guests may be
+        * trying to look through this Guest's DMAs to send something while
+        * we're doing this. */
        mutex_lock(&lguest_lock);
        down_read(fshared);
        if (get_futex_key((u32 __user *)ukey, fshared, &key) != 0) {
                kill_guest(lg, "bad dma key %#lx", ukey);
                goto unlock;
        }
+
+       /* We want to keep this key valid once we drop mmap_sem, so we have to
+        * hold a reference. */
        get_futex_key_refs(&key);
 
+       /* If the Guest specified an interrupt of 0, that means they want to
+        * unregister this array of "struct lguest_dma"s. */
        if (interrupt == 0)
                ret = unbind_dma(lg, &key, dmas);
        else {
+               /* Look through this Guest's dma array for an unused entry. */
                for (i = 0; i < LGUEST_MAX_DMA; i++) {
+                       /* If the interrupt is non-zero, the entry is already
+                        * used. */
                        if (lg->dma[i].interrupt)
                                continue;
 
+                       /* OK, a free one!  Fill on our details. */
                        lg->dma[i].dmas = dmas;
                        lg->dma[i].num_dmas = numdmas;
                        lg->dma[i].next_dma = 0;
                        lg->dma[i].key = key;
                        lg->dma[i].guestid = lg->guestid;
                        lg->dma[i].interrupt = interrupt;
+
+                       /* Now we add it to the hash table: the position
+                        * depends on the futex key that we got. */
                        list_add(&lg->dma[i].list, &dma_hash[hash(&key)]);
+                       /* Success! */
                        ret = 1;
                        goto unlock;
                }
        }
+       /* If we didn't find a slot to put the key in, drop the reference
+        * again. */
        drop_futex_key_refs(&key);
 unlock:
+       /* Unlock and out. */
        up_read(fshared);
        mutex_unlock(&lguest_lock);
        return ret;
 }
 
-/* lgread from another guest */
+/*L:385 Note that our routines to access a different Guest's memory are called
+ * lgread_other() and lgwrite_other(): these names emphasize that they are only
+ * used when the Guest is *not* the current Guest.
+ *
+ * The interface for copying from another process's memory is called
+ * access_process_vm(), with a final argument of 0 for a read, and 1 for a
+ * write.
+ *
+ * We need lgread_other() to read the destination Guest's "struct lguest_dma"
+ * array. */
 static int lgread_other(struct lguest *lg,
                        void *buf, u32 addr, unsigned bytes)
 {
@@ -153,7 +255,8 @@ static int lgread_other(struct lguest *lg,
        return 1;
 }
 
-/* lgwrite to another guest */
+/* "lgwrite()" to another Guest: used to update the destination "used_len" once
+ * we've transferred data into the buffer. */
 static int lgwrite_other(struct lguest *lg, u32 addr,
                         const void *buf, unsigned bytes)
 {
@@ -166,6 +269,15 @@ static int lgwrite_other(struct lguest *lg, u32 addr,
        return 1;
 }
 
+/*L:400 This is the generic engine which copies from a source "struct
+ * lguest_dma" from this Guest into another Guest's "struct lguest_dma".  The
+ * destination Guest's pages have already been mapped, as contained in the
+ * pages array.
+ *
+ * If you're wondering if there's a nice "copy from one process to another"
+ * routine, so was I.  But Linux isn't really set up to copy between two
+ * unrelated processes, so we have to write it ourselves.
+ */
 static u32 copy_data(struct lguest *srclg,
                     const struct lguest_dma *src,
                     const struct lguest_dma *dst,
@@ -174,33 +286,59 @@ static u32 copy_data(struct lguest *srclg,
        unsigned int totlen, si, di, srcoff, dstoff;
        void *maddr = NULL;
 
+       /* We return the total length transferred. */
        totlen = 0;
+
+       /* We keep indexes into the source and destination "struct lguest_dma",
+        * and an offset within each region. */
        si = di = 0;
        srcoff = dstoff = 0;
+
+       /* We loop until the source or destination is exhausted. */
        while (si < LGUEST_MAX_DMA_SECTIONS && src->len[si]
               && di < LGUEST_MAX_DMA_SECTIONS && dst->len[di]) {
+               /* We can only transfer the rest of the src buffer, or as much
+                * as will fit into the destination buffer. */
                u32 len = min(src->len[si] - srcoff, dst->len[di] - dstoff);
 
+               /* For systems using "highmem" we need to use kmap() to access
+                * the page we want.  We often use the same page over and over,
+                * so rather than kmap() it on every loop, we set the maddr
+                * pointer to NULL when we need to move to the next
+                * destination page. */
                if (!maddr)
                        maddr = kmap(pages[di]);
 
-               /* FIXME: This is not completely portable, since
-                  archs do different things for copy_to_user_page. */
+               /* Copy directly from (this Guest's) source address to the
+                * destination Guest's kmap()ed buffer.  Note that maddr points
+                * to the start of the page: we need to add the offset of the
+                * destination address and offset within the buffer. */
+
+               /* FIXME: This is not completely portable.  I looked at
+                * 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) {
+                       /* If a copy failed, it's the source's fault. */
                        kill_guest(srclg, "bad address in sending DMA");
                        totlen = 0;
                        break;
                }
 
+               /* Increment the total and src & dst offsets */
                totlen += len;
                srcoff += len;
                dstoff += len;
+
+               /* Presumably we reached the end of the src or dest buffers: */
                if (srcoff == src->len[si]) {
+                       /* Move to the next buffer at offset 0 */
                        si++;
                        srcoff = 0;
                }
                if (dstoff == dst->len[di]) {
+                       /* We need to unmap that destination page and reset
+                        * maddr ready for the next one. */
                        kunmap(pages[di]);
                        maddr = NULL;
                        di++;
@@ -208,13 +346,15 @@ static u32 copy_data(struct lguest *srclg,
                }
        }
 
+       /* If we still had a page mapped at the end, unmap now. */
        if (maddr)
                kunmap(pages[di]);
 
        return totlen;
 }
 
-/* Src is us, ie. current. */
+/*L:390 This is how we transfer a "struct lguest_dma" from the source Guest
+ * (the current Guest which called SEND_DMA) to another Guest. */
 static u32 do_dma(struct lguest *srclg, const struct lguest_dma *src,
                  struct lguest *dstlg, const struct lguest_dma *dst)
 {
@@ -222,23 +362,31 @@ static u32 do_dma(struct lguest *srclg, const struct lguest_dma *src,
        u32 ret;
        struct page *pages[LGUEST_MAX_DMA_SECTIONS];
 
+       /* We check that both source and destination "struct lguest_dma"s are
+        * within the bounds of the source and destination Guests */
        if (!check_dma_list(dstlg, dst) || !check_dma_list(srclg, src))
                return 0;
 
-       /* First get the destination pages */
+       /* We need to map the pages which correspond to each parts of
+        * destination buffer. */
        for (i = 0; i < LGUEST_MAX_DMA_SECTIONS; i++) {
                if (dst->len[i] == 0)
                        break;
+               /* get_user_pages() is a complicated function, especially since
+                * we only want a single page.  But it works, and returns the
+                * 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)
                    != 1) {
+                       /* This means the destination gave us a bogus buffer */
                        kill_guest(dstlg, "Error mapping DMA pages");
                        ret = 0;
                        goto drop_pages;
                }
        }
 
-       /* Now copy until we run out of src or dst. */
+       /* Now copy the data until we run out of src or dst. */
        ret = copy_data(srclg, src, dst, pages);
 
 drop_pages:
@@ -247,6 +395,11 @@ drop_pages:
        return ret;
 }
 
+/*L:380 Transferring data from one Guest to another is not as simple as I'd
+ * like.  We've found the "struct lguest_dma_info" bound to the same address as
+ * the send, we need to copy into it.
+ *
+ * This function returns true if the destination array was empty. */
 static int dma_transfer(struct lguest *srclg,
                        unsigned long udma,
                        struct lguest_dma_info *dst)
@@ -255,15 +408,23 @@ static int dma_transfer(struct lguest *srclg,
        struct lguest *dstlg;
        u32 i, dma = 0;
 
+       /* From the "struct lguest_dma_info" we found in the hash, grab the
+        * Guest. */
        dstlg = &lguests[dst->guestid];
-       /* Get our dma list. */
+       /* Read in the source "struct lguest_dma" handed to SEND_DMA. */
        lgread(srclg, &src_dma, udma, sizeof(src_dma));
 
-       /* We can't deadlock against them dmaing to us, because this
-        * is all under the lguest_lock. */
+       /* We need the destination's mmap_sem, and we already hold the source's
+        * mmap_sem for the futex key lookup.  Normally this would suggest that
+        * we could deadlock if the destination Guest was trying to send to
+        * this source Guest at the same time, which is another reason that all
+        * I/O is done under the big lguest_lock. */
        down_read(&dstlg->mm->mmap_sem);
 
+       /* Look through the destination DMA array for an available buffer. */
        for (i = 0; i < dst->num_dmas; i++) {
+               /* We keep a "next_dma" pointer which often helps us avoid
+                * looking at lots of previously-filled entries. */
                dma = (dst->next_dma + i) % dst->num_dmas;
                if (!lgread_other(dstlg, &dst_dma,
                                  dst->dmas + dma * sizeof(struct lguest_dma),
@@ -273,30 +434,46 @@ static int dma_transfer(struct lguest *srclg,
                if (!dst_dma.used_len)
                        break;
        }
+
+       /* If we found a buffer, we do the actual data copy. */
        if (i != dst->num_dmas) {
                unsigned long used_lenp;
                unsigned int ret;
 
                ret = do_dma(srclg, &src_dma, dstlg, &dst_dma);
-               /* Put used length in src. */
+               /* Put used length in the source "struct lguest_dma"'s used_len
+                * field.  It's a little tricky to figure out where that is,
+                * though. */
                lgwrite_u32(srclg,
                            udma+offsetof(struct lguest_dma, used_len), ret);
+               /* Tranferring 0 bytes is OK if the source buffer was empty. */
                if (ret == 0 && src_dma.len[0] != 0)
                        goto fail;
 
-               /* Make sure destination sees contents before length. */
+               /* The destination Guest might be running on a different CPU:
+                * we have to make sure that it will see the "used_len" field
+                * change to non-zero *after* it sees the data we copied into
+                * the buffer.  Hence a write memory barrier. */
                wmb();
+               /* Figuring out where the destination's used_len field for this
+                * "struct lguest_dma" in the array is also a little ugly. */
                used_lenp = dst->dmas
                        + dma * sizeof(struct lguest_dma)
                        + offsetof(struct lguest_dma, used_len);
                lgwrite_other(dstlg, used_lenp, &ret, sizeof(ret));
+               /* Move the cursor for next time. */
                dst->next_dma++;
        }
        up_read(&dstlg->mm->mmap_sem);
 
-       /* Do this last so dst doesn't simply sleep on lock. */
+       /* We trigger the destination interrupt, even if the destination was
+        * empty and we didn't transfer anything: this gives them a chance to
+        * wake up and refill. */
        set_bit(dst->interrupt, dstlg->irqs_pending);
+       /* Wake up the destination process. */
        wake_up_process(dstlg->tsk);
+       /* If we passed the last "struct lguest_dma", the receive had no
+        * buffers left. */
        return i == dst->num_dmas;
 
 fail:
@@ -304,6 +481,8 @@ fail:
        return 0;
 }
 
+/*L:370 This is the counter-side to the BIND_DMA hypercall; the SEND_DMA
+ * hypercall.  We find out who's listening, and send to them. */
 void send_dma(struct lguest *lg, unsigned long ukey, unsigned long udma)
 {
        union futex_key key;
@@ -313,31 +492,43 @@ void send_dma(struct lguest *lg, unsigned long ukey, unsigned long udma)
 again:
        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) {
                kill_guest(lg, "bad sending DMA key");
                goto unlock;
        }
-       /* Shared mapping?  Look for other guests... */
+       /* Since the key must be a multiple of 4, the futex key uses the lower
+        * bit of the "offset" field (which would always be 0) to indicate a
+        * mapping which is shared with other processes (ie. Guests). */
        if (key.shared.offset & 1) {
                struct lguest_dma_info *i;
+               /* Look through the hash for other Guests. */
                list_for_each_entry(i, &dma_hash[hash(&key)], list) {
+                       /* Don't send to ourselves. */
                        if (i->guestid == lg->guestid)
                                continue;
                        if (!key_eq(&key, &i->key))
                                continue;
 
+                       /* If dma_transfer() tells us the destination has no
+                        * available buffers, we increment "empty". */
                        empty += dma_transfer(lg, udma, i);
                        break;
                }
+               /* If the destination is empty, we release our locks and
+                * give the destination Guest a brief chance to restock. */
                if (empty == 1) {
                        /* Give any recipients one chance to restock. */
                        up_read(&current->mm->mmap_sem);
                        mutex_unlock(&lguest_lock);
+                       /* Next time, we won't try again. */
                        empty++;
                        goto again;
                }
        } else {
-               /* Private mapping: tell our userspace. */
+               /* Private mapping: Guest is sending to its Launcher.  We set
+                * the "dma_is_pending" flag so that the main loop will exit
+                * and the Launcher's read() from /dev/lguest will return. */