aboutsummaryrefslogtreecommitdiffstats
path: root/xen/arch/x86/bzimage.c
diff options
context:
space:
mode:
authorKeir Fraser <keir.fraser@citrix.com>2009-01-22 18:00:48 +0000
committerKeir Fraser <keir.fraser@citrix.com>2009-01-22 18:00:48 +0000
commite2b1ebf4de503eef701bf122362355ec11af34f3 (patch)
tree504ff98b3f0a7fcfc8a8c9cbda62e84ba4d48f49 /xen/arch/x86/bzimage.c
parent85952ca7cefe27cdf13e1c24571d964708b876dc (diff)
downloadxen-e2b1ebf4de503eef701bf122362355ec11af34f3.tar.gz
xen-e2b1ebf4de503eef701bf122362355ec11af34f3.tar.bz2
xen-e2b1ebf4de503eef701bf122362355ec11af34f3.zip
x86: Support booting a bzImage format domain 0 kernel.
This requires a bzImage v2.08 or later kernel. xen/common/inflate.c is taken unmodified from Linux v2.6.28. Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
Diffstat (limited to 'xen/arch/x86/bzimage.c')
-rw-r--r--xen/arch/x86/bzimage.c242
1 files changed, 242 insertions, 0 deletions
diff --git a/xen/arch/x86/bzimage.c b/xen/arch/x86/bzimage.c
new file mode 100644
index 0000000000..f8a64e4360
--- /dev/null
+++ b/xen/arch/x86/bzimage.c
@@ -0,0 +1,242 @@
+#include <xen/cache.h>
+#include <xen/errno.h>
+#include <xen/lib.h>
+#include <xen/mm.h>
+#include <xen/string.h>
+#include <xen/types.h>
+
+#define HEAPORDER 3
+
+static unsigned char *window;
+#define memptr long
+static memptr free_mem_ptr;
+static memptr free_mem_end_ptr;
+
+#define WSIZE 0x80000000
+
+static unsigned char *inbuf;
+static unsigned insize;
+
+/* Index of next byte to be processed in inbuf: */
+static unsigned inptr;
+
+/* Bytes in output buffer: */
+static unsigned outcnt;
+
+#define OF(args) args
+#define STATIC static
+
+#define memzero(s, n) memset((s), 0, (n))
+
+typedef unsigned char uch;
+typedef unsigned short ush;
+typedef unsigned long ulg;
+
+#define INIT __init
+
+#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf())
+
+/* Diagnostic functions */
+#ifdef DEBUG
+# define Assert(cond, msg) do { if (!(cond)) error(msg); } while (0)
+# define Trace(x) do { fprintf x; } while (0)
+# define Tracev(x) do { if (verbose) fprintf x ; } while (0)
+# define Tracevv(x) do { if (verbose > 1) fprintf x ; } while (0)
+# define Tracec(c, x) do { if (verbose && (c)) fprintf x ; } while (0)
+# define Tracecv(c, x) do { if (verbose > 1 && (c)) fprintf x ; } while (0)
+#else
+# define Assert(cond, msg)
+# define Trace(x)
+# define Tracev(x)
+# define Tracevv(x)
+# define Tracec(c, x)
+# define Tracecv(c, x)
+#endif
+
+static long bytes_out;
+static void flush_window(void);
+
+static __init void error(char *x)
+{
+ printk("%s\n", x);
+ BUG();
+}
+
+static __init int fill_inbuf(void)
+{
+ error("ran out of input data");
+ return 0;
+}
+
+
+#include "../../common/inflate.c"
+
+static __init void flush_window(void)
+{
+ /*
+ * The window is equal to the output buffer therefore only need to
+ * compute the crc.
+ */
+ unsigned long c = crc;
+ unsigned n;
+ unsigned char *in, ch;
+
+ in = window;
+ for ( n = 0; n < outcnt; n++ )
+ {
+ ch = *in++;
+ c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8);
+ }
+ crc = c;
+
+ bytes_out += (unsigned long)outcnt;
+ outcnt = 0;
+}
+
+static __init int gzip_length(char *image, unsigned long image_len)
+{
+ return *(uint32_t *)&image[image_len - 4];
+}
+
+static __init int perform_gunzip(char *output, char **_image_start, unsigned long *image_len)
+{
+ char *image = *_image_start;
+ int rc;
+ unsigned char magic0 = (unsigned char)image[0];
+ unsigned char magic1 = (unsigned char)image[1];
+
+ if ( magic0 != 0x1f || ( (magic1 != 0x8b) && (magic1 != 0x9e) ) )
+ return 0;
+
+ window = (unsigned char *)output;
+
+ free_mem_ptr = (unsigned long)alloc_xenheap_pages(HEAPORDER);
+ free_mem_end_ptr = free_mem_ptr + (PAGE_SIZE << HEAPORDER);
+
+ inbuf = (unsigned char *)image;
+ insize = *image_len;
+ inptr = 0;
+
+ makecrc();
+
+ if ( gunzip() < 0 )
+ {
+ rc = -EINVAL;
+ }
+ else
+ {
+ *_image_start = (char *)window;
+ *image_len = gzip_length(image, *image_len);
+ rc = 0;
+ }
+
+ free_xenheap_pages((void *)free_mem_ptr, HEAPORDER);
+
+ return rc;
+}
+
+struct setup_header {
+ uint8_t _pad0[0x1f1]; /* skip uninteresting stuff */
+ uint8_t setup_sects;
+ uint16_t root_flags;
+ uint32_t syssize;
+ uint16_t ram_size;
+ uint16_t vid_mode;
+ uint16_t root_dev;
+ uint16_t boot_flag;
+ uint16_t jump;
+ uint32_t header;
+#define HDR_MAGIC "HdrS"
+#define HDR_MAGIC_SZ 4
+ uint16_t version;
+#define VERSION(h,l) (((h)<<8) | (l))
+ uint32_t realmode_swtch;
+ uint16_t start_sys;
+ uint16_t kernel_version;
+ uint8_t type_of_loader;
+ uint8_t loadflags;
+ uint16_t setup_move_size;
+ uint32_t code32_start;
+ uint32_t ramdisk_image;
+ uint32_t ramdisk_size;
+ uint32_t bootsect_kludge;
+ uint16_t heap_end_ptr;
+ uint16_t _pad1;
+ uint32_t cmd_line_ptr;
+ uint32_t initrd_addr_max;
+ uint32_t kernel_alignment;
+ uint8_t relocatable_kernel;
+ uint8_t _pad2[3];
+ uint32_t cmdline_size;
+ uint32_t hardware_subarch;
+ uint64_t hardware_subarch_data;
+ uint32_t payload_offset;
+ uint32_t payload_length;
+ } __attribute__((packed));
+
+static __init int bzimage_check(struct setup_header *hdr, unsigned long len)
+{
+ if ( len < sizeof(struct setup_header) )
+ return 0;
+
+ if ( memcmp(&hdr->header, HDR_MAGIC, HDR_MAGIC_SZ) != 0 )
+ return 0;
+
+ if ( hdr->version < VERSION(2,8) ) {
+ printk("Cannot load bzImage v%d.%02d at least v2.08 is required\n",
+ hdr->version >> 8, hdr->version & 0xff);
+ return -EINVAL;
+ }
+ return 1;
+}
+
+int __init bzimage_headroom(char *image_start, unsigned long image_length)
+{
+ struct setup_header *hdr = (struct setup_header *)image_start;
+ char *img;
+ int err, headroom;
+
+ err = bzimage_check(hdr, image_length);
+ if (err < 1)
+ return err;
+
+ img = image_start + (hdr->setup_sects+1) * 512;
+ img += hdr->payload_offset;
+
+ headroom = gzip_length(img, hdr->payload_length);
+ headroom += headroom >> 12; /* Add 8 bytes for every 32K input block */
+ headroom += (32768 + 18); /* Add 32K + 18 bytes of extra headroom */
+ headroom = (headroom + 4095) & ~4095;
+
+ return headroom;
+}
+
+int __init bzimage_parse(char *image_base, char **image_start, unsigned long *image_len)
+{
+ struct setup_header *hdr = (struct setup_header *)(*image_start);
+ int err = bzimage_check(hdr, *image_len);
+
+ if (err < 1)
+ return err;
+
+ BUG_ON(!(image_base < *image_start));
+
+ *image_start += (hdr->setup_sects+1) * 512;
+ *image_start += hdr->payload_offset;
+ *image_len = hdr->payload_length;
+
+ if ( (err = perform_gunzip(image_base, image_start, image_len)) < 0 )
+ return err;
+
+ return 0;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */