summaryrefslogtreecommitdiff
path: root/kexec/crashdump-xen.c
diff options
context:
space:
mode:
authorOlaf Hering <olaf@aepfle.de>2011-08-03 20:07:05 +0200
committerSimon Horman <horms@verge.net.au>2011-08-04 08:34:41 +0900
commit1d920c284bf899a52ab458d40295e28f16a2b202 (patch)
tree9c143be631b4bc2866dfaf1b86a405216df35394 /kexec/crashdump-xen.c
parente8b7939b1e7249aecbbe45b47c7a2a6169681072 (diff)
downloadkexec-tools-1d920c284bf899a52ab458d40295e28f16a2b202.tar.gz
fix Xen detection for xenfs in pv_ops kernel
The pv_ops kernel in mainline Linux provides xenfs which has to be mounted at /proc/xen. It creates /proc/xen/capabilities unconditionally which makes it impossible to distinguish PVonHVM guests from PV guests. Use code from xen-detect.c to check wether kexec runs on a PV guest. Without this change PVonHVM guests will be detected incorrectly as plain PV guests. Signed-off-by: Olaf Hering <olaf@aepfle.de> Signed-off-by: Simon Horman <horms@verge.net.au>
Diffstat (limited to 'kexec/crashdump-xen.c')
-rw-r--r--kexec/crashdump-xen.c86
1 files changed, 84 insertions, 2 deletions
diff --git a/kexec/crashdump-xen.c b/kexec/crashdump-xen.c
index 44e5dfc..b347764 100644
--- a/kexec/crashdump-xen.c
+++ b/kexec/crashdump-xen.c
@@ -10,6 +10,8 @@
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
+#include <setjmp.h>
+#include <signal.h>
#include "kexec.h"
#include "crashdump.h"
#include "kexec-syscall.h"
@@ -27,13 +29,93 @@ struct crash_note_info {
static int xen_phys_cpus;
static struct crash_note_info *xen_phys_notes;
+
+/* based on code from xen-detect.c */
static int is_dom0;
+#if defined(__i386__) || defined(__x86_64__)
+static jmp_buf xen_sigill_jmp;
+void xen_sigill_handler(int sig)
+{
+ longjmp(xen_sigill_jmp, 1);
+}
+
+static void xen_cpuid(uint32_t idx, uint32_t *regs, int pv_context)
+{
+ asm volatile (
+#ifdef __i386__
+#define R(x) "%%e"#x"x"
+#else
+#define R(x) "%%r"#x"x"
+#endif
+ "push "R(a)"; push "R(b)"; push "R(c)"; push "R(d)"\n\t"
+ "test %1,%1 ; jz 1f ; ud2a ; .ascii \"xen\" ; 1: cpuid\n\t"
+ "mov %%eax,(%2); mov %%ebx,4(%2)\n\t"
+ "mov %%ecx,8(%2); mov %%edx,12(%2)\n\t"
+ "pop "R(d)"; pop "R(c)"; pop "R(b)"; pop "R(a)"\n\t"
+ : : "a" (idx), "c" (pv_context), "S" (regs) : "memory" );
+}
+
+static int check_for_xen(int pv_context)
+{
+ uint32_t regs[4];
+ char signature[13];
+ uint32_t base;
+
+ for (base = 0x40000000; base < 0x40010000; base += 0x100)
+ {
+ xen_cpuid(base, regs, pv_context);
+
+ *(uint32_t *)(signature + 0) = regs[1];
+ *(uint32_t *)(signature + 4) = regs[2];
+ *(uint32_t *)(signature + 8) = regs[3];
+ signature[12] = '\0';
+
+ if (strcmp("XenVMMXenVMM", signature) == 0 && regs[0] >= (base + 2))
+ goto found;
+ }
+
+ return 0;
+
+found:
+ xen_cpuid(base + 1, regs, pv_context);
+ return regs[0];
+}
+
+static int xen_detect_pv_guest(void)
+{
+ struct sigaction act, oldact;
+ int is_pv = -1;
+
+ if (setjmp(xen_sigill_jmp))
+ return is_pv;
+
+ memset(&act, 0, sizeof(act));
+ act.sa_handler = xen_sigill_handler;
+ sigemptyset (&act.sa_mask);
+ if (sigaction(SIGILL, &act, &oldact))
+ return is_pv;
+ if (check_for_xen(1))
+ is_pv = 1;
+ sigaction(SIGILL, &oldact, NULL);
+ return is_pv;
+}
+#else
+static int xen_detect_pv_guest(void)
+{
+ return 1;
+}
+#endif
+/*
+ * Return 1 if its a PV guest.
+ * This includes dom0, which is the only PV guest where kexec/kdump works.
+ * HVM guests have to be handled as native hardware.
+ */
int xen_present(void)
{
if (!is_dom0) {
- if (access("/proc/xen/capabilities", F_OK) == 0)
- is_dom0 = 1;
+ if (access("/proc/xen", F_OK) == 0)
+ is_dom0 = xen_detect_pv_guest();
else
is_dom0 = -1;
}