diff options
author | Emmanuel Ackaouy <ack@xensource.com> | 2007-01-25 22:16:52 +0000 |
---|---|---|
committer | Emmanuel Ackaouy <ack@xensource.com> | 2007-01-25 22:16:52 +0000 |
commit | b4feb14b3dd705b59ce7a2d66fe0879d54e408e8 (patch) | |
tree | d2786344b21060b576e5d9bc484652a1e14b16de /tools/libxc/xc_dom_binloader.c | |
parent | a62512128bdc7632982ddc0b3285703e5ab66c98 (diff) | |
download | xen-b4feb14b3dd705b59ce7a2d66fe0879d54e408e8.tar.gz xen-b4feb14b3dd705b59ce7a2d66fe0879d54e408e8.tar.bz2 xen-b4feb14b3dd705b59ce7a2d66fe0879d54e408e8.zip |
libxc domain builder rewrite, core bits.
Signed-off-by: Gerd Hoffmann <kraxel@suse.de>
---
tools/libxc/Makefile | 14
tools/libxc/xc_dom.h | 261 +++++++++++++
tools/libxc/xc_dom_binloader.c | 294 +++++++++++++++
tools/libxc/xc_dom_boot.c | 515 +++++++++++++++++++++++++++
tools/libxc/xc_dom_core.c | 773 +++++++++++++++++++++++++++++++++++++++++
tools/libxc/xc_dom_elfloader.c | 283 +++++++++++++++
tools/libxc/xc_dom_ia64.c | 118 ++++++
tools/libxc/xc_dom_powerpc64.c | 100 +++++
tools/libxc/xc_dom_x86.c | 559 +++++++++++++++++++++++++++++
9 files changed, 2917 insertions(+)
Diffstat (limited to 'tools/libxc/xc_dom_binloader.c')
-rw-r--r-- | tools/libxc/xc_dom_binloader.c | 294 |
1 files changed, 294 insertions, 0 deletions
diff --git a/tools/libxc/xc_dom_binloader.c b/tools/libxc/xc_dom_binloader.c new file mode 100644 index 0000000000..dfaef31f27 --- /dev/null +++ b/tools/libxc/xc_dom_binloader.c @@ -0,0 +1,294 @@ +/****************************************************************************** + * + * Loads simple binary images. It's like a .COM file in MS-DOS. No headers are + * present. The only requirement is that it must have a xen_bin_image table + * somewhere in the first 8192 bytes, starting on a 32-bit aligned address. + * Those familiar with the multiboot specification should recognize this, it's + * (almost) the same as the multiboot header. + * The layout of the xen_bin_image table is: + * + * Offset Type Name Note + * 0 uint32_t magic required + * 4 uint32_t flags required + * 8 uint32_t checksum required + * 12 uint32_t header_addr required + * 16 uint32_t load_addr required + * 20 uint32_t load_end_addr required + * 24 uint32_t bss_end_addr required + * 28 uint32_t entry_addr required + * + * - magic + * Magic number identifying the table. For images to be loaded by Xen 3, the + * magic value is 0x336ec578 ("xEn3" with the 0x80 bit of the "E" set). + * - flags + * bit 0: indicates whether the image needs to be loaded on a page boundary + * bit 1: reserved, must be 0 (the multiboot spec uses this bit to indicate + * that memory info should be passed to the image) + * bit 2: reserved, must be 0 (the multiboot spec uses this bit to indicate + * that the bootloader should pass video mode info to the image) + * bit 16: reserved, must be 1 (the multiboot spec uses this bit to indicate + * that the values in the fields header_addr - entry_addr are + * valid) + * All other bits should be set to 0. + * - checksum + * When added to "magic" and "flags", the resulting value should be 0. + * - header_addr + * Contains the virtual address corresponding to the beginning of the + * table - the memory location at which the magic value is supposed to be + * loaded. This field serves to synchronize the mapping between OS image + * offsets and virtual memory addresses. + * - load_addr + * Contains the virtual address of the beginning of the text segment. The + * offset in the OS image file at which to start loading is defined by the + * offset at which the table was found, minus (header addr - load addr). + * load addr must be less than or equal to header addr. + * - load_end_addr + * Contains the virtual address of the end of the data segment. + * (load_end_addr - load_addr) specifies how much data to load. This implies + * that the text and data segments must be consecutive in the OS image. If + * this field is zero, the domain builder assumes that the text and data + * segments occupy the whole OS image file. + * - bss_end_addr + * Contains the virtual address of the end of the bss segment. The domain + * builder initializes this area to zero, and reserves the memory it occupies + * to avoid placing boot modules and other data relevant to the loaded image + * in that area. If this field is zero, the domain builder assumes that no bss + * segment is present. + * - entry_addr + * The virtual address at which to start execution of the loaded image. + * + * Some of the field descriptions were copied from "The Multiboot + * Specification", Copyright 1995, 96 Bryan Ford <baford@cs.utah.edu>, + * Erich Stefan Boleyn <erich@uruk.org> Copyright 1999, 2000, 2001, 2002 + * Free Software Foundation, Inc. + */ + +#include <stdlib.h> +#include <inttypes.h> + +#include "xg_private.h" +#include "xc_dom.h" + +#define round_pgup(_p) (((_p)+(PAGE_SIZE_X86-1))&PAGE_MASK_X86) +#define round_pgdown(_p) ((_p)&PAGE_MASK_X86) + +struct xen_bin_image_table +{ + uint32_t magic; + uint32_t flags; + uint32_t checksum; + uint32_t header_addr; + uint32_t load_addr; + uint32_t load_end_addr; + uint32_t bss_end_addr; + uint32_t entry_addr; +}; + +#define XEN_MULTIBOOT_MAGIC3 0x336ec578 + +#define XEN_MULTIBOOT_FLAG_ALIGN4K 0x00000001 +#define XEN_MULTIBOOT_FLAG_NEEDMEMINFO 0x00000002 +#define XEN_MULTIBOOT_FLAG_NEEDVIDINFO 0x00000004 +#define XEN_MULTIBOOT_FLAG_ADDRSVALID 0x00010000 +#define XEN_MULTIBOOT_FLAG_PAE_SHIFT 14 +#define XEN_MULTIBOOT_FLAG_PAE_MASK (3 << XEN_MULTIBOOT_FLAG_PAE_SHIFT) + +/* Flags we test for */ +#define FLAGS_MASK ((~ 0) & (~ XEN_MULTIBOOT_FLAG_ALIGN4K) & \ + (~ XEN_MULTIBOOT_FLAG_PAE_MASK)) +#define FLAGS_REQUIRED XEN_MULTIBOOT_FLAG_ADDRSVALID + +/* --------------------------------------------------------------------- */ + +static struct xen_bin_image_table *find_table(struct xc_dom_image *dom) +{ + struct xen_bin_image_table *table; + uint32_t *probe_ptr; + uint32_t *probe_end; + + probe_ptr = dom->kernel_blob; + probe_end = dom->kernel_blob + dom->kernel_size - sizeof(*table); + if ((void*)probe_end > dom->kernel_blob + 8192) + probe_end = dom->kernel_blob + 8192; + + for (table = NULL; probe_ptr < probe_end; probe_ptr++) + { + if (XEN_MULTIBOOT_MAGIC3 == *probe_ptr) + { + table = (struct xen_bin_image_table *) probe_ptr; + /* Checksum correct? */ + if (0 == table->magic + table->flags + table->checksum) + { + return table; + } + } + } + return NULL; +} + +static int xc_dom_probe_bin_kernel(struct xc_dom_image *dom) +{ + struct xen_bin_image_table *table; + + table = find_table(dom); + if (!table) + return -EINVAL; + return 0; +} + +static int xc_dom_parse_bin_kernel(struct xc_dom_image *dom) +{ + struct xen_bin_image_table *image_info; + char *image = dom->kernel_blob; + size_t image_size = dom->kernel_size; + uint32_t start_addr; + uint32_t load_end_addr; + uint32_t bss_end_addr; + uint32_t pae_flags; + + image_info = find_table(dom); + if (!image_info) + return -EINVAL; + + xc_dom_printf("%s: multiboot header fields\n", __FUNCTION__); + xc_dom_printf(" flags: 0x%" PRIx32 "\n", image_info->flags); + xc_dom_printf(" header_addr: 0x%" PRIx32 "\n", image_info->header_addr); + xc_dom_printf(" load_addr: 0x%" PRIx32 "\n", image_info->load_addr); + xc_dom_printf(" load_end_addr: 0x%" PRIx32 "\n", image_info->load_end_addr); + xc_dom_printf(" bss_end_addr: 0x%" PRIx32 "\n", image_info->bss_end_addr); + xc_dom_printf(" entry_addr: 0x%" PRIx32 "\n", image_info->entry_addr); + + /* Check the flags */ + if ( FLAGS_REQUIRED != (image_info->flags & FLAGS_MASK) ) + { + xc_dom_panic(XC_INVALID_KERNEL, + "%s: xen_bin_image_table flags required " + "0x%08" PRIx32 " found 0x%08" PRIx32 "\n", + __FUNCTION__, FLAGS_REQUIRED, image_info->flags & FLAGS_MASK); + return -EINVAL; + } + + /* Sanity check on the addresses */ + if ( image_info->header_addr < image_info->load_addr || + ((char *) image_info - image) < + (image_info->header_addr - image_info->load_addr) ) + { + xc_dom_panic(XC_INVALID_KERNEL, "%s: Invalid header_addr.", + __FUNCTION__); + return -EINVAL; + } + + start_addr = image_info->header_addr - ((char *)image_info - image); + load_end_addr = image_info->load_end_addr ?: start_addr + image_size; + bss_end_addr = image_info->bss_end_addr ?: load_end_addr; + + xc_dom_printf("%s: calculated addresses\n", __FUNCTION__); + xc_dom_printf(" start_addr: 0x%" PRIx32 "\n", start_addr); + xc_dom_printf(" load_end_addr: 0x%" PRIx32 "\n", load_end_addr); + xc_dom_printf(" bss_end_addr: 0x%" PRIx32 "\n", bss_end_addr); + + if ( start_addr + image_size < load_end_addr ) + { + xc_dom_panic(XC_INVALID_KERNEL, "%s: Invalid load_end_addr.\n", + __FUNCTION__); + return -EINVAL; + } + + if ( bss_end_addr < load_end_addr) + { + xc_dom_panic(XC_INVALID_KERNEL, "%s: Invalid bss_end_addr.\n", + __FUNCTION__); + return -EINVAL; + } + + dom->kernel_seg.vstart = image_info->load_addr; + dom->kernel_seg.vend = bss_end_addr; + dom->parms.virt_base = start_addr; + dom->parms.virt_entry = image_info->entry_addr; + + pae_flags = image_info->flags & XEN_MULTIBOOT_FLAG_PAE_MASK; + switch (pae_flags >> XEN_MULTIBOOT_FLAG_PAE_SHIFT) { + case 0: + dom->guest_type = "xen-3.0-x86_32"; + break; + case 1: + dom->guest_type = "xen-3.0-x86_32p"; + break; + case 2: + dom->guest_type = "xen-3.0-x86_64"; + break; + case 3: + /* Kernel detects PAE at runtime. So try to figure whenever + * xen supports PAE and advertise a PAE-capable kernel in case + * it does. */ + dom->guest_type = "xen-3.0-x86_32"; + if (strstr(dom->xen_caps, "xen-3.0-x86_32p")) { + xc_dom_printf("%s: PAE fixup\n", __FUNCTION__); + dom->guest_type = "xen-3.0-x86_32p"; + dom->parms.pae = 2; + } + break; + } + return 0; +} + +static int xc_dom_load_bin_kernel(struct xc_dom_image *dom) +{ + struct xen_bin_image_table *image_info; + char *image = dom->kernel_blob; + char *dest; + size_t image_size = dom->kernel_size; + uint32_t start_addr; + uint32_t load_end_addr; + uint32_t bss_end_addr; + uint32_t skip, text_size, bss_size; + uint32_t pae_flags; + + image_info = find_table(dom); + if (!image_info) + return -EINVAL; + + start_addr = image_info->header_addr - ((char *)image_info - image); + load_end_addr = image_info->load_end_addr ?: start_addr + image_size; + bss_end_addr = image_info->bss_end_addr ?: load_end_addr; + + /* It's possible that we need to skip the first part of the image */ + skip = image_info->load_addr - start_addr; + text_size = load_end_addr - image_info->load_addr; + bss_size = bss_end_addr - load_end_addr; + + xc_dom_printf("%s: calculated sizes\n", __FUNCTION__); + xc_dom_printf(" skip: 0x%" PRIx32 "\n", skip); + xc_dom_printf(" text_size: 0x%" PRIx32 "\n", text_size); + xc_dom_printf(" bss_size: 0x%" PRIx32 "\n", bss_size); + + dest = xc_dom_vaddr_to_ptr(dom, dom->kernel_seg.vstart); + memcpy(dest, image + skip, text_size); + memset(dest + text_size, 0, bss_size); + + pae_flags = image_info->flags & XEN_MULTIBOOT_FLAG_PAE_MASK; + if (3 == (pae_flags >> XEN_MULTIBOOT_FLAG_PAE_SHIFT) && dom->guest_xc > 0) + { + } + return 0; +} + +/* ------------------------------------------------------------------------ */ + +static struct xc_dom_loader bin_loader = { + .name = "multiboot-binary", + .probe = xc_dom_probe_bin_kernel, + .parser = xc_dom_parse_bin_kernel, + .loader = xc_dom_load_bin_kernel, +}; + +static void __init register_loader(void) +{ + xc_dom_register_loader(&bin_loader); +} + +/* + * Local variables: + * c-basic-offset: 4 + * End: + */ |