diff options
author | Olaf Hering <olaf@aepfle.de> | 2011-08-03 20:07:05 +0200 |
---|---|---|
committer | Simon Horman <horms@verge.net.au> | 2011-08-04 08:34:41 +0900 |
commit | 1d920c284bf899a52ab458d40295e28f16a2b202 (patch) | |
tree | 9c143be631b4bc2866dfaf1b86a405216df35394 /kexec/crashdump-xen.c | |
parent | e8b7939b1e7249aecbbe45b47c7a2a6169681072 (diff) | |
download | kexec-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.c | 86 |
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; } |