[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [xen master] tools/libs: move xc_core* from libxenctrl to libxenguest
commit 455790573d3bbad6d5a1bb7e9d28b6dd71075693 Author: Juergen Gross <jgross@xxxxxxxx> AuthorDate: Fri Jun 4 08:02:13 2021 +0200 Commit: Julien Grall <jgrall@xxxxxxxxxx> CommitDate: Fri Jun 4 18:56:46 2021 +0100 tools/libs: move xc_core* from libxenctrl to libxenguest The functionality in xc_core* should be part of libxenguest instead of libxenctrl. Users are already either in libxenguest, or in xl. There is one single exception: xc_core_arch_auto_translated_physmap() is being used by xc_domain_memory_mapping(), which is used by qemu. So leave the xc_core_arch_auto_translated_physmap() functionality in libxenctrl. This will make it easier to merge common functionality of xc_core* and xg_sr_save*. Signed-off-by: Juergen Gross <jgross@xxxxxxxx> Acked-by: Wei Liu <wl@xxxxxxx> --- tools/libs/ctrl/Makefile | 3 - tools/libs/ctrl/xc_core.c | 1027 ------------------------------------ tools/libs/ctrl/xc_core.h | 176 ------ tools/libs/ctrl/xc_core_arm.c | 113 ---- tools/libs/ctrl/xc_core_arm.h | 59 --- tools/libs/ctrl/xc_core_x86.c | 391 -------------- tools/libs/ctrl/xc_core_x86.h | 60 --- tools/libs/ctrl/xc_domain.c | 2 - tools/libs/ctrl/xc_private.h | 12 + tools/libs/guest/Makefile | 3 + tools/libs/guest/xg_core.c | 1027 ++++++++++++++++++++++++++++++++++++ tools/libs/guest/xg_core.h | 175 ++++++ tools/libs/guest/xg_core_arm.c | 107 ++++ tools/libs/guest/xg_core_arm.h | 59 +++ tools/libs/guest/xg_core_x86.c | 385 ++++++++++++++ tools/libs/guest/xg_core_x86.h | 60 +++ tools/libs/guest/xg_dom_boot.c | 2 +- tools/libs/guest/xg_domain.c | 2 +- tools/libs/guest/xg_offline_page.c | 2 +- tools/libs/guest/xg_resume.c | 2 +- 20 files changed, 1832 insertions(+), 1835 deletions(-) diff --git a/tools/libs/ctrl/Makefile b/tools/libs/ctrl/Makefile index fbeb3a3537..519246b0d6 100644 --- a/tools/libs/ctrl/Makefile +++ b/tools/libs/ctrl/Makefile @@ -2,9 +2,6 @@ XEN_ROOT = $(CURDIR)/../../.. include $(XEN_ROOT)/tools/Rules.mk SRCS-y += xc_altp2m.c -SRCS-y += xc_core.c -SRCS-$(CONFIG_X86) += xc_core_x86.c -SRCS-$(CONFIG_ARM) += xc_core_arm.c SRCS-y += xc_cpupool.c SRCS-y += xc_domain.c SRCS-y += xc_evtchn.c diff --git a/tools/libs/ctrl/xc_core.c b/tools/libs/ctrl/xc_core.c deleted file mode 100644 index 9576bec5a3..0000000000 --- a/tools/libs/ctrl/xc_core.c +++ /dev/null @@ -1,1027 +0,0 @@ -/* - * Elf format, (pfn, gmfn) table, IA64 support. - * Copyright (c) 2007 Isaku Yamahata <yamahata at valinux co jp> - * VA Linux Systems Japan K.K. - * - * 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/>. - */ - -/* - * xen dump-core file format follows ELF format specification. - * Analisys tools shouldn't depends on the order of sections. - * They should follow elf header and check section names. - * - * +--------------------------------------------------------+ - * |ELF header | - * +--------------------------------------------------------+ - * |section headers | - * | null section header | - * | .shstrtab | - * | .note.Xen | - * | .xen_prstatus | - * | .xen_shared_info if present | - * | .xen_pages | - * | .xen_p2m or .xen_pfn | - * +--------------------------------------------------------+ - * |.note.Xen:note section | - * | "Xen" is used as note name, | - * | types are defined in xen/include/public/elfnote.h | - * | and descriptors are defined in xc_core.h. | - * | dumpcore none | - * | dumpcore header | - * | dumpcore xen version | - * | dumpcore format version | - * +--------------------------------------------------------+ - * |.xen_prstatus | - * | vcpu_guest_context_t[nr_vcpus] | - * +--------------------------------------------------------+ - * |.xen_shared_info if possible | - * +--------------------------------------------------------+ - * |.xen_pages | - * | page * nr_pages | - * +--------------------------------------------------------+ - * |.xen_p2m or .xen_pfn | - * | .xen_p2m: struct xen_dumpcore_p2m[nr_pages] | - * | .xen_pfn: uint64_t[nr_pages] | - * +--------------------------------------------------------+ - * |.shstrtab: section header string table | - * +--------------------------------------------------------+ - * - */ - -#include "xc_private.h" -#include "xc_core.h" -#include <stdlib.h> -#include <unistd.h> - -#include <xen/libelf/libelf.h> - -/* number of pages to write at a time */ -#define DUMP_INCREMENT (4 * 1024) - -/* string table */ -struct xc_core_strtab { - char *strings; - uint16_t length; - uint16_t max; -}; - -static struct xc_core_strtab* -xc_core_strtab_init(xc_interface *xch) -{ - struct xc_core_strtab *strtab; - char *strings; - strtab = malloc(sizeof(*strtab)); - if ( strtab == NULL ) - return NULL; - - strings = malloc(PAGE_SIZE); - if ( strings == NULL ) - { - PERROR("Could not allocate string table init"); - free(strtab); - return NULL; - } - strtab->strings = strings; - strtab->max = PAGE_SIZE; - - /* index 0 represents none */ - strtab->strings[0] = '\0'; - strtab->length = 1; - - return strtab; -} - -static void -xc_core_strtab_free(struct xc_core_strtab *strtab) -{ - free(strtab->strings); - free(strtab); -} - -static uint16_t -xc_core_strtab_get(xc_interface *xch, struct xc_core_strtab *strtab, const char *name) -{ - uint16_t ret = 0; - uint16_t len = strlen(name) + 1; - - if ( strtab->length > UINT16_MAX - len ) - { - PERROR("too long string table"); - errno = E2BIG; - return ret; - } - - if ( strtab->length + len > strtab->max ) - { - char *tmp; - if ( strtab->max > UINT16_MAX / 2 ) - { - PERROR("too long string table"); - errno = ENOMEM; - return ret; - } - - tmp = realloc(strtab->strings, strtab->max * 2); - if ( tmp == NULL ) - { - PERROR("Could not allocate string table"); - return ret; - } - - strtab->strings = tmp; - strtab->max *= 2; - } - - ret = strtab->length; - strcpy(strtab->strings + strtab->length, name); - strtab->length += len; - return ret; -} - - -/* section headers */ -struct xc_core_section_headers { - uint16_t num; - uint16_t num_max; - - Elf64_Shdr *shdrs; -}; -#define SHDR_INIT ((uint16_t)16) -#define SHDR_INC ((uint16_t)4) - -static struct xc_core_section_headers* -xc_core_shdr_init(xc_interface *xch) -{ - struct xc_core_section_headers *sheaders; - sheaders = malloc(sizeof(*sheaders)); - if ( sheaders == NULL ) - return NULL; - - sheaders->num = 0; - sheaders->num_max = SHDR_INIT; - sheaders->shdrs = malloc(sizeof(sheaders->shdrs[0]) * sheaders->num_max); - if ( sheaders->shdrs == NULL ) - { - free(sheaders); - return NULL; - } - return sheaders; -} - -static void -xc_core_shdr_free(struct xc_core_section_headers *sheaders) -{ - free(sheaders->shdrs); - free(sheaders); -} - -Elf64_Shdr* -xc_core_shdr_get(xc_interface *xch, - struct xc_core_section_headers *sheaders) -{ - Elf64_Shdr *shdr; - - if ( sheaders->num == sheaders->num_max ) - { - Elf64_Shdr *shdrs; - if ( sheaders->num_max > UINT16_MAX - SHDR_INC ) - { - errno = E2BIG; - return NULL; - } - sheaders->num_max += SHDR_INC; - shdrs = realloc(sheaders->shdrs, - sizeof(sheaders->shdrs[0]) * sheaders->num_max); - if ( shdrs == NULL ) - return NULL; - sheaders->shdrs = shdrs; - } - - shdr = &sheaders->shdrs[sheaders->num]; - sheaders->num++; - memset(shdr, 0, sizeof(*shdr)); - return shdr; -} - -int -xc_core_shdr_set(xc_interface *xch, - Elf64_Shdr *shdr, - struct xc_core_strtab *strtab, - const char *name, uint32_t type, - uint64_t offset, uint64_t size, - uint64_t addralign, uint64_t entsize) -{ - uint64_t name_idx = xc_core_strtab_get(xch, strtab, name); - if ( name_idx == 0 ) - return -1; - - shdr->sh_name = name_idx; - shdr->sh_type = type; - shdr->sh_offset = offset; - shdr->sh_size = size; - shdr->sh_addralign = addralign; - shdr->sh_entsize = entsize; - return 0; -} - -static void -xc_core_ehdr_init(Elf64_Ehdr *ehdr) -{ - memset(ehdr, 0, sizeof(*ehdr)); - ehdr->e_ident[EI_MAG0] = ELFMAG0; - ehdr->e_ident[EI_MAG1] = ELFMAG1; - ehdr->e_ident[EI_MAG2] = ELFMAG2; - ehdr->e_ident[EI_MAG3] = ELFMAG3; - ehdr->e_ident[EI_CLASS] = ELFCLASS64; - ehdr->e_ident[EI_DATA] = ELF_ARCH_DATA; - ehdr->e_ident[EI_VERSION] = EV_CURRENT; - ehdr->e_ident[EI_OSABI] = ELFOSABI_SYSV; - ehdr->e_ident[EI_ABIVERSION] = EV_CURRENT; - - ehdr->e_type = ET_CORE; - /* e_machine will be filled in later */ - ehdr->e_version = EV_CURRENT; - ehdr->e_entry = 0; - ehdr->e_phoff = 0; - ehdr->e_shoff = sizeof(*ehdr); - ehdr->e_flags = ELF_CORE_EFLAGS; - ehdr->e_ehsize = sizeof(*ehdr); - ehdr->e_phentsize = sizeof(Elf64_Phdr); - ehdr->e_phnum = 0; - ehdr->e_shentsize = sizeof(Elf64_Shdr); - /* ehdr->e_shnum and ehdr->e_shstrndx aren't known here yet. - * fill it later */ -} - -static int -elfnote_fill_xen_version(xc_interface *xch, - struct xen_dumpcore_elfnote_xen_version_desc - *xen_version) -{ - int rc; - memset(xen_version, 0, sizeof(*xen_version)); - - rc = xc_version(xch, XENVER_version, NULL); - if ( rc < 0 ) - return rc; - xen_version->major_version = rc >> 16; - xen_version->minor_version = rc & ((1 << 16) - 1); - - rc = xc_version(xch, XENVER_extraversion, - &xen_version->extra_version); - if ( rc < 0 ) - return rc; - - rc = xc_version(xch, XENVER_compile_info, - &xen_version->compile_info); - if ( rc < 0 ) - return rc; - - rc = xc_version(xch, - XENVER_capabilities, &xen_version->capabilities); - if ( rc < 0 ) - return rc; - - rc = xc_version(xch, XENVER_changeset, &xen_version->changeset); - if ( rc < 0 ) - return rc; - - rc = xc_version(xch, XENVER_platform_parameters, - &xen_version->platform_parameters); - if ( rc < 0 ) - return rc; - - rc = xc_version(xch, XENVER_pagesize, NULL); - if ( rc < 0 ) - return rc; - xen_version->pagesize = rc; - - return 0; -} - -static void -elfnote_fill_format_version(struct xen_dumpcore_elfnote_format_version_desc - *format_version) -{ - format_version->version = XEN_DUMPCORE_FORMAT_VERSION_CURRENT; -} - -static void -elfnote_init(struct elfnote *elfnote) -{ - /* elf note section */ - memset(elfnote, 0, sizeof(*elfnote)); - elfnote->namesz = strlen(XEN_DUMPCORE_ELFNOTE_NAME) + 1; - strncpy(elfnote->name, XEN_DUMPCORE_ELFNOTE_NAME, sizeof(elfnote->name)); -} - -static int -elfnote_dump_none(xc_interface *xch, void *args, dumpcore_rtn_t dump_rtn) -{ - int sts; - struct elfnote elfnote; - struct xen_dumpcore_elfnote_none_desc none; - - elfnote_init(&elfnote); - /* Avoid compile warning about constant-zero-sized memset(). */ - /*memset(&none, 0, sizeof(none));*/ - - elfnote.descsz = sizeof(none); - elfnote.type = XEN_ELFNOTE_DUMPCORE_NONE; - sts = dump_rtn(xch, args, (char*)&elfnote, sizeof(elfnote)); - if ( sts != 0 ) - return sts; - return dump_rtn(xch, args, (char*)&none, sizeof(none)); -} - -static int -elfnote_dump_core_header( - xc_interface *xch, - void *args, dumpcore_rtn_t dump_rtn, const xc_dominfo_t *info, - int nr_vcpus, unsigned long nr_pages) -{ - int sts; - struct elfnote elfnote; - struct xen_dumpcore_elfnote_header_desc header; - - elfnote_init(&elfnote); - memset(&header, 0, sizeof(header)); - - elfnote.descsz = sizeof(header); - elfnote.type = XEN_ELFNOTE_DUMPCORE_HEADER; - header.xch_magic = info->hvm ? XC_CORE_MAGIC_HVM : XC_CORE_MAGIC; - header.xch_nr_vcpus = nr_vcpus; - header.xch_nr_pages = nr_pages; - header.xch_page_size = PAGE_SIZE; - sts = dump_rtn(xch, args, (char*)&elfnote, sizeof(elfnote)); - if ( sts != 0 ) - return sts; - return dump_rtn(xch, args, (char*)&header, sizeof(header)); -} - -static int -elfnote_dump_xen_version(xc_interface *xch, void *args, - dumpcore_rtn_t dump_rtn, unsigned int guest_width) -{ - int sts; - struct elfnote elfnote; - struct xen_dumpcore_elfnote_xen_version_desc xen_version; - - elfnote_init(&elfnote); - memset(&xen_version, 0, sizeof(xen_version)); - - elfnote.descsz = sizeof(xen_version); - elfnote.type = XEN_ELFNOTE_DUMPCORE_XEN_VERSION; - elfnote_fill_xen_version(xch, &xen_version); - if (guest_width < sizeof(unsigned long)) - { - // 32 bit elf file format differs in pagesize's alignment - char *p = (char *)&xen_version.pagesize; - memmove(p - 4, p, sizeof(xen_version.pagesize)); - } - sts = dump_rtn(xch, args, (char*)&elfnote, sizeof(elfnote)); - if ( sts != 0 ) - return sts; - return dump_rtn(xch, args, (char*)&xen_version, sizeof(xen_version)); -} - -static int -elfnote_dump_format_version(xc_interface *xch, - void *args, dumpcore_rtn_t dump_rtn) -{ - int sts; - struct elfnote elfnote; - struct xen_dumpcore_elfnote_format_version_desc format_version; - - elfnote_init(&elfnote); - memset(&format_version, 0, sizeof(format_version)); - - elfnote.descsz = sizeof(format_version); - elfnote.type = XEN_ELFNOTE_DUMPCORE_FORMAT_VERSION; - elfnote_fill_format_version(&format_version); - sts = dump_rtn(xch, args, (char*)&elfnote, sizeof(elfnote)); - if ( sts != 0 ) - return sts; - return dump_rtn(xch, args, (char*)&format_version, sizeof(format_version)); -} - -int -xc_domain_dumpcore_via_callback(xc_interface *xch, - uint32_t domid, - void *args, - dumpcore_rtn_t dump_rtn) -{ - xc_dominfo_t info; - shared_info_any_t *live_shinfo = NULL; - struct domain_info_context _dinfo = {}; - struct domain_info_context *dinfo = &_dinfo; - - int nr_vcpus = 0; - char *dump_mem, *dump_mem_start = NULL; - vcpu_guest_context_any_t *ctxt = NULL; - struct xc_core_arch_context arch_ctxt; - char dummy[PAGE_SIZE]; - int dummy_len; - int sts = -1; - - unsigned long i; - unsigned long j; - unsigned long nr_pages; - unsigned long max_mfn; - - xc_core_memory_map_t *memory_map = NULL; - unsigned int nr_memory_map; - unsigned int map_idx; - - int auto_translated_physmap; - xen_pfn_t *p2m = NULL; - struct xen_dumpcore_p2m *p2m_array = NULL; - - uint64_t *pfn_array = NULL; - - Elf64_Ehdr ehdr; - uint64_t filesz; - uint64_t offset; - uint64_t fixup; - - struct xc_core_strtab *strtab = NULL; - uint16_t strtab_idx; - struct xc_core_section_headers *sheaders = NULL; - Elf64_Shdr *shdr; - - xc_core_arch_context_init(&arch_ctxt); - if ( (dump_mem_start = malloc(DUMP_INCREMENT*PAGE_SIZE)) == NULL ) - { - PERROR("Could not allocate dump_mem"); - goto out; - } - - if ( xc_domain_getinfo(xch, domid, 1, &info) != 1 ) - { - PERROR("Could not get info for domain"); - goto out; - } - /* Map the shared info frame */ - live_shinfo = xc_map_foreign_range(xch, domid, PAGE_SIZE, - PROT_READ, info.shared_info_frame); - if ( !live_shinfo && !info.hvm ) - { - PERROR("Couldn't map live_shinfo"); - goto out; - } - auto_translated_physmap = xc_core_arch_auto_translated_physmap(&info); - - if ( !auto_translated_physmap ) - - { - if ( xc_domain_get_guest_width(xch, domid, &dinfo->guest_width) != 0 ) - { - PERROR("Could not get address size for domain"); - goto out; - } - } - else - { - /* - * Autotranslated guest never sets guest width in the first - * place. Force guest_width to be sizeof(unsigned long) so - * code below functions properly. - * - * Here is why this is correct. - * - * 1. Before f969bc9fc, xc_domain_get_guest_width for HVM (x86 - * and ARM) always returned hypervisor's idea of - * sizeof(unsigned long). - * - * 2. There has never been a situation in which hypervisor's - * word width is smaller than toolstack domain's (i.e. no - * 32bit hypervisor + 64bit toolstack). - * - * Predicates in code test guest_width against toolstack - * domain's sizeof(unsigned long), so setting guest_width to - * toolstack domain's idea of sizeof(unsigned long) matches - * the original behaviour for HVM guests. - */ - dinfo->guest_width = sizeof(unsigned long); - } - - if ( domid != info.domid ) - { - PERROR("Domain %d does not exist", domid); - goto out; - } - - ctxt = calloc(sizeof(*ctxt), info.max_vcpu_id + 1); - if ( !ctxt ) - { - PERROR("Could not allocate vcpu context array"); - goto out; - } - - for ( i = 0; i <= info.max_vcpu_id; i++ ) - { - if ( xc_vcpu_getcontext(xch, domid, i, &ctxt[nr_vcpus]) == 0 ) - { - if ( xc_core_arch_context_get(&arch_ctxt, &ctxt[nr_vcpus], - xch, domid) ) - continue; - nr_vcpus++; - } - } - if ( nr_vcpus == 0 ) - { - PERROR("No VCPU context could be grabbed"); - goto out; - } - - /* obtain memory map */ - sts = xc_core_arch_memory_map_get(xch, &arch_ctxt, &info, - live_shinfo, &memory_map, - &nr_memory_map); - if ( sts != 0 ) - goto out; - - /* - * Note: this is the *current* number of pages and may change under - * a live dump-core. We'll just take this value, and if more pages - * exist, we'll skip them. If there's less, then we'll just not use - * all the array... - * - * We don't want to use the total potential size of the memory map - * since that is usually much higher than info.nr_pages. - */ - nr_pages = info.nr_pages; - - if ( !auto_translated_physmap ) - { - /* obtain p2m table */ - p2m_array = malloc(nr_pages * sizeof(p2m_array[0])); - if ( p2m_array == NULL ) - { - PERROR("Could not allocate p2m array"); - goto out; - } - - sts = xc_core_arch_map_p2m(xch, dinfo, &info, live_shinfo, &p2m); - if ( sts != 0 ) - goto out; - - sts = xc_maximum_ram_page(xch, &max_mfn); - if ( sts != 0 ) - goto out; - } - else - { - pfn_array = malloc(nr_pages * sizeof(pfn_array[0])); - if ( pfn_array == NULL ) - { - PERROR("Could not allocate pfn array"); - goto out; - } - } - - /* ehdr.e_shnum and ehdr.e_shstrndx aren't known here yet. fill it later*/ - xc_core_ehdr_init(&ehdr); - - /* create section header */ - strtab = xc_core_strtab_init(xch); - if ( strtab == NULL ) - { - PERROR("Could not allocate string table"); - goto out; - } - sheaders = xc_core_shdr_init(xch); - if ( sheaders == NULL ) - { - PERROR("Could not allocate section headers"); - goto out; - } - /* null section */ - shdr = xc_core_shdr_get(xch,sheaders); - if ( shdr == NULL ) - { - PERROR("Could not get section header for null section"); - goto out; - } - - /* .shstrtab */ - shdr = xc_core_shdr_get(xch,sheaders); - if ( shdr == NULL ) - { - PERROR("Could not get section header for shstrtab"); - goto out; - } - strtab_idx = shdr - sheaders->shdrs; - /* strtab_shdr.sh_offset, strtab_shdr.sh_size aren't unknown. - * fill it later - */ - sts = xc_core_shdr_set(xch, shdr, strtab, ELF_SHSTRTAB, SHT_STRTAB, 0, 0, 0, 0); - if ( sts != 0 ) - goto out; - - /* elf note section */ - /* here the number of section header is unknown. fix up offset later. */ - offset = sizeof(ehdr); - filesz = - sizeof(struct xen_dumpcore_elfnote_none) + /* none */ - sizeof(struct xen_dumpcore_elfnote_header) + /* core header */ - sizeof(struct xen_dumpcore_elfnote_xen_version) + /* xen version */ - sizeof(struct xen_dumpcore_elfnote_format_version);/* format version */ - shdr = xc_core_shdr_get(xch,sheaders); - if ( shdr == NULL ) - { - PERROR("Could not get section header for note section"); - goto out; - } - sts = xc_core_shdr_set(xch, shdr, strtab, XEN_DUMPCORE_SEC_NOTE, SHT_NOTE, - offset, filesz, 0, 0); - if ( sts != 0 ) - goto out; - offset += filesz; - - /* prstatus */ - shdr = xc_core_shdr_get(xch,sheaders); - if ( shdr == NULL ) - { - PERROR("Could not get section header for .xen_prstatus"); - goto out; - } - filesz = sizeof(*ctxt) * nr_vcpus; - sts = xc_core_shdr_set(xch, shdr, strtab, XEN_DUMPCORE_SEC_PRSTATUS, - SHT_PROGBITS, offset, filesz, - __alignof__(*ctxt), sizeof(*ctxt)); - if ( sts != 0 ) - goto out; - offset += filesz; - - /* arch context */ - sts = xc_core_arch_context_get_shdr(xch, &arch_ctxt, sheaders, strtab, - &filesz, offset); - if ( sts != 0 ) - goto out; - offset += filesz; - - /* shared_info */ - if ( live_shinfo != NULL ) - { - shdr = xc_core_shdr_get(xch,sheaders); - if ( shdr == NULL ) - { - PERROR("Could not get section header for .xen_shared_info"); - goto out; - } - filesz = PAGE_SIZE; - sts = xc_core_shdr_set(xch, shdr, strtab, XEN_DUMPCORE_SEC_SHARED_INFO, - SHT_PROGBITS, offset, filesz, - __alignof__(*live_shinfo), PAGE_SIZE); - if ( sts != 0 ) - goto out; - offset += filesz; - } - - /* - * pages and p2m/pfn are the last section to allocate section headers - * so that we know the number of section headers here. - * 2 = pages section and p2m/pfn table section - */ - fixup = (sheaders->num + 2) * sizeof(*shdr); - /* zeroth section should have zero offset */ - for ( i = 1; i < sheaders->num; i++ ) - sheaders->shdrs[i].sh_offset += fixup; - offset += fixup; - dummy_len = ROUNDUP(offset, PAGE_SHIFT) - offset; /* padding length */ - offset += dummy_len; - - /* pages */ - shdr = xc_core_shdr_get(xch,sheaders); - if ( shdr == NULL ) - { - PERROR("could not get section headers for .xen_pages"); - goto out; - } - filesz = (uint64_t)nr_pages * PAGE_SIZE; - sts = xc_core_shdr_set(xch, shdr, strtab, XEN_DUMPCORE_SEC_PAGES, SHT_PROGBITS, - offset, filesz, PAGE_SIZE, PAGE_SIZE); - if ( sts != 0 ) - goto out; - offset += filesz; - - /* p2m/pfn table */ - shdr = xc_core_shdr_get(xch,sheaders); - if ( shdr == NULL ) - { - PERROR("Could not get section header for .xen_{p2m, pfn} table"); - goto out; - } - if ( !auto_translated_physmap ) - { - filesz = (uint64_t)nr_pages * sizeof(p2m_array[0]); - sts = xc_core_shdr_set(xch, shdr, strtab, XEN_DUMPCORE_SEC_P2M, - SHT_PROGBITS, - offset, filesz, __alignof__(p2m_array[0]), - sizeof(p2m_array[0])); - } - else - { - filesz = (uint64_t)nr_pages * sizeof(pfn_array[0]); - sts = xc_core_shdr_set(xch, shdr, strtab, XEN_DUMPCORE_SEC_PFN, - SHT_PROGBITS, - offset, filesz, __alignof__(pfn_array[0]), - sizeof(pfn_array[0])); - } - if ( sts != 0 ) - goto out; - offset += filesz; - - /* fixing up section header string table section header */ - filesz = strtab->length; - sheaders->shdrs[strtab_idx].sh_offset = offset; - sheaders->shdrs[strtab_idx].sh_size = filesz; - - /* write out elf header */ - ehdr.e_shnum = sheaders->num; - ehdr.e_shstrndx = strtab_idx; - ehdr.e_machine = ELF_ARCH_MACHINE; - sts = dump_rtn(xch, args, (char*)&ehdr, sizeof(ehdr)); - if ( sts != 0 ) - goto out; - - /* section headers */ - sts = dump_rtn(xch, args, (char*)sheaders->shdrs, - sheaders->num * sizeof(sheaders->shdrs[0])); - if ( sts != 0 ) - goto out; - - /* elf note section: xen core header */ - sts = elfnote_dump_none(xch, args, dump_rtn); - if ( sts != 0 ) - goto out; - - /* elf note section: xen core header */ - sts = elfnote_dump_core_header(xch, args, dump_rtn, &info, nr_vcpus, nr_pages); - if ( sts != 0 ) - goto out; - - /* elf note section: xen version */ - sts = elfnote_dump_xen_version(xch, args, dump_rtn, dinfo->guest_width); - if ( sts != 0 ) - goto out; - - /* elf note section: format version */ - sts = elfnote_dump_format_version(xch, args, dump_rtn); - if ( sts != 0 ) - goto out; - - /* prstatus: .xen_prstatus */ - sts = dump_rtn(xch, args, (char *)ctxt, sizeof(*ctxt) * nr_vcpus); - if ( sts != 0 ) - goto out; - - if ( live_shinfo != NULL ) - { - /* shared_info: .xen_shared_info */ - sts = dump_rtn(xch, args, (char*)live_shinfo, PAGE_SIZE); - if ( sts != 0 ) - goto out; - } - - /* arch specific context */ - sts = xc_core_arch_context_dump(xch, &arch_ctxt, args, dump_rtn); - if ( sts != 0 ) - goto out; - - /* Pad the output data to page alignment. */ - memset(dummy, 0, PAGE_SIZE); - sts = dump_rtn(xch, args, dummy, dummy_len); - if ( sts != 0 ) - goto out; - - /* dump pages: .xen_pages */ - j = 0; - dump_mem = dump_mem_start; - for ( map_idx = 0; map_idx < nr_memory_map; map_idx++ ) - { - uint64_t pfn_start; - uint64_t pfn_end; - - pfn_start = memory_map[map_idx].addr >> PAGE_SHIFT; - pfn_end = pfn_start + (memory_map[map_idx].size >> PAGE_SHIFT); - for ( i = pfn_start; i < pfn_end; i++ ) - { - uint64_t gmfn; - void *vaddr; - - if ( !auto_translated_physmap ) - { - if ( i >= dinfo->p2m_size ) - break; - - if ( dinfo->guest_width >= sizeof(unsigned long) ) - { - if ( dinfo->guest_width == sizeof(unsigned long) ) - gmfn = p2m[i]; - else - gmfn = ((uint64_t *)p2m)[i]; - if ( gmfn == INVALID_PFN ) - continue; - } - else - { - gmfn = ((uint32_t *)p2m)[i]; - if ( gmfn == (uint32_t)INVALID_PFN ) - continue; - } - if ( gmfn > max_mfn ) - continue; - - if ( j >= nr_pages ) - { - j++; - continue; - } - - p2m_array[j].pfn = i; - p2m_array[j].gmfn = gmfn; - } - else - { - if ( !xc_core_arch_gpfn_may_present(&arch_ctxt, i) ) - continue; - - if ( j >= nr_pages ) - { - j++; - continue; - } - - gmfn = i; - pfn_array[j] = i; - } - - vaddr = xc_map_foreign_range( - xch, domid, PAGE_SIZE, PROT_READ, gmfn); - if ( vaddr == NULL ) - continue; - memcpy(dump_mem, vaddr, PAGE_SIZE); - munmap(vaddr, PAGE_SIZE); - dump_mem += PAGE_SIZE; - if ( (j + 1) % DUMP_INCREMENT == 0 ) - { - sts = dump_rtn( - xch, args, dump_mem_start, dump_mem - dump_mem_start); - if ( sts != 0 ) - goto out; - dump_mem = dump_mem_start; - } - - j++; - } - } - - if ( j > nr_pages ) - { - /* - * When live dump-mode (-L option) is specified, - * guest domain may increase memory. - */ - IPRINTF("exceeded nr_pages (%ld) losing %ld pages", nr_pages, j - nr_pages); - } - - sts = dump_rtn(xch, args, dump_mem_start, dump_mem - dump_mem_start); - if ( sts != 0 ) - goto out; - if ( j < nr_pages ) - { - /* When live dump-mode (-L option) is specified, - * guest domain may reduce memory. pad with zero pages. - */ - DPRINTF("j (%ld) != nr_pages (%ld)", j, nr_pages); - memset(dump_mem_start, 0, PAGE_SIZE); - for (; j < nr_pages; j++) { - sts = dump_rtn(xch, args, dump_mem_start, PAGE_SIZE); - if ( sts != 0 ) - goto out; - if ( !auto_translated_physmap ) - { - p2m_array[j].pfn = XC_CORE_INVALID_PFN; - p2m_array[j].gmfn = XC_CORE_INVALID_GMFN; - } - else - pfn_array[j] = XC_CORE_INVALID_PFN; - } - } - - /* p2m/pfn table: .xen_p2m/.xen_pfn */ - if ( !auto_translated_physmap ) - sts = dump_rtn( - xch, args, (char *)p2m_array, sizeof(p2m_array[0]) * nr_pages); - else - sts = dump_rtn( - xch, args, (char *)pfn_array, sizeof(pfn_array[0]) * nr_pages); - if ( sts != 0 ) - goto out; - - /* elf section header string table: .shstrtab */ - sts = dump_rtn(xch, args, strtab->strings, strtab->length); - if ( sts != 0 ) - goto out; - - sts = 0; - -out: - if ( memory_map != NULL ) - free(memory_map); - if ( p2m != NULL ) - munmap(p2m, PAGE_SIZE * dinfo->p2m_frames); - if ( p2m_array != NULL ) - free(p2m_array); - if ( pfn_array != NULL ) - free(pfn_array); - if ( sheaders != NULL ) - xc_core_shdr_free(sheaders); - if ( strtab != NULL ) - xc_core_strtab_free(strtab); - if ( ctxt != NULL ) - free(ctxt); - if ( dump_mem_start != NULL ) - free(dump_mem_start); - if ( live_shinfo != NULL ) - munmap(live_shinfo, PAGE_SIZE); - xc_core_arch_context_free(&arch_ctxt); - - return sts; -} - -/* Callback args for writing to a local dump file. */ -struct dump_args { - int fd; -}; - -/* Callback routine for writing to a local dump file. */ -static int local_file_dump(xc_interface *xch, - void *args, char *buffer, unsigned int length) -{ - struct dump_args *da = args; - - if ( write_exact(da->fd, buffer, length) == -1 ) - { - PERROR("Failed to write buffer"); - return -errno; - } - - if ( length >= (DUMP_INCREMENT * PAGE_SIZE) ) - { - // Now dumping pages -- make sure we discard clean pages from - // the cache after each write - discard_file_cache(xch, da->fd, 0 /* no flush */); - } - - return 0; -} - -int -xc_domain_dumpcore(xc_interface *xch, - uint32_t domid, - const char *corename) -{ - struct dump_args da; - int sts; - - if ( (da.fd = open(corename, O_CREAT|O_RDWR|O_TRUNC, S_IWUSR|S_IRUSR)) < 0 ) - { - PERROR("Could not open corefile %s", corename); - return -errno; - } - - sts = xc_domain_dumpcore_via_callback( - xch, domid, &da, &local_file_dump); - - /* flush and discard any remaining portion of the file from cache */ - discard_file_cache(xch, da.fd, 1/* flush first*/); - - close(da.fd); - - return sts; -} - -/* - * Local variables: - * mode: C - * c-file-style: "BSD" - * c-basic-offset: 4 - * tab-width: 4 - * indent-tabs-mode: nil - * End: - */ diff --git a/tools/libs/ctrl/xc_core.h b/tools/libs/ctrl/xc_core.h deleted file mode 100644 index 8ea1f93a10..0000000000 --- a/tools/libs/ctrl/xc_core.h +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright (c) 2006 Isaku Yamahata <yamahata at valinux co jp> - * VA Linux Systems Japan K.K. - * - * 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; either - * version 2.1 of the License, or (at your option) any later version. - * - * 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/>. - * - */ - -#ifndef XC_CORE_H -#define XC_CORE_H - -#include "xen/version.h" -#include "xc_private.h" -#include "xen/libelf/elfstructs.h" - -/* section names */ -#define XEN_DUMPCORE_SEC_NOTE ".note.Xen" -#define XEN_DUMPCORE_SEC_PRSTATUS ".xen_prstatus" -#define XEN_DUMPCORE_SEC_SHARED_INFO ".xen_shared_info" -#define XEN_DUMPCORE_SEC_P2M ".xen_p2m" -#define XEN_DUMPCORE_SEC_PFN ".xen_pfn" -#define XEN_DUMPCORE_SEC_PAGES ".xen_pages" - -/* elf note name */ -#define XEN_DUMPCORE_ELFNOTE_NAME "Xen" -/* note numbers are defined in xen/elfnote.h */ - -struct elfnote { - uint32_t namesz; /* Elf_Note note; */ - uint32_t descsz; - uint32_t type; - char name[4]; /* sizeof("Xen") = 4 - * Fotunately this is 64bit aligned so that - * we can use same structore for both 32/64bit - */ -}; - -struct xen_dumpcore_elfnote_none_desc { - /* nothing */ -}; - -struct xen_dumpcore_elfnote_header_desc { - uint64_t xch_magic; - uint64_t xch_nr_vcpus; - uint64_t xch_nr_pages; - uint64_t xch_page_size; -}; - -struct xen_dumpcore_elfnote_xen_version_desc { - uint64_t major_version; - uint64_t minor_version; - xen_extraversion_t extra_version; - xen_compile_info_t compile_info; - xen_capabilities_info_t capabilities; - xen_changeset_info_t changeset; - xen_platform_parameters_t platform_parameters; - uint64_t pagesize; -}; - -#define XEN_DUMPCORE_FORMAT_VERSION(major, minor) \ - ((major) << 32) | ((minor) & 0xffffffff) -#define XEN_DUMPCORE_FORMAT_MAJOR(version) ((major) >> 32) -#define XEN_DUMPCORE_FORMAT_MINOR(version) ((minor) & 0xffffffff) - -#define XEN_DUMPCORE_FORMAT_MAJOR_CURRENT ((uint64_t)0) -#define XEN_DUMPCORE_FORMAT_MINOR_CURRENT ((uint64_t)1) -#define XEN_DUMPCORE_FORMAT_VERSION_CURRENT \ - XEN_DUMPCORE_FORMAT_VERSION(XEN_DUMPCORE_FORMAT_MAJOR_CURRENT, \ - XEN_DUMPCORE_FORMAT_MINOR_CURRENT) - -struct xen_dumpcore_elfnote_format_version_desc { - uint64_t version; -}; - - -struct xen_dumpcore_elfnote_none { - struct elfnote elfnote; - struct xen_dumpcore_elfnote_none_desc none; -}; - -struct xen_dumpcore_elfnote_header { - struct elfnote elfnote; - struct xen_dumpcore_elfnote_header_desc header; -}; - -struct xen_dumpcore_elfnote_xen_version { - struct elfnote elfnote; - struct xen_dumpcore_elfnote_xen_version_desc xen_version; -}; - -struct xen_dumpcore_elfnote_format_version { - struct elfnote elfnote; - struct xen_dumpcore_elfnote_format_version_desc format_version; -}; - -#define XC_CORE_INVALID_PFN (~(uint64_t)0) -#define XC_CORE_INVALID_GMFN (~(uint64_t)0) -struct xen_dumpcore_p2m { - uint64_t pfn; - uint64_t gmfn; -}; - - -struct xc_core_strtab; -struct xc_core_section_headers; - -Elf64_Shdr* -xc_core_shdr_get(xc_interface *xch, - struct xc_core_section_headers *sheaders); -int -xc_core_shdr_set(xc_interface *xch, - Elf64_Shdr *shdr, - struct xc_core_strtab *strtab, - const char *name, uint32_t type, - uint64_t offset, uint64_t size, - uint64_t addralign, uint64_t entsize); - -struct xc_core_memory_map { - uint64_t addr; - uint64_t size; -}; -typedef struct xc_core_memory_map xc_core_memory_map_t; -int xc_core_arch_auto_translated_physmap(const xc_dominfo_t *info); -struct xc_core_arch_context; -int xc_core_arch_memory_map_get(xc_interface *xch, - struct xc_core_arch_context *arch_ctxt, - xc_dominfo_t *info, shared_info_any_t *live_shinfo, - xc_core_memory_map_t **mapp, - unsigned int *nr_entries); -int xc_core_arch_map_p2m(xc_interface *xch, struct domain_info_context *dinfo, - xc_dominfo_t *info, shared_info_any_t *live_shinfo, - xen_pfn_t **live_p2m); - -int xc_core_arch_map_p2m_writable(xc_interface *xch, struct domain_info_context *dinfo, - xc_dominfo_t *info, - shared_info_any_t *live_shinfo, - xen_pfn_t **live_p2m); - -int xc_core_arch_get_scratch_gpfn(xc_interface *xch, uint32_t domid, - xen_pfn_t *gpfn); - - -#if defined (__i386__) || defined (__x86_64__) -# include "xc_core_x86.h" -#elif defined (__arm__) || defined(__aarch64__) -# include "xc_core_arm.h" -#else -# error "unsupported architecture" -#endif - -#ifndef ELF_CORE_EFLAGS -# define ELF_CORE_EFLAGS 0 -#endif - -#endif /* XC_CORE_H */ - -/* - * Local variables: - * mode: C - * c-file-style: "BSD" - * c-basic-offset: 4 - * tab-width: 4 - * indent-tabs-mode: nil - * End: - */ diff --git a/tools/libs/ctrl/xc_core_arm.c b/tools/libs/ctrl/xc_core_arm.c deleted file mode 100644 index 93765a565f..0000000000 --- a/tools/libs/ctrl/xc_core_arm.c +++ /dev/null @@ -1,113 +0,0 @@ -/* - * 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; either - * version 2.1 of the License, or (at your option) any later version. - * - * 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/>. - * - * Copyright (c) 2011 Citrix Systems - * - */ - -#include "xc_private.h" -#include "xc_core.h" - -#include <xen-tools/libs.h> - -int -xc_core_arch_gpfn_may_present(struct xc_core_arch_context *arch_ctxt, - unsigned long pfn) -{ - /* TODO: memory from DT */ - if (pfn >= 0x80000 && pfn < 0x88000) - return 1; - return 0; -} - -int -xc_core_arch_auto_translated_physmap(const xc_dominfo_t *info) -{ - return 1; -} - -int -xc_core_arch_memory_map_get(xc_interface *xch, struct xc_core_arch_context *unused, - xc_dominfo_t *info, shared_info_any_t *live_shinfo, - xc_core_memory_map_t **mapp, - unsigned int *nr_entries) -{ - xen_pfn_t p2m_size = 0; - xc_core_memory_map_t *map; - - if ( xc_domain_nr_gpfns(xch, info->domid, &p2m_size) < 0 ) - return -1; - - map = malloc(sizeof(*map)); - if ( map == NULL ) - { - PERROR("Could not allocate memory"); - return -1; - } - - map->addr = 0; - map->size = ((uint64_t)p2m_size) << PAGE_SHIFT; - - *mapp = map; - *nr_entries = 1; - return 0; -} - -static int -xc_core_arch_map_p2m_rw(xc_interface *xch, struct domain_info_context *dinfo, xc_dominfo_t *info, - shared_info_any_t *live_shinfo, xen_pfn_t **live_p2m, int rw) -{ - errno = ENOSYS; - return -1; -} - -int -xc_core_arch_map_p2m(xc_interface *xch, struct domain_info_context *dinfo, xc_dominfo_t *info, - shared_info_any_t *live_shinfo, xen_pfn_t **live_p2m) -{ - return xc_core_arch_map_p2m_rw(xch, dinfo, info, live_shinfo, live_p2m, 0); -} - -int -xc_core_arch_map_p2m_writable(xc_interface *xch, struct domain_info_context *dinfo, xc_dominfo_t *info, - shared_info_any_t *live_shinfo, xen_pfn_t **live_p2m) -{ - return xc_core_arch_map_p2m_rw(xch, dinfo, info, live_shinfo, live_p2m, 1); -} - -int -xc_core_arch_get_scratch_gpfn(xc_interface *xch, uint32_t domid, - xen_pfn_t *gpfn) -{ - /* - * The Grant Table region space is not used until the guest is - * booting. Use the first page for the scratch pfn. - */ - BUILD_BUG_ON(GUEST_GNTTAB_SIZE < XC_PAGE_SIZE); - - *gpfn = GUEST_GNTTAB_BASE >> XC_PAGE_SHIFT; - - return 0; -} - - -/* - * Local variables: - * mode: C - * c-file-style: "BSD" - * c-basic-offset: 4 - * tab-width: 4 - * indent-tabs-mode: nil - * End: - */ diff --git a/tools/libs/ctrl/xc_core_arm.h b/tools/libs/ctrl/xc_core_arm.h deleted file mode 100644 index 162f7a7569..0000000000 --- a/tools/libs/ctrl/xc_core_arm.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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; either - * version 2.1 of the License, or (at your option) any later version. - * - * 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/>. - * - * Copyright (c) 2012 Citrix Systems - * - */ - -#ifndef XC_CORE_ARM_H -#define XC_CORE_ARM_H - -#define ELF_ARCH_DATA ELFDATA2LSB -#define ELF_ARCH_MACHINE EM_ARM - -struct xc_core_arch_context { - /* nothing */ -}; - -#define xc_core_arch_context_init(arch_ctxt) do {} while (0) -#define xc_core_arch_context_free(arch_ctxt) do {} while (0) -#define xc_core_arch_context_get(arch_ctxt, ctxt, xch, domid) \ - (0) -#define xc_core_arch_context_dump(xch, arch_ctxt, args, dump_rtn) (0) - -int -xc_core_arch_gpfn_may_present(struct xc_core_arch_context *arch_ctxt, - unsigned long pfn); -static inline int -xc_core_arch_context_get_shdr(xc_interface *xch, - struct xc_core_arch_context *arch_ctxt, - struct xc_core_section_headers *sheaders, - struct xc_core_strtab *strtab, - uint64_t *filesz, uint64_t offset) -{ - *filesz = 0; - return 0; -} - -#endif /* XC_CORE_ARM_H */ - -/* - * Local variables: - * mode: C - * c-file-style: "BSD" - * c-basic-offset: 4 - * tab-width: 4 - * indent-tabs-mode: nil - * End: - */ diff --git a/tools/libs/ctrl/xc_core_x86.c b/tools/libs/ctrl/xc_core_x86.c deleted file mode 100644 index c8f71d4b75..0000000000 --- a/tools/libs/ctrl/xc_core_x86.c +++ /dev/null @@ -1,391 +0,0 @@ -/* - * 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; either - * version 2.1 of the License, or (at your option) any later version. - * - * 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/>. - * - * Copyright (c) 2007 Isaku Yamahata <yamahata at valinux co jp> - * VA Linux Systems Japan K.K. - * - */ - -#include <inttypes.h> -#include "xc_private.h" -#include "xc_core.h" -#include <xen/hvm/e820.h> - -int -xc_core_arch_gpfn_may_present(struct xc_core_arch_context *arch_ctxt, - unsigned long pfn) -{ - if ((pfn >= 0xa0 && pfn < 0xc0) /* VGA hole */ - || (pfn >= (HVM_BELOW_4G_MMIO_START >> PAGE_SHIFT) - && pfn < (1ULL<<32) >> PAGE_SHIFT)) /* MMIO */ - return 0; - return 1; -} - -int -xc_core_arch_auto_translated_physmap(const xc_dominfo_t *info) -{ - return info->hvm; -} - -int -xc_core_arch_memory_map_get(xc_interface *xch, struct xc_core_arch_context *unused, - xc_dominfo_t *info, shared_info_any_t *live_shinfo, - xc_core_memory_map_t **mapp, - unsigned int *nr_entries) -{ - xen_pfn_t p2m_size = 0; - xc_core_memory_map_t *map; - - if ( xc_domain_nr_gpfns(xch, info->domid, &p2m_size) < 0 ) - return -1; - - map = malloc(sizeof(*map)); - if ( map == NULL ) - { - PERROR("Could not allocate memory"); - return -1; - } - - map->addr = 0; - map->size = ((uint64_t)p2m_size) << PAGE_SHIFT; - - *mapp = map; - *nr_entries = 1; - return 0; -} - -static inline bool is_canonical_address(uint64_t vaddr) -{ - return ((int64_t)vaddr >> 47) == ((int64_t)vaddr >> 63); -} - -/* Virtual address ranges reserved for hypervisor. */ -#define HYPERVISOR_VIRT_START_X86_64 0xFFFF800000000000ULL -#define HYPERVISOR_VIRT_END_X86_64 0xFFFF87FFFFFFFFFFULL - -#define HYPERVISOR_VIRT_START_X86_32 0x00000000F5800000ULL -#define HYPERVISOR_VIRT_END_X86_32 0x00000000FFFFFFFFULL - -static xen_pfn_t * -xc_core_arch_map_p2m_list_rw(xc_interface *xch, struct domain_info_context *dinfo, - uint32_t dom, shared_info_any_t *live_shinfo, - uint64_t p2m_cr3) -{ - uint64_t p2m_vaddr, p2m_end, mask, off; - xen_pfn_t p2m_mfn, mfn, saved_mfn, max_pfn; - uint64_t *ptes = NULL; - xen_pfn_t *mfns = NULL; - unsigned int fpp, n_pages, level, n_levels, shift, - idx_start, idx_end, idx, saved_idx; - - p2m_vaddr = GET_FIELD(live_shinfo, arch.p2m_vaddr, dinfo->guest_width); - fpp = PAGE_SIZE / dinfo->guest_width; - dinfo->p2m_frames = (dinfo->p2m_size - 1) / fpp + 1; - p2m_end = p2m_vaddr + dinfo->p2m_frames * PAGE_SIZE - 1; - - if ( dinfo->guest_width == 8 ) - { - mask = 0x0000ffffffffffffULL; - n_levels = 4; - p2m_mfn = p2m_cr3 >> 12; - if ( !is_canonical_address(p2m_vaddr) || - !is_canonical_address(p2m_end) || - p2m_end < p2m_vaddr || - (p2m_vaddr <= HYPERVISOR_VIRT_END_X86_64 && - p2m_end > HYPERVISOR_VIRT_START_X86_64) ) - { - ERROR("Bad virtual p2m address range %#" PRIx64 "-%#" PRIx64, - p2m_vaddr, p2m_end); - errno = ERANGE; - goto out; - } - } - else - { - mask = 0x00000000ffffffffULL; - n_levels = 3; - if ( p2m_cr3 & ~mask ) - p2m_mfn = ~0UL; - else - p2m_mfn = (uint32_t)((p2m_cr3 >> 12) | (p2m_cr3 << 20)); - if ( p2m_vaddr > mask || p2m_end > mask || p2m_end < p2m_vaddr || - (p2m_vaddr <= HYPERVISOR_VIRT_END_X86_32 && - p2m_end > HYPERVISOR_VIRT_START_X86_32) ) - { - ERROR("Bad virtual p2m address range %#" PRIx64 "-%#" PRIx64, - p2m_vaddr, p2m_end); - errno = ERANGE; - goto out; - } - } - - mfns = malloc(sizeof(*mfns)); - if ( !mfns ) - { - ERROR("Cannot allocate memory for array of %u mfns", 1); - goto out; - } - mfns[0] = p2m_mfn; - off = 0; - saved_mfn = 0; - idx_start = idx_end = saved_idx = 0; - - for ( level = n_levels; level > 0; level-- ) - { - n_pages = idx_end - idx_start + 1; - ptes = xc_map_foreign_pages(xch, dom, PROT_READ, mfns, n_pages); - if ( !ptes ) - { - PERROR("Failed to map %u page table pages for p2m list", n_pages); - goto out; - } - free(mfns); - - shift = level * 9 + 3; - idx_start = ((p2m_vaddr - off) & mask) >> shift; - idx_end = ((p2m_end - off) & mask) >> shift; - idx = idx_end - idx_start + 1; - mfns = malloc(sizeof(*mfns) * idx); - if ( !mfns ) - { - ERROR("Cannot allocate memory for array of %u mfns", idx); - goto out; - } - - for ( idx = idx_start; idx <= idx_end; idx++ ) - { - mfn = (ptes[idx] & 0x000ffffffffff000ULL) >> PAGE_SHIFT; - if ( mfn == 0 ) - { - ERROR("Bad mfn %#lx during page table walk for vaddr %#" PRIx64 " at level %d of p2m list", - mfn, off + ((uint64_t)idx << shift), level); - errno = ERANGE; - goto out; - } - mfns[idx - idx_start] = mfn; - - /* Maximum pfn check at level 2. Same reasoning as for p2m tree. */ - if ( level == 2 ) - { - if ( mfn != saved_mfn ) - { - saved_mfn = mfn; - saved_idx = idx - idx_start; - } - } - } - - if ( level == 2 ) - { - if ( saved_idx == idx_end ) - saved_idx++; - max_pfn = ((xen_pfn_t)saved_idx << 9) * fpp; - if ( max_pfn < dinfo->p2m_size ) - { - dinfo->p2m_size = max_pfn; - dinfo->p2m_frames = (dinfo->p2m_size + fpp - 1) / fpp; - p2m_end = p2m_vaddr + dinfo->p2m_frames * PAGE_SIZE - 1; - idx_end = idx_start + saved_idx; - } - } - - munmap(ptes, n_pages * PAGE_SIZE); - ptes = NULL; - off = p2m_vaddr & ((mask >> shift) << shift); - } - - return mfns; - - out: - free(mfns); - if ( ptes ) - munmap(ptes, n_pages * PAGE_SIZE); - - return NULL; -} - -static xen_pfn_t * -xc_core_arch_map_p2m_tree_rw(xc_interface *xch, struct domain_info_context *dinfo, - uint32_t dom, shared_info_any_t *live_shinfo) -{ - /* Double and single indirect references to the live P2M table */ - xen_pfn_t *live_p2m_frame_list_list; - xen_pfn_t *live_p2m_frame_list = NULL; - /* Copies of the above. */ - xen_pfn_t *p2m_frame_list_list = NULL; - xen_pfn_t *p2m_frame_list; - - int err; - int i; - - live_p2m_frame_list_list = - xc_map_foreign_range(xch, dom, PAGE_SIZE, PROT_READ, - GET_FIELD(live_shinfo, arch.pfn_to_mfn_frame_list_list, dinfo->guest_width)); - - if ( !live_p2m_frame_list_list ) - { - PERROR("Couldn't map p2m_frame_list_list (errno %d)", errno); - goto out; - } - - /* Get a local copy of the live_P2M_frame_list_list */ - if ( !(p2m_frame_list_list = malloc(PAGE_SIZE)) ) - { - ERROR("Couldn't allocate p2m_frame_list_list array"); - goto out; - } - memcpy(p2m_frame_list_list, live_p2m_frame_list_list, PAGE_SIZE); - - /* Canonicalize guest's unsigned long vs ours */ - if ( dinfo->guest_width > sizeof(unsigned long) ) - for ( i = 0; i < PAGE_SIZE/sizeof(unsigned long); i++ ) - if ( i < PAGE_SIZE/dinfo->guest_width ) - p2m_frame_list_list[i] = ((uint64_t *)p2m_frame_list_list)[i]; - else - p2m_frame_list_list[i] = 0; - else if ( dinfo->guest_width < sizeof(unsigned long) ) - for ( i = PAGE_SIZE/sizeof(unsigned long) - 1; i >= 0; i-- ) - p2m_frame_list_list[i] = ((uint32_t *)p2m_frame_list_list)[i]; - - live_p2m_frame_list = - xc_map_foreign_pages(xch, dom, PROT_READ, - p2m_frame_list_list, - P2M_FLL_ENTRIES); - - if ( !live_p2m_frame_list ) - { - PERROR("Couldn't map p2m_frame_list"); - goto out; - } - - /* Get a local copy of the live_P2M_frame_list */ - if ( !(p2m_frame_list = malloc(P2M_TOOLS_FL_SIZE)) ) - { - ERROR("Couldn't allocate p2m_frame_list array"); - goto out; - } - memset(p2m_frame_list, 0, P2M_TOOLS_FL_SIZE); - memcpy(p2m_frame_list, live_p2m_frame_list, P2M_GUEST_FL_SIZE); - - /* Canonicalize guest's unsigned long vs ours */ - if ( dinfo->guest_width > sizeof(unsigned long) ) - for ( i = 0; i < P2M_FL_ENTRIES; i++ ) - p2m_frame_list[i] = ((uint64_t *)p2m_frame_list)[i]; - else if ( dinfo->guest_width < sizeof(unsigned long) ) - for ( i = P2M_FL_ENTRIES - 1; i >= 0; i-- ) - p2m_frame_list[i] = ((uint32_t *)p2m_frame_list)[i]; - - dinfo->p2m_frames = P2M_FL_ENTRIES; - - return p2m_frame_list; - - out: - err = errno; - - if ( live_p2m_frame_list_list ) - munmap(live_p2m_frame_list_list, PAGE_SIZE); - - if ( live_p2m_frame_list ) - munmap(live_p2m_frame_list, P2M_FLL_ENTRIES * PAGE_SIZE); - - free(p2m_frame_list_list); - - errno = err; - - return NULL; -} - -static int -xc_core_arch_map_p2m_rw(xc_interface *xch, struct domain_info_context *dinfo, xc_dominfo_t *info, - shared_info_any_t *live_shinfo, xen_pfn_t **live_p2m, int rw) -{ - xen_pfn_t *p2m_frame_list = NULL; - uint64_t p2m_cr3; - uint32_t dom = info->domid; - int ret = -1; - int err; - - if ( xc_domain_nr_gpfns(xch, info->domid, &dinfo->p2m_size) < 0 ) - { - ERROR("Could not get maximum GPFN!"); - goto out; - } - - if ( dinfo->p2m_size < info->nr_pages ) - { - ERROR("p2m_size < nr_pages -1 (%lx < %lx", dinfo->p2m_size, info->nr_pages - 1); - goto out; - } - - p2m_cr3 = GET_FIELD(live_shinfo, arch.p2m_cr3, dinfo->guest_width); - - p2m_frame_list = p2m_cr3 ? xc_core_arch_map_p2m_list_rw(xch, dinfo, dom, live_shinfo, p2m_cr3) - : xc_core_arch_map_p2m_tree_rw(xch, dinfo, dom, live_shinfo); - - if ( !p2m_frame_list ) - goto out; - - *live_p2m = xc_map_foreign_pages(xch, dom, - rw ? (PROT_READ | PROT_WRITE) : PROT_READ, - p2m_frame_list, - dinfo->p2m_frames); - - if ( !*live_p2m ) - { - PERROR("Couldn't map p2m table"); - goto out; - } - - ret = 0; - -out: - err = errno; - - free(p2m_frame_list); - - errno = err; - return ret; -} - -int -xc_core_arch_map_p2m(xc_interface *xch, struct domain_info_context *dinfo, xc_dominfo_t *info, - shared_info_any_t *live_shinfo, xen_pfn_t **live_p2m) -{ - return xc_core_arch_map_p2m_rw(xch, dinfo, info, live_shinfo, live_p2m, 0); -} - -int -xc_core_arch_map_p2m_writable(xc_interface *xch, struct domain_info_context *dinfo, xc_dominfo_t *info, - shared_info_any_t *live_shinfo, xen_pfn_t **live_p2m) -{ - return xc_core_arch_map_p2m_rw(xch, dinfo, info, live_shinfo, live_p2m, 1); -} - -int -xc_core_arch_get_scratch_gpfn(xc_interface *xch, uint32_t domid, - xen_pfn_t *gpfn) -{ - return xc_domain_nr_gpfns(xch, domid, gpfn); -} - -/* - * Local variables: - * mode: C - * c-file-style: "BSD" - * c-basic-offset: 4 - * tab-width: 4 - * indent-tabs-mode: nil - * End: - */ diff --git a/tools/libs/ctrl/xc_core_x86.h b/tools/libs/ctrl/xc_core_x86.h deleted file mode 100644 index 867146b1d9..0000000000 --- a/tools/libs/ctrl/xc_core_x86.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * 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; either - * version 2.1 of the License, or (at your option) any later version. - * - * 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/>. - * - * Copyright (c) 2007 Isaku Yamahata <yamahata at valinux co jp> - * VA Linux Systems Japan K.K. - * - */ - -#ifndef XC_CORE_X86_H -#define XC_CORE_X86_H - -#define ELF_ARCH_DATA ELFDATA2LSB -#define ELF_ARCH_MACHINE (dinfo->guest_width == 8 ? EM_X86_64 : EM_386) - -struct xc_core_arch_context { - /* nothing */ -}; - -#define xc_core_arch_context_init(arch_ctxt) do {} while (0) -#define xc_core_arch_context_free(arch_ctxt) do {} while (0) -#define xc_core_arch_context_get(arch_ctxt, ctxt, xch, domid) \ - (0) -#define xc_core_arch_context_dump(xch, arch_ctxt, args, dump_rtn) (0) - -int -xc_core_arch_gpfn_may_present(struct xc_core_arch_context *arch_ctxt, - unsigned long pfn); -static inline int -xc_core_arch_context_get_shdr(xc_interface *xch, - struct xc_core_arch_context *arch_ctxt, - struct xc_core_section_headers *sheaders, - struct xc_core_strtab *strtab, - uint64_t *filesz, uint64_t offset) -{ - *filesz = 0; - return 0; -} - -#endif /* XC_CORE_X86_H */ - -/* - * Local variables: - * mode: C - * c-file-style: "BSD" - * c-basic-offset: 4 - * tab-width: 4 - * indent-tabs-mode: nil - * End: - */ diff --git a/tools/libs/ctrl/xc_domain.c b/tools/libs/ctrl/xc_domain.c index e7cea4a17d..7d118848f1 100644 --- a/tools/libs/ctrl/xc_domain.c +++ b/tools/libs/ctrl/xc_domain.c @@ -19,8 +19,6 @@ * Copyright (c) 2003, K A Fraser. */ -#include "xc_private.h" -#include "xc_core.h" #include "xc_private.h" #include <xen/memory.h> #include <xen/hvm/hvm_op.h> diff --git a/tools/libs/ctrl/xc_private.h b/tools/libs/ctrl/xc_private.h index 8ebc0b59da..dff0f0289b 100644 --- a/tools/libs/ctrl/xc_private.h +++ b/tools/libs/ctrl/xc_private.h @@ -467,6 +467,18 @@ void *xc_vm_event_enable(xc_interface *xch, uint32_t domain_id, int param, int do_dm_op(xc_interface *xch, uint32_t domid, unsigned int nr_bufs, ...); +#if defined (__i386__) || defined (__x86_64__) +static inline int xc_core_arch_auto_translated_physmap(const xc_dominfo_t *info) +{ + return info->hvm; +} +#elif defined (__arm__) || defined(__aarch64__) +static inline int xc_core_arch_auto_translated_physmap(const xc_dominfo_t *info) +{ + return 1; +} +#endif + #endif /* __XC_PRIVATE_H__ */ /* diff --git a/tools/libs/guest/Makefile b/tools/libs/guest/Makefile index 2a2323ff09..2ce92d247e 100644 --- a/tools/libs/guest/Makefile +++ b/tools/libs/guest/Makefile @@ -24,6 +24,9 @@ SRCS-y += xg_offline_page.c else SRCS-y += xg_nomigrate.c endif +SRCS-y += xg_core.c +SRCS-$(CONFIG_X86) += xg_core_x86.c +SRCS-$(CONFIG_ARM) += xg_core_arm.c CFLAGS += -I$(XEN_libxenctrl) diff --git a/tools/libs/guest/xg_core.c b/tools/libs/guest/xg_core.c new file mode 100644 index 0000000000..c52f1161c1 --- /dev/null +++ b/tools/libs/guest/xg_core.c @@ -0,0 +1,1027 @@ +/* + * Elf format, (pfn, gmfn) table, IA64 support. + * Copyright (c) 2007 Isaku Yamahata <yamahata at valinux co jp> + * VA Linux Systems Japan K.K. + * + * 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/>. + */ + +/* + * xen dump-core file format follows ELF format specification. + * Analisys tools shouldn't depends on the order of sections. + * They should follow elf header and check section names. + * + * +--------------------------------------------------------+ + * |ELF header | + * +--------------------------------------------------------+ + * |section headers | + * | null section header | + * | .shstrtab | + * | .note.Xen | + * | .xen_prstatus | + * | .xen_shared_info if present | + * | .xen_pages | + * | .xen_p2m or .xen_pfn | + * +--------------------------------------------------------+ + * |.note.Xen:note section | + * | "Xen" is used as note name, | + * | types are defined in xen/include/public/elfnote.h | + * | and descriptors are defined in xc_core.h. | + * | dumpcore none | + * | dumpcore header | + * | dumpcore xen version | + * | dumpcore format version | + * +--------------------------------------------------------+ + * |.xen_prstatus | + * | vcpu_guest_context_t[nr_vcpus] | + * +--------------------------------------------------------+ + * |.xen_shared_info if possible | + * +--------------------------------------------------------+ + * |.xen_pages | + * | page * nr_pages | + * +--------------------------------------------------------+ + * |.xen_p2m or .xen_pfn | + * | .xen_p2m: struct xen_dumpcore_p2m[nr_pages] | + * | .xen_pfn: uint64_t[nr_pages] | + * +--------------------------------------------------------+ + * |.shstrtab: section header string table | + * +--------------------------------------------------------+ + * + */ + +#include "xc_private.h" +#include "xg_core.h" +#include <stdlib.h> +#include <unistd.h> + +#include <xen/libelf/libelf.h> + +/* number of pages to write at a time */ +#define DUMP_INCREMENT (4 * 1024) + +/* string table */ +struct xc_core_strtab { + char *strings; + uint16_t length; + uint16_t max; +}; + +static struct xc_core_strtab* +xc_core_strtab_init(xc_interface *xch) +{ + struct xc_core_strtab *strtab; + char *strings; + strtab = malloc(sizeof(*strtab)); + if ( strtab == NULL ) + return NULL; + + strings = malloc(PAGE_SIZE); + if ( strings == NULL ) + { + PERROR("Could not allocate string table init"); + free(strtab); + return NULL; + } + strtab->strings = strings; + strtab->max = PAGE_SIZE; + + /* index 0 represents none */ + strtab->strings[0] = '\0'; + strtab->length = 1; + + return strtab; +} + +static void +xc_core_strtab_free(struct xc_core_strtab *strtab) +{ + free(strtab->strings); + free(strtab); +} + +static uint16_t +xc_core_strtab_get(xc_interface *xch, struct xc_core_strtab *strtab, const char *name) +{ + uint16_t ret = 0; + uint16_t len = strlen(name) + 1; + + if ( strtab->length > UINT16_MAX - len ) + { + PERROR("too long string table"); + errno = E2BIG; + return ret; + } + + if ( strtab->length + len > strtab->max ) + { + char *tmp; + if ( strtab->max > UINT16_MAX / 2 ) + { + PERROR("too long string table"); + errno = ENOMEM; + return ret; + } + + tmp = realloc(strtab->strings, strtab->max * 2); + if ( tmp == NULL ) + { + PERROR("Could not allocate string table"); + return ret; + } + + strtab->strings = tmp; + strtab->max *= 2; + } + + ret = strtab->length; + strcpy(strtab->strings + strtab->length, name); + strtab->length += len; + return ret; +} + + +/* section headers */ +struct xc_core_section_headers { + uint16_t num; + uint16_t num_max; + + Elf64_Shdr *shdrs; +}; +#define SHDR_INIT ((uint16_t)16) +#define SHDR_INC ((uint16_t)4) + +static struct xc_core_section_headers* +xc_core_shdr_init(xc_interface *xch) +{ + struct xc_core_section_headers *sheaders; + sheaders = malloc(sizeof(*sheaders)); + if ( sheaders == NULL ) + return NULL; + + sheaders->num = 0; + sheaders->num_max = SHDR_INIT; + sheaders->shdrs = malloc(sizeof(sheaders->shdrs[0]) * sheaders->num_max); + if ( sheaders->shdrs == NULL ) + { + free(sheaders); + return NULL; + } + return sheaders; +} + +static void +xc_core_shdr_free(struct xc_core_section_headers *sheaders) +{ + free(sheaders->shdrs); + free(sheaders); +} + +Elf64_Shdr* +xc_core_shdr_get(xc_interface *xch, + struct xc_core_section_headers *sheaders) +{ + Elf64_Shdr *shdr; + + if ( sheaders->num == sheaders->num_max ) + { + Elf64_Shdr *shdrs; + if ( sheaders->num_max > UINT16_MAX - SHDR_INC ) + { + errno = E2BIG; + return NULL; + } + sheaders->num_max += SHDR_INC; + shdrs = realloc(sheaders->shdrs, + sizeof(sheaders->shdrs[0]) * sheaders->num_max); + if ( shdrs == NULL ) + return NULL; + sheaders->shdrs = shdrs; + } + + shdr = &sheaders->shdrs[sheaders->num]; + sheaders->num++; + memset(shdr, 0, sizeof(*shdr)); + return shdr; +} + +int +xc_core_shdr_set(xc_interface *xch, + Elf64_Shdr *shdr, + struct xc_core_strtab *strtab, + const char *name, uint32_t type, + uint64_t offset, uint64_t size, + uint64_t addralign, uint64_t entsize) +{ + uint64_t name_idx = xc_core_strtab_get(xch, strtab, name); + if ( name_idx == 0 ) + return -1; + + shdr->sh_name = name_idx; + shdr->sh_type = type; + shdr->sh_offset = offset; + shdr->sh_size = size; + shdr->sh_addralign = addralign; + shdr->sh_entsize = entsize; + return 0; +} + +static void +xc_core_ehdr_init(Elf64_Ehdr *ehdr) +{ + memset(ehdr, 0, sizeof(*ehdr)); + ehdr->e_ident[EI_MAG0] = ELFMAG0; + ehdr->e_ident[EI_MAG1] = ELFMAG1; + ehdr->e_ident[EI_MAG2] = ELFMAG2; + ehdr->e_ident[EI_MAG3] = ELFMAG3; + ehdr->e_ident[EI_CLASS] = ELFCLASS64; + ehdr->e_ident[EI_DATA] = ELF_ARCH_DATA; + ehdr->e_ident[EI_VERSION] = EV_CURRENT; + ehdr->e_ident[EI_OSABI] = ELFOSABI_SYSV; + ehdr->e_ident[EI_ABIVERSION] = EV_CURRENT; + + ehdr->e_type = ET_CORE; + /* e_machine will be filled in later */ + ehdr->e_version = EV_CURRENT; + ehdr->e_entry = 0; + ehdr->e_phoff = 0; + ehdr->e_shoff = sizeof(*ehdr); + ehdr->e_flags = ELF_CORE_EFLAGS; + ehdr->e_ehsize = sizeof(*ehdr); + ehdr->e_phentsize = sizeof(Elf64_Phdr); + ehdr->e_phnum = 0; + ehdr->e_shentsize = sizeof(Elf64_Shdr); + /* ehdr->e_shnum and ehdr->e_shstrndx aren't known here yet. + * fill it later */ +} + +static int +elfnote_fill_xen_version(xc_interface *xch, + struct xen_dumpcore_elfnote_xen_version_desc + *xen_version) +{ + int rc; + memset(xen_version, 0, sizeof(*xen_version)); + + rc = xc_version(xch, XENVER_version, NULL); + if ( rc < 0 ) + return rc; + xen_version->major_version = rc >> 16; + xen_version->minor_version = rc & ((1 << 16) - 1); + + rc = xc_version(xch, XENVER_extraversion, + &xen_version->extra_version); + if ( rc < 0 ) + return rc; + + rc = xc_version(xch, XENVER_compile_info, + &xen_version->compile_info); + if ( rc < 0 ) + return rc; + + rc = xc_version(xch, + XENVER_capabilities, &xen_version->capabilities); + if ( rc < 0 ) + return rc; + + rc = xc_version(xch, XENVER_changeset, &xen_version->changeset); + if ( rc < 0 ) + return rc; + + rc = xc_version(xch, XENVER_platform_parameters, + &xen_version->platform_parameters); + if ( rc < 0 ) + return rc; + + rc = xc_version(xch, XENVER_pagesize, NULL); + if ( rc < 0 ) + return rc; + xen_version->pagesize = rc; + + return 0; +} + +static void +elfnote_fill_format_version(struct xen_dumpcore_elfnote_format_version_desc + *format_version) +{ + format_version->version = XEN_DUMPCORE_FORMAT_VERSION_CURRENT; +} + +static void +elfnote_init(struct elfnote *elfnote) +{ + /* elf note section */ + memset(elfnote, 0, sizeof(*elfnote)); + elfnote->namesz = strlen(XEN_DUMPCORE_ELFNOTE_NAME) + 1; + strncpy(elfnote->name, XEN_DUMPCORE_ELFNOTE_NAME, sizeof(elfnote->name)); +} + +static int +elfnote_dump_none(xc_interface *xch, void *args, dumpcore_rtn_t dump_rtn) +{ + int sts; + struct elfnote elfnote; + struct xen_dumpcore_elfnote_none_desc none; + + elfnote_init(&elfnote); + /* Avoid compile warning about constant-zero-sized memset(). */ + /*memset(&none, 0, sizeof(none));*/ + + elfnote.descsz = sizeof(none); + elfnote.type = XEN_ELFNOTE_DUMPCORE_NONE; + sts = dump_rtn(xch, args, (char*)&elfnote, sizeof(elfnote)); + if ( sts != 0 ) + return sts; + return dump_rtn(xch, args, (char*)&none, sizeof(none)); +} + +static int +elfnote_dump_core_header( + xc_interface *xch, + void *args, dumpcore_rtn_t dump_rtn, const xc_dominfo_t *info, + int nr_vcpus, unsigned long nr_pages) +{ + int sts; + struct elfnote elfnote; + struct xen_dumpcore_elfnote_header_desc header; + + elfnote_init(&elfnote); + memset(&header, 0, sizeof(header)); + + elfnote.descsz = sizeof(header); + elfnote.type = XEN_ELFNOTE_DUMPCORE_HEADER; + header.xch_magic = info->hvm ? XC_CORE_MAGIC_HVM : XC_CORE_MAGIC; + header.xch_nr_vcpus = nr_vcpus; + header.xch_nr_pages = nr_pages; + header.xch_page_size = PAGE_SIZE; + sts = dump_rtn(xch, args, (char*)&elfnote, sizeof(elfnote)); + if ( sts != 0 ) + return sts; + return dump_rtn(xch, args, (char*)&header, sizeof(header)); +} + +static int +elfnote_dump_xen_version(xc_interface *xch, void *args, + dumpcore_rtn_t dump_rtn, unsigned int guest_width) +{ + int sts; + struct elfnote elfnote; + struct xen_dumpcore_elfnote_xen_version_desc xen_version; + + elfnote_init(&elfnote); + memset(&xen_version, 0, sizeof(xen_version)); + + elfnote.descsz = sizeof(xen_version); + elfnote.type = XEN_ELFNOTE_DUMPCORE_XEN_VERSION; + elfnote_fill_xen_version(xch, &xen_version); + if (guest_width < sizeof(unsigned long)) + { + // 32 bit elf file format differs in pagesize's alignment + char *p = (char *)&xen_version.pagesize; + memmove(p - 4, p, sizeof(xen_version.pagesize)); + } + sts = dump_rtn(xch, args, (char*)&elfnote, sizeof(elfnote)); + if ( sts != 0 ) + return sts; + return dump_rtn(xch, args, (char*)&xen_version, sizeof(xen_version)); +} + +static int +elfnote_dump_format_version(xc_interface *xch, + void *args, dumpcore_rtn_t dump_rtn) +{ + int sts; + struct elfnote elfnote; + struct xen_dumpcore_elfnote_format_version_desc format_version; + + elfnote_init(&elfnote); + memset(&format_version, 0, sizeof(format_version)); + + elfnote.descsz = sizeof(format_version); + elfnote.type = XEN_ELFNOTE_DUMPCORE_FORMAT_VERSION; + elfnote_fill_format_version(&format_version); + sts = dump_rtn(xch, args, (char*)&elfnote, sizeof(elfnote)); + if ( sts != 0 ) + return sts; + return dump_rtn(xch, args, (char*)&format_version, sizeof(format_version)); +} + +int +xc_domain_dumpcore_via_callback(xc_interface *xch, + uint32_t domid, + void *args, + dumpcore_rtn_t dump_rtn) +{ + xc_dominfo_t info; + shared_info_any_t *live_shinfo = NULL; + struct domain_info_context _dinfo = {}; + struct domain_info_context *dinfo = &_dinfo; + + int nr_vcpus = 0; + char *dump_mem, *dump_mem_start = NULL; + vcpu_guest_context_any_t *ctxt = NULL; + struct xc_core_arch_context arch_ctxt; + char dummy[PAGE_SIZE]; + int dummy_len; + int sts = -1; + + unsigned long i; + unsigned long j; + unsigned long nr_pages; + unsigned long max_mfn; + + xc_core_memory_map_t *memory_map = NULL; + unsigned int nr_memory_map; + unsigned int map_idx; + + int auto_translated_physmap; + xen_pfn_t *p2m = NULL; + struct xen_dumpcore_p2m *p2m_array = NULL; + + uint64_t *pfn_array = NULL; + + Elf64_Ehdr ehdr; + uint64_t filesz; + uint64_t offset; + uint64_t fixup; + + struct xc_core_strtab *strtab = NULL; + uint16_t strtab_idx; + struct xc_core_section_headers *sheaders = NULL; + Elf64_Shdr *shdr; + + xc_core_arch_context_init(&arch_ctxt); + if ( (dump_mem_start = malloc(DUMP_INCREMENT*PAGE_SIZE)) == NULL ) + { + PERROR("Could not allocate dump_mem"); + goto out; + } + + if ( xc_domain_getinfo(xch, domid, 1, &info) != 1 ) + { + PERROR("Could not get info for domain"); + goto out; + } + /* Map the shared info frame */ + live_shinfo = xc_map_foreign_range(xch, domid, PAGE_SIZE, + PROT_READ, info.shared_info_frame); + if ( !live_shinfo && !info.hvm ) + { + PERROR("Couldn't map live_shinfo"); + goto out; + } + auto_translated_physmap = xc_core_arch_auto_translated_physmap(&info); + + if ( !auto_translated_physmap ) + + { + if ( xc_domain_get_guest_width(xch, domid, &dinfo->guest_width) != 0 ) + { + PERROR("Could not get address size for domain"); + goto out; + } + } + else + { + /* + * Autotranslated guest never sets guest width in the first + * place. Force guest_width to be sizeof(unsigned long) so + * code below functions properly. + * + * Here is why this is correct. + * + * 1. Before f969bc9fc, xc_domain_get_guest_width for HVM (x86 + * and ARM) always returned hypervisor's idea of + * sizeof(unsigned long). + * + * 2. There has never been a situation in which hypervisor's + * word width is smaller than toolstack domain's (i.e. no + * 32bit hypervisor + 64bit toolstack). + * + * Predicates in code test guest_width against toolstack + * domain's sizeof(unsigned long), so setting guest_width to + * toolstack domain's idea of sizeof(unsigned long) matches + * the original behaviour for HVM guests. + */ + dinfo->guest_width = sizeof(unsigned long); + } + + if ( domid != info.domid ) + { + PERROR("Domain %d does not exist", domid); + goto out; + } + + ctxt = calloc(sizeof(*ctxt), info.max_vcpu_id + 1); + if ( !ctxt ) + { + PERROR("Could not allocate vcpu context array"); + goto out; + } + + for ( i = 0; i <= info.max_vcpu_id; i++ ) + { + if ( xc_vcpu_getcontext(xch, domid, i, &ctxt[nr_vcpus]) == 0 ) + { + if ( xc_core_arch_context_get(&arch_ctxt, &ctxt[nr_vcpus], + xch, domid) ) + continue; + nr_vcpus++; + } + } + if ( nr_vcpus == 0 ) + { + PERROR("No VCPU context could be grabbed"); + goto out; + } + + /* obtain memory map */ + sts = xc_core_arch_memory_map_get(xch, &arch_ctxt, &info, + live_shinfo, &memory_map, + &nr_memory_map); + if ( sts != 0 ) + goto out; + + /* + * Note: this is the *current* number of pages and may change under + * a live dump-core. We'll just take this value, and if more pages + * exist, we'll skip them. If there's less, then we'll just not use + * all the array... + * + * We don't want to use the total potential size of the memory map + * since that is usually much higher than info.nr_pages. + */ + nr_pages = info.nr_pages; + + if ( !auto_translated_physmap ) + { + /* obtain p2m table */ + p2m_array = malloc(nr_pages * sizeof(p2m_array[0])); + if ( p2m_array == NULL ) + { + PERROR("Could not allocate p2m array"); + goto out; + } + + sts = xc_core_arch_map_p2m(xch, dinfo, &info, live_shinfo, &p2m); + if ( sts != 0 ) + goto out; + + sts = xc_maximum_ram_page(xch, &max_mfn); + if ( sts != 0 ) + goto out; + } + else + { + pfn_array = malloc(nr_pages * sizeof(pfn_array[0])); + if ( pfn_array == NULL ) + { + PERROR("Could not allocate pfn array"); + goto out; + } + } + + /* ehdr.e_shnum and ehdr.e_shstrndx aren't known here yet. fill it later*/ + xc_core_ehdr_init(&ehdr); + + /* create section header */ + strtab = xc_core_strtab_init(xch); + if ( strtab == NULL ) + { + PERROR("Could not allocate string table"); + goto out; + } + sheaders = xc_core_shdr_init(xch); + if ( sheaders == NULL ) + { + PERROR("Could not allocate section headers"); + goto out; + } + /* null section */ + shdr = xc_core_shdr_get(xch,sheaders); + if ( shdr == NULL ) + { + PERROR("Could not get section header for null section"); + goto out; + } + + /* .shstrtab */ + shdr = xc_core_shdr_get(xch,sheaders); + if ( shdr == NULL ) + { + PERROR("Could not get section header for shstrtab"); + goto out; + } + strtab_idx = shdr - sheaders->shdrs; + /* strtab_shdr.sh_offset, strtab_shdr.sh_size aren't unknown. + * fill it later + */ + sts = xc_core_shdr_set(xch, shdr, strtab, ELF_SHSTRTAB, SHT_STRTAB, 0, 0, 0, 0); + if ( sts != 0 ) + goto out; + + /* elf note section */ + /* here the number of section header is unknown. fix up offset later. */ + offset = sizeof(ehdr); + filesz = + sizeof(struct xen_dumpcore_elfnote_none) + /* none */ + sizeof(struct xen_dumpcore_elfnote_header) + /* core header */ + sizeof(struct xen_dumpcore_elfnote_xen_version) + /* xen version */ + sizeof(struct xen_dumpcore_elfnote_format_version);/* format version */ + shdr = xc_core_shdr_get(xch,sheaders); + if ( shdr == NULL ) + { + PERROR("Could not get section header for note section"); + goto out; + } + sts = xc_core_shdr_set(xch, shdr, strtab, XEN_DUMPCORE_SEC_NOTE, SHT_NOTE, + offset, filesz, 0, 0); + if ( sts != 0 ) + goto out; + offset += filesz; + + /* prstatus */ + shdr = xc_core_shdr_get(xch,sheaders); + if ( shdr == NULL ) + { + PERROR("Could not get section header for .xen_prstatus"); + goto out; + } + filesz = sizeof(*ctxt) * nr_vcpus; + sts = xc_core_shdr_set(xch, shdr, strtab, XEN_DUMPCORE_SEC_PRSTATUS, + SHT_PROGBITS, offset, filesz, + __alignof__(*ctxt), sizeof(*ctxt)); + if ( sts != 0 ) + goto out; + offset += filesz; + + /* arch context */ + sts = xc_core_arch_context_get_shdr(xch, &arch_ctxt, sheaders, strtab, + &filesz, offset); + if ( sts != 0 ) + goto out; + offset += filesz; + + /* shared_info */ + if ( live_shinfo != NULL ) + { + shdr = xc_core_shdr_get(xch,sheaders); + if ( shdr == NULL ) + { + PERROR("Could not get section header for .xen_shared_info"); + goto out; + } + filesz = PAGE_SIZE; + sts = xc_core_shdr_set(xch, shdr, strtab, XEN_DUMPCORE_SEC_SHARED_INFO, + SHT_PROGBITS, offset, filesz, + __alignof__(*live_shinfo), PAGE_SIZE); + if ( sts != 0 ) + goto out; + offset += filesz; + } + + /* + * pages and p2m/pfn are the last section to allocate section headers + * so that we know the number of section headers here. + * 2 = pages section and p2m/pfn table section + */ + fixup = (sheaders->num + 2) * sizeof(*shdr); + /* zeroth section should have zero offset */ + for ( i = 1; i < sheaders->num; i++ ) + sheaders->shdrs[i].sh_offset += fixup; + offset += fixup; + dummy_len = ROUNDUP(offset, PAGE_SHIFT) - offset; /* padding length */ + offset += dummy_len; + + /* pages */ + shdr = xc_core_shdr_get(xch,sheaders); + if ( shdr == NULL ) + { + PERROR("could not get section headers for .xen_pages"); + goto out; + } + filesz = (uint64_t)nr_pages * PAGE_SIZE; + sts = xc_core_shdr_set(xch, shdr, strtab, XEN_DUMPCORE_SEC_PAGES, SHT_PROGBITS, + offset, filesz, PAGE_SIZE, PAGE_SIZE); + if ( sts != 0 ) + goto out; + offset += filesz; + + /* p2m/pfn table */ + shdr = xc_core_shdr_get(xch,sheaders); + if ( shdr == NULL ) + { + PERROR("Could not get section header for .xen_{p2m, pfn} table"); + goto out; + } + if ( !auto_translated_physmap ) + { + filesz = (uint64_t)nr_pages * sizeof(p2m_array[0]); + sts = xc_core_shdr_set(xch, shdr, strtab, XEN_DUMPCORE_SEC_P2M, + SHT_PROGBITS, + offset, filesz, __alignof__(p2m_array[0]), + sizeof(p2m_array[0])); + } + else + { + filesz = (uint64_t)nr_pages * sizeof(pfn_array[0]); + sts = xc_core_shdr_set(xch, shdr, strtab, XEN_DUMPCORE_SEC_PFN, + SHT_PROGBITS, + offset, filesz, __alignof__(pfn_array[0]), + sizeof(pfn_array[0])); + } + if ( sts != 0 ) + goto out; + offset += filesz; + + /* fixing up section header string table section header */ + filesz = strtab->length; + sheaders->shdrs[strtab_idx].sh_offset = offset; + sheaders->shdrs[strtab_idx].sh_size = filesz; + + /* write out elf header */ + ehdr.e_shnum = sheaders->num; + ehdr.e_shstrndx = strtab_idx; + ehdr.e_machine = ELF_ARCH_MACHINE; + sts = dump_rtn(xch, args, (char*)&ehdr, sizeof(ehdr)); + if ( sts != 0 ) + goto out; + + /* section headers */ + sts = dump_rtn(xch, args, (char*)sheaders->shdrs, + sheaders->num * sizeof(sheaders->shdrs[0])); + if ( sts != 0 ) + goto out; + + /* elf note section: xen core header */ + sts = elfnote_dump_none(xch, args, dump_rtn); + if ( sts != 0 ) + goto out; + + /* elf note section: xen core header */ + sts = elfnote_dump_core_header(xch, args, dump_rtn, &info, nr_vcpus, nr_pages); + if ( sts != 0 ) + goto out; + + /* elf note section: xen version */ + sts = elfnote_dump_xen_version(xch, args, dump_rtn, dinfo->guest_width); + if ( sts != 0 ) + goto out; + + /* elf note section: format version */ + sts = elfnote_dump_format_version(xch, args, dump_rtn); + if ( sts != 0 ) + goto out; + + /* prstatus: .xen_prstatus */ + sts = dump_rtn(xch, args, (char *)ctxt, sizeof(*ctxt) * nr_vcpus); + if ( sts != 0 ) + goto out; + + if ( live_shinfo != NULL ) + { + /* shared_info: .xen_shared_info */ + sts = dump_rtn(xch, args, (char*)live_shinfo, PAGE_SIZE); + if ( sts != 0 ) + goto out; + } + + /* arch specific context */ + sts = xc_core_arch_context_dump(xch, &arch_ctxt, args, dump_rtn); + if ( sts != 0 ) + goto out; + + /* Pad the output data to page alignment. */ + memset(dummy, 0, PAGE_SIZE); + sts = dump_rtn(xch, args, dummy, dummy_len); + if ( sts != 0 ) + goto out; + + /* dump pages: .xen_pages */ + j = 0; + dump_mem = dump_mem_start; + for ( map_idx = 0; map_idx < nr_memory_map; map_idx++ ) + { + uint64_t pfn_start; + uint64_t pfn_end; + + pfn_start = memory_map[map_idx].addr >> PAGE_SHIFT; + pfn_end = pfn_start + (memory_map[map_idx].size >> PAGE_SHIFT); + for ( i = pfn_start; i < pfn_end; i++ ) + { + uint64_t gmfn; + void *vaddr; + + if ( !auto_translated_physmap ) + { + if ( i >= dinfo->p2m_size ) + break; + + if ( dinfo->guest_width >= sizeof(unsigned long) ) + { + if ( dinfo->guest_width == sizeof(unsigned long) ) + gmfn = p2m[i]; + else + gmfn = ((uint64_t *)p2m)[i]; + if ( gmfn == INVALID_PFN ) + continue; + } + else + { + gmfn = ((uint32_t *)p2m)[i]; + if ( gmfn == (uint32_t)INVALID_PFN ) + continue; + } + if ( gmfn > max_mfn ) + continue; + + if ( j >= nr_pages ) + { + j++; + continue; + } + + p2m_array[j].pfn = i; + p2m_array[j].gmfn = gmfn; + } + else + { + if ( !xc_core_arch_gpfn_may_present(&arch_ctxt, i) ) + continue; + + if ( j >= nr_pages ) + { + j++; + continue; + } + + gmfn = i; + pfn_array[j] = i; + } + + vaddr = xc_map_foreign_range( + xch, domid, PAGE_SIZE, PROT_READ, gmfn); + if ( vaddr == NULL ) + continue; + memcpy(dump_mem, vaddr, PAGE_SIZE); + munmap(vaddr, PAGE_SIZE); + dump_mem += PAGE_SIZE; + if ( (j + 1) % DUMP_INCREMENT == 0 ) + { + sts = dump_rtn( + xch, args, dump_mem_start, dump_mem - dump_mem_start); + if ( sts != 0 ) + goto out; + dump_mem = dump_mem_start; + } + + j++; + } + } + + if ( j > nr_pages ) + { + /* + * When live dump-mode (-L option) is specified, + * guest domain may increase memory. + */ + IPRINTF("exceeded nr_pages (%ld) losing %ld pages", nr_pages, j - nr_pages); + } + + sts = dump_rtn(xch, args, dump_mem_start, dump_mem - dump_mem_start); + if ( sts != 0 ) + goto out; + if ( j < nr_pages ) + { + /* When live dump-mode (-L option) is specified, + * guest domain may reduce memory. pad with zero pages. + */ + DPRINTF("j (%ld) != nr_pages (%ld)", j, nr_pages); + memset(dump_mem_start, 0, PAGE_SIZE); + for (; j < nr_pages; j++) { + sts = dump_rtn(xch, args, dump_mem_start, PAGE_SIZE); + if ( sts != 0 ) + goto out; + if ( !auto_translated_physmap ) + { + p2m_array[j].pfn = XC_CORE_INVALID_PFN; + p2m_array[j].gmfn = XC_CORE_INVALID_GMFN; + } + else + pfn_array[j] = XC_CORE_INVALID_PFN; + } + } + + /* p2m/pfn table: .xen_p2m/.xen_pfn */ + if ( !auto_translated_physmap ) + sts = dump_rtn( + xch, args, (char *)p2m_array, sizeof(p2m_array[0]) * nr_pages); + else + sts = dump_rtn( + xch, args, (char *)pfn_array, sizeof(pfn_array[0]) * nr_pages); + if ( sts != 0 ) + goto out; + + /* elf section header string table: .shstrtab */ + sts = dump_rtn(xch, args, strtab->strings, strtab->length); + if ( sts != 0 ) + goto out; + + sts = 0; + +out: + if ( memory_map != NULL ) + free(memory_map); + if ( p2m != NULL ) + munmap(p2m, PAGE_SIZE * dinfo->p2m_frames); + if ( p2m_array != NULL ) + free(p2m_array); + if ( pfn_array != NULL ) + free(pfn_array); + if ( sheaders != NULL ) + xc_core_shdr_free(sheaders); + if ( strtab != NULL ) + xc_core_strtab_free(strtab); + if ( ctxt != NULL ) + free(ctxt); + if ( dump_mem_start != NULL ) + free(dump_mem_start); + if ( live_shinfo != NULL ) + munmap(live_shinfo, PAGE_SIZE); + xc_core_arch_context_free(&arch_ctxt); + + return sts; +} + +/* Callback args for writing to a local dump file. */ +struct dump_args { + int fd; +}; + +/* Callback routine for writing to a local dump file. */ +static int local_file_dump(xc_interface *xch, + void *args, char *buffer, unsigned int length) +{ + struct dump_args *da = args; + + if ( write_exact(da->fd, buffer, length) == -1 ) + { + PERROR("Failed to write buffer"); + return -errno; + } + + if ( length >= (DUMP_INCREMENT * PAGE_SIZE) ) + { + // Now dumping pages -- make sure we discard clean pages from + // the cache after each write + discard_file_cache(xch, da->fd, 0 /* no flush */); + } + + return 0; +} + +int +xc_domain_dumpcore(xc_interface *xch, + uint32_t domid, + const char *corename) +{ + struct dump_args da; + int sts; + + if ( (da.fd = open(corename, O_CREAT|O_RDWR|O_TRUNC, S_IWUSR|S_IRUSR)) < 0 ) + { + PERROR("Could not open corefile %s", corename); + return -errno; + } + + sts = xc_domain_dumpcore_via_callback( + xch, domid, &da, &local_file_dump); + + /* flush and discard any remaining portion of the file from cache */ + discard_file_cache(xch, da.fd, 1/* flush first*/); + + close(da.fd); + + return sts; +} + +/* + * Local variables:
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |