aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorcl349@firebug.cl.cam.ac.uk <cl349@firebug.cl.cam.ac.uk>2005-06-06 08:44:42 +0000
committercl349@firebug.cl.cam.ac.uk <cl349@firebug.cl.cam.ac.uk>2005-06-06 08:44:42 +0000
commitce52246261870f4389783e71a8cb0d806c672850 (patch)
treea5fddf24fdc41ec26f4e450d3ff6222e9348d69b
parent361f01aebc40d039b253e0112552928f7b149d1d (diff)
parentaac7970f2642ba831248bc0748985e49d4fd32ba (diff)
downloadxen-ce52246261870f4389783e71a8cb0d806c672850.tar.gz
xen-ce52246261870f4389783e71a8cb0d806c672850.tar.bz2
xen-ce52246261870f4389783e71a8cb0d806c672850.zip
bitkeeper revision 1.1679 (42a40cfaZ0Dy-HjTM0W3L10VllkAnw)
Merge firebug.cl.cam.ac.uk:/auto/groups/xeno-xenod/BK/xen-unstable.bk into firebug.cl.cam.ac.uk:/local/scratch/cl349/xen-unstable.bk-clean
-rw-r--r--.rootkeys2
-rw-r--r--tools/libxc/Makefile2
-rw-r--r--tools/libxc/xc_linux_build.c308
-rw-r--r--tools/libxc/xc_load_bin.c299
-rw-r--r--tools/libxc/xc_load_elf.c310
-rw-r--r--tools/libxc/xc_private.h35
-rw-r--r--tools/libxc/xc_vmx_build.c20
7 files changed, 671 insertions, 305 deletions
diff --git a/.rootkeys b/.rootkeys
index 1233ae7a83..bd90121bad 100644
--- a/.rootkeys
+++ b/.rootkeys
@@ -712,6 +712,8 @@
3fbba6dbNCU7U6nsMYiXzKkp3ztaJg tools/libxc/xc_linux_build.c
3fbba6dbl267zZOAVHYLOdLCdhcZMw tools/libxc/xc_linux_restore.c
3fbba6db7li3FJiABYtCmuGxOJxEGw tools/libxc/xc_linux_save.c
+42a40bc3vE3p9fPSJZQZK0MdQF9B8g tools/libxc/xc_load_bin.c
+42a40bc4diWfFsPGf0RW7qXMufU4YQ tools/libxc/xc_load_elf.c
3fbba6db7WnnJr0KFrIFrqNlSKvFYg tools/libxc/xc_misc.c
4051bce6CHAsYh8P5t2OHDtRWOP9og tools/libxc/xc_physdev.c
41cc934aO1m6NxEh_8eDr9bJIMoLFA tools/libxc/xc_plan9_build.c
diff --git a/tools/libxc/Makefile b/tools/libxc/Makefile
index 598abedb7d..cbe7983a44 100644
--- a/tools/libxc/Makefile
+++ b/tools/libxc/Makefile
@@ -19,6 +19,8 @@ SRCS += xc_core.c
SRCS += xc_domain.c
SRCS += xc_evtchn.c
SRCS += xc_gnttab.c
+SRCS += xc_load_bin.c
+SRCS += xc_load_elf.c
SRCS += xc_linux_build.c
SRCS += xc_plan9_build.c
SRCS += xc_linux_restore.c
diff --git a/tools/libxc/xc_linux_build.c b/tools/libxc/xc_linux_build.c
index 9060f5ace2..f90f3f3aef 100644
--- a/tools/libxc/xc_linux_build.c
+++ b/tools/libxc/xc_linux_build.c
@@ -33,30 +33,19 @@
#define round_pgup(_p) (((_p)+(PAGE_SIZE-1))&PAGE_MASK)
#define round_pgdown(_p) ((_p)&PAGE_MASK)
-struct domain_setup_info
+static int probeimageformat(char *image,
+ unsigned long image_size,
+ struct load_funcs *load_funcs)
{
- unsigned long v_start;
- unsigned long v_end;
- unsigned long v_kernstart;
- unsigned long v_kernend;
- unsigned long v_kernentry;
-
- unsigned int load_symtab;
- unsigned long symtab_addr;
- unsigned long symtab_len;
-};
-
-static int
-parseelfimage(
- char *elfbase, unsigned long elfsize, struct domain_setup_info *dsi);
-static int
-loadelfimage(
- char *elfbase, int xch, u32 dom, unsigned long *parray,
- struct domain_setup_info *dsi);
-static int
-loadelfsymtab(
- char *elfbase, int xch, u32 dom, unsigned long *parray,
- struct domain_setup_info *dsi);
+ if ( probe_elf(image, image_size, load_funcs) &&
+ probe_bin(image, image_size, load_funcs) )
+ {
+ ERROR( "Unrecognized image format" );
+ return -EINVAL;
+ }
+
+ return 0;
+}
static int setup_guest(int xc_handle,
u32 dom,
@@ -94,6 +83,7 @@ static int setup_guest(int xc_handle,
unsigned long ppt_alloc;
unsigned long *physmap, *physmap_e, physmap_pfn;
+ struct load_funcs load_funcs;
struct domain_setup_info dsi;
unsigned long vinitrd_start;
unsigned long vinitrd_end;
@@ -107,9 +97,13 @@ static int setup_guest(int xc_handle,
unsigned long vpt_end;
unsigned long v_end;
+ rc = probeimageformat(image, image_size, &load_funcs);
+ if ( rc != 0 )
+ goto error_out;
+
memset(&dsi, 0, sizeof(struct domain_setup_info));
- rc = parseelfimage(image, image_size, &dsi);
+ rc = (load_funcs.parseimage)(image, image_size, &dsi);
if ( rc != 0 )
goto error_out;
@@ -198,7 +192,8 @@ static int setup_guest(int xc_handle,
goto error_out;
}
- loadelfimage(image, xc_handle, dom, page_array, &dsi);
+ (load_funcs.loadimage)(image, image_size, xc_handle, dom, page_array,
+ &dsi);
/* Load the initial ramdisk image. */
if ( initrd_len != 0 )
@@ -593,266 +588,3 @@ int xc_linux_build(int xc_handle,
return -1;
}
-
-static inline int is_loadable_phdr(Elf_Phdr *phdr)
-{
- return ((phdr->p_type == PT_LOAD) &&
- ((phdr->p_flags & (PF_W|PF_X)) != 0));
-}
-
-static int parseelfimage(char *elfbase,
- unsigned long elfsize,
- struct domain_setup_info *dsi)
-{
- Elf_Ehdr *ehdr = (Elf_Ehdr *)elfbase;
- Elf_Phdr *phdr;
- Elf_Shdr *shdr;
- unsigned long kernstart = ~0UL, kernend=0UL;
- char *shstrtab, *guestinfo=NULL, *p;
- int h;
-
- if ( !IS_ELF(*ehdr) )
- {
- ERROR("Kernel image does not have an ELF header.");
- return -EINVAL;
- }
-
- if ( (ehdr->e_phoff + (ehdr->e_phnum * ehdr->e_phentsize)) > elfsize )
- {
- ERROR("ELF program headers extend beyond end of image.");
- return -EINVAL;
- }
-
- if ( (ehdr->e_shoff + (ehdr->e_shnum * ehdr->e_shentsize)) > elfsize )
- {
- ERROR("ELF section headers extend beyond end of image.");
- return -EINVAL;
- }
-
- /* Find the section-header strings table. */
- if ( ehdr->e_shstrndx == SHN_UNDEF )
- {
- ERROR("ELF image has no section-header strings table (shstrtab).");
- return -EINVAL;
- }
- shdr = (Elf_Shdr *)(elfbase + ehdr->e_shoff +
- (ehdr->e_shstrndx*ehdr->e_shentsize));
- shstrtab = elfbase + shdr->sh_offset;
-
- /* Find the special '__xen_guest' section and check its contents. */
- for ( h = 0; h < ehdr->e_shnum; h++ )
- {
- shdr = (Elf_Shdr *)(elfbase + ehdr->e_shoff + (h*ehdr->e_shentsize));
- if ( strcmp(&shstrtab[shdr->sh_name], "__xen_guest") != 0 )
- continue;
-
- guestinfo = elfbase + shdr->sh_offset;
-
- if ( (strstr(guestinfo, "LOADER=generic") == NULL) &&
- (strstr(guestinfo, "GUEST_OS=linux") == NULL) )
- {
- ERROR("Will only load images built for the generic loader "
- "or Linux images");
- ERROR("Actually saw: '%s'", guestinfo);
- return -EINVAL;
- }
-
- if ( (strstr(guestinfo, "XEN_VER=3.0") == NULL) )
- {
- ERROR("Will only load images built for Xen v3.0");
- ERROR("Actually saw: '%s'", guestinfo);
- return -EINVAL;
- }
-
- break;
- }
- if ( guestinfo == NULL )
- {
- ERROR("Not a Xen-ELF image: '__xen_guest' section not found.");
- return -EINVAL;
- }
-
- for ( h = 0; h < ehdr->e_phnum; h++ )
- {
- phdr = (Elf_Phdr *)(elfbase + ehdr->e_phoff + (h*ehdr->e_phentsize));
- if ( !is_loadable_phdr(phdr) )
- continue;
- if ( phdr->p_paddr < kernstart )
- kernstart = phdr->p_paddr;
- if ( (phdr->p_paddr + phdr->p_memsz) > kernend )
- kernend = phdr->p_paddr + phdr->p_memsz;
- }
-
- if ( (kernstart > kernend) ||
- (ehdr->e_entry < kernstart) ||
- (ehdr->e_entry > kernend) )
- {
- ERROR("Malformed ELF image.");
- return -EINVAL;
- }
-
- dsi->v_start = kernstart;
- if ( (p = strstr(guestinfo, "VIRT_BASE=")) != NULL )
- dsi->v_start = strtoul(p+10, &p, 0);
-
- if ( (p = strstr(guestinfo, "BSD_SYMTAB")) != NULL )
- dsi->load_symtab = 1;
-
- dsi->v_kernstart = kernstart;
- dsi->v_kernend = kernend;
- dsi->v_kernentry = ehdr->e_entry;
- dsi->v_end = dsi->v_kernend;
-
- loadelfsymtab(elfbase, 0, 0, NULL, dsi);
-
- return 0;
-}
-
-static int
-loadelfimage(
- char *elfbase, int xch, u32 dom, unsigned long *parray,
- struct domain_setup_info *dsi)
-{
- Elf_Ehdr *ehdr = (Elf_Ehdr *)elfbase;
- Elf_Phdr *phdr;
- int h;
-
- char *va;
- unsigned long pa, done, chunksz;
-
- for ( h = 0; h < ehdr->e_phnum; h++ )
- {
- phdr = (Elf_Phdr *)(elfbase + ehdr->e_phoff + (h*ehdr->e_phentsize));
- if ( !is_loadable_phdr(phdr) )
- continue;
-
- for ( done = 0; done < phdr->p_filesz; done += chunksz )
- {
- pa = (phdr->p_paddr + done) - dsi->v_start;
- va = xc_map_foreign_range(
- xch, dom, PAGE_SIZE, PROT_WRITE, parray[pa>>PAGE_SHIFT]);
- chunksz = phdr->p_filesz - done;
- if ( chunksz > (PAGE_SIZE - (pa & (PAGE_SIZE-1))) )
- chunksz = PAGE_SIZE - (pa & (PAGE_SIZE-1));
- memcpy(va + (pa & (PAGE_SIZE-1)),
- elfbase + phdr->p_offset + done, chunksz);
- munmap(va, PAGE_SIZE);
- }
-
- for ( ; done < phdr->p_memsz; done += chunksz )
- {
- pa = (phdr->p_paddr + done) - dsi->v_start;
- va = xc_map_foreign_range(
- xch, dom, PAGE_SIZE, PROT_WRITE, parray[pa>>PAGE_SHIFT]);
- chunksz = phdr->p_memsz - done;
- if ( chunksz > (PAGE_SIZE - (pa & (PAGE_SIZE-1))) )
- chunksz = PAGE_SIZE - (pa & (PAGE_SIZE-1));
- memset(va + (pa & (PAGE_SIZE-1)), 0, chunksz);
- munmap(va, PAGE_SIZE);
- }
- }
-
- loadelfsymtab(elfbase, xch, dom, parray, dsi);
-
- return 0;
-}
-
-#define ELFROUND (ELFSIZE / 8)
-
-static int
-loadelfsymtab(
- char *elfbase, int xch, u32 dom, unsigned long *parray,
- struct domain_setup_info *dsi)
-{
- Elf_Ehdr *ehdr = (Elf_Ehdr *)elfbase, *sym_ehdr;
- Elf_Shdr *shdr;
- unsigned long maxva, symva;
- char *p;
- int h, i;
-
- if ( !dsi->load_symtab )
- return 0;
-
- p = malloc(sizeof(int) + sizeof(Elf_Ehdr) +
- ehdr->e_shnum * sizeof(Elf_Shdr));
- if (p == NULL)
- return 0;
-
- maxva = (dsi->v_kernend + ELFROUND - 1) & ~(ELFROUND - 1);
- symva = maxva;
- maxva += sizeof(int);
- dsi->symtab_addr = maxva;
- dsi->symtab_len = 0;
- maxva += sizeof(Elf_Ehdr) + ehdr->e_shnum * sizeof(Elf_Shdr);
- maxva = (maxva + ELFROUND - 1) & ~(ELFROUND - 1);
-
- shdr = (Elf_Shdr *)(p + sizeof(int) + sizeof(Elf_Ehdr));
- memcpy(shdr, elfbase + ehdr->e_shoff, ehdr->e_shnum * sizeof(Elf_Shdr));
-
- for ( h = 0; h < ehdr->e_shnum; h++ )
- {
- if ( shdr[h].sh_type == SHT_STRTAB )
- {
- /* Look for a strtab @i linked to symtab @h. */
- for ( i = 0; i < ehdr->e_shnum; i++ )
- if ( (shdr[i].sh_type == SHT_SYMTAB) &&
- (shdr[i].sh_link == h) )
- break;
- /* Skip symtab @h if we found no corresponding strtab @i. */
- if ( i == ehdr->e_shnum )
- {
- shdr[h].sh_offset = 0;
- continue;
- }
- }
-
- if ( (shdr[h].sh_type == SHT_STRTAB) ||
- (shdr[h].sh_type == SHT_SYMTAB) )
- {
- if ( parray != NULL )
- xc_map_memcpy(maxva, elfbase + shdr[h].sh_offset, shdr[h].sh_size,
- xch, dom, parray, dsi->v_start);
-
- /* Mangled to be based on ELF header location. */
- shdr[h].sh_offset = maxva - dsi->symtab_addr;
-
- dsi->symtab_len += shdr[h].sh_size;
- maxva += shdr[h].sh_size;
- maxva = (maxva + ELFROUND - 1) & ~(ELFROUND - 1);
- }
-
- shdr[h].sh_name = 0; /* Name is NULL. */
- }
-
- if ( dsi->symtab_len == 0 )
- {
- dsi->symtab_addr = 0;
- goto out;
- }
-
- if ( parray != NULL )
- {
- *(int *)p = maxva - dsi->symtab_addr;
- sym_ehdr = (Elf_Ehdr *)(p + sizeof(int));
- memcpy(sym_ehdr, ehdr, sizeof(Elf_Ehdr));
- sym_ehdr->e_phoff = 0;
- sym_ehdr->e_shoff = sizeof(Elf_Ehdr);
- sym_ehdr->e_phentsize = 0;
- sym_ehdr->e_phnum = 0;
- sym_ehdr->e_shstrndx = SHN_UNDEF;
-
- /* Copy total length, crafted ELF header and section header table */
- xc_map_memcpy(symva, p, sizeof(int) + sizeof(Elf_Ehdr) +
- ehdr->e_shnum * sizeof(Elf_Shdr), xch, dom, parray,
- dsi->v_start);
- }
-
- dsi->symtab_len = maxva - dsi->symtab_addr;
- dsi->v_end = round_pgup(maxva);
-
- out:
- if ( p != NULL )
- free(p);
-
- return 0;
-}
diff --git a/tools/libxc/xc_load_bin.c b/tools/libxc/xc_load_bin.c
new file mode 100644
index 0000000000..21b3e5ce51
--- /dev/null
+++ b/tools/libxc/xc_load_bin.c
@@ -0,0 +1,299 @@
+/******************************************************************************
+ * xc_bin_load.c
+ *
+ * Based on xc_elf_load.c
+ *
+ * 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 u32 magic required
+ * 4 u32 flags required
+ * 8 u32 checksum required
+ * 12 u32 header_addr required
+ * 16 u32 load_addr required
+ * 20 u32 load_end_addr required
+ * 24 u32 bss_end_addr required
+ * 28 u32 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 "xc_private.h"
+#include <stdlib.h>
+
+#define L1_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED)
+#define L2_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
+
+#define round_pgup(_p) (((_p)+(PAGE_SIZE-1))&PAGE_MASK)
+#define round_pgdown(_p) ((_p)&PAGE_MASK)
+
+struct xen_bin_image_table
+{
+ unsigned long magic;
+ unsigned long flags;
+ unsigned long checksum;
+ unsigned long header_addr;
+ unsigned long load_addr;
+ unsigned long load_end_addr;
+ unsigned long bss_end_addr;
+ unsigned long entry_addr;
+};
+
+#define XEN_REACTOS_MAGIC3 0x336ec578
+
+#define XEN_REACTOS_FLAG_ALIGN4K 0x00000001
+#define XEN_REACTOS_FLAG_NEEDMEMINFO 0x00000002
+#define XEN_REACTOS_FLAG_NEEDVIDINFO 0x00000004
+#define XEN_REACTOS_FLAG_ADDRSVALID 0x00010000
+
+/* Flags we test for */
+#define FLAGS_MASK ((~ 0) & (~ XEN_REACTOS_FLAG_ALIGN4K))
+#define FLAGS_REQUIRED XEN_REACTOS_FLAG_ADDRSVALID
+
+static struct xen_bin_image_table *
+findtable(char *image, unsigned long image_size);
+static int
+parsebinimage(
+ char *image, unsigned long image_size, struct domain_setup_info *dsi);
+static int
+loadbinimage(
+ char *image, unsigned long image_size, int xch, u32 dom,
+ unsigned long *parray, struct domain_setup_info *dsi);
+
+int xc_bin_probe(char *image,
+ unsigned long image_size,
+ struct load_funcs *load_funcs)
+{
+ if ( NULL == findtable(image, image_size) )
+ {
+ return -EINVAL;
+ }
+
+ load_funcs->parseimage = parsebinimage;
+ load_funcs->loadimage = loadbinimage;
+
+ return 0;
+}
+
+static struct xen_bin_image_table *
+findtable(char *image, unsigned long image_size)
+{
+ struct xen_bin_image_table *table;
+ unsigned long *probe_ptr;
+ unsigned probe_index;
+ unsigned probe_count;
+
+ /* Don't go outside the image */
+ if ( image_size < sizeof(struct xen_bin_image_table) )
+ {
+ return NULL;
+ }
+ probe_count = image_size;
+ /* Restrict to first 8k */
+ if ( 8192 < probe_count )
+ {
+ probe_count = 8192;
+ }
+ probe_count = (probe_count - sizeof(struct xen_bin_image_table)) /
+ sizeof(unsigned long);
+
+ /* Search for the magic header */
+ probe_ptr = (unsigned long *) image;
+ table = NULL;
+ for ( probe_index = 0; probe_index < probe_count; probe_index++ )
+ {
+ if ( XEN_REACTOS_MAGIC3 == *probe_ptr )
+ {
+ table = (struct xen_bin_image_table *) probe_ptr;
+ /* Checksum correct? */
+ if ( 0 == table->magic + table->flags + table->checksum )
+ {
+ return table;
+ }
+ }
+ probe_ptr++;
+ }
+
+ return NULL;
+}
+
+static int parsebinimage(char *image,
+ unsigned long image_size,
+ struct domain_setup_info *dsi)
+{
+ struct xen_bin_image_table *image_info;
+ unsigned long start_addr;
+ unsigned long end_addr;
+
+ image_info = findtable(image, image_size);
+ if ( NULL == image_info )
+ {
+ ERROR("Image does not have a valid xen_bin_image_table table.");
+ return -EINVAL;
+ }
+
+ /* Check the flags */
+ if ( FLAGS_REQUIRED != (image_info->flags & FLAGS_MASK) )
+ {
+ ERROR("xen_bin_image_table flags required 0x%08x found 0x%08lx",
+ 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) )
+ {
+ ERROR("Invalid header_addr.");
+ return -EINVAL;
+ }
+ start_addr = image_info->header_addr - ((char *) image_info - image);
+ if ( 0 != image_info->load_end_addr &&
+ ( image_info->load_end_addr < image_info->load_end_addr ||
+ start_addr + image_size < image_info->load_end_addr ) )
+ {
+ ERROR("Invalid load_end_addr");
+ return -EINVAL;
+ }
+ end_addr = (0 == image_info->load_end_addr ? start_addr + image_size :
+ image_info->load_end_addr);
+ if ( 0 != image_info->bss_end_addr &&
+ image_info->bss_end_addr < end_addr )
+ {
+ ERROR("Invalid bss_end_addr");
+ return -EINVAL;
+ }
+
+ dsi->v_start = image_info->load_addr;
+ if ( 0 != image_info->bss_end_addr )
+ {
+ dsi->v_end = image_info->bss_end_addr;
+ }
+ else if ( 0 != image_info->load_end_addr )
+ {
+ dsi->v_end = image_info->load_end_addr;
+ }
+ else
+ {
+ dsi->v_end = image_info->load_addr + image_size -
+ (((char *) image_info - image) -
+ (image_info->header_addr - image_info->load_addr));
+ }
+ dsi->v_kernstart = dsi->v_start;
+ dsi->v_kernend = dsi->v_end;
+ dsi->v_kernentry = image_info->entry_addr;
+
+ return 0;
+}
+
+static int
+loadbinimage(
+ char *image, unsigned long image_size, int xch, u32 dom,
+ unsigned long *parray, struct domain_setup_info *dsi)
+{
+ unsigned long size;
+ char *va;
+ unsigned long done, chunksz;
+ struct xen_bin_image_table *image_info;
+
+ image_info = findtable(image, image_size);
+ if ( NULL == image_info )
+ {
+ ERROR("Image does not have a valid xen_bin_image_table table.");
+ return -EINVAL;
+ }
+
+ /* Determine image size */
+ if ( 0 == image_info->load_end_addr )
+ {
+ size = image_size - (((char *) image_info - image) -
+ (image_info->header_addr -
+ image_info->load_addr));
+ }
+ else
+ {
+ size = image_info->load_end_addr - image_info->load_addr;
+ }
+
+ /* It's possible that we need to skip the first part of the image */
+ image += ((char *)image_info - image) -
+ (image_info->header_addr - image_info->load_addr);
+
+ for ( done = 0; done < size; done += chunksz )
+ {
+ va = xc_map_foreign_range(
+ xch, dom, PAGE_SIZE, PROT_WRITE, parray[done>>PAGE_SHIFT]);
+ chunksz = size - done;
+ if ( chunksz > PAGE_SIZE )
+ chunksz = PAGE_SIZE;
+ memcpy(va, image + done, chunksz);
+ munmap(va, PAGE_SIZE);
+ }
+
+ if ( 0 != image_info->bss_end_addr &&
+ image_info->load_addr + size < image_info->bss_end_addr )
+ {
+ size = image_info->bss_end_addr - image_info->load_addr;
+ }
+ for ( ; done < size; done += chunksz )
+ {
+ va = xc_map_foreign_range(
+ xch, dom, PAGE_SIZE, PROT_WRITE, parray[done>>PAGE_SHIFT]);
+ chunksz = size - done;
+ if ( chunksz > (PAGE_SIZE - (done & (PAGE_SIZE-1))) )
+ chunksz = PAGE_SIZE - (done & (PAGE_SIZE-1));
+ memset(va + (done & (PAGE_SIZE-1)), 0, chunksz);
+ munmap(va, PAGE_SIZE);
+ }
+
+ return 0;
+}
diff --git a/tools/libxc/xc_load_elf.c b/tools/libxc/xc_load_elf.c
new file mode 100644
index 0000000000..c4b93e53a8
--- /dev/null
+++ b/tools/libxc/xc_load_elf.c
@@ -0,0 +1,310 @@
+/******************************************************************************
+ * xc_elf_load.c
+ */
+
+#include "xc_private.h"
+
+#if defined(__i386__)
+#define ELFSIZE 32
+#endif
+#if defined(__x86_64__)
+#define ELFSIZE 64
+#endif
+
+#include "xc_elf.h"
+#include <stdlib.h>
+
+#define round_pgup(_p) (((_p)+(PAGE_SIZE-1))&PAGE_MASK)
+#define round_pgdown(_p) ((_p)&PAGE_MASK)
+
+static int
+parseelfimage(
+ char *image, unsigned long image_size, struct domain_setup_info *dsi);
+static int
+loadelfimage(
+ char *image, unsigned long image_size, int xch, u32 dom,
+ unsigned long *parray, struct domain_setup_info *dsi);
+static int
+loadelfsymtab(
+ char *image, int xch, u32 dom, unsigned long *parray,
+ struct domain_setup_info *dsi);
+
+int xc_elf_probe(char *image,
+ unsigned long image_size,
+ struct load_funcs *load_funcs)
+{
+ Elf_Ehdr *ehdr = (Elf_Ehdr *)image;
+
+ if ( !IS_ELF(*ehdr) )
+ {
+ return -EINVAL;
+ }
+
+ load_funcs->parseimage = parseelfimage;
+ load_funcs->loadimage = loadelfimage;
+
+ return 0;
+}
+
+static inline int is_loadable_phdr(Elf_Phdr *phdr)
+{
+ return ((phdr->p_type == PT_LOAD) &&
+ ((phdr->p_flags & (PF_W|PF_X)) != 0));
+}
+
+static int parseelfimage(char *image,
+ unsigned long elfsize,
+ struct domain_setup_info *dsi)
+{
+ Elf_Ehdr *ehdr = (Elf_Ehdr *)image;
+ Elf_Phdr *phdr;
+ Elf_Shdr *shdr;
+ unsigned long kernstart = ~0UL, kernend=0UL;
+ char *shstrtab, *guestinfo=NULL, *p;
+ int h;
+
+ if ( !IS_ELF(*ehdr) )
+ {
+ ERROR("Kernel image does not have an ELF header.");
+ return -EINVAL;
+ }
+
+ if ( (ehdr->e_phoff + (ehdr->e_phnum * ehdr->e_phentsize)) > elfsize )
+ {
+ ERROR("ELF program headers extend beyond end of image.");
+ return -EINVAL;
+ }
+
+ if ( (ehdr->e_shoff + (ehdr->e_shnum * ehdr->e_shentsize)) > elfsize )
+ {
+ ERROR("ELF section headers extend beyond end of image.");
+ return -EINVAL;
+ }
+
+ /* Find the section-header strings table. */
+ if ( ehdr->e_shstrndx == SHN_UNDEF )
+ {
+ ERROR("ELF image has no section-header strings table (shstrtab).");
+ return -EINVAL;
+ }
+ shdr = (Elf_Shdr *)(image + ehdr->e_shoff +
+ (ehdr->e_shstrndx*ehdr->e_shentsize));
+ shstrtab = image + shdr->sh_offset;
+
+ /* Find the special '__xen_guest' section and check its contents. */
+ for ( h = 0; h < ehdr->e_shnum; h++ )
+ {
+ shdr = (Elf_Shdr *)(image + ehdr->e_shoff + (h*ehdr->e_shentsize));
+ if ( strcmp(&shstrtab[shdr->sh_name], "__xen_guest") != 0 )
+ continue;
+
+ guestinfo = image + shdr->sh_offset;
+
+ if ( (strstr(guestinfo, "LOADER=generic") == NULL) &&
+ (strstr(guestinfo, "GUEST_OS=linux") == NULL) )
+ {
+ ERROR("Will only load images built for the generic loader "
+ "or Linux images");
+ ERROR("Actually saw: '%s'", guestinfo);
+ return -EINVAL;
+ }
+
+ if ( (strstr(guestinfo, "XEN_VER=3.0") == NULL) )
+ {
+ ERROR("Will only load images built for Xen v3.0");
+ ERROR("Actually saw: '%s'", guestinfo);
+ return -EINVAL;
+ }
+
+ break;
+ }
+ if ( guestinfo == NULL )
+ {
+ ERROR("Not a Xen-ELF image: '__xen_guest' section not found.");
+ return -EINVAL;
+ }
+
+ for ( h = 0; h < ehdr->e_phnum; h++ )
+ {
+ phdr = (Elf_Phdr *)(image + ehdr->e_phoff + (h*ehdr->e_phentsize));
+ if ( !is_loadable_phdr(phdr) )
+ continue;
+ if ( phdr->p_paddr < kernstart )
+ kernstart = phdr->p_paddr;
+ if ( (phdr->p_paddr + phdr->p_memsz) > kernend )
+ kernend = phdr->p_paddr + phdr->p_memsz;
+ }
+
+ if ( (kernstart > kernend) ||
+ (ehdr->e_entry < kernstart) ||
+ (ehdr->e_entry > kernend) )
+ {
+ ERROR("Malformed ELF image.");
+ return -EINVAL;
+ }
+
+ dsi->v_start = kernstart;
+ if ( (p = strstr(guestinfo, "VIRT_BASE=")) != NULL )
+ dsi->v_start = strtoul(p+10, &p, 0);
+
+ if ( (p = strstr(guestinfo, "BSD_SYMTAB")) != NULL )
+ dsi->load_symtab = 1;
+
+ dsi->v_kernstart = kernstart;
+ dsi->v_kernend = kernend;
+ dsi->v_kernentry = ehdr->e_entry;
+ dsi->v_end = dsi->v_kernend;
+
+ loadelfsymtab(image, 0, 0, NULL, dsi);
+
+ return 0;
+}
+
+static int
+loadelfimage(
+ char *image, unsigned long elfsize, int xch, u32 dom,
+ unsigned long *parray, struct domain_setup_info *dsi)
+{
+ Elf_Ehdr *ehdr = (Elf_Ehdr *)image;
+ Elf_Phdr *phdr;
+ int h;
+
+ char *va;
+ unsigned long pa, done, chunksz;
+
+ for ( h = 0; h < ehdr->e_phnum; h++ )
+ {
+ phdr = (Elf_Phdr *)(image + ehdr->e_phoff + (h*ehdr->e_phentsize));
+ if ( !is_loadable_phdr(phdr) )
+ continue;
+
+ for ( done = 0; done < phdr->p_filesz; done += chunksz )
+ {
+ pa = (phdr->p_paddr + done) - dsi->v_start;
+ va = xc_map_foreign_range(
+ xch, dom, PAGE_SIZE, PROT_WRITE, parray[pa>>PAGE_SHIFT]);
+ chunksz = phdr->p_filesz - done;
+ if ( chunksz > (PAGE_SIZE - (pa & (PAGE_SIZE-1))) )
+ chunksz = PAGE_SIZE - (pa & (PAGE_SIZE-1));
+ memcpy(va + (pa & (PAGE_SIZE-1)),
+ image + phdr->p_offset + done, chunksz);
+ munmap(va, PAGE_SIZE);
+ }
+
+ for ( ; done < phdr->p_memsz; done += chunksz )
+ {
+ pa = (phdr->p_paddr + done) - dsi->v_start;
+ va = xc_map_foreign_range(
+ xch, dom, PAGE_SIZE, PROT_WRITE, parray[pa>>PAGE_SHIFT]);
+ chunksz = phdr->p_memsz - done;
+ if ( chunksz > (PAGE_SIZE - (pa & (PAGE_SIZE-1))) )
+ chunksz = PAGE_SIZE - (pa & (PAGE_SIZE-1));
+ memset(va + (pa & (PAGE_SIZE-1)), 0, chunksz);
+ munmap(va, PAGE_SIZE);
+ }
+ }
+
+ loadelfsymtab(image, xch, dom, parray, dsi);
+
+ return 0;
+}
+
+#define ELFROUND (ELFSIZE / 8)
+
+static int
+loadelfsymtab(
+ char *image, int xch, u32 dom, unsigned long *parray,
+ struct domain_setup_info *dsi)
+{
+ Elf_Ehdr *ehdr = (Elf_Ehdr *)image, *sym_ehdr;
+ Elf_Shdr *shdr;
+ unsigned long maxva, symva;
+ char *p;
+ int h, i;
+
+ if ( !dsi->load_symtab )
+ return 0;
+
+ p = malloc(sizeof(int) + sizeof(Elf_Ehdr) +
+ ehdr->e_shnum * sizeof(Elf_Shdr));
+ if (p == NULL)
+ return 0;
+
+ maxva = (dsi->v_kernend + ELFROUND - 1) & ~(ELFROUND - 1);
+ symva = maxva;
+ maxva += sizeof(int);
+ dsi->symtab_addr = maxva;
+ dsi->symtab_len = 0;
+ maxva += sizeof(Elf_Ehdr) + ehdr->e_shnum * sizeof(Elf_Shdr);
+ maxva = (maxva + ELFROUND - 1) & ~(ELFROUND - 1);
+
+ shdr = (Elf_Shdr *)(p + sizeof(int) + sizeof(Elf_Ehdr));
+ memcpy(shdr, image + ehdr->e_shoff, ehdr->e_shnum * sizeof(Elf_Shdr));
+
+ for ( h = 0; h < ehdr->e_shnum; h++ )
+ {
+ if ( shdr[h].sh_type == SHT_STRTAB )
+ {
+ /* Look for a strtab @i linked to symtab @h. */
+ for ( i = 0; i < ehdr->e_shnum; i++ )
+ if ( (shdr[i].sh_type == SHT_SYMTAB) &&
+ (shdr[i].sh_link == h) )
+ break;
+ /* Skip symtab @h if we found no corresponding strtab @i. */
+ if ( i == ehdr->e_shnum )
+ {
+ shdr[h].sh_offset = 0;
+ continue;
+ }
+ }
+
+ if ( (shdr[h].sh_type == SHT_STRTAB) ||
+ (shdr[h].sh_type == SHT_SYMTAB) )
+ {
+ if ( parray != NULL )
+ xc_map_memcpy(maxva, image + shdr[h].sh_offset, shdr[h].sh_size,
+ xch, dom, parray, dsi->v_start);
+
+ /* Mangled to be based on ELF header location. */
+ shdr[h].sh_offset = maxva - dsi->symtab_addr;
+
+ dsi->symtab_len += shdr[h].sh_size;
+ maxva += shdr[h].sh_size;
+ maxva = (maxva + ELFROUND - 1) & ~(ELFROUND - 1);
+ }
+
+ shdr[h].sh_name = 0; /* Name is NULL. */
+ }
+
+ if ( dsi->symtab_len == 0 )
+ {
+ dsi->symtab_addr = 0;
+ goto out;
+ }
+
+ if ( parray != NULL )
+ {
+ *(int *)p = maxva - dsi->symtab_addr;
+ sym_ehdr = (Elf_Ehdr *)(p + sizeof(int));
+ memcpy(sym_ehdr, ehdr, sizeof(Elf_Ehdr));
+ sym_ehdr->e_phoff = 0;
+ sym_ehdr->e_shoff = sizeof(Elf_Ehdr);
+ sym_ehdr->e_phentsize = 0;
+ sym_ehdr->e_phnum = 0;
+ sym_ehdr->e_shstrndx = SHN_UNDEF;
+
+ /* Copy total length, crafted ELF header and section header table */
+ xc_map_memcpy(symva, p, sizeof(int) + sizeof(Elf_Ehdr) +
+ ehdr->e_shnum * sizeof(Elf_Shdr), xch, dom, parray,
+ dsi->v_start);
+ }
+
+ dsi->symtab_len = maxva - dsi->symtab_addr;
+ dsi->v_end = round_pgup(maxva);
+
+ out:
+ if ( p != NULL )
+ free(p);
+
+ return 0;
+}
diff --git a/tools/libxc/xc_private.h b/tools/libxc/xc_private.h
index f5ab319e66..baf1e5f26d 100644
--- a/tools/libxc/xc_private.h
+++ b/tools/libxc/xc_private.h
@@ -76,6 +76,31 @@ typedef unsigned long l4_pgentry_t;
(((_a) >> L4_PAGETABLE_SHIFT) & (L4_PAGETABLE_ENTRIES - 1))
#endif
+struct domain_setup_info
+{
+ unsigned long v_start;
+ unsigned long v_end;
+ unsigned long v_kernstart;
+ unsigned long v_kernend;
+ unsigned long v_kernentry;
+
+ unsigned int load_symtab;
+ unsigned long symtab_addr;
+ unsigned long symtab_len;
+};
+
+typedef int (*parseimagefunc)(char *image, unsigned long image_size,
+ struct domain_setup_info *dsi);
+typedef int (*loadimagefunc)(char *image, unsigned long image_size, int xch,
+ u32 dom, unsigned long *parray,
+ struct domain_setup_info *dsi);
+
+struct load_funcs
+{
+ parseimagefunc parseimage;
+ loadimagefunc loadimage;
+};
+
#define ERROR(_m, _a...) \
fprintf(stderr, "ERROR: " _m "\n" , ## _a )
@@ -260,7 +285,7 @@ typedef struct mfn_mapper {
} mfn_mapper_t;
-unsigned long xc_get_m2p_start_mfn ( int xc_handle );
+unsigned long xc_get_m2p_start_mfn (int xc_handle);
int xc_copy_to_domain_page(int xc_handle, u32 domid,
unsigned long dst_pfn, void *src_page);
@@ -273,7 +298,11 @@ void xc_map_memcpy(unsigned long dst, char *src, unsigned long size,
int xch, u32 dom, unsigned long *parray,
unsigned long vstart);
-int pin_table(
- int xc_handle, unsigned int type, unsigned long mfn, domid_t dom);
+int pin_table(int xc_handle, unsigned int type, unsigned long mfn,
+ domid_t dom);
+
+/* image loading */
+int probe_elf(char *image, unsigned long image_size, struct load_funcs *funcs);
+int probe_bin(char *image, unsigned long image_size, struct load_funcs *funcs);
#endif /* __XC_PRIVATE_H__ */
diff --git a/tools/libxc/xc_vmx_build.c b/tools/libxc/xc_vmx_build.c
index 5cbd9b8577..b5e948c622 100644
--- a/tools/libxc/xc_vmx_build.c
+++ b/tools/libxc/xc_vmx_build.c
@@ -20,22 +20,13 @@
#define LINUX_KERNEL_ENTR_ADDR 0x00100000
#define LINUX_PAGE_OFFSET 0xC0000000
-struct domain_setup_info
-{
- unsigned long v_start;
- unsigned long v_end;
- unsigned long v_kernstart;
- unsigned long v_kernend;
- unsigned long v_kernentry;
-};
-
static int
parseelfimage(
char *elfbase, unsigned long elfsize, struct domain_setup_info *dsi);
static int
loadelfimage(
char *elfbase, int xch, u32 dom, unsigned long *parray,
- unsigned long vstart);
+ struct domain_setup_info *dsi);
static void build_e820map(struct mem_map *mem_mapp, unsigned long mem_size)
{
@@ -255,7 +246,7 @@ static int setup_guest(int xc_handle,
goto error_out;
}
- loadelfimage(image, xc_handle, dom, page_array, dsi.v_start);
+ loadelfimage(image, xc_handle, dom, page_array, &dsi);
/* Load the initial ramdisk image. */
if ( initrd_len != 0 )
@@ -626,6 +617,7 @@ int xc_vmx_build(int xc_handle,
launch_op.cmd = DOM0_SETDOMAININFO;
rc = do_dom0_op(xc_handle, &launch_op);
+
return rc;
error_out:
@@ -717,7 +709,7 @@ static int parseelfimage(char *elfbase,
static int
loadelfimage(
char *elfbase, int xch, u32 dom, unsigned long *parray,
- unsigned long vstart)
+ struct domain_setup_info *dsi)
{
Elf_Ehdr *ehdr = (Elf_Ehdr *)elfbase;
Elf_Phdr *phdr;
@@ -734,7 +726,7 @@ loadelfimage(
for ( done = 0; done < phdr->p_filesz; done += chunksz )
{
- pa = (phdr->p_paddr + done) - vstart - LINUX_PAGE_OFFSET;
+ pa = (phdr->p_paddr + done) - dsi->v_start - LINUX_PAGE_OFFSET;
if ((va = xc_map_foreign_range(
xch, dom, PAGE_SIZE, PROT_WRITE,
parray[pa>>PAGE_SHIFT])) == 0)
@@ -749,7 +741,7 @@ loadelfimage(
for ( ; done < phdr->p_memsz; done += chunksz )
{
- pa = (phdr->p_paddr + done) - vstart - LINUX_PAGE_OFFSET;
+ pa = (phdr->p_paddr + done) - dsi->v_start - LINUX_PAGE_OFFSET;
if ((va = xc_map_foreign_range(
xch, dom, PAGE_SIZE, PROT_WRITE,
parray[pa>>PAGE_SHIFT])) == 0)