mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 10:11:27 +01:00
The tools that use kexec are asynchronous in nature and do not keep state changes. As such provide an hypercall to find out whether an image has been loaded for either type. Note: No need to modify XSM as it has one size fits all check and does not check for subcommands. Note: No need to check KEXEC_FLAG_IN_PROGRESS (and error out of kexec_status()) as this flag is set only once by the first/only cpu on the crash path. Note: This is just the Xen side of the hypercall, kexec-tools patch to come separately. Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> Signed-off-by: Eric DeVolder <eric.devolder@oracle.com> Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com> Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> Acked-by: Wei Liu <wei.liu2@citrix.com>
153 lines
4.0 KiB
C
153 lines
4.0 KiB
C
/******************************************************************************
|
|
* 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_BUFFER(xen_kexec_exec_t, exec);
|
|
int ret = -1;
|
|
|
|
exec = xc_hypercall_buffer_alloc(xch, exec, sizeof(*exec));
|
|
if ( exec == NULL )
|
|
{
|
|
PERROR("Could not alloc bounce buffer for kexec_exec hypercall");
|
|
goto out;
|
|
}
|
|
|
|
exec->type = type;
|
|
|
|
ret = xencall2(xch->xcall, __HYPERVISOR_kexec_op,
|
|
KEXEC_CMD_kexec,
|
|
HYPERCALL_BUFFER_AS_ARG(exec));
|
|
|
|
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_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;
|
|
|
|
ret = xencall2(xch->xcall, __HYPERVISOR_kexec_op,
|
|
KEXEC_CMD_kexec_get_range,
|
|
HYPERCALL_BUFFER_AS_ARG(get_range));
|
|
|
|
*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_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);
|
|
|
|
ret = xencall2(xch->xcall, __HYPERVISOR_kexec_op,
|
|
KEXEC_CMD_kexec_load,
|
|
HYPERCALL_BUFFER_AS_ARG(load));
|
|
|
|
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_BUFFER(xen_kexec_unload_t, unload);
|
|
int ret = -1;
|
|
|
|
unload = xc_hypercall_buffer_alloc(xch, unload, sizeof(*unload));
|
|
if ( unload == NULL )
|
|
{
|
|
PERROR("Could not alloc buffer for kexec unload hypercall");
|
|
goto out;
|
|
}
|
|
|
|
unload->type = type;
|
|
|
|
ret = xencall2(xch->xcall, __HYPERVISOR_kexec_op,
|
|
KEXEC_CMD_kexec_unload,
|
|
HYPERCALL_BUFFER_AS_ARG(unload));
|
|
|
|
out:
|
|
xc_hypercall_buffer_free(xch, unload);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int xc_kexec_status(xc_interface *xch, int type)
|
|
{
|
|
DECLARE_HYPERCALL_BUFFER(xen_kexec_status_t, status);
|
|
int ret = -1;
|
|
|
|
status = xc_hypercall_buffer_alloc(xch, status, sizeof(*status));
|
|
if ( status == NULL )
|
|
{
|
|
PERROR("Could not alloc buffer for kexec status hypercall");
|
|
goto out;
|
|
}
|
|
|
|
status->type = type;
|
|
|
|
ret = xencall2(xch->xcall, __HYPERVISOR_kexec_op,
|
|
KEXEC_CMD_kexec_status,
|
|
HYPERCALL_BUFFER_AS_ARG(status));
|
|
|
|
out:
|
|
xc_hypercall_buffer_free(xch, status);
|
|
|
|
return ret;
|
|
}
|