[Xen-devel] [PATCH 4/4] kexec/xen: directly load images images into Xen

Don Slutz dslutz at verizon.com
Thu Nov 7 15:36:40 EST 2013


For what it is worth.

Reviewed-by: Don Slutz <dslutz at verizon.com>
     -Don Slutz

On 11/06/13 09:55, David Vrabel wrote:
> From: David Vrabel <david.vrabel at citrix.com>
>
> Xen 4.4 has an improvided kexec hypercall ABI that allows images to be
> loaded and executed without any kernel involvement.  Use the API
> provided by libxc to load images when running in a Xen guest.
>
> Support for loading images via the kexec_load syscall in non-upstream
> ("classic") Xen kernels is no longer supported.
>
> Signed-off-by: David Vrabel <david.vrabel at citrix.com>
> Reviewed-by: Daniel Kiper <daniel.kiper at oracle.com>
> ---
>   kexec/Makefile                  |    1 +
>   kexec/arch/i386/crashdump-x86.c |   20 +++++-
>   kexec/crashdump-xen.c           |   34 ++++++++++
>   kexec/crashdump.h               |    3 +-
>   kexec/kexec-xen.c               |  139 +++++++++++++++++++++++++++++++++++++++
>   kexec/kexec.c                   |   24 +++++--
>   kexec/kexec.h                   |    5 ++
>   7 files changed, 218 insertions(+), 8 deletions(-)
>   create mode 100644 kexec/kexec-xen.c
>
> diff --git a/kexec/Makefile b/kexec/Makefile
> index 8a6138d..dc9dab1 100644
> --- a/kexec/Makefile
> +++ b/kexec/Makefile
> @@ -25,6 +25,7 @@ KEXEC_SRCS_base += kexec/phys_arch.c
>   KEXEC_SRCS_base += kexec/kernel_version.c
>   KEXEC_SRCS_base += kexec/lzma.c
>   KEXEC_SRCS_base += kexec/zlib.c
> +KEXEC_SRCS_base += kexec/kexec-xen.c
>   
>   KEXEC_GENERATED_SRCS += $(PURGATORY_HEX_C)
>   
> diff --git a/kexec/arch/i386/crashdump-x86.c b/kexec/arch/i386/crashdump-x86.c
> index 7aa5a12..85f3a87 100644
> --- a/kexec/arch/i386/crashdump-x86.c
> +++ b/kexec/arch/i386/crashdump-x86.c
> @@ -990,8 +990,24 @@ static int crashkernel_mem_callback(void *UNUSED(data), int nr,
>   
>   int is_crashkernel_mem_reserved(void)
>   {
> -	crash_reserved_mem_nr = kexec_iomem_for_each_line("Crash kernel\n",
> -                                       crashkernel_mem_callback, NULL);
> +	int ret;
> +
> +	if (xen_present()) {
> +		uint64_t start, end;
> +
> +		ret = xen_get_crashkernel_region(&start, &end);
> +		if (ret < 0)
> +			return 0;
> +
> +		crash_reserved_mem[0].start = start;
> +		crash_reserved_mem[0].end   = end;
> +		crash_reserved_mem[0].type  = RANGE_RAM;
> +		crash_reserved_mem_nr = 1;
> +	} else {
> +		ret = kexec_iomem_for_each_line("Crash kernel\n",
> +						crashkernel_mem_callback, NULL);
> +		crash_reserved_mem_nr = ret;
> +	}
>   
>   	return !!crash_reserved_mem_nr;
>   }
> diff --git a/kexec/crashdump-xen.c b/kexec/crashdump-xen.c
> index 79b68e0..60594f6 100644
> --- a/kexec/crashdump-xen.c
> +++ b/kexec/crashdump-xen.c
> @@ -252,3 +252,37 @@ int xen_get_note(int cpu, uint64_t *addr, uint64_t *len)
>   
>   	return 0;
>   }
> +
> +#ifdef HAVE_LIBXENCTRL
> +int xen_get_crashkernel_region(uint64_t *start, uint64_t *end)
> +{
> +	uint64_t size;
> +	xc_interface *xc;
> +	int rc = -1;
> +
> +	xc = xc_interface_open(NULL, NULL, 0);
> +	if (!xc) {
> +		fprintf(stderr, "failed to open xen control interface.\n");
> +		goto out;
> +	}
> +
> +	rc = xc_kexec_get_range(xc, KEXEC_RANGE_MA_CRASH, 0, &size, start);
> +	if (rc < 0) {
> +		fprintf(stderr, "failed to get crash region from hypervisor.\n");
> +		goto out_close;
> +	}
> +
> +	*end = *start + size - 1;
> +
> +out_close:
> +	xc_interface_close(xc);
> +
> +out:
> +	return rc;
> +}
> +#else
> +int xen_get_crashkernel_region(uint64_t *start, uint64_t *end)
> +{
> +	return -1;
> +}
> +#endif
> diff --git a/kexec/crashdump.h b/kexec/crashdump.h
> index 0f7c2ea..95f1f0c 100644
> --- a/kexec/crashdump.h
> +++ b/kexec/crashdump.h
> @@ -1,6 +1,7 @@
>   #ifndef CRASHDUMP_H
>   #define CRASHDUMP_H
>   
> +int get_crashkernel_region(uint64_t *start, uint64_t *end);
>   extern int get_crash_notes_per_cpu(int cpu, uint64_t *addr, uint64_t *len);
>   extern int get_kernel_vmcoreinfo(uint64_t *addr, uint64_t *len);
>   extern int get_xen_vmcoreinfo(uint64_t *addr, uint64_t *len);
> @@ -56,9 +57,9 @@ unsigned long crash_architecture(struct crash_elf_info *elf_info);
>   unsigned long phys_to_virt(struct crash_elf_info *elf_info,
>   			   unsigned long paddr);
>   
> -int xen_present(void);
>   unsigned long xen_architecture(struct crash_elf_info *elf_info);
>   int xen_get_nr_phys_cpus(void);
>   int xen_get_note(int cpu, uint64_t *addr, uint64_t *len);
> +int xen_get_crashkernel_region(uint64_t *start, uint64_t *end);
>   
>   #endif /* CRASHDUMP_H */
> diff --git a/kexec/kexec-xen.c b/kexec/kexec-xen.c
> new file mode 100644
> index 0000000..77f65c0
> --- /dev/null
> +++ b/kexec/kexec-xen.c
> @@ -0,0 +1,139 @@
> +#define _GNU_SOURCE
> +#include <stdio.h>
> +#include <string.h>
> +#include <stdlib.h>
> +#include <elf.h>
> +#include "kexec.h"
> +#include "kexec-syscall.h"
> +#include "crashdump.h"
> +
> +#include "config.h"
> +
> +#ifdef HAVE_LIBXENCTRL
> +#include <xenctrl.h>
> +
> +#include "crashdump.h"
> +
> +int xen_kexec_load(struct kexec_info *info)
> +{
> +	uint32_t nr_segments = info->nr_segments;
> +	struct kexec_segment *segments = info->segment;
> +	xc_interface *xch;
> +	xc_hypercall_buffer_array_t *array = NULL;
> +	uint8_t type;
> +	uint8_t arch;
> +	xen_kexec_segment_t *xen_segs;
> +	int s;
> +	int ret = -1;
> +
> +	xch = xc_interface_open(NULL, NULL, 0);
> +	if (!xch)
> +		return -1;
> +
> +	xen_segs = calloc(nr_segments + 1, sizeof(*xen_segs));
> +	if (!xen_segs)
> +		goto out;
> +
> +	array = xc_hypercall_buffer_array_create(xch, nr_segments);
> +	if (array == NULL)
> +		goto out;
> +
> +	for (s = 0; s < nr_segments; s++) {
> +		DECLARE_HYPERCALL_BUFFER(void, seg_buf);
> +
> +		seg_buf = xc_hypercall_buffer_array_alloc(xch, array, s,
> +							  seg_buf, segments[s].bufsz);
> +		if (seg_buf == NULL)
> +			goto out;
> +		memcpy(seg_buf, segments[s].buf, segments[s].bufsz);
> +
> +		set_xen_guest_handle(xen_segs[s].buf.h, seg_buf);
> +		xen_segs[s].buf_size = segments[s].bufsz;
> +		xen_segs[s].dest_maddr = (uint64_t)segments[s].mem;
> +		xen_segs[s].dest_size = segments[s].memsz;
> +	}
> +
> +	/*
> +	 * Ensure 0 - 1 MiB is mapped and accessible by the image.
> +	 *
> +	 * This allows access to the VGA memory and the region
> +	 * purgatory copies in the crash case.
> +	 */
> +	set_xen_guest_handle(xen_segs[s].buf.h, HYPERCALL_BUFFER_NULL);
> +	xen_segs[s].buf_size = 0;
> +	xen_segs[s].dest_maddr = 0;
> +	xen_segs[s].dest_size = 1 * 1024 * 1024;
> +	nr_segments++;
> +
> +	type = (info->kexec_flags & KEXEC_ON_CRASH) ? KEXEC_TYPE_CRASH
> +		: KEXEC_TYPE_DEFAULT;
> +
> +	arch = (info->kexec_flags & KEXEC_ARCH_MASK) >> 16;
> +#if defined(_i386__) || defined(__x86_64__)
> +	if (!arch)
> +		arch = EM_386;
> +#endif
> +
> +	ret = xc_kexec_load(xch, type, arch, (uint64_t)info->entry,
> +			    nr_segments, xen_segs);
> +
> +out:
> +	xc_hypercall_buffer_array_destroy(xch, array);
> +	free(xen_segs);
> +	xc_interface_close(xch);
> +
> +	return ret;
> +}
> +
> +int xen_kexec_unload(uint64_t kexec_flags)
> +{
> +	xc_interface *xch;
> +	uint8_t type;
> +	int ret;
> +
> +	xch = xc_interface_open(NULL, NULL, 0);
> +	if (!xch)
> +		return -1;
> +
> +	type = (kexec_flags & KEXEC_ON_CRASH) ? KEXEC_TYPE_CRASH
> +		: KEXEC_TYPE_DEFAULT;
> +
> +	ret = xc_kexec_unload(xch, type);
> +
> +	xc_interface_close(xch);
> +
> +	return ret;
> +}
> +
> +void xen_kexec_exec(void)
> +{
> +	xc_interface *xch;
> +	
> +	xch = xc_interface_open(NULL, NULL, 0);
> +	if (!xch)
> +		return;
> +
> +	xc_kexec_exec(xch, KEXEC_TYPE_DEFAULT);
> +
> +	xc_interface_close(xch);
> +}
> +
> +#else /* ! HAVE_LIBXENCTRL */
> +
> +int xen_kexec_load(uint64_t entry,
> +		   uint32_t nr_segments, struct kexec_segment *segments,
> +		   uint64_t kexec_flags)
> +{
> +	return -1;
> +}
> +
> +int xen_kexec_unload(uin64_t kexec_flags);
> +{
> +	return -1;
> +}
> +
> +void xen_kexec_exec(void)
> +{
> +}
> +
> +#endif
> diff --git a/kexec/kexec.c b/kexec/kexec.c
> index 2ce570f..9dc3fa4 100644
> --- a/kexec/kexec.c
> +++ b/kexec/kexec.c
> @@ -764,8 +764,12 @@ static int my_load(const char *type, int fileind, int argc, char **argv,
>   	if (kexec_debug)
>   		print_segments(stderr, &info);
>   
> -	result = kexec_load(
> -		info.entry, info.nr_segments, info.segment, info.kexec_flags);
> +	if (xen_present())
> +		result = xen_kexec_load(&info);
> +	else
> +		result = kexec_load(info.entry,
> +				    info.nr_segments, info.segment,
> +				    info.kexec_flags);
>   	if (result != 0) {
>   		/* The load failed, print some debugging information */
>   		fprintf(stderr, "kexec_load failed: %s\n",
> @@ -789,10 +793,13 @@ static int k_unload (unsigned long kexec_flags)
>   	}
>   	kexec_flags |= native_arch;
>   
> -	result = kexec_load(NULL, 0, NULL, kexec_flags);
> +	if (xen_present())
> +		result = xen_kexec_unload(kexec_flags);
> +	else
> +		result = kexec_load(NULL, 0, NULL, kexec_flags);
>   	if (result != 0) {
>   		/* The unload failed, print some debugging information */
> -		fprintf(stderr, "kexec_load (0 segments) failed: %s\n",
> +		fprintf(stderr, "kexec unload failed: %s\n",
>   			strerror(errno));
>   	}
>   	return result;
> @@ -823,7 +830,10 @@ static int my_shutdown(void)
>    */
>   static int my_exec(void)
>   {
> -	reboot(LINUX_REBOOT_CMD_KEXEC);
> +	if (xen_present())
> +		xen_kexec_exec();
> +	else
> +		reboot(LINUX_REBOOT_CMD_KEXEC);
>   	/* I have failed if I make it here */
>   	fprintf(stderr, "kexec failed: %s\n",
>   		strerror(errno));
> @@ -928,6 +938,10 @@ static int kexec_loaded(void)
>   	char *p;
>   	char line[3];
>   
> +	/* No way to tell if an image is loaded under Xen, assume it is. */
> +	if (xen_present())
> +		return 1;
> +
>   	fp = fopen("/sys/kernel/kexec_loaded", "r");
>   	if (fp == NULL)
>   		return -1;
> diff --git a/kexec/kexec.h b/kexec/kexec.h
> index 2904e03..c8be4a5 100644
> --- a/kexec/kexec.h
> +++ b/kexec/kexec.h
> @@ -289,4 +289,9 @@ const char * proc_iomem(void);
>   
>   char *concat_cmdline(const char *base, const char *append);
>   
> +int xen_present(void);
> +int xen_kexec_load(struct kexec_info *info);
> +int xen_kexec_unload(uint64_t kexec_flags);
> +void xen_kexec_exec(void);
> +
>   #endif /* KEXEC_H */




More information about the kexec mailing list