projects/linux·commit 0d681009

Merge git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux-2.6-lguest

0d681009 · Linus Torvalds <[email protected]> · 2007-10-23 09:03:07 -07:00

* git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux-2.6-lguest: (45 commits)
  Use "struct boot_params" in example launcher
  Loading bzImage directly.
  Revert lguest magic and use hook in head.S
  Update lguest documentation to reflect the new virtual block device name.
  generalize lgread_u32/lgwrite_u32.
  Example launcher handle guests not being ready for input
  Update example launcher for virtio
  Lguest support for Virtio
  Remove old lguest I/O infrrasructure.
  Remove old lguest bus and drivers.
  Virtio helper routines for a descriptor ringbuffer implementation
  Module autoprobing support for virtio drivers.
  Virtio console driver
  Block driver using virtio.
  Net driver using virtio
  Virtio interface
  Boot with virtual == physical to get closer to native Linux.
  Allow guest to specify syscall vector to use.
  Rename "cr3" to "gpgdir" to avoid x86-specific naming.
  Pagetables to use normal kernel types
  ...
Commit
0d6810091cdbd05efeb31654c6a41a6cbdfdd2c8
Parents
a98ce5c6 · 43d33b21

Merge commit. Changes below are compared with the first parent: a98ce5c6.

Changes

70 files changed · +4822 −4401

FileStatusAddDelContent
Documentation/lguest/Makefilemodified+3−23View file
Documentation/lguest/lguest.cmodified+882−747View file
Documentation/lguest/lguest.txtmodified+31−41View file
arch/i386/Kconfigmodified+22−10View file
arch/i386/Makefilemodified+3−0View file
arch/x86/kernel/asm-offsets_32.cmodified+1−0View file
arch/x86/lguest/Kconfigadded+14−0View file
arch/x86/lguest/Makefileadded+1−0View file
drivers/lguest/lguest.c → arch/x86/lguest/boot.crenamed+32−70View file
drivers/lguest/lguest_asm.S → arch/x86/lguest/i386_head.Srenamed+34−12View file
arch/x86/xen/Kconfigmodified+3−2View file
drivers/Kconfigmodified+1−1View file
drivers/Makefilemodified+1−0View file
drivers/block/Kconfigmodified+6−0View file
drivers/block/Makefilemodified+1−1View file
drivers/block/lguest_blk.cdeleted+0−421View before deletion
drivers/block/virtio_blk.cadded+308−0View file
drivers/char/Kconfigmodified+4−0View file
drivers/char/Makefilemodified+1−1View file
drivers/char/hvc_lguest.cdeleted+0−177View before deletion
drivers/char/virtio_console.cadded+225−0View file
drivers/kvm/Kconfigmodified+4−0View file
drivers/lguest/Kconfigmodified+1−12View file
drivers/lguest/Makefilemodified+6−4View file
drivers/lguest/core.cmodified+51−517View file
drivers/lguest/hypercalls.cmodified+58−119View file
drivers/lguest/interrupts_and_traps.cmodified+83−42View file
drivers/lguest/io.cdeleted+0−626View before deletion
drivers/lguest/lg.hmodified+57−132View file
drivers/lguest/lguest_bus.cdeleted+0−218View before deletion
drivers/lguest/lguest_device.cadded+373−0View file
drivers/lguest/lguest_user.cmodified+33−105View file
drivers/lguest/page_tables.cmodified+136−114View file
drivers/lguest/segments.cmodified+14−14View file
drivers/lguest/x86/core.cadded+577−0View file
drivers/lguest/switcher.S → drivers/lguest/x86/switcher_32.Srenamed+4−3View file
drivers/net/Kconfigmodified+6−0View file
drivers/net/Makefilemodified+1−1View file
drivers/net/lguest_net.cdeleted+0−555View before deletion
drivers/net/virtio_net.cadded+435−0View file
drivers/virtio/Kconfigadded+8−0View file
drivers/virtio/Makefileadded+2−0View file
drivers/virtio/config.cadded+13−0View file
drivers/virtio/virtio.cadded+189−0View file
drivers/virtio/virtio_ring.cadded+313−0View file
include/asm-x86/Kbuildmodified+3−0View file
include/asm-x86/bootparam.hmodified+54−54View file
include/asm-x86/e820.hmodified+28−0View file
include/asm-x86/e820_32.hmodified+0−21View file
include/asm-x86/e820_64.hmodified+0−20View file
include/asm-x86/ist.hmodified+6−6View file
include/asm-x86/lguest.hadded+86−0View file
include/asm-x86/lguest_hcall.hadded+71−0View file
include/linux/Kbuildmodified+5−0View file
include/linux/apm_bios.hmodified+15−15View file
include/linux/edd.hmodified+69−68View file
include/linux/lguest.hmodified+12−68View file
include/linux/lguest_bus.hdeleted+0−51View before deletion
include/linux/lguest_launcher.hmodified+22−90View file
include/linux/mod_devicetable.hmodified+6−0View file
include/linux/screen_info.hmodified+46−35View file
include/linux/virtio.hadded+110−0View file
include/linux/virtio_blk.hadded+51−0View file
include/linux/virtio_config.hadded+111−0View file
include/linux/virtio_console.hadded+12−0View file
include/linux/virtio_net.hadded+36−0View file
include/linux/virtio_ring.hadded+119−0View file
include/video/Kbuildmodified+1−0View file
include/video/edid.hmodified+4−5View file
scripts/mod/file2alias.cmodified+18−0View file

Only the first 600 diff lines are shown. Download the complete patch.

Documentation/lguest/Makefile

View file
diff --git a/Documentation/lguest/Makefile b/Documentation/lguest/Makefile
index c0b7a45..bac037e 100644
--- a/Documentation/lguest/Makefile
+++ b/Documentation/lguest/Makefile
@@ -1,28 +1,8 @@
# This creates the demonstration utility "lguest" which runs a Linux guest.
-
-# For those people that have a separate object dir, look there for .config
-KBUILD_OUTPUT := ../..
-ifdef O
- ifeq ("$(origin O)", "command line")
- KBUILD_OUTPUT := $(O)
- endif
-endif
-# We rely on CONFIG_PAGE_OFFSET to know where to put lguest binary.
-include $(KBUILD_OUTPUT)/.config
-LGUEST_GUEST_TOP := ($(CONFIG_PAGE_OFFSET) - 0x08000000)
-
-CFLAGS:=-Wall -Wmissing-declarations -Wmissing-prototypes -O3 -Wl,-T,lguest.lds
+CFLAGS:=-Wall -Wmissing-declarations -Wmissing-prototypes -O3 -I../../include
LDLIBS:=-lz
-# Removing this works for some versions of ld.so (eg. Ubuntu Feisty) and
-# not others (eg. FC7).
-LDFLAGS+=-static
-all: lguest.lds lguest
-# The linker script on x86 is so complex the only way of creating one
-# which will link our binary in the right place is to mangle the
-# default one.
-lguest.lds:
- $(LD) --verbose | awk '/^==========/ { PRINT=1; next; } /SIZEOF_HEADERS/ { gsub(/0x[0-9A-F]*/, "$(LGUEST_GUEST_TOP)") } { if (PRINT) print $$0; }' > $@
+all: lguest
clean:
- rm -f lguest.lds lguest
+ rm -f lguest

Documentation/lguest/lguest.c

View file
diff --git a/Documentation/lguest/lguest.c b/Documentation/lguest/lguest.c
index 103e346..5bdc37f 100644
--- a/Documentation/lguest/lguest.c
+++ b/Documentation/lguest/lguest.c
@@ -1,10 +1,7 @@
/*P:100 This is the Launcher code, a simple program which lays out the
* "physical" memory for the new Guest by mapping the kernel image and the
* virtual devices, then reads repeatedly from /dev/lguest to run the Guest.
- *
- * 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>
@@ -15,6 +12,7 @@
#include <stdlib.h>
#include <elf.h>
#include <sys/mman.h>
+#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
@@ -34,7 +32,9 @@
#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
+#include <assert.h>
+#include <sched.h>
+/*L:110 We can ignore the 30 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
@@ -45,8 +45,14 @@ 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-x86/e820_32.h"
+#include "linux/lguest_launcher.h"
+#include "linux/pci_ids.h"
+#include "linux/virtio_config.h"
+#include "linux/virtio_net.h"
+#include "linux/virtio_blk.h"
+#include "linux/virtio_console.h"
+#include "linux/virtio_ring.h"
+#include "asm-x86/bootparam.h"
/*:*/
#define PAGE_PRESENT 0x7 /* Present, RW, Execute */
@@ -55,6 +61,10 @@ typedef uint8_t u8;
#ifndef SIOCBRADDIF
#define SIOCBRADDIF 0x89a2 /* add interface to bridge */
#endif
+/* We can have up to 256 pages for devices. */
+#define DEVICE_PAGES 256
+/* This fits nicely in a single 4096-byte page. */
+#define VIRTQUEUE_NUM 127
/*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. */
@@ -65,8 +75,10 @@ static bool verbose;
/* The pipe to send commands to the waker process */
static int waker_fd;
-/* The top of guest physical memory. */
-static u32 top;
+/* The pointer to the start of guest memory. */
+static void *guest_base;
+/* The maximum guest physical address allowed, and maximum possible. */
+static unsigned long guest_limit, guest_max;
/* This is our list of devices. */
struct device_list
@@ -76,8 +88,17 @@ struct device_list
fd_set infds;
int max_infd;
+ /* Counter to assign interrupt numbers. */
+ unsigned int next_irq;
+
+ /* Counter to print out convenient device numbers. */
+ unsigned int device_num;
+
/* The descriptor page for the devices. */
- struct lguest_device_desc *descs;
+ u8 *descpage;
+
+ /* The tail of the last descriptor. */
+ unsigned int desc_used;
/* A single linked list of devices. */
struct device *dev;
@@ -85,31 +106,111 @@ struct device_list
struct device **lastdev;
};
+/* The list of Guest devices, based on command line arguments. */
+static struct device_list devices;
+
/* 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. */
+
+ /* The this device's descriptor, 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;
+
+ /* The name of this device, for --verbose. */
+ const char *name;
/* 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);
- /* 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);
+ /* Any queues attached to this device */
+ struct virtqueue *vq;
/* Device-specific data. */
void *priv;
};
+/* The virtqueue structure describes a queue attached to a device. */
+struct virtqueue
+{
+ struct virtqueue *next;
+
+ /* Which device owns me. */
+ struct device *dev;
+
+ /* The configuration for this queue. */
+ struct lguest_vqconfig config;
+
+ /* The actual ring of buffers. */
+ struct vring vring;
+
+ /* Last available index we saw. */
+ u16 last_avail_idx;
+
+ /* The routine to call when the Guest pings us. */
+ void (*handle_output)(int fd, struct virtqueue *me);
+};
+
+/* Since guest is UP and we don't run at the same time, we don't need barriers.
+ * But I include them in the code in case others copy it. */
+#define wmb()
+
+/* Convert an iovec element to the given type.
+ *
+ * This is a fairly ugly trick: we need to know the size of the type and
+ * alignment requirement to check the pointer is kosher. It's also nice to
+ * have the name of the type in case we report failure.
+ *
+ * Typing those three things all the time is cumbersome and error prone, so we
+ * have a macro which sets them all up and passes to the real function. */
+#define convert(iov, type) \
+ ((type *)_convert((iov), sizeof(type), __alignof__(type), #type))
+
+static void *_convert(struct iovec *iov, size_t size, size_t align,
+ const char *name)
+{
+ if (iov->iov_len != size)
+ errx(1, "Bad iovec size %zu for %s", iov->iov_len, name);
+ if ((unsigned long)iov->iov_base % align != 0)
+ errx(1, "Bad alignment %p for %s", iov->iov_base, name);
+ return iov->iov_base;
+}
+
+/* The virtio configuration space is defined to be little-endian. x86 is
+ * little-endian too, but it's nice to be explicit so we have these helpers. */
+#define cpu_to_le16(v16) (v16)
+#define cpu_to_le32(v32) (v32)
+#define cpu_to_le64(v64) (v64)
+#define le16_to_cpu(v16) (v16)
+#define le32_to_cpu(v32) (v32)
+#define le64_to_cpu(v32) (v64)
+
+/*L:100 The Launcher code itself takes us out into userspace, that scary place
+ * where pointers run wild and free! Unfortunately, like most userspace
+ * programs, it's quite boring (which is why everyone likes to hack on the
+ * kernel!). Perhaps if you make up an Lguest Drinking Game at this point, it
+ * will get you through this section. Or, maybe not.
+ *
+ * The Launcher sets up a big chunk of memory to be the Guest's "physical"
+ * memory and stores it in "guest_base". In other words, Guest physical ==
+ * Launcher virtual with an offset.
+ *
+ * This can be tough to get your head around, but usually it just means that we
+ * use these trivial conversion functions when the Guest gives us it's
+ * "physical" addresses: */
+static void *from_guest_phys(unsigned long addr)
+{
+ return guest_base + addr;
+}
+
+static unsigned long to_guest_phys(const void *addr)
+{
+ return (addr - guest_base);
+}
+
/*L:130
* Loading the Kernel.
*
@@ -123,43 +224,55 @@ 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)
+/* map_zeroed_pages() takes a number of pages. */
+static void *map_zeroed_pages(unsigned int num)
{
- /* We cache the /dev/zero file-descriptor so we only open it once. */
- static int fd = -1;
-
- if (fd == -1)
- fd = open_or_die("/dev/zero", O_RDONLY);
+ int fd = open_or_die("/dev/zero", O_RDONLY);
+ void *addr;
/* We use a private mapping (ie. if we write to the page, it will be
- * copied), and obviously we insist that it be mapped where we ask. */
- if (mmap((void *)addr, getpagesize() * num,
- PROT_READ|PROT_WRITE|PROT_EXEC, MAP_FIXED|MAP_PRIVATE, fd, 0)
- != (void *)addr)
- err(1, "Mmaping %u pages of /dev/zero @%p", num, (void *)addr);
-
- /* Returning the address is just a courtesy: can simplify callers. */
- return (void *)addr;
+ * copied). */
+ addr = mmap(NULL, getpagesize() * num,
+ PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE, fd, 0);
+ if (addr == MAP_FAILED)
+ err(1, "Mmaping %u pages of /dev/zero", num);
+
+ return addr;
}
-/* 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)
+/* Get some more pages for a device. */
+static void *get_pages(unsigned int num)
{
- void *p;
+ void *addr = from_guest_phys(guest_limit);
- /* 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;
+ guest_limit += num * getpagesize();
+ if (guest_limit > guest_max)
+ errx(1, "Not enough memory for devices");
+ return addr;
+}
- err(1, "Is this image a genuine lguest?");
+/* This routine is used to load the kernel or initrd. It tries mmap, but if
+ * that fails (Plan 9's kernel file isn't nicely aligned on page boundaries),
+ * it falls back to reading the memory in. */
+static void map_at(int fd, void *addr, unsigned long offset, unsigned long len)
+{
+ ssize_t r;
+
+ /* We map writable even though for some segments are marked read-only.
+ * The kernel really wants to be writable: it patches its own
+ * instructions.
+ *
+ * MAP_PRIVATE means that the page won't be copied until a write is
+ * done to it. This allows us to share untouched memory between
+ * Guests. */
+ if (mmap(addr, len, PROT_READ|PROT_WRITE|PROT_EXEC,
+ MAP_FIXED|MAP_PRIVATE, fd, offset) != MAP_FAILED)
+ return;
+
+ /* pread does a seek and a read in one shot: saves a few lines. */
+ r = pread(fd, addr, len, offset);
+ if (r != len)
+ err(1, "Reading offset %lu len %lu gave %zi", offset, len, r);
}
/* This routine takes an open vmlinux image, which is in ELF, and maps it into
@@ -167,19 +280,14 @@ static unsigned long entry_point(void *start, void *end,
* 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.
+ * address. We use the physical address; the Guest will map itself to the
+ * virtual address.
*
* We return the starting address. */
-static unsigned long map_elf(int elf_fd, const Elf32_Ehdr *ehdr,
- unsigned long *page_offset)
+static unsigned long map_elf(int elf_fd, const Elf32_Ehdr *ehdr)
{
- void *addr;
Elf32_Phdr phdr[ehdr->e_phnum];
unsigned int i;
- unsigned long start = -1UL, end = 0;
/* Sanity checks on the main ELF header: an x86 executable with a
* reasonable number of correctly-sized program headers. */
@@ -199,9 +307,6 @@ static unsigned long map_elf(int elf_fd, const Elf32_Ehdr *ehdr,
if (read(elf_fd, phdr, sizeof(phdr)) != sizeof(phdr))
err(1, "Reading program headers");
- /* We don't know page_offset yet. */
- *page_offset = 0;
-
/* 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++) {
@@ -212,158 +317,53 @@ static unsigned long map_elf(int elf_fd, const Elf32_Ehdr *ehdr,
verbose("Section %i: size %i addr %p\n",
i, phdr[i].p_memsz, (void *)phdr[i].p_paddr);
- /* 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 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,
- MAP_FIXED|MAP_PRIVATE,
- elf_fd, phdr[i].p_offset);
- if (addr != (void *)phdr[i].p_paddr)
- err(1, "Mmaping vmlinux seg %i gave %p not %p",
- i, addr, (void *)phdr[i].p_paddr);
+ /* We map this section of the file at its physical address. */
+ map_at(elf_fd, from_guest_phys(phdr[i].p_paddr),
+ phdr[i].p_offset, phdr[i].p_filesz);
}
- return entry_point((void *)start, (void *)end, *page_offset);
+ /* The entry point is given in the ELF header. */
+ return ehdr->e_entry;
}
-/*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.
+/*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 used to have to
+ * perform some hairy magic because the unpacking code scared me.
*
- * This is amazingly reliable. */
-static unsigned long intuit_page_offset(unsigned char *img, unsigned long len)
+ * Fortunately, Jeremy Fitzhardinge convinced me it wasn't that hard and wrote
+ * a small patch to jump over the tricky bits in the Guest, so now we just read
+ * the funky header so we know where in the file to load, and away we go! */
+static unsigned long load_bzimage(int fd)
{
- unsigned int i, possibilities[256] = { 0 };
+ struct boot_params boot;
+ int r;
+ /* Modern bzImages get loaded at 1M. */
+ void *p = from_guest_phys(0x100000);
- for (i = 0; i + 4 < len; i++) {
- /* mov 0xXXXXXXXX,%eax */
- if (img[i] == 0xA1 && ++possibilities[img[i+4]] > 3)
- return (unsigned long)img[i+4] << 24;
- }
- errx(1, "could not determine page offset");
-}
+ /* Go back to the start of the file and read the header. It should be
+ * a Linux boot header (see Documentation/i386/boot.txt) */
+ lseek(fd, 0, SEEK_SET);
+ read(fd, &boot, sizeof(boot));
-/*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);
-}
+ /* Inside the setup_hdr, we expect the magic "HdrS" */
+ if (memcmp(&boot.hdr.header, "HdrS", 4) != 0)
+ errx(1, "This doesn't look like a bzImage to me");
-/*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;
-
- /* GZIP header is 0x1F 0x8B <method> <flags>... <compressed-by>. */
- while (read(fd, &c, 1) == 1) {
- switch (state) {
- case 0:
- if (c == 0x1F)
- state++;
- break;
- case 1:
- if (c == 0x8B)
- state++;
- else
- state = 0;
- break;
- case 2 ... 8:
- state++;
- break;
- case 9:
- /* Seek back to the start of the gzip header. */
- lseek(fd, -10, SEEK_CUR);
- /* One final check: "compressed under UNIX". */
- if (c != 0x03)
- state = -1;
- else
- return unpack_bzimage(fd, page_offset);
- }
- }
- errx(1, "Could not find kernel in bzImage");
+ /* Skip over the extra sectors of the header. */
+ lseek(fd, (boot.hdr.setup_sects+1) * 512, SEEK_SET);
+
+ /* Now read everything into memory. in nice big chunks. */
+ while ((r = read(fd, p, 65536)) > 0)
+ p += r;
+
+ /* Finally, code32_start tells us where to enter the kernel. */
+ return boot.hdr.code32_start;
}
/*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)
+static unsigned long load_kernel(int fd)
{
Elf32_Ehdr hdr;
@@ -373,10 +373,10 @@ static unsigned long load_kernel(int fd, unsigned long *page_offset)
/* 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);
+ return map_elf(fd, &hdr);
/* Otherwise we assume it's a bzImage, and try to unpack it */
- return load_bzimage(fd, page_offset);
+ return load_bzimage(fd);
}
/* This is a trivial little helper to align pages. Andi Kleen hated it because
@@ -402,59 +402,45 @@ static unsigned long load_initrd(const char *name, unsigned long mem)
int ifd;
struct stat st;
unsigned long len;
- 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. */
+ /* We map the initrd at the top of memory, but mmap wants it to be
+ * page-aligned, so we round the size up for that. */
len = page_align(st.st_size);
- /* 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);
+ map_at(ifd, from_guest_phys(mem - len), 0, st.st_size);
/* Once a file is mapped, you can close the file descriptor. It's a
* little odd, but quite useful. */

This diff is incomplete. Download the complete patch.

Documentation/lguest/lguest.txt

View file

This diff is incomplete. Download the complete patch.

arch/i386/Kconfig

View file

This diff is incomplete. Download the complete patch.

arch/i386/Makefile

View file

This diff is incomplete. Download the complete patch.

arch/x86/kernel/asm-offsets_32.c

View file

This diff is incomplete. Download the complete patch.

arch/x86/lguest/Kconfig

View file

This diff is incomplete. Download the complete patch.

arch/x86/lguest/Makefile

View file

This diff is incomplete. Download the complete patch.

arch/x86/lguest/boot.c

View file

This diff is incomplete. Download the complete patch.

arch/x86/lguest/i386_head.S

View file

This diff is incomplete. Download the complete patch.

arch/x86/xen/Kconfig

View file

This diff is incomplete. Download the complete patch.

drivers/Kconfig

View file

This diff is incomplete. Download the complete patch.

drivers/Makefile

View file

This diff is incomplete. Download the complete patch.

drivers/block/Kconfig

View file

This diff is incomplete. Download the complete patch.

drivers/block/Makefile

View file

This diff is incomplete. Download the complete patch.

drivers/block/lguest_blk.c

View before deletion

This diff is incomplete. Download the complete patch.

drivers/block/virtio_blk.c

View file

This diff is incomplete. Download the complete patch.

drivers/char/Kconfig

View file

This diff is incomplete. Download the complete patch.

drivers/char/Makefile

View file

This diff is incomplete. Download the complete patch.

drivers/char/hvc_lguest.c

View before deletion

This diff is incomplete. Download the complete patch.

drivers/char/virtio_console.c

View file

This diff is incomplete. Download the complete patch.

drivers/kvm/Kconfig

View file

This diff is incomplete. Download the complete patch.

drivers/lguest/Kconfig

View file

This diff is incomplete. Download the complete patch.

drivers/lguest/Makefile

View file

This diff is incomplete. Download the complete patch.

drivers/lguest/core.c

View file

This diff is incomplete. Download the complete patch.

drivers/lguest/hypercalls.c

View file

This diff is incomplete. Download the complete patch.

drivers/lguest/interrupts_and_traps.c

View file

This diff is incomplete. Download the complete patch.

drivers/lguest/io.c

View before deletion

This diff is incomplete. Download the complete patch.

drivers/lguest/lg.h

View file

This diff is incomplete. Download the complete patch.

drivers/lguest/lguest_bus.c

View before deletion

This diff is incomplete. Download the complete patch.

drivers/lguest/lguest_device.c

View file

This diff is incomplete. Download the complete patch.

drivers/lguest/lguest_user.c

View file

This diff is incomplete. Download the complete patch.

drivers/lguest/page_tables.c

View file

This diff is incomplete. Download the complete patch.

drivers/lguest/segments.c

View file

This diff is incomplete. Download the complete patch.

drivers/lguest/x86/core.c

View file

This diff is incomplete. Download the complete patch.

drivers/lguest/x86/switcher_32.S

View file

This diff is incomplete. Download the complete patch.

drivers/net/Kconfig

View file

This diff is incomplete. Download the complete patch.

drivers/net/Makefile

View file

This diff is incomplete. Download the complete patch.

drivers/net/lguest_net.c

View before deletion

This diff is incomplete. Download the complete patch.

drivers/net/virtio_net.c

View file

This diff is incomplete. Download the complete patch.

drivers/virtio/Kconfig

View file

This diff is incomplete. Download the complete patch.

drivers/virtio/Makefile

View file

This diff is incomplete. Download the complete patch.

drivers/virtio/config.c

View file

This diff is incomplete. Download the complete patch.

drivers/virtio/virtio.c

View file

This diff is incomplete. Download the complete patch.

drivers/virtio/virtio_ring.c

View file

This diff is incomplete. Download the complete patch.

include/asm-x86/Kbuild

View file

This diff is incomplete. Download the complete patch.

include/asm-x86/bootparam.h

View file

This diff is incomplete. Download the complete patch.

include/asm-x86/e820.h

View file

This diff is incomplete. Download the complete patch.

include/asm-x86/e820_32.h

View file

This diff is incomplete. Download the complete patch.

include/asm-x86/e820_64.h

View file

This diff is incomplete. Download the complete patch.

include/asm-x86/ist.h

View file

This diff is incomplete. Download the complete patch.

include/asm-x86/lguest.h

View file

This diff is incomplete. Download the complete patch.

include/asm-x86/lguest_hcall.h

View file

This diff is incomplete. Download the complete patch.

include/linux/Kbuild

View file

This diff is incomplete. Download the complete patch.

include/linux/apm_bios.h

View file

This diff is incomplete. Download the complete patch.

include/linux/edd.h

View file

This diff is incomplete. Download the complete patch.

include/linux/lguest.h

View file

This diff is incomplete. Download the complete patch.

include/linux/lguest_bus.h

View before deletion

This diff is incomplete. Download the complete patch.

include/linux/lguest_launcher.h

View file

This diff is incomplete. Download the complete patch.

include/linux/mod_devicetable.h

View file

This diff is incomplete. Download the complete patch.

include/linux/screen_info.h

View file

This diff is incomplete. Download the complete patch.

include/linux/virtio.h

View file

This diff is incomplete. Download the complete patch.

include/linux/virtio_blk.h

View file

This diff is incomplete. Download the complete patch.

include/linux/virtio_config.h

View file

This diff is incomplete. Download the complete patch.

include/linux/virtio_console.h

View file

This diff is incomplete. Download the complete patch.

include/linux/virtio_net.h

View file

This diff is incomplete. Download the complete patch.

include/linux/virtio_ring.h

View file

This diff is incomplete. Download the complete patch.

include/video/Kbuild

View file

This diff is incomplete. Download the complete patch.

include/video/edid.h

View file

This diff is incomplete. Download the complete patch.

scripts/mod/file2alias.c

View file

This diff is incomplete. Download the complete patch.