diff options
author | cl349@firebug.cl.cam.ac.uk <cl349@firebug.cl.cam.ac.uk> | 2005-06-06 08:44:42 +0000 |
---|---|---|
committer | cl349@firebug.cl.cam.ac.uk <cl349@firebug.cl.cam.ac.uk> | 2005-06-06 08:44:42 +0000 |
commit | ce52246261870f4389783e71a8cb0d806c672850 (patch) | |
tree | a5fddf24fdc41ec26f4e450d3ff6222e9348d69b | |
parent | 361f01aebc40d039b253e0112552928f7b149d1d (diff) | |
parent | aac7970f2642ba831248bc0748985e49d4fd32ba (diff) | |
download | xen-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-- | .rootkeys | 2 | ||||
-rw-r--r-- | tools/libxc/Makefile | 2 | ||||
-rw-r--r-- | tools/libxc/xc_linux_build.c | 308 | ||||
-rw-r--r-- | tools/libxc/xc_load_bin.c | 299 | ||||
-rw-r--r-- | tools/libxc/xc_load_elf.c | 310 | ||||
-rw-r--r-- | tools/libxc/xc_private.h | 35 | ||||
-rw-r--r-- | tools/libxc/xc_vmx_build.c | 20 |
7 files changed, 671 insertions, 305 deletions
@@ -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) |