get_crash_memory_ranges() is unreliable under Xen. Proper machine memory map could be obtained under Xen by calling __HYPERVISOR_memory_op hypercall with XENMEM_machine_memory_map argument. get_crash_memory_ranges_xen() does that. It is implemented using ioctl() or libxenctrl interface. This solution is compatible with 3.x and 4.x Xen versions. Signed-off-by: Daniel Kiper <daniel.kiper at oracle.com> --- kexec/arch/i386/crashdump-x86.c | 203 ++++++++++++++++++++++++++++++++++++--- 1 files changed, 191 insertions(+), 12 deletions(-) diff --git a/kexec/arch/i386/crashdump-x86.c b/kexec/arch/i386/crashdump-x86.c index c6b9354..09c3fd4 100644 --- a/kexec/arch/i386/crashdump-x86.c +++ b/kexec/arch/i386/crashdump-x86.c @@ -18,21 +18,41 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#define _XOPEN_SOURCE 600 +#define _BSD_SOURCE + +#include <fcntl.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <errno.h> #include <limits.h> #include <elf.h> +#include <sys/ioctl.h> +#include <sys/mman.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include "../../kexec.h" #include "../../kexec-elf.h" #include "../../kexec-syscall.h" +#include "../../firmware_memmap.h" #include "../../crashdump.h" #include "kexec-x86.h" #include "crashdump-x86.h" + +#ifdef HAVE_LIBXENCTRL +#ifdef HAVE_XC_GET_MACHINE_MEMORY_MAP +#include <xenctrl.h> +#else +#define __XEN_TOOLS__ 1 +#include <xen/xen.h> +#include <xen/memory.h> +#include <xen/sys/privcmd.h> +#endif /* HAVE_XC_GET_MACHINE_MEMORY_MAP */ +#endif /* HAVE_LIBXENCTRL */ + #include <x86/x86-linux.h> extern struct arch_options_t arch_options; @@ -273,6 +293,162 @@ static int get_crash_memory_ranges(struct memory_range **range, int *ranges, return 0; } +#ifdef HAVE_LIBXENCTRL +#ifdef HAVE_XC_GET_MACHINE_MEMORY_MAP +static int get_crash_memory_ranges_xen(struct memory_range **range, + int *ranges, unsigned long lowmem_limit) +{ + int j, rc, ret = -1; + struct e820entry e820entries[CRASH_MAX_MEMORY_RANGES]; + unsigned int i; +#ifdef XENCTRL_HAS_XC_INTERFACE + xc_interface *xc; +#else + int xc; +#endif + +#ifdef XENCTRL_HAS_XC_INTERFACE + xc = xc_interface_open(NULL, NULL, 0); + + if (!xc) { + fprintf(stderr, "%s: Failed to open Xen control interface\n", __func__); + goto err; + } +#else + xc = xc_interface_open(); + + if (xc == -1) { + fprintf(stderr, "%s: Failed to open Xen control interface\n", __func__); + goto err; + } +#endif + + rc = xc_get_machine_memory_map(xc, e820entries, CRASH_MAX_MEMORY_RANGES); + + if (rc < 0) { + fprintf(stderr, "%s: xc_get_machine_memory_map: %s\n", __func__, strerror(-rc)); + goto err; + } + + for (i = 0, j = 0; i < rc && j < CRASH_MAX_MEMORY_RANGES; ++i, ++j) { + crash_memory_range[j].start = e820entries[i].addr; + crash_memory_range[j].end = e820entries[i].addr + e820entries[i].size - 1; + crash_memory_range[j].type = xen_e820_to_kexec_type(e820entries[i].type); + segregate_lowmem_region(&j, lowmem_limit); + } + + *range = crash_memory_range; + *ranges = j; + + qsort(*range, *ranges, sizeof(struct memory_range), compare_ranges); + + if (exclude_region(ranges, crash_reserved_mem.start, + crash_reserved_mem.end) < 0) + goto err; + + ret = 0; + +err: + xc_interface_close(xc); + + return ret; +} +#else +static int get_crash_memory_ranges_xen(struct memory_range **range, + int *ranges, unsigned long lowmem_limit) +{ + int fd, j, rc, ret = -1; + privcmd_hypercall_t hypercall; + struct e820entry *e820entries = NULL; + struct xen_memory_map *xen_memory_map = NULL; + unsigned int i; + + fd = open("/proc/xen/privcmd", O_RDWR); + + if (fd == -1) { + fprintf(stderr, "%s: open(/proc/xen/privcmd): %m\n", __func__); + goto err; + } + + rc = posix_memalign((void **)&e820entries, getpagesize(), + sizeof(struct e820entry) * CRASH_MAX_MEMORY_RANGES); + + if (rc) { + fprintf(stderr, "%s: posix_memalign(e820entries): %s\n", __func__, strerror(rc)); + e820entries = NULL; + goto err; + } + + rc = posix_memalign((void **)&xen_memory_map, getpagesize(), + sizeof(struct xen_memory_map)); + + if (rc) { + fprintf(stderr, "%s: posix_memalign(xen_memory_map): %s\n", __func__, strerror(rc)); + xen_memory_map = NULL; + goto err; + } + + if (mlock(e820entries, sizeof(struct e820entry) * CRASH_MAX_MEMORY_RANGES) == -1) { + fprintf(stderr, "%s: mlock(e820entries): %m\n", __func__); + goto err; + } + + if (mlock(xen_memory_map, sizeof(struct xen_memory_map)) == -1) { + fprintf(stderr, "%s: mlock(xen_memory_map): %m\n", __func__); + goto err; + } + + xen_memory_map->nr_entries = CRASH_MAX_MEMORY_RANGES; + set_xen_guest_handle(xen_memory_map->buffer, e820entries); + + hypercall.op = __HYPERVISOR_memory_op; + hypercall.arg[0] = XENMEM_machine_memory_map; + hypercall.arg[1] = (__u64)xen_memory_map; + + rc = ioctl(fd, IOCTL_PRIVCMD_HYPERCALL, &hypercall); + + if (rc == -1) { + fprintf(stderr, "%s: ioctl(IOCTL_PRIVCMD_HYPERCALL): %m\n", __func__); + goto err; + } + + for (i = 0, j = 0; i < xen_memory_map->nr_entries && + j < CRASH_MAX_MEMORY_RANGES; ++i, ++j) { + crash_memory_range[j].start = e820entries[i].addr; + crash_memory_range[j].end = e820entries[i].addr + e820entries[i].size - 1; + crash_memory_range[j].type = xen_e820_to_kexec_type(e820entries[i].type); + segregate_lowmem_region(&j, lowmem_limit); + } + + *range = crash_memory_range; + *ranges = j; + + qsort(*range, *ranges, sizeof(struct memory_range), compare_ranges); + + if (exclude_region(ranges, crash_reserved_mem.start, + crash_reserved_mem.end) < 0) + goto err; + + ret = 0; + +err: + munlock(xen_memory_map, sizeof(struct xen_memory_map)); + munlock(e820entries, sizeof(struct e820entry) * CRASH_MAX_MEMORY_RANGES); + free(xen_memory_map); + free(e820entries); + close(fd); + + return ret; +} +#endif /* HAVE_XC_GET_MACHINE_MEMORY_MAP */ +#else +static int get_crash_memory_ranges_xen(struct memory_range **range, + int *ranges, unsigned long lowmem_limit) +{ + return 0; +} +#endif /* HAVE_LIBXENCTRL */ + static void segregate_lowmem_region(int *nr_ranges, unsigned long lowmem_limit) { unsigned long long end, start; @@ -724,10 +900,15 @@ int load_crashdump_segments(struct kexec_info *info, char* mod_cmdline, return -1; } - if (get_crash_memory_ranges(&mem_range, &nr_ranges, - info->kexec_flags, - elf_info.lowmem_limit) < 0) - return -1; + if (xen_present()) { + if (get_crash_memory_ranges_xen(&mem_range, &nr_ranges, + elf_info.lowmem_limit) < 0) + return -1; + } else + if (get_crash_memory_ranges(&mem_range, &nr_ranges, + info->kexec_flags, + elf_info.lowmem_limit) < 0) + return -1; get_backup_area(info, mem_range, nr_ranges); @@ -784,17 +965,15 @@ int load_crashdump_segments(struct kexec_info *info, char* mod_cmdline, /* Create elf header segment and store crash image data. */ if (arch_options.core_header_type == CORE_TYPE_ELF64) { - if (crash_create_elf64_headers(info, &elf_info, - crash_memory_range, nr_ranges, - &tmp, &bufsz, - ELF_CORE_HEADER_ALIGN) < 0) + if (crash_create_elf64_headers(info, &elf_info, mem_range, + nr_ranges, &tmp, &bufsz, + ELF_CORE_HEADER_ALIGN) < 0) return EFAILED; } else { - if (crash_create_elf32_headers(info, &elf_info, - crash_memory_range, nr_ranges, - &tmp, &bufsz, - ELF_CORE_HEADER_ALIGN) < 0) + if (crash_create_elf32_headers(info, &elf_info, mem_range, + nr_ranges, &tmp, &bufsz, + ELF_CORE_HEADER_ALIGN) < 0) return EFAILED; } /* the size of the elf headers allocated is returned in 'bufsz' */ -- 1.5.6.5