[PATCH 7/9] libxc: add API for kexec hypercall
Don Slutz
dslutz at verizon.com
Thu Nov 7 15:48:06 EST 2013
For what it is worth.
Reviewed-by: Don Slutz <dslutz at verizon.com>
-Don Slutz
On 11/06/13 09:49, David Vrabel wrote:
> From: David Vrabel <david.vrabel at citrix.com>
>
> Add xc_kexec_exec(), xc_kexec_get_ranges(), xc_kexec_load(), and
> xc_kexec_unload(). The load and unload calls require the v2 load and
> unload ops.
>
> Signed-off-by: David Vrabel <david.vrabel at citrix.com>
> Acked-by: Ian Campbell <ian.campbell at citrix.com>
> Reviewed-by: Daniel Kiper <daniel.kiper at oracle.com>
> Tested-by: Daniel Kiper <daniel.kiper at oracle.com>
> Reviewed-by: Andrew Cooper <andrew.cooper3 at citrix.com>
> ---
> tools/libxc/Makefile | 1 +
> tools/libxc/xc_kexec.c | 140 ++++++++++++++++++++++++++++++++++++++++++++++++
> tools/libxc/xenctrl.h | 55 +++++++++++++++++++
> 3 files changed, 196 insertions(+), 0 deletions(-)
> create mode 100644 tools/libxc/xc_kexec.c
>
> diff --git a/tools/libxc/Makefile b/tools/libxc/Makefile
> index 4c64c15..f2d6e56 100644
> --- a/tools/libxc/Makefile
> +++ b/tools/libxc/Makefile
> @@ -31,6 +31,7 @@ CTRL_SRCS-y += xc_mem_access.c
> CTRL_SRCS-y += xc_memshr.c
> CTRL_SRCS-y += xc_hcall_buf.c
> CTRL_SRCS-y += xc_foreign_memory.c
> +CTRL_SRCS-y += xc_kexec.c
> CTRL_SRCS-y += xtl_core.c
> CTRL_SRCS-y += xtl_logger_stdio.c
> CTRL_SRCS-$(CONFIG_X86) += xc_pagetab.c
> diff --git a/tools/libxc/xc_kexec.c b/tools/libxc/xc_kexec.c
> new file mode 100644
> index 0000000..a49cffb
> --- /dev/null
> +++ b/tools/libxc/xc_kexec.c
> @@ -0,0 +1,140 @@
> +/******************************************************************************
> + * xc_kexec.c
> + *
> + * API for loading and executing kexec images.
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation;
> + * version 2.1 of the License.
> + *
> + * Copyright (C) 2013 Citrix Systems R&D Ltd.
> + */
> +#include "xc_private.h"
> +
> +int xc_kexec_exec(xc_interface *xch, int type)
> +{
> + DECLARE_HYPERCALL;
> + DECLARE_HYPERCALL_BUFFER(xen_kexec_exec_t, exec);
> + int ret = -1;
> +
> + exec = xc_hypercall_buffer_alloc(xch, exec, sizeof(*exec));
> + if ( exec == NULL )
> + {
> + PERROR("Count not alloc bounce buffer for kexec_exec hypercall");
> + goto out;
> + }
> +
> + exec->type = type;
> +
> + hypercall.op = __HYPERVISOR_kexec_op;
> + hypercall.arg[0] = KEXEC_CMD_kexec;
> + hypercall.arg[1] = HYPERCALL_BUFFER_AS_ARG(exec);
> +
> + ret = do_xen_hypercall(xch, &hypercall);
> +
> +out:
> + xc_hypercall_buffer_free(xch, exec);
> +
> + return ret;
> +}
> +
> +int xc_kexec_get_range(xc_interface *xch, int range, int nr,
> + uint64_t *size, uint64_t *start)
> +{
> + DECLARE_HYPERCALL;
> + DECLARE_HYPERCALL_BUFFER(xen_kexec_range_t, get_range);
> + int ret = -1;
> +
> + get_range = xc_hypercall_buffer_alloc(xch, get_range, sizeof(*get_range));
> + if ( get_range == NULL )
> + {
> + PERROR("Could not alloc bounce buffer for kexec_get_range hypercall");
> + goto out;
> + }
> +
> + get_range->range = range;
> + get_range->nr = nr;
> +
> + hypercall.op = __HYPERVISOR_kexec_op;
> + hypercall.arg[0] = KEXEC_CMD_kexec_get_range;
> + hypercall.arg[1] = HYPERCALL_BUFFER_AS_ARG(get_range);
> +
> + ret = do_xen_hypercall(xch, &hypercall);
> +
> + *size = get_range->size;
> + *start = get_range->start;
> +
> +out:
> + xc_hypercall_buffer_free(xch, get_range);
> +
> + return ret;
> +}
> +
> +int xc_kexec_load(xc_interface *xch, uint8_t type, uint16_t arch,
> + uint64_t entry_maddr,
> + uint32_t nr_segments, xen_kexec_segment_t *segments)
> +{
> + int ret = -1;
> + DECLARE_HYPERCALL;
> + DECLARE_HYPERCALL_BOUNCE(segments, sizeof(*segments) * nr_segments,
> + XC_HYPERCALL_BUFFER_BOUNCE_IN);
> + DECLARE_HYPERCALL_BUFFER(xen_kexec_load_t, load);
> +
> + if ( xc_hypercall_bounce_pre(xch, segments) )
> + {
> + PERROR("Could not allocate bounce buffer for kexec load hypercall");
> + goto out;
> + }
> + load = xc_hypercall_buffer_alloc(xch, load, sizeof(*load));
> + if ( load == NULL )
> + {
> + PERROR("Could not allocate buffer for kexec load hypercall");
> + goto out;
> + }
> +
> + load->type = type;
> + load->arch = arch;
> + load->entry_maddr = entry_maddr;
> + load->nr_segments = nr_segments;
> + set_xen_guest_handle(load->segments.h, segments);
> +
> + hypercall.op = __HYPERVISOR_kexec_op;
> + hypercall.arg[0] = KEXEC_CMD_kexec_load;
> + hypercall.arg[1] = HYPERCALL_BUFFER_AS_ARG(load);
> +
> + ret = do_xen_hypercall(xch, &hypercall);
> +
> +out:
> + xc_hypercall_buffer_free(xch, load);
> + xc_hypercall_bounce_post(xch, segments);
> +
> + return ret;
> +}
> +
> +int xc_kexec_unload(xc_interface *xch, int type)
> +{
> + DECLARE_HYPERCALL;
> + DECLARE_HYPERCALL_BUFFER(xen_kexec_unload_t, unload);
> + int ret = -1;
> +
> + unload = xc_hypercall_buffer_alloc(xch, unload, sizeof(*unload));
> + if ( unload == NULL )
> + {
> + PERROR("Count not alloc buffer for kexec unload hypercall");
> + goto out;
> + }
> +
> + unload->type = type;
> +
> + hypercall.op = __HYPERVISOR_kexec_op;
> + hypercall.arg[0] = KEXEC_CMD_kexec_unload;
> + hypercall.arg[1] = HYPERCALL_BUFFER_AS_ARG(unload);
> +
> + ret = do_xen_hypercall(xch, &hypercall);
> +
> +out:
> + xc_hypercall_buffer_free(xch, unload);
> +
> + return ret;
> +}
> diff --git a/tools/libxc/xenctrl.h b/tools/libxc/xenctrl.h
> index a7e8c31..4ac6b8a 100644
> --- a/tools/libxc/xenctrl.h
> +++ b/tools/libxc/xenctrl.h
> @@ -46,6 +46,7 @@
> #include <xen/hvm/params.h>
> #include <xen/xsm/flask_op.h>
> #include <xen/tmem.h>
> +#include <xen/kexec.h>
>
> #include "xentoollog.h"
>
> @@ -2340,4 +2341,58 @@ int xc_compression_uncompress_page(xc_interface *xch, char *compbuf,
> unsigned long compbuf_size,
> unsigned long *compbuf_pos, char *dest);
>
> +/*
> + * Execute an image previously loaded with xc_kexec_load().
> + *
> + * Does not return on success.
> + *
> + * Fails with:
> + * ENOENT if the specified image has not been loaded.
> + */
> +int xc_kexec_exec(xc_interface *xch, int type);
> +
> +/*
> + * Find the machine address and size of certain memory areas.
> + *
> + * KEXEC_RANGE_MA_CRASH crash area
> + * KEXEC_RANGE_MA_XEN Xen itself
> + * KEXEC_RANGE_MA_CPU CPU note for CPU number 'nr'
> + * KEXEC_RANGE_MA_XENHEAP xenheap
> + * KEXEC_RANGE_MA_EFI_MEMMAP EFI Memory Map
> + * KEXEC_RANGE_MA_VMCOREINFO vmcoreinfo
> + *
> + * Fails with:
> + * EINVAL if the range or CPU number isn't valid.
> + */
> +int xc_kexec_get_range(xc_interface *xch, int range, int nr,
> + uint64_t *size, uint64_t *start);
> +
> +/*
> + * Load a kexec image into memory.
> + *
> + * The image may be of type KEXEC_TYPE_DEFAULT (executed on request)
> + * or KEXEC_TYPE_CRASH (executed on a crash).
> + *
> + * The image architecture may be a 32-bit variant of the hypervisor
> + * architecture (e.g, EM_386 on a x86-64 hypervisor).
> + *
> + * Fails with:
> + * ENOMEM if there is insufficient memory for the new image.
> + * EINVAL if the image does not fit into the crash area or the entry
> + * point isn't within one of segments.
> + * EBUSY if another image is being executed.
> + */
> +int xc_kexec_load(xc_interface *xch, uint8_t type, uint16_t arch,
> + uint64_t entry_maddr,
> + uint32_t nr_segments, xen_kexec_segment_t *segments);
> +
> +/*
> + * Unload a kexec image.
> + *
> + * This prevents a KEXEC_TYPE_DEFAULT or KEXEC_TYPE_CRASH image from
> + * being executed. The crash images are not cleared from the crash
> + * region.
> + */
> +int xc_kexec_unload(xc_interface *xch, int type);
> +
> #endif /* XENCTRL_H */
More information about the kexec
mailing list