[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [PATCH]: Implement bzip2 and LZMA loaders / fixed patch for Xen 3.4.1



On Thu, Aug 13, 2009 at 09:47:27AM +0200, Chris Lalancette wrote:
> All,
>      Recent upstream kernels can be compressed using either gzip, bzip2, or
> LZMA.  However, the PV kernel loader in Xen currently only understands gzip, 
> and
> will fail on the other two types.  The attached patch implements kernel
> decompression for gzip, bzip2, and LZMA so that kernels compressed with any of
> these methods can be launched.  Note that the patch is still a little bit 
> rough,
> but I thought I would post it to get feedback about what I'm doing wrong.
>      I developed this against the RHEL-5 version of the xen tools, but a quick
> look through xen-unstable shows that this should apply pretty easily to the
> current code.
> 

Attached are two patches:

- Patch by Chris modified to apply to Xen 3.4.1 (only a small Makefile change)
- Patch by me to fix compilation with gcc 4.4.0.

-- Pasi

> Signed-off-by: Chris Lalancette <clalance@xxxxxxxxxx>

> diff -urp xen-3.1.0-src/tools/libxc/Makefile 
> xen-3.1.0-src.working/tools/libxc/Makefile
> --- xen-3.1.0-src/tools/libxc/Makefile        2009-08-13 03:03:55.000000000 
> -0400
> +++ xen-3.1.0-src.working/tools/libxc/Makefile        2009-08-12 
> 11:56:38.000000000 -0400
> @@ -161,7 +161,7 @@ libxenguest.so.$(MAJOR): libxenguest.so.
>       ln -sf $< $@
>  
>  libxenguest.so.$(MAJOR).$(MINOR): $(GUEST_PIC_OBJS) libxenctrl.so
> -     $(CC) $(CFLAGS) $(LDFLAGS) -Wl,$(SONAME_LDFLAG) 
> -Wl,libxenguest.so.$(MAJOR) $(SHLIB_CFLAGS) -o $@ $(GUEST_PIC_OBJS) -lz 
> -lxenctrl -lpthread
> +     $(CC) $(CFLAGS) $(LDFLAGS) -Wl,$(SONAME_LDFLAG) 
> -Wl,libxenguest.so.$(MAJOR) $(SHLIB_CFLAGS) -o $@ $(GUEST_PIC_OBJS) -lz 
> -llzma -lbz2 -lxenctrl -lpthread
>  
>  -include $(DEPS)
>  
> diff -urp xen-3.1.0-src/tools/libxc/xc_dom_bzimageloader.c 
> xen-3.1.0-src.working/tools/libxc/xc_dom_bzimageloader.c
> --- xen-3.1.0-src/tools/libxc/xc_dom_bzimageloader.c  2009-08-13 
> 03:03:55.000000000 -0400
> +++ xen-3.1.0-src.working/tools/libxc/xc_dom_bzimageloader.c  2009-08-13 
> 03:06:19.000000000 -0400
> @@ -11,15 +11,208 @@
>   * written 2006 by Gerd Hoffmann <kraxel@xxxxxxx>.
>   * written 2007 by Jeremy Fitzhardinge <jeremy@xxxxxxxxxxxxx>
>   * written 2008 by Ian Campbell <ijc@xxxxxxxxxxxxxx>
> + * written 2009 by Chris Lalancette <clalance@xxxxxxxxxx>
>   *
>   */
>  #include <stdio.h>
>  #include <stdlib.h>
>  #include <inttypes.h>
> +#include <bzlib.h>
> +#include <lzma.h>
>  
>  #include "xg_private.h"
>  #include "xc_dom.h"
>  
> +static inline uint64_t physmem(void)
> +{
> +     uint64_t ret = 0;
> +
> +     const long pagesize = sysconf(_SC_PAGESIZE);
> +     const long pages = sysconf(_SC_PHYS_PAGES);
> +     if (pagesize != -1 || pages != -1)
> +             // According to docs, pagesize * pages can overflow.
> +             // Simple case is 32-bit box with 4 GiB or more RAM,
> +             // which may report exactly 4 GiB of RAM, and "long"
> +             // being 32-bit will overflow. Casting to uint64_t
> +             // hopefully avoids overflows in the near future.
> +             ret = (uint64_t)(pagesize) * (uint64_t)(pages);
> +
> +    return ret;
> +}
> +
> +static int xc_try_bzip2_decode(struct xc_dom_image *dom, void **blob, size_t 
> *size)
> +{
> +    bz_stream stream;
> +    int ret;
> +    char *out_buf;
> +    int retval = -1;
> +    int outsize;
> +    uint64_t total;
> +
> +    stream.bzalloc = NULL;
> +    stream.bzfree = NULL;
> +    stream.opaque = NULL;
> +
> +    ret = BZ2_bzDecompressInit(&stream, 0, 0);
> +    if (ret != BZ_OK) {
> +        xc_dom_printf("Error initting bz2 stream\n");
> +        return -1;
> +    }
> +
> +    /* sigh.  We don't know up-front how much memory we are going to need
> +     * for the output buffer.  Allocate the output buffer to be equal
> +     * the input buffer to start, and we'll realloc as needed.
> +     */
> +    outsize = dom->kernel_size;
> +    out_buf = malloc(outsize);
> +    if (out_buf == NULL) {
> +        xc_dom_printf("Failed to alloc memory\n");
> +        goto bzip2_cleanup;
> +    }
> +
> +    stream.next_in = dom->kernel_blob;
> +    stream.avail_in = dom->kernel_size;
> +
> +    stream.next_out = out_buf;
> +    stream.avail_out = dom->kernel_size;
> +
> +    while (1) {
> +        ret = BZ2_bzDecompress(&stream);
> +        if (stream.avail_out == 0 || ret != BZ_OK) {
> +            out_buf = realloc(out_buf, outsize * 2);
> +            if (out_buf == NULL) {
> +                xc_dom_printf("Failed to realloc memory\n");
> +                break;
> +            }
> +
> +            stream.next_out = out_buf + outsize;
> +            stream.avail_out = (outsize * 2) - outsize;
> +            outsize *= 2;
> +        }
> +
> +        if (ret != BZ_OK) {
> +            if (ret == BZ_STREAM_END) {
> +                xc_dom_printf("Saw data stream end\n");
> +                retval = 0;
> +                break;
> +            }
> +            xc_dom_printf("BZIP error\n");
> +        }
> +    }
> +
> +    total = (stream.total_out_hi32 << 31) | stream.total_out_lo32;
> +
> +    xc_dom_printf("%s: BZIP2 decompress OK, 0x%zx -> 0x%lx\n", __FUNCTION__, 
> *size, total);
> +
> +    *blob = out_buf;
> +    *size = total;
> +
> +bzip2_cleanup:
> +    BZ2_bzDecompressEnd(&stream);
> +
> +    return retval;
> +}
> +
> +static int xc_try_lzma_decode(struct xc_dom_image *dom, void **blob, size_t 
> *size)
> +{
> +    lzma_stream stream = LZMA_STREAM_INIT;
> +    lzma_ret ret;
> +    lzma_action action = LZMA_RUN;
> +    unsigned char *out_buf;
> +    int retval = -1;
> +    int outsize;
> +    const char *msg;
> +
> +    ret = lzma_alone_decoder(&stream, physmem() / 3);
> +    if (ret != LZMA_OK) {
> +        xc_dom_printf("Failed to init lzma stream decoder\n");
> +        return -1;
> +    }
> +
> +    /* sigh.  We don't know up-front how much memory we are going to need
> +     * for the output buffer.  Allocate the output buffer to be equal
> +     * the input buffer to start, and we'll realloc as needed.
> +     */
> +    outsize = dom->kernel_size;
> +    out_buf = malloc(outsize);
> +    if (out_buf == NULL) {
> +        xc_dom_printf("Failed to alloc memory\n");
> +        goto lzma_cleanup;
> +    }
> +
> +    stream.next_in = dom->kernel_blob;
> +    stream.avail_in = dom->kernel_size;
> +
> +    stream.next_out = out_buf;
> +    stream.avail_out = dom->kernel_size;
> +
> +    while (1) {
> +        ret = lzma_code(&stream, action);
> +        if (stream.avail_out == 0 || ret != LZMA_OK) {
> +            out_buf = realloc(out_buf, outsize * 2);
> +            if (out_buf == NULL) {
> +                xc_dom_printf("Failed to realloc memory\n");
> +                break;
> +            }
> +
> +            stream.next_out = out_buf + outsize;
> +            stream.avail_out = (outsize * 2) - outsize;
> +            outsize *= 2;
> +        }
> +
> +        if (ret != LZMA_OK) {
> +            if (ret == LZMA_STREAM_END) {
> +                xc_dom_printf("Saw data stream end\n");
> +                retval = 0;
> +                break;
> +            }
> +
> +            switch (ret) {
> +            case LZMA_MEM_ERROR:
> +                msg = strerror(ENOMEM);
> +                break;
> +
> +            case LZMA_MEMLIMIT_ERROR:
> +                msg = "Memory usage limit reached";
> +                break;
> +
> +            case LZMA_FORMAT_ERROR:
> +                msg = "File format not recognized";
> +                break;
> +
> +            case LZMA_OPTIONS_ERROR:
> +                // FIXME: Better message?
> +                msg = "Unsupported compression options";
> +                break;
> +
> +            case LZMA_DATA_ERROR:
> +                msg = "File is corrupt";
> +                break;
> +
> +            case LZMA_BUF_ERROR:
> +                msg = "Unexpected end of input";
> +                break;
> +
> +            default:
> +                msg = "Internal program error (bug)";
> +                break;
> +            }
> +            xc_dom_printf("%s: LZMA decompression error %s\n", __FUNCTION__, 
> msg);
> +            break;
> +        }
> +    }
> +
> +    xc_dom_printf("%s: LZMA decompress OK, 0x%zx -> 0x%zx\n", __FUNCTION__, 
> *size, stream.total_out);
> +
> +    *blob = out_buf;
> +    *size = stream.total_out;
> +
> + lzma_cleanup:
> +    lzma_end(&stream);
> +
> +    return retval;
> +}
> +
>  struct setup_header {
>       uint8_t         _pad0[0x1f1];           /* skip uninteresting stuff */
>       uint8_t         setup_sects;
> @@ -70,22 +263,22 @@ static unsigned int payload_offset(struc
>      return off;
>  }
>  
> -static int check_bzimage_kernel(struct xc_dom_image *dom, int verbose)
> +static int xc_dom_probe_bzimage_kernel(struct xc_dom_image *dom)
>  {
>      struct setup_header *hdr;
> +    int ret;
>  
>      if ( dom->kernel_blob == NULL )
>      {
> -        if ( verbose )
> -            xc_dom_panic(XC_INTERNAL_ERROR, "%s: no kernel image loaded\n",
> -                         __FUNCTION__);
> +        xc_dom_panic(XC_INTERNAL_ERROR, "%s: no kernel image loaded\n",
> +                     __FUNCTION__);
>          return -EINVAL;
>      }
> +
>      if ( dom->kernel_size < sizeof(struct setup_header) )
>      {
> -        if ( verbose )
> -            xc_dom_panic(XC_INTERNAL_ERROR, "%s: kernel image too small\n",
> -                         __FUNCTION__);
> +        xc_dom_panic(XC_INTERNAL_ERROR, "%s: kernel image too small\n",
> +                     __FUNCTION__);
>          return -EINVAL;
>      }
>  
> @@ -93,39 +286,54 @@ static int check_bzimage_kernel(struct x
>  
>      if ( memcmp(&hdr->header, HDR_MAGIC, HDR_MAGIC_SZ) != 0 )
>      {
> -        if ( verbose )
> -            xc_dom_panic(XC_INVALID_KERNEL, "%s: kernel is not a bzImage\n",
> -                         __FUNCTION__);
> +        xc_dom_panic(XC_INVALID_KERNEL, "%s: kernel is not a bzImage\n",
> +                     __FUNCTION__);
>          return -EINVAL;
>      }
>  
>      if ( hdr->version < VERSION(2,8) )
>      {
> -        if ( verbose )
> -            xc_dom_panic(XC_INVALID_KERNEL, "%s: boot protocol too old 
> (%04x)\n",
> -                         __FUNCTION__, hdr->version);
> +        xc_dom_panic(XC_INVALID_KERNEL, "%s: boot protocol too old (%04x)\n",
> +                     __FUNCTION__, hdr->version);
>          return -EINVAL;
>      }
>  
>      dom->kernel_blob = dom->kernel_blob + payload_offset(hdr);
>      dom->kernel_size = hdr->payload_length;
>  
> -    if ( xc_dom_try_gunzip(dom, &dom->kernel_blob, &dom->kernel_size) == -1 )
> -    {
> -        if ( verbose )
> -            xc_dom_panic(XC_INVALID_KERNEL, "%s: unable to decompress 
> kernel\n",
> +    if (memcmp(dom->kernel_blob, "\037\213", 2) == 0) {
> +        ret = xc_dom_try_gunzip(dom, &dom->kernel_blob, &dom->kernel_size);
> +        if (ret == -1) {
> +            xc_dom_panic(XC_INVALID_KERNEL, "%s: unable to gzip decompress 
> kernel\n",
> +                         __FUNCTION__);
> +            return -EINVAL;
> +        }
> +    }
> +    else if (memcmp(dom->kernel_blob, "\102\132\150", 3) == 0) {
> +        ret = xc_try_bzip2_decode(dom, &dom->kernel_blob, &dom->kernel_size);
> +        if (ret < 0) {
> +            xc_dom_panic(XC_INVALID_KERNEL, "%s unable to BZIP2 decompress 
> kernel",
> +                         __FUNCTION__);
> +            return -EINVAL;
> +        }
> +    }
> +    else if (memcmp(dom->kernel_blob, "\135\000", 2) == 0) {
> +        ret = xc_try_lzma_decode(dom, &dom->kernel_blob, &dom->kernel_size);
> +        if (ret < 0) {
> +            xc_dom_panic(XC_INVALID_KERNEL, "%s unable to LZMA decompress 
> kernel\n",
>                           __FUNCTION__);
> +            return -EINVAL;
> +        }
> +    }
> +    else {
> +        xc_dom_panic(XC_INVALID_KERNEL, "%s: unknown compression format\n",
> +                     __FUNCTION__);
>          return -EINVAL;
>      }
>  
>      return elf_loader.probe(dom);
>  }
>  
> -static int xc_dom_probe_bzimage_kernel(struct xc_dom_image *dom)
> -{
> -    return check_bzimage_kernel(dom, 0);
> -}
> -
>  static int xc_dom_parse_bzimage_kernel(struct xc_dom_image *dom)
>  {
>      return elf_loader.parser(dom);

> _______________________________________________
> Xen-devel mailing list
> Xen-devel@xxxxxxxxxxxxxxxxxxx
> http://lists.xensource.com/xen-devel

Attachment: xen-loader-bzip2-lzma-xen34-fixed.patch
Description: Text Data

Attachment: xen-loader-bzip2-lzma-xen34-fixed-compilefix-gcc440.patch
Description: Text Data

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.