[PATCH RFC] add domain builder support for bzImage kernels

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

 



This implements a loader for version 2.07 boot protocol bzImage format
files.  This allows a single bzImage kernel file to boot either native
from a normal bootloader (grub, etc), or paravirtualized under Xen.

These bzImages have two changes to make this possible:

   1. There's a new field for the bootloader to tell the booted kernel
      what kind of environment its coming up under.  We can use this to
      tell the kernel to unambigiously tell that its booting under Xen. 
      There's also an extra field for storing some environment-specific
      data; we use this to store the Xen start_info pointer.
   2. The 32-part of the bzImage code, which includes a decompressor and
      the compressed data for the actual kernel, is wrapped in an ELF
      file.  This allows us to decorate it with the Xen-spceific ELF
      notes, and also use the PHDRs to specify how much memory Xen needs
      to map initially.  The ELF file is constructed so that the PHDRs
      map enough memory for the kernel to decompress itself, and run
      enough until it can build its own initial pagetables.


The Linux boot protocol requires that %esi point to the boot_params
block on entry.  Unfortunately this conflicts with the normal Xen boot
protocol, which starts with %esi pointing to a struct start_info.

In order to implement this, I've had to muck up Gerd's nice clean
layering a little bit.  struct xc_dom_image now has a bootparams_pfn,
which is set by the bzImage loader.  Then, when xc_dom_x86 sees that its
non-NULL when setting up the initial vcpu state, it points %esi that
rather than start_info (and the boot_params contains a pointer to
start_info).  Fortunately, the embedded ELF file makes it easy to reuse
a lot of the existing ELF machinery, so there's not a lot of new code.

Signed-off-by: Jeremy Fitzhardinge <jeremy@xxxxxxxxxxxxx>

diff -r 3af164753238 tools/libxc/Makefile
--- a/tools/libxc/Makefile	Thu Jun 14 08:15:19 2007 -0700
+++ b/tools/libxc/Makefile	Thu Jun 14 08:43:44 2007 -0700
@@ -47,6 +47,7 @@ GUEST_SRCS-y += $(LIBELF_SRCS)
 # new domain builder
 GUEST_SRCS-y += xc_dom_core.c xc_dom_boot.c
 GUEST_SRCS-y += xc_dom_elfloader.c
+GUEST_SRCS-y += xc_dom_bzimageloader.c
 GUEST_SRCS-y += xc_dom_binloader.c
 GUEST_SRCS-y += xc_dom_compat_linux.c
 
diff -r 3af164753238 tools/libxc/bootparam.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/libxc/bootparam.h	Thu Jun 14 08:43:44 2007 -0700
@@ -0,0 +1,53 @@
+#ifndef _ASM_BOOTPARAM_H
+#define _ASM_BOOTPARAM_H
+
+#include <stdint.h>
+
+#define HDR_MAGIC "HdrS"
+#define HDR_MAGIC_SZ 4
+
+struct setup_header {
+	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;
+	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;
+#define LOADED_HIGH	(1<<0)
+#define KEEP_SEGMENTS	(1<<6)
+#define CAN_USE_HEAP	(1<<7)
+	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;
+} __attribute__((packed));
+
+/* The so-called "zeropage" */
+struct boot_params {
+	uint8_t	_pad0[0x1f1];		/* skip uninteresting stuff */
+	struct setup_header hdr;/* setup header */	/* 0x1f1 */
+	uint8_t  _pad7[0x1000-0x1f1-sizeof(struct setup_header)];
+} __attribute__((packed));
+
+#endif /* _ASM_BOOTPARAM_H */
diff -r 3af164753238 tools/libxc/xc_dom.h
--- a/tools/libxc/xc_dom.h	Thu Jun 14 08:15:19 2007 -0700
+++ b/tools/libxc/xc_dom.h	Thu Jun 14 08:43:44 2007 -0700
@@ -55,6 +55,7 @@ struct xc_dom_image {
     xen_pfn_t xenstore_pfn;
     xen_pfn_t shared_info_pfn;
     xen_pfn_t bootstack_pfn;
+    xen_pfn_t bootparams_pfn;
     xen_vaddr_t virt_alloc_end;
     xen_vaddr_t bsd_symtab_start;
 
@@ -254,6 +255,11 @@ static inline xen_pfn_t xc_dom_p2m_guest
     return dom->p2m_host[pfn];
 }
 
+char *xc_dom_guest_type(struct xc_dom_image *dom,
+                        struct elf_binary *elf);
+int xc_dom_load_elf_symtab(struct xc_dom_image *dom,
+                           struct elf_binary *elf, int load);
+
 /* --- arch bits --------------------------------------------------- */
 
 int arch_setup_meminit(struct xc_dom_image *dom);
diff -r 3af164753238 tools/libxc/xc_dom_bzimageloader.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/libxc/xc_dom_bzimageloader.c	Thu Jun 14 08:43:44 2007 -0700
@@ -0,0 +1,169 @@
+/*
+ * Xen domain builder -- bzImage bits
+ *
+ * Parse and load bzImage kernel images.
+ *
+ * This relies on version 2.07 of the boot protocol, which an ELF file
+ * embedded in the bzImage.  The loader extracts the boot_params from
+ * the bzImage and updates it appropriately, then loads and runs the
+ * self-extracting kernel ELF file.
+ *
+ * This code is licenced under the GPL.
+ * written 2006 by Gerd Hoffmann <kraxel@xxxxxxx>.
+ * written 2007 by Jeremy Fitzhardinge <jeremy@xxxxxxxxxxxxx>
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <inttypes.h>
+
+#include "xg_private.h"
+#include "xc_dom.h"
+#include "bootparam.h"
+
+#define XEN_VER "xen-3.0"
+
+static unsigned elf_offset(struct boot_params *params)
+{
+    return (params->hdr.setup_sects + 1) * 512;
+}
+
+static int check_bzimage_kernel(struct xc_dom_image *dom, int verbose)
+{
+    struct boot_params *params;
+    const char *elf;
+
+    if ( dom->kernel_blob == NULL || dom->kernel_size < 512*8)
+    {
+        if ( verbose )
+            xc_dom_panic(XC_INTERNAL_ERROR, "%s: no kernel image loaded\n",
+                         __FUNCTION__);
+        return -EINVAL;
+    }
+
+    params = dom->kernel_blob;
+
+    if ( memcmp(&params->hdr.header, HDR_MAGIC, HDR_MAGIC_SZ) != 0 )
+    {
+        if ( verbose )
+            xc_dom_panic(XC_INVALID_KERNEL, "%s: kernel is not a bzImage\n",
+                         __FUNCTION__);
+        return -EINVAL;
+    }
+
+    if ( params->hdr.version < VERSION(2,07) )
+    {
+        if ( verbose )
+            xc_dom_panic(XC_INVALID_KERNEL, "%s: boot protocol too old (%04x)\n",
+                         __FUNCTION__, params->hdr.version);
+        return -EINVAL;
+    }
+
+    elf = dom->kernel_blob + elf_offset(params);
+    if ( !elf_is_elfbinary(elf) )
+    {
+        if ( verbose )
+            xc_dom_panic(XC_INVALID_KERNEL, "%s: bzImage does not contain ELF image\n",
+                         __FUNCTION__);
+        return -EINVAL;
+    }
+
+    return 0;
+}
+
+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)
+{
+    int rc;
+    struct boot_params *params;
+    struct elf_binary *elf;
+    unsigned offset;
+
+    rc = check_bzimage_kernel(dom, 1);
+    if ( rc != 0 )
+        return rc;
+
+    params = dom->kernel_blob;
+    offset = elf_offset(params);
+
+    elf = xc_dom_malloc(dom, sizeof(*elf));
+    dom->private_loader = elf;
+
+    rc = elf_init(elf, dom->kernel_blob + offset, dom->kernel_size - offset);
+    if ( xc_dom_logfile )
+        elf_set_logfile(elf, xc_dom_logfile, 1);
+    if ( rc != 0 )
+    {
+        xc_dom_panic(XC_INVALID_KERNEL, "%s: corrupted ELF image\n",
+                     __FUNCTION__);
+        return rc;
+    }
+
+    /* parse binary and get xen meta info */
+    elf_parse_binary(elf);
+    if ( (rc = elf_xen_parse(elf, &dom->parms)) != 0 )
+        return rc;
+
+    /* find kernel segment */
+    dom->kernel_seg.vstart = dom->parms.virt_kstart;
+    dom->kernel_seg.vend   = dom->parms.virt_kend;
+
+    if ( dom->parms.bsd_symtab )
+        xc_dom_load_elf_symtab(dom, elf, 0);
+
+    dom->guest_type = xc_dom_guest_type(dom, elf);
+    xc_dom_printf("%s: %s: 0x%" PRIx64 " -> 0x%" PRIx64 "\n",
+                  __FUNCTION__, dom->guest_type,
+                  dom->kernel_seg.vstart, dom->kernel_seg.vend);
+    return 0;
+}
+
+static int xc_dom_load_bzimage_kernel(struct xc_dom_image *dom)
+{
+    struct elf_binary *elf = dom->private_loader;
+    xen_pfn_t bootparams_pfn;
+    struct boot_params *bzparams, *bootparams;
+
+    bzparams = dom->kernel_blob;
+
+    elf->dest = xc_dom_seg_to_ptr(dom, &dom->kernel_seg);
+    elf_load_binary(elf);
+    if ( dom->parms.bsd_symtab )
+        xc_dom_load_elf_symtab(dom, elf, 1);
+
+    bootparams_pfn = xc_dom_alloc_page(dom, "bootparams");
+    bootparams = xc_dom_pfn_to_ptr(dom, bootparams_pfn, 1);
+    memset(bootparams, 0, sizeof(*bootparams));
+
+    memcpy(&bootparams->hdr, &bzparams->hdr, sizeof(bootparams->hdr));
+
+    dom->bootparams_pfn = bootparams_pfn;
+
+    return 0;
+}
+
+static struct xc_dom_loader bzimage_loader = {
+    .name = "bzImage",
+    .probe = xc_dom_probe_bzimage_kernel,
+    .parser = xc_dom_parse_bzimage_kernel,
+    .loader = xc_dom_load_bzimage_kernel,
+};
+
+static void __init register_loader(void)
+{
+    xc_dom_register_loader(&bzimage_loader);
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff -r 3af164753238 tools/libxc/xc_dom_elfloader.c
--- a/tools/libxc/xc_dom_elfloader.c	Thu Jun 14 08:15:19 2007 -0700
+++ b/tools/libxc/xc_dom_elfloader.c	Thu Jun 14 08:43:44 2007 -0700
@@ -18,8 +18,8 @@
 
 /* ------------------------------------------------------------------------ */
 
-static char *xc_dom_guest_type(struct xc_dom_image *dom,
-                               struct elf_binary *elf)
+char *xc_dom_guest_type(struct xc_dom_image *dom,
+                        struct elf_binary *elf)
 {
     uint64_t machine = elf_uval(elf, elf->ehdr, e_machine);
 
@@ -78,8 +78,8 @@ static int xc_dom_probe_elf_kernel(struc
     return check_elf_kernel(dom, 0);
 }
 
-static int xc_dom_load_elf_symtab(struct xc_dom_image *dom,
-                                  struct elf_binary *elf, int load)
+int xc_dom_load_elf_symtab(struct xc_dom_image *dom,
+                           struct elf_binary *elf, int load)
 {
     struct elf_binary syms;
     const elf_shdr *shdr, *shdr2;
diff -r 3af164753238 tools/libxc/xc_dom_x86.c
--- a/tools/libxc/xc_dom_x86.c	Thu Jun 14 08:15:19 2007 -0700
+++ b/tools/libxc/xc_dom_x86.c	Thu Jun 14 08:43:44 2007 -0700
@@ -23,6 +23,7 @@
 #include "xg_private.h"
 #include "xc_dom.h"
 #include "xenctrl.h"
+#include "bootparam.h"
 
 /* ------------------------------------------------------------------------ */
 
@@ -407,6 +408,36 @@ static int alloc_magic_pages(struct xc_d
 
 /* ------------------------------------------------------------------------ */
 
+static unsigned long guest_pfn_addr(struct xc_dom_image *dom, xen_pfn_t pfn,
+                                    size_t offset)
+{
+    return dom->parms.virt_base + pfn * PAGE_SIZE_X86 + offset;
+}
+
+static void setup_boot_params(struct xc_dom_image *dom)
+{
+    struct boot_params *params =
+        xc_dom_pfn_to_ptr(dom, dom->bootparams_pfn, 1);
+
+    params->hdr.type_of_loader = (9 << 4) | 0;  /* xen v0 */
+    params->hdr.loadflags |= LOADED_HIGH | KEEP_SEGMENTS;
+
+    params->hdr.hardware_subarch = 2;  /* xen */
+    params->hdr.hardware_subarch_data =
+        (uint64_t)guest_pfn_addr(dom, dom->start_info_pfn, 0);
+
+    if ( dom->ramdisk_blob )
+    {
+        params->hdr.ramdisk_image = (uint32_t)dom->ramdisk_seg.vstart;
+        params->hdr.ramdisk_size = dom->ramdisk_seg.vend - dom->ramdisk_seg.vstart;
+    }
+
+    params->hdr.cmd_line_ptr =
+        guest_pfn_addr(dom, dom->start_info_pfn,
+                       offsetof(start_info_x86_32_t, cmd_line));
+    params->hdr.cmdline_size = MAX_GUEST_CMDLINE;
+}
+
 static int start_info_x86_32(struct xc_dom_image *dom)
 {
     start_info_x86_32_t *start_info =
@@ -440,6 +471,12 @@ static int start_info_x86_32(struct xc_d
     {
         strncpy((char *)start_info->cmd_line, dom->cmdline, MAX_GUEST_CMDLINE);
         start_info->cmd_line[MAX_GUEST_CMDLINE - 1] = '\0';
+    }
+
+    if ( dom->bootparams_pfn != 0 )
+    {
+        setup_boot_params(dom);
+        dom->start_info_pfn = dom->bootparams_pfn;
     }
 
     return 0;
@@ -528,10 +565,8 @@ static int vcpu_x86_32(struct xc_dom_ima
     ctxt->user_regs.ss = FLAT_KERNEL_SS_X86_32;
     ctxt->user_regs.cs = FLAT_KERNEL_CS_X86_32;
     ctxt->user_regs.eip = dom->parms.virt_entry;
-    ctxt->user_regs.esp =
-        dom->parms.virt_base + (dom->bootstack_pfn + 1) * PAGE_SIZE_X86;
-    ctxt->user_regs.esi =
-        dom->parms.virt_base + (dom->start_info_pfn) * PAGE_SIZE_X86;
+    ctxt->user_regs.esp = guest_pfn_addr(dom, dom->bootstack_pfn, PAGE_SIZE_X86);
+    ctxt->user_regs.esi = guest_pfn_addr(dom, dom->start_info_pfn, 0);
     ctxt->user_regs.eflags = 1 << 9; /* Interrupt Enable */
 
     ctxt->kernel_ss = ctxt->user_regs.ss;

_______________________________________________
Virtualization mailing list
Virtualization@xxxxxxxxxxxxxxxxxxxxxxxxxx
https://lists.linux-foundation.org/mailman/listinfo/virtualization

[Index of Archives]     [KVM Development]     [Libvirt Development]     [Libvirt Users]     [CentOS Virtualization]     [Netdev]     [Ethernet Bridging]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite Forum]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux