summaryrefslogtreecommitdiff
path: root/kexec/kexec-xen.c
diff options
context:
space:
mode:
authorDavid Vrabel <david.vrabel@citrix.com>2013-11-06 14:55:22 +0000
committerSimon Horman <horms@verge.net.au>2013-11-19 10:20:53 +0900
commitc0b4a3f95dd80256cc6d7084436235e69b4933fb (patch)
tree225478b34f2a0d893fd99afd854495e45a37ba5c /kexec/kexec-xen.c
parentccd6099112f38eab768d1ce481e9fe3000ba7fda (diff)
kexec/xen: directly load images images into Xen
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@citrix.com> Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com> Signed-off-by: Simon Horman <horms@verge.net.au>
Diffstat (limited to 'kexec/kexec-xen.c')
-rw-r--r--kexec/kexec-xen.c139
1 files changed, 139 insertions, 0 deletions
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