lkml.org 
[lkml]   [2007]   [Oct]   [2]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Subject[PATCH 5/5] lguest: loading bzImage directly
    From
    Date
    Now arch/i386/boot/compressed/head.S understands the hardware_platform field,
    we can directly execute bzImages. No more horrific unpacking code.

    Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
    ---
    Documentation/lguest/lguest.c | 97 ++++++++++++--------------------------
    arch/i386/boot/compressed/head.S | 6 ++
    drivers/lguest/lguest.c | 5 +
    3 files changed, 42 insertions(+), 66 deletions(-)

    diff -r b0480fd71a72 Documentation/lguest/lguest.c
    --- a/Documentation/lguest/lguest.c Tue Oct 02 22:28:13 2007 +1000
    +++ b/Documentation/lguest/lguest.c Tue Oct 02 22:52:07 2007 +1000
    @@ -326,74 +326,39 @@ static unsigned long map_elf(int elf_fd,
    return ehdr->e_entry;
    }

    -/*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)
    -{
    - 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 = from_guest_phys(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);
    -
    - /* The entry point for a bzImage is always the first byte */
    - return (unsigned long)img;
    -}
    -
    /*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. */
    + * 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.
    + *
    + * 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 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);
    - }
    - }
    - errx(1, "Could not find kernel in bzImage");
    + u8 hdr[1024];
    + int r;
    + /* Modern bzImages get loaded at 1M. */
    + void *p = from_guest_phys(0x100000);
    +
    + /* Go back to the start of the file and read the header. It should be
    + * a Linux boot header (see Documentation/i386/boot.txt) */
    + lseek(fd, 0, SEEK_SET);
    + read(fd, hdr, sizeof(hdr));
    +
    + /* At offset 0x202, we expect the magic "HdrS" */
    + if (memcmp(hdr + 0x202, "HdrS", 4) != 0)
    + errx(1, "This doesn't look like a bzImage to me");
    +
    + /* The byte at 0x1F1 tells us how many extra sectors of
    + * header: skip over them all. */
    + lseek(fd, (unsigned long)(hdr[0x1F1]+1) * 512, SEEK_SET);
    +
    + /* Now read everything into memory. in nice big chunks. */
    + while ((r = read(fd, p, 65536)) > 0)
    + p += r;
    +
    + /* Finally, 0x214 tells us where to start the kernel. */
    + return *(unsigned long *)&hdr[0x214];
    }

    /*L:140 Loading the kernel is easy when it's a "vmlinux", but most kernels

    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

    \
     
     \ /
      Last update: 2007-10-03 01:43    [W:0.026 / U:29.816 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site