/* * Xen domain builder -- ELF bits. * * Parse and load ELF kernel images. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; If not, see . * * written 2006 by Gerd Hoffmann . * */ #include #include #include #include #include "xg_private.h" #include "xc_dom.h" #include "xc_bitops.h" #define XEN_VER "xen-3.0" /* ------------------------------------------------------------------------ */ static void log_callback(struct elf_binary *elf, void *caller_data, bool iserr, const char *fmt, va_list al) { xc_interface *xch = caller_data; xc_reportv(xch, xch->dombuild_logger ? xch->dombuild_logger : xch->error_handler, iserr ? XTL_ERROR : XTL_DETAIL, iserr ? XC_INVALID_KERNEL : XC_ERROR_NONE, fmt, al); } void xc_elf_set_logfile(xc_interface *xch, struct elf_binary *elf, int verbose) { elf_set_log(elf, log_callback, xch, verbose /* convert to bool */); } /* ------------------------------------------------------------------------ */ static char *xc_dom_guest_type(struct xc_dom_image *dom, struct elf_binary *elf) { uint64_t machine = elf_uval(elf, elf->ehdr, e_machine); if ( dom->container_type == XC_DOM_HVM_CONTAINER && dom->parms.phys_entry != UNSET_ADDR32 ) return "hvm-3.0-x86_32"; if ( dom->container_type == XC_DOM_HVM_CONTAINER ) { xc_dom_panic(dom->xch, XC_INVALID_KERNEL, "%s: image not capable of booting inside a HVM container", __FUNCTION__); return "xen-3.0-unknown"; } switch ( machine ) { case EM_386: switch ( dom->parms.pae ) { case XEN_PAE_BIMODAL: if ( strstr(dom->xen_caps, "xen-3.0-x86_32p") ) return "xen-3.0-x86_32p"; return "xen-3.0-x86_32"; case XEN_PAE_EXTCR3: case XEN_PAE_YES: return "xen-3.0-x86_32p"; case XEN_PAE_NO: default: return "xen-3.0-x86_32"; } case EM_X86_64: return "xen-3.0-x86_64"; default: return "xen-3.0-unknown"; } } /* ------------------------------------------------------------------------ */ /* parse elf binary */ static elf_negerrnoval check_elf_kernel(struct xc_dom_image *dom, bool verbose) { if ( dom->kernel_blob == NULL ) { if ( verbose ) xc_dom_panic(dom->xch, XC_INTERNAL_ERROR, "%s: no kernel image loaded", __FUNCTION__); return -EINVAL; } if ( !elf_is_elfbinary(dom->kernel_blob, dom->kernel_size) ) { if ( verbose ) xc_dom_panic(dom->xch, XC_INVALID_KERNEL, "%s: kernel is not an ELF image", __FUNCTION__); return -EINVAL; } return 0; } static elf_negerrnoval xc_dom_probe_elf_kernel(struct xc_dom_image *dom) { struct elf_binary elf; int rc; rc = check_elf_kernel(dom, 0); if ( rc != 0 ) return rc; rc = elf_init(&elf, dom->kernel_blob, dom->kernel_size); if ( rc != 0 ) return rc; /* * We need to check that it contains Xen ELFNOTES, * or else we might be trying to load a plain ELF. */ elf_parse_binary(&elf); rc = elf_xen_parse(&elf, &dom->parms); if ( rc != 0 ) return rc; return 0; } static elf_errorstatus xc_dom_parse_elf_kernel(struct xc_dom_image *dom) /* * This function sometimes returns -1 for error and sometimes * an errno value. ?!?! */ { struct elf_binary *elf; elf_errorstatus rc; rc = check_elf_kernel(dom, 1); if ( rc != 0 ) return rc; elf = xc_dom_malloc(dom, sizeof(*elf)); if ( elf == NULL ) return -1; dom->private_loader = elf; rc = elf_init(elf, dom->kernel_blob, dom->kernel_size); xc_elf_set_logfile(dom->xch, elf, 1); if ( rc != 0 ) { xc_dom_panic(dom->xch, XC_INVALID_KERNEL, "%s: corrupted ELF image", __FUNCTION__); return rc; } /* Find the section-header strings table. */ if ( ELF_PTRVAL_INVALID(elf->sec_strtab) ) { xc_dom_panic(dom->xch, XC_INVALID_KERNEL, "%s: ELF image" " has no shstrtab", __FUNCTION__); rc = -EINVAL; goto out; } /* parse binary and get xen meta info */ elf_parse_binary(elf); if ( (rc = elf_xen_parse(elf, &dom->parms)) != 0 ) { goto out; } if ( elf_xen_feature_get(XENFEAT_dom0, dom->parms.f_required) ) { xc_dom_panic(dom->xch, XC_INVALID_KERNEL, "%s: Kernel does not" " support unprivileged (DomU) operation", __FUNCTION__); rc = -EINVAL; goto out; } /* find kernel segment */ dom->kernel_seg.vstart = dom->parms.virt_kstart; dom->kernel_seg.vend = dom->parms.virt_kend; dom->guest_type = xc_dom_guest_type(dom, elf); DOMPRINTF("%s: %s: 0x%" PRIx64 " -> 0x%" PRIx64 "", __FUNCTION__, dom->guest_type, dom->kernel_seg.vstart, dom->kernel_seg.vend); rc = 0; out: if ( elf_check_broken(elf) ) DOMPRINTF("%s: ELF broken: %s", __FUNCTION__, elf_check_broken(elf)); return rc; } static elf_errorstatus xc_dom_load_elf_kernel(struct xc_dom_image *dom) { struct elf_binary *elf = dom->private_loader; elf_errorstatus rc; xen_pfn_t pages; elf->dest_base = xc_dom_seg_to_ptr_pages(dom, &dom->kernel_seg, &pages); if ( elf->dest_base == NULL ) { DOMPRINTF("%s: xc_dom_vaddr_to_ptr(dom,dom->kernel_seg)" " => NULL", __FUNCTION__); return -1; } elf->dest_size = pages * XC_DOM_PAGE_SIZE(dom); rc = elf_load_binary(elf); if ( rc < 0 ) { DOMPRINTF("%s: failed to load elf binary", __FUNCTION__); return rc; } return 0; } /* ------------------------------------------------------------------------ */ struct xc_dom_loader elf_loader = { .name = "ELF-generic", .probe = xc_dom_probe_elf_kernel, .parser = xc_dom_parse_elf_kernel, .loader = xc_dom_load_elf_kernel, }; static void __init register_loader(void) { xc_dom_register_loader(&elf_loader); } /* * Local variables: * mode: C * c-file-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */