mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 10:40:03 +01:00
As recommended in http://www.gnu.org/licenses/gpl-howto.en.html. This is the result of: $ git grep -El Mass\|Temple\|Franklin | xargs ./fsf.pl Where fsf.pl is: #!/usr/bin/perl -w -pi.bak -0777 my $repl = 'If not, see <http://www.gnu.org/licenses/>.'; my $br = qr/(?:\s*\n\s*(?:[\*\#]|\/\/|\.\\" )?\s*|\s+)/; my $inwt = qr/[Ii]f${br}not,${br}write${br}(?:to${br})?the${br}Free${br}Software${br}Foundation,(?:${br}Inc\.,)?/; my $mass = qr/675${br}Mass${br}Ave,?${br}Cambridge,?${br}MA${br}02139,?${br}USA,?\.?/; my $franklin = qr/51${br}Franklin${br}St(?:reet)?(?:,${br}| - )Fifth${br}Floor,?${br}Boston,?${br}MA,?${br}02110-1301,?${br}USA,?\.?/; my $temple = qr/59${br}Temple${br}Place(?:,${br}| - )Suite${br}330,?${br}Boston,?${br}MA,?${br}021110?-1307,?${br}USA,?\.?/; s|$inwt$br$mass|$repl|m; s|$inwt$br$franklin|$repl|m; s|$inwt$br$temple|$repl|m; The only remaining mentions of these addresses are in COPYING files which I haven't touched. Some of the changed files are imports from elsewhere, however filtering them out is tricky, I think it is tolerable to have these files be modified here and then perhaps reverted on the next sync, since it's only 1-2 lines and obvious what is going on. Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
429 lines
13 KiB
C
429 lines
13 KiB
C
/*
|
|
* 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 <http://www.gnu.org/licenses/>.
|
|
*
|
|
* written 2006 by Gerd Hoffmann <kraxel@suse.de>.
|
|
*
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdarg.h>
|
|
#include <inttypes.h>
|
|
|
|
#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);
|
|
|
|
switch ( machine )
|
|
{
|
|
case EM_386:
|
|
switch ( dom->parms.pae )
|
|
{
|
|
case 3 /* PAEKERN_bimodal */:
|
|
if ( strstr(dom->xen_caps, "xen-3.0-x86_32p") )
|
|
return "xen-3.0-x86_32p";
|
|
return "xen-3.0-x86_32";
|
|
case PAEKERN_extended_cr3:
|
|
case PAEKERN_yes:
|
|
return "xen-3.0-x86_32p";
|
|
case PAEKERN_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)
|
|
{
|
|
return check_elf_kernel(dom, 0);
|
|
}
|
|
|
|
static elf_errorstatus xc_dom_load_elf_symtab(struct xc_dom_image *dom,
|
|
struct elf_binary *elf, bool load)
|
|
{
|
|
struct elf_binary syms;
|
|
ELF_HANDLE_DECL(elf_shdr) shdr; ELF_HANDLE_DECL(elf_shdr) shdr2;
|
|
xen_vaddr_t symtab, maxaddr;
|
|
elf_ptrval hdr;
|
|
size_t size;
|
|
unsigned h, count, type, i, tables = 0;
|
|
unsigned long *strtab_referenced = NULL;
|
|
|
|
if ( elf_swap(elf) )
|
|
{
|
|
DOMPRINTF("%s: non-native byte order, bsd symtab not supported",
|
|
__FUNCTION__);
|
|
return 0;
|
|
}
|
|
|
|
size = elf->bsd_symtab_pend - elf->bsd_symtab_pstart;
|
|
|
|
if ( load )
|
|
{
|
|
char *hdr_ptr;
|
|
size_t allow_size;
|
|
|
|
if ( !dom->bsd_symtab_start )
|
|
return 0;
|
|
hdr_ptr = xc_dom_vaddr_to_ptr(dom, dom->bsd_symtab_start, &allow_size);
|
|
if ( hdr_ptr == NULL )
|
|
{
|
|
DOMPRINTF("%s: xc_dom_vaddr_to_ptr(dom,dom->bsd_symtab_start"
|
|
" => NULL", __FUNCTION__);
|
|
return -1;
|
|
}
|
|
elf->caller_xdest_base = hdr_ptr;
|
|
elf->caller_xdest_size = allow_size;
|
|
hdr = ELF_REALPTR2PTRVAL(hdr_ptr);
|
|
elf_store_val(elf, unsigned, hdr, size - sizeof(unsigned));
|
|
}
|
|
else
|
|
{
|
|
char *hdr_ptr;
|
|
|
|
hdr_ptr = xc_dom_malloc(dom, size);
|
|
if ( hdr_ptr == NULL )
|
|
return 0;
|
|
elf->caller_xdest_base = hdr_ptr;
|
|
elf->caller_xdest_size = size;
|
|
hdr = ELF_REALPTR2PTRVAL(hdr_ptr);
|
|
dom->bsd_symtab_start = elf_round_up(elf, dom->kernel_seg.vend);
|
|
dom->kernel_seg.vend = elf_round_up(elf, dom->bsd_symtab_start + size);
|
|
return 0;
|
|
}
|
|
|
|
elf_memcpy_safe(elf, hdr + sizeof(unsigned),
|
|
ELF_IMAGE_BASE(elf),
|
|
elf_size(elf, elf->ehdr));
|
|
elf_memcpy_safe(elf, hdr + sizeof(unsigned) + elf_size(elf, elf->ehdr),
|
|
ELF_IMAGE_BASE(elf) + elf_uval(elf, elf->ehdr, e_shoff),
|
|
elf_shdr_count(elf) * elf_size(elf, shdr));
|
|
if ( elf_64bit(elf) )
|
|
{
|
|
Elf64_Ehdr *ehdr = (Elf64_Ehdr *)(hdr + sizeof(unsigned));
|
|
ehdr->e_phoff = 0;
|
|
ehdr->e_phentsize = 0;
|
|
ehdr->e_phnum = 0;
|
|
ehdr->e_shoff = elf_size(elf, elf->ehdr);
|
|
ehdr->e_shstrndx = SHN_UNDEF;
|
|
}
|
|
else
|
|
{
|
|
Elf32_Ehdr *ehdr = (Elf32_Ehdr *)(hdr + sizeof(unsigned));
|
|
ehdr->e_phoff = 0;
|
|
ehdr->e_phentsize = 0;
|
|
ehdr->e_phnum = 0;
|
|
ehdr->e_shoff = elf_size(elf, elf->ehdr);
|
|
ehdr->e_shstrndx = SHN_UNDEF;
|
|
}
|
|
if ( elf->caller_xdest_size < sizeof(unsigned) )
|
|
{
|
|
DOMPRINTF("%s: header size %"PRIx64" too small",
|
|
__FUNCTION__, (uint64_t)elf->caller_xdest_size);
|
|
return -1;
|
|
}
|
|
if ( elf_init(&syms, elf->caller_xdest_base + sizeof(unsigned),
|
|
elf->caller_xdest_size - sizeof(unsigned)) )
|
|
return -1;
|
|
|
|
/*
|
|
* The caller_xdest_{base,size} and dest_{base,size} need to
|
|
* remain valid so long as each struct elf_image does. The
|
|
* principle we adopt is that these values are set when the
|
|
* memory is allocated or mapped, and cleared when (and if)
|
|
* they are unmapped.
|
|
*
|
|
* Mappings of the guest are normally undone by xc_dom_unmap_all
|
|
* (directly or via xc_dom_release). We do not explicitly clear
|
|
* these because in fact that happens only at the end of
|
|
* xc_dom_boot_image, at which time all of these ELF loading
|
|
* functions have returned. No relevant struct elf_binary*
|
|
* escapes this file.
|
|
*/
|
|
|
|
xc_elf_set_logfile(dom->xch, &syms, 1);
|
|
|
|
symtab = dom->bsd_symtab_start + sizeof(unsigned);
|
|
maxaddr = elf_round_up(&syms, symtab + elf_size(&syms, syms.ehdr) +
|
|
elf_shdr_count(&syms) * elf_size(&syms, shdr));
|
|
|
|
DOMPRINTF("%s: bsd_symtab_start=%" PRIx64 ", kernel.end=0x%" PRIx64
|
|
" -- symtab=0x%" PRIx64 ", maxaddr=0x%" PRIx64 "",
|
|
__FUNCTION__, dom->bsd_symtab_start, dom->kernel_seg.vend,
|
|
symtab, maxaddr);
|
|
|
|
count = elf_shdr_count(&syms);
|
|
/* elf_shdr_count guarantees that count is reasonable */
|
|
|
|
strtab_referenced = xc_dom_malloc(dom, bitmap_size(count));
|
|
if ( strtab_referenced == NULL )
|
|
return -1;
|
|
bitmap_clear(strtab_referenced, count);
|
|
/* Note the symtabs @h linked to by any strtab @i. */
|
|
for ( i = 0; i < count; i++ )
|
|
{
|
|
shdr2 = elf_shdr_by_index(&syms, i);
|
|
if ( elf_uval(&syms, shdr2, sh_type) == SHT_SYMTAB )
|
|
{
|
|
h = elf_uval(&syms, shdr2, sh_link);
|
|
if (h < count)
|
|
set_bit(h, strtab_referenced);
|
|
}
|
|
}
|
|
|
|
for ( h = 0; h < count; h++ )
|
|
{
|
|
shdr = elf_shdr_by_index(&syms, h);
|
|
if ( !elf_access_ok(elf, ELF_HANDLE_PTRVAL(shdr), 1) )
|
|
/* input has an insane section header count field */
|
|
break;
|
|
type = elf_uval(&syms, shdr, sh_type);
|
|
if ( type == SHT_STRTAB )
|
|
{
|
|
/* Skip symtab @h if we found no corresponding strtab @i. */
|
|
if ( !test_bit(h, strtab_referenced) )
|
|
{
|
|
if ( elf_64bit(&syms) )
|
|
elf_store_field(elf, shdr, e64.sh_offset, 0);
|
|
else
|
|
elf_store_field(elf, shdr, e32.sh_offset, 0);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if ( (type == SHT_STRTAB) || (type == SHT_SYMTAB) )
|
|
{
|
|
/* Mangled to be based on ELF header location. */
|
|
if ( elf_64bit(&syms) )
|
|
elf_store_field(elf, shdr, e64.sh_offset, maxaddr - symtab);
|
|
else
|
|
elf_store_field(elf, shdr, e32.sh_offset, maxaddr - symtab);
|
|
size = elf_uval(&syms, shdr, sh_size);
|
|
maxaddr = elf_round_up(&syms, maxaddr + size);
|
|
tables++;
|
|
DOMPRINTF("%s: h=%u %s, size=0x%zx, maxaddr=0x%" PRIx64 "",
|
|
__FUNCTION__, h,
|
|
type == SHT_SYMTAB ? "symtab" : "strtab",
|
|
size, maxaddr);
|
|
|
|
shdr2 = elf_shdr_by_index(elf, h);
|
|
elf_memcpy_safe(elf, elf_section_start(&syms, shdr),
|
|
elf_section_start(elf, shdr2),
|
|
size);
|
|
}
|
|
|
|
/* Name is NULL. */
|
|
if ( elf_64bit(&syms) )
|
|
elf_store_field(elf, shdr, e64.sh_name, 0);
|
|
else
|
|
elf_store_field(elf, shdr, e32.sh_name, 0);
|
|
}
|
|
|
|
if ( elf_check_broken(&syms) )
|
|
DOMPRINTF("%s: symbols ELF broken: %s", __FUNCTION__,
|
|
elf_check_broken(&syms));
|
|
if ( elf_check_broken(elf) )
|
|
DOMPRINTF("%s: ELF broken: %s", __FUNCTION__,
|
|
elf_check_broken(elf));
|
|
|
|
if ( tables == 0 )
|
|
{
|
|
DOMPRINTF("%s: no symbol table present", __FUNCTION__);
|
|
dom->bsd_symtab_start = 0;
|
|
return 0;
|
|
}
|
|
|
|
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;
|
|
|
|
if ( dom->parms.bsd_symtab )
|
|
xc_dom_load_elf_symtab(dom, elf, 0);
|
|
|
|
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;
|
|
}
|
|
if ( dom->parms.bsd_symtab )
|
|
xc_dom_load_elf_symtab(dom, elf, 1);
|
|
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:
|
|
*/
|