All of lore.kernel.org
 help / color / mirror / Atom feed
From: Chris Lalancette <clalance@redhat.com>
To: "xen-devel@lists.xensource.com" <xen-devel@lists.xensource.com>
Subject: [PATCH]: Implement bzip2 and LZMA loaders
Date: Thu, 13 Aug 2009 09:47:27 +0200	[thread overview]
Message-ID: <4A83C50F.1070005@redhat.com> (raw)

[-- Attachment #1: Type: text/plain, Size: 692 bytes --]

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.

Signed-off-by: Chris Lalancette <clalance@redhat.com>

[-- Attachment #2: xen-loader-bzip2-lzma.patch --]
[-- Type: text/x-patch, Size: 10446 bytes --]

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@suse.de>.
  * written 2007 by Jeremy Fitzhardinge <jeremy@xensource.com>
  * written 2008 by Ian Campbell <ijc@hellion.org.uk>
+ * written 2009 by Chris Lalancette <clalance@redhat.com>
  *
  */
 #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);

[-- Attachment #3: Type: text/plain, Size: 138 bytes --]

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

             reply	other threads:[~2009-08-13  7:47 UTC|newest]

Thread overview: 29+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-08-13  7:47 Chris Lalancette [this message]
2009-08-20 18:34 ` [PATCH]: Implement bzip2 and LZMA loaders / fixed patch for Xen 3.4.1 Pasi Kärkkäinen
2009-08-20 20:14   ` Pasi Kärkkäinen
2009-08-20 21:15     ` Keir Fraser
2009-08-20 21:27       ` Keir Fraser
2009-08-21  9:22         ` Pasi Kärkkäinen
2009-08-21  9:38           ` Keir Fraser
2009-08-21  9:42             ` Chris Lalancette
2009-08-21  9:45               ` Pasi Kärkkäinen
2009-08-21  9:43             ` Keir Fraser
2009-08-21  9:44           ` Pasi Kärkkäinen
2009-08-21  9:43     ` Gerd Hoffmann
2009-08-21  9:49       ` Pasi Kärkkäinen
2009-08-21  9:54         ` Keir Fraser
2009-08-21 10:13           ` Keir Fraser
2009-08-21 10:57             ` Pasi Kärkkäinen
2009-08-21 13:09               ` Keir Fraser
2009-08-21 14:01                 ` Pasi Kärkkäinen
2009-08-21 15:03                   ` Pasi Kärkkäinen
2009-08-21 15:06                     ` Pasi Kärkkäinen
2009-08-21 15:58                   ` Keir Fraser
2009-08-21 20:12             ` Pasi Kärkkäinen
2009-08-21 21:22               ` Pasi Kärkkäinen
2009-08-22  6:56                 ` Keir Fraser
2009-08-24 14:04                 ` Stefano Stabellini
2009-08-25 15:23                   ` Pasi Kärkkäinen
2009-09-01 19:08                     ` [PATCH]: Implement bzip2 and LZMA loaders / xen-unstable stubdom pvgrub support Pasi Kärkkäinen
2009-10-08 20:08                       ` Pasi Kärkkäinen
2009-10-13 16:17                         ` Stefano Stabellini

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4A83C50F.1070005@redhat.com \
    --to=clalance@redhat.com \
    --cc=xen-devel@lists.xensource.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.