summaryrefslogtreecommitdiff
path: root/kexec/kexec-xen.c
diff options
context:
space:
mode:
Diffstat (limited to 'kexec/kexec-xen.c')
-rw-r--r--kexec/kexec-xen.c137
1 files changed, 137 insertions, 0 deletions
diff --git a/kexec/kexec-xen.c b/kexec/kexec-xen.c
new file mode 100644
index 0000000..24a4191
--- /dev/null
+++ b/kexec/kexec-xen.c
@@ -0,0 +1,137 @@
+#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(struct kexec_info *UNUSED(info))
+{
+ return -1;
+}
+
+int xen_kexec_unload(uint64_t kexec_flags)
+{
+ return -1;
+}
+
+void xen_kexec_exec(void)
+{
+}
+
+#endif