2008-11-13 17:45:31

by Eduardo Habkost

[permalink] [raw]
Subject: [PATCH 00/11] x86: disable virt on kdump and emergency_restart (v3)

Hi,

This is a new spin of the series to disable vmx on kdump and on
emergency_restart. Now we avoid doing the function pointer stuff by
moving 4 small KVM functions to a header, as inline functions. The code
looks much simpler now, but we have to be more careful because some
additional code will run on kdump and reboot even when KVM is never
loaded.

I haven't tested the SVM changes on AMD CPUs. The changes are really
simple, but some testing is welcome.

This series is against tip.git#master, that already contains the
nmi_shootdown_cpus() changes I've submitted previously.


*Note: With this series, we will run the NMI stuff only when the CPU
where emergency_restart() was called has VMX enabled. This should work
on most cases because KVM enables VMX on all CPUs, but we may miss it if
we get called during the tiny window where KVM is enabling VMX.
Also, I don't know if all code using VMX out there always enable VMX on
all CPUs like KVM does.

We have two other alternatives for that:

a) Have an API that all code that enables VMX on any CPU should use
to tell the kernel core that it is going to enable VMX on the CPUs.
b) Always call nmi_shootdown_cpus() if the CPU supports VMX. This is
a bit intrusive and more risky, as it would unnecessarily run
nmi_shootdown_cpus() on emergency_reboot() even on systems where
virtualization is never enabled.

--
Eduardo


2008-11-13 17:45:58

by Eduardo Habkost

[permalink] [raw]
Subject: [PATCH 05/11] x86: cpu_emergency_vmxoff() function

Add cpu_emergency_vmxoff() and its friends: cpu_vmx_enabled() and
__cpu_emergency_vmxoff().

Signed-off-by: Eduardo Habkost <[email protected]>
---
arch/x86/include/asm/virtext.h | 23 +++++++++++++++++++++++
1 files changed, 23 insertions(+), 0 deletions(-)

diff --git a/arch/x86/include/asm/virtext.h b/arch/x86/include/asm/virtext.h
index 475fb17..2d090f3 100644
--- a/arch/x86/include/asm/virtext.h
+++ b/arch/x86/include/asm/virtext.h
@@ -58,4 +58,27 @@ static inline void cpu_vmxoff(void)
write_cr4(read_cr4() & ~X86_CR4_VMXE);
}

+static inline int cpu_vmx_enabled(void)
+{
+ return read_cr4() & X86_CR4_VMXE;
+}
+
+/** Disable VMX if it is enabled on the current CPU
+ *
+ * You shouldn't call this if cpu_has_vmx() returns 0.
+ */
+static inline void __cpu_emergency_vmxoff(void)
+{
+ if (cpu_vmx_enabled())
+ cpu_vmxoff();
+}
+
+/** Disable VMX if it is supportd and enabled on the current CPU
+ */
+static inline void cpu_emergency_vmxoff(void)
+{
+ if (cpu_has_vmx())
+ __cpu_emergency_vmxoff();
+}
+
#endif /* _ASM_X86_VIRTEX_H */
--
1.5.5.GIT

2008-11-13 17:46:25

by Eduardo Habkost

[permalink] [raw]
Subject: [PATCH 07/11] kvm: svm: move has_svm() code to asm/virtext.h

Use a trick to keep the printk()s on has_svm() working as before. gcc
will take care of not generating code for the 'msg' stuff when the
function is called with a NULL msg argument.

Signed-off-by: Eduardo Habkost <[email protected]>
---
arch/x86/include/asm/virtext.h | 33 +++++++++++++++++++++++++++++++++
arch/x86/kvm/svm.c | 19 +++++--------------
2 files changed, 38 insertions(+), 14 deletions(-)

diff --git a/arch/x86/include/asm/virtext.h b/arch/x86/include/asm/virtext.h
index f6adf9d..e900015 100644
--- a/arch/x86/include/asm/virtext.h
+++ b/arch/x86/include/asm/virtext.h
@@ -95,4 +95,37 @@ static inline void cpu_emergency_vmxoff(void)

#define SVM_VM_CR_SVM_DISABLE 4

+/** Check if the CPU has SVM support
+ *
+ * You can use the 'msg' arg to get a message describing the problem,
+ * if the function returns zero. Simply pass NULL if you are not interested
+ * on the messages; gcc should take care of not generating code for
+ * the messages on this case.
+ */
+static inline int cpu_has_svm(const char **msg)
+{
+ uint32_t eax, ebx, ecx, edx;
+
+ if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD) {
+ if (msg)
+ *msg = "not amd";
+ return 0;
+ }
+
+ cpuid(0x80000000, &eax, &ebx, &ecx, &edx);
+ if (eax < SVM_CPUID_FUNC) {
+ if (msg)
+ *msg = "can't execute cpuid_8000000a";
+ return 0;
+ }
+
+ cpuid(0x80000001, &eax, &ebx, &ecx, &edx);
+ if (!(ecx & (1 << SVM_CPUID_FEATURE_SHIFT))) {
+ if (msg)
+ *msg = "svm not available";
+ return 0;
+ }
+ return 1;
+}
+
#endif /* _ASM_X86_VIRTEX_H */
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 9c4ce65..64241f5 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -28,6 +28,8 @@

#include <asm/desc.h>

+#include <asm/virtext.h>
+
#define __ex(x) __kvm_handle_fault_on_reboot(x)

MODULE_AUTHOR("Qumranet");
@@ -245,24 +247,13 @@ static void skip_emulated_instruction(struct kvm_vcpu *vcpu)

static int has_svm(void)
{
- uint32_t eax, ebx, ecx, edx;
-
- if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD) {
- printk(KERN_INFO "has_svm: not amd\n");
- return 0;
- }
+ const char *msg;

- cpuid(0x80000000, &eax, &ebx, &ecx, &edx);
- if (eax < SVM_CPUID_FUNC) {
- printk(KERN_INFO "has_svm: can't execute cpuid_8000000a\n");
+ if (!cpu_has_svm(&msg)) {
+ printk(KERN_INFO "has_svn: %s\n", msg);
return 0;
}

- cpuid(0x80000001, &eax, &ebx, &ecx, &edx);
- if (!(ecx & (1 << SVM_CPUID_FEATURE_SHIFT))) {
- printk(KERN_DEBUG "has_svm: svm not available\n");
- return 0;
- }
return 1;
}

--
1.5.5.GIT

2008-11-13 17:46:41

by Eduardo Habkost

[permalink] [raw]
Subject: [PATCH 01/11] kvm: vmx: move cpu_has_kvm_support() to an inline on asm/virtext.h

It will be used by core code on kdump and reboot, to disable
vmx if needed.

Signed-off-by: Eduardo Habkost <[email protected]>
---
arch/x86/include/asm/virtext.h | 31 +++++++++++++++++++++++++++++++
arch/x86/kvm/vmx.c | 4 ++--
2 files changed, 33 insertions(+), 2 deletions(-)
create mode 100644 arch/x86/include/asm/virtext.h

diff --git a/arch/x86/include/asm/virtext.h b/arch/x86/include/asm/virtext.h
new file mode 100644
index 0000000..298b6a0
--- /dev/null
+++ b/arch/x86/include/asm/virtext.h
@@ -0,0 +1,31 @@
+/* CPU virtualization extensions handling
+ *
+ * This should carry the code for handling CPU virtualization extensions
+ * that needs to live in the kernel core.
+ *
+ * Author: Eduardo Habkost <[email protected]>
+ *
+ * Copyright (C) 2008, Red Hat Inc.
+ *
+ * Contains code from KVM, Copyright (C) 2006 Qumranet, Inc.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ */
+#ifndef _ASM_X86_VIRTEX_H
+#define _ASM_X86_VIRTEX_H
+
+#include <asm/processor.h>
+#include <asm/system.h>
+
+/*
+ * VMX functions:
+ */
+
+static inline int cpu_has_vmx(void)
+{
+ unsigned long ecx = cpuid_ecx(1);
+ return test_bit(5, &ecx); /* CPUID.1:ECX.VMX[bit 5] -> VT */
+}
+
+#endif /* _ASM_X86_VIRTEX_H */
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index d06b4dc..5cde1e3 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -31,6 +31,7 @@

#include <asm/io.h>
#include <asm/desc.h>
+#include <asm/virtext.h>

#define __ex(x) __kvm_handle_fault_on_reboot(x)

@@ -1032,8 +1033,7 @@ static int vmx_get_irq(struct kvm_vcpu *vcpu)

static __init int cpu_has_kvm_support(void)
{
- unsigned long ecx = cpuid_ecx(1);
- return test_bit(5, &ecx); /* CPUID.1:ECX.VMX[bit 5] -> VT */
+ return cpu_has_vmx();
}

static __init int vmx_disabled_by_bios(void)
--
1.5.5.GIT

2008-11-13 17:46:59

by Eduardo Habkost

[permalink] [raw]
Subject: [PATCH 06/11] kvm: svm: move some SVM_* #defines to asm/virtext.h

Signed-off-by: Eduardo Habkost <[email protected]>
---
arch/x86/include/asm/virtext.h | 14 ++++++++++++++
arch/x86/kvm/svm.h | 12 +++---------
2 files changed, 17 insertions(+), 9 deletions(-)

diff --git a/arch/x86/include/asm/virtext.h b/arch/x86/include/asm/virtext.h
index 2d090f3..f6adf9d 100644
--- a/arch/x86/include/asm/virtext.h
+++ b/arch/x86/include/asm/virtext.h
@@ -81,4 +81,18 @@ static inline void cpu_emergency_vmxoff(void)
__cpu_emergency_vmxoff();
}

+
+/*
+ * SVM functions:
+ */
+
+#define SVM_CPUID_FEATURE_SHIFT 2
+#define SVM_CPUID_FUNC 0x8000000a
+
+#define MSR_EFER_SVME_MASK (1ULL << 12)
+#define MSR_VM_CR 0xc0010114
+#define MSR_VM_HSAVE_PA 0xc0010117ULL
+
+#define SVM_VM_CR_SVM_DISABLE 4
+
#endif /* _ASM_X86_VIRTEX_H */
diff --git a/arch/x86/kvm/svm.h b/arch/x86/kvm/svm.h
index 1b8afa7..4649f5c 100644
--- a/arch/x86/kvm/svm.h
+++ b/arch/x86/kvm/svm.h
@@ -1,6 +1,9 @@
#ifndef __SVM_H
#define __SVM_H

+#include <asm/virtext.h>
+
+
enum {
INTERCEPT_INTR,
INTERCEPT_NMI,
@@ -171,15 +174,6 @@ struct __attribute__ ((__packed__)) vmcb {
struct vmcb_save_area save;
};

-#define SVM_CPUID_FEATURE_SHIFT 2
-#define SVM_CPUID_FUNC 0x8000000a
-
-#define MSR_EFER_SVME_MASK (1ULL << 12)
-#define MSR_VM_CR 0xc0010114
-#define MSR_VM_HSAVE_PA 0xc0010117ULL
-
-#define SVM_VM_CR_SVM_DISABLE 4
-
#define SVM_SELECTOR_S_SHIFT 4
#define SVM_SELECTOR_DPL_SHIFT 5
#define SVM_SELECTOR_P_SHIFT 7
--
1.5.5.GIT

2008-11-13 17:47:24

by Eduardo Habkost

[permalink] [raw]
Subject: [PATCH 04/11] kvm: vmx: extract kvm_cpu_vmxoff() from hardware_disable()

Along with some comments on why it is different from the core cpu_vmxoff()
function.

Signed-off-by: Eduardo Habkost <[email protected]>
---
arch/x86/kvm/vmx.c | 13 +++++++++++--
1 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 5cde1e3..5b15373 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -1079,13 +1079,22 @@ static void vmclear_local_vcpus(void)
__vcpu_clear(vmx);
}

-static void hardware_disable(void *garbage)
+
+/* Just like cpu_vmxoff(), but with the __kvm_handle_fault_on_reboot()
+ * tricks.
+ */
+static void kvm_cpu_vmxoff(void)
{
- vmclear_local_vcpus();
asm volatile (__ex(ASM_VMX_VMXOFF) : : : "cc");
write_cr4(read_cr4() & ~X86_CR4_VMXE);
}

+static void hardware_disable(void *garbage)
+{
+ vmclear_local_vcpus();
+ kvm_cpu_vmxoff();
+}
+
static __init int adjust_vmx_controls(u32 ctl_min, u32 ctl_opt,
u32 msr, u32 *result)
{
--
1.5.5.GIT

2008-11-13 17:47:44

by Eduardo Habkost

[permalink] [raw]
Subject: [PATCH 03/11] x86: asm/virtext.h: add cpu_vmxoff() inline function

Unfortunately we can't use exactly the same code from vmx
hardware_disable(), because the KVM function uses the
__kvm_handle_fault_on_reboot() tricks.

Signed-off-by: Eduardo Habkost <[email protected]>
---
arch/x86/include/asm/virtext.h | 13 +++++++++++++
1 files changed, 13 insertions(+), 0 deletions(-)

diff --git a/arch/x86/include/asm/virtext.h b/arch/x86/include/asm/virtext.h
index 351fa23..475fb17 100644
--- a/arch/x86/include/asm/virtext.h
+++ b/arch/x86/include/asm/virtext.h
@@ -45,4 +45,17 @@ static inline int cpu_has_vmx(void)
return test_bit(5, &ecx); /* CPUID.1:ECX.VMX[bit 5] -> VT */
}

+
+/** Disable VMX on the current CPU
+ *
+ * vmxoff causes a undefined-opcode exception if vmxon was not run
+ * on the CPU previously. Only call this function if you know VMX
+ * is enabled.
+ */
+static inline void cpu_vmxoff(void)
+{
+ asm volatile (ASM_VMX_VMXOFF : : : "cc");
+ write_cr4(read_cr4() & ~X86_CR4_VMXE);
+}
+
#endif /* _ASM_X86_VIRTEX_H */
--
1.5.5.GIT

2008-11-13 17:47:59

by Eduardo Habkost

[permalink] [raw]
Subject: [PATCH 02/11] kvm: vmx: move ASM_VMX_* definitions to asm/virtext.h

Move the definitions so they can be used by non-kvm code.

Signed-off-by: Eduardo Habkost <[email protected]>
---
arch/x86/include/asm/kvm_host.h | 14 ++------------
arch/x86/include/asm/virtext.h | 17 +++++++++++++++++
2 files changed, 19 insertions(+), 12 deletions(-)

diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 8346be8..5920e9a 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -22,6 +22,8 @@
#include <asm/pvclock-abi.h>
#include <asm/desc.h>

+#include <asm/virtext.h>
+
#define KVM_MAX_VCPUS 16
#define KVM_MEMORY_SLOTS 32
/* memory slots that does not exposed to userspace */
@@ -702,18 +704,6 @@ static inline void kvm_inject_gp(struct kvm_vcpu *vcpu, u32 error_code)
kvm_queue_exception_e(vcpu, GP_VECTOR, error_code);
}

-#define ASM_VMX_VMCLEAR_RAX ".byte 0x66, 0x0f, 0xc7, 0x30"
-#define ASM_VMX_VMLAUNCH ".byte 0x0f, 0x01, 0xc2"
-#define ASM_VMX_VMRESUME ".byte 0x0f, 0x01, 0xc3"
-#define ASM_VMX_VMPTRLD_RAX ".byte 0x0f, 0xc7, 0x30"
-#define ASM_VMX_VMREAD_RDX_RAX ".byte 0x0f, 0x78, 0xd0"
-#define ASM_VMX_VMWRITE_RAX_RDX ".byte 0x0f, 0x79, 0xd0"
-#define ASM_VMX_VMWRITE_RSP_RDX ".byte 0x0f, 0x79, 0xd4"
-#define ASM_VMX_VMXOFF ".byte 0x0f, 0x01, 0xc4"
-#define ASM_VMX_VMXON_RAX ".byte 0xf3, 0x0f, 0xc7, 0x30"
-#define ASM_VMX_INVEPT ".byte 0x66, 0x0f, 0x38, 0x80, 0x08"
-#define ASM_VMX_INVVPID ".byte 0x66, 0x0f, 0x38, 0x81, 0x08"
-
#define MSR_IA32_TIME_STAMP_COUNTER 0x010

#define TSS_IOPB_BASE_OFFSET 0x66
diff --git a/arch/x86/include/asm/virtext.h b/arch/x86/include/asm/virtext.h
index 298b6a0..351fa23 100644
--- a/arch/x86/include/asm/virtext.h
+++ b/arch/x86/include/asm/virtext.h
@@ -19,6 +19,23 @@
#include <asm/system.h>

/*
+ * VMX asm instructions:
+ */
+
+#define ASM_VMX_VMCLEAR_RAX ".byte 0x66, 0x0f, 0xc7, 0x30"
+#define ASM_VMX_VMLAUNCH ".byte 0x0f, 0x01, 0xc2"
+#define ASM_VMX_VMRESUME ".byte 0x0f, 0x01, 0xc3"
+#define ASM_VMX_VMPTRLD_RAX ".byte 0x0f, 0xc7, 0x30"
+#define ASM_VMX_VMREAD_RDX_RAX ".byte 0x0f, 0x78, 0xd0"
+#define ASM_VMX_VMWRITE_RAX_RDX ".byte 0x0f, 0x79, 0xd0"
+#define ASM_VMX_VMWRITE_RSP_RDX ".byte 0x0f, 0x79, 0xd4"
+#define ASM_VMX_VMXOFF ".byte 0x0f, 0x01, 0xc4"
+#define ASM_VMX_VMXON_RAX ".byte 0xf3, 0x0f, 0xc7, 0x30"
+#define ASM_VMX_INVEPT ".byte 0x66, 0x0f, 0x38, 0x80, 0x08"
+#define ASM_VMX_INVVPID ".byte 0x66, 0x0f, 0x38, 0x81, 0x08"
+
+
+/*
* VMX functions:
*/

--
1.5.5.GIT

2008-11-13 17:48:29

by Eduardo Habkost

[permalink] [raw]
Subject: [PATCH 11/11] x86: disable VMX on all CPUs on reboot

On emergency_restart, we may need to use an NMI to disable virtualization
on all CPUs. We do that using nmi_shootdown_cpus() if VMX is enabled.

Finding a proper point to hook the nmi_shootdown_cpus() call isn't
trivial, as the non-emergency machine_restart() (that doesn't need the
NMI tricks) uses machine_emergency_restart() directly.

The solution to make this work without adding a new function or argument
to machine_ops was setting a 'reboot_emergency' flag that tells if
native_machine_emergency_restart() needs to do the virt cleanup or not.

Signed-off-by: Eduardo Habkost <[email protected]>
---
arch/x86/kernel/reboot.c | 63 ++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 61 insertions(+), 2 deletions(-)

diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c
index 6f05a28..a5f8c09 100644
--- a/arch/x86/kernel/reboot.c
+++ b/arch/x86/kernel/reboot.c
@@ -12,6 +12,7 @@
#include <asm/proto.h>
#include <asm/reboot_fixups.h>
#include <asm/reboot.h>
+#include <asm/virtext.h>

#ifdef CONFIG_X86_32
# include <linux/dmi.h>
@@ -39,6 +40,13 @@ int reboot_force;
static int reboot_cpu = -1;
#endif

+/* This is set if we need to go through the 'emergency' path.
+ * When machine_emergency_restart() is called, we may be on
+ * an inconsistent state and won't be able to do a clean cleanup
+ */
+static int reboot_emergency;
+
+
/* This is set by the PCI code if either type 1 or type 2 PCI is detected */
bool port_cf9_safe = false;

@@ -359,6 +367,48 @@ static inline void kb_wait(void)
}
}

+static void vmxoff_nmi(int cpu, struct die_args *args)
+{
+ cpu_emergency_vmxoff();
+}
+
+/* Use NMIs as IPIs to tell all CPUs to disable virtualization
+ */
+static void emergency_vmx_disable_all(void)
+{
+ /* Just make sure we won't change CPUs while doing this */
+ local_irq_disable();
+
+ /* We need to disable VMX on all CPUs before rebooting, otherwise
+ * we risk hanging up the machine, because the CPU ignore INIT
+ * signals when VMX is enabled.
+ *
+ * We can't take any locks and we may be on an inconsistent
+ * state, so we use NMIs as IPIs to tell the other CPUs to disable
+ * VMX and halt.
+ *
+ * For safety, we will avoid running the nmi_shootdown_cpus()
+ * stuff unnecessarily, but we don't have a way to check
+ * if other CPUs have VMX enabled. So we will call it only if the
+ * CPU we are running on has VMX enabled.
+ *
+ * We will miss cases where VMX is not enabled on all CPUs. This
+ * shouldn't do much harm because KVM always enable VMX on all
+ * CPUs anyway. But we can miss it on the small window where KVM
+ * is still enabling VMX.
+ */
+ if (cpu_has_vmx() && cpu_vmx_enabled()) {
+ /* Disable VMX on this CPU.
+ */
+ cpu_vmxoff();
+
+ /* Halt and disable VMX on the other CPUs */
+ nmi_shootdown_cpus(vmxoff_nmi);
+
+ }
+}
+
+
void __attribute__((weak)) mach_reboot_fixups(void)
{
}
@@ -367,6 +417,9 @@ static void native_machine_emergency_restart(void)
{
int i;

+ if (reboot_emergency)
+ emergency_vmx_disable_all();
+
/* Tell the BIOS if we want cold or warm reboot */
*((unsigned short *)__va(0x472)) = reboot_mode;

@@ -473,13 +526,19 @@ void native_machine_shutdown(void)
#endif
}

+static void __machine_emergency_restart(int emergency)
+{
+ reboot_emergency = emergency;
+ machine_ops.emergency_restart();
+}
+
static void native_machine_restart(char *__unused)
{
printk("machine restart\n");

if (!reboot_force)
machine_shutdown();
- machine_emergency_restart();
+ __machine_emergency_restart(0);
}

static void native_machine_halt(void)
@@ -523,7 +582,7 @@ void machine_shutdown(void)

void machine_emergency_restart(void)
{
- machine_ops.emergency_restart();
+ __machine_emergency_restart(1);
}

void machine_restart(char *cmd)
--
1.5.5.GIT

2008-11-13 17:48:48

by Eduardo Habkost

[permalink] [raw]
Subject: [PATCH 08/11] kvm: svm: move svm_hardware_disable() code to asm/virtext.h

Create cpu_svm_disable() function.

Signed-off-by: Eduardo Habkost <[email protected]>
---
arch/x86/include/asm/virtext.h | 14 ++++++++++++++
arch/x86/kvm/svm.c | 6 +-----
2 files changed, 15 insertions(+), 5 deletions(-)

diff --git a/arch/x86/include/asm/virtext.h b/arch/x86/include/asm/virtext.h
index e900015..7281e10 100644
--- a/arch/x86/include/asm/virtext.h
+++ b/arch/x86/include/asm/virtext.h
@@ -128,4 +128,18 @@ static inline int cpu_has_svm(const char **msg)
return 1;
}

+
+/** Disable SVM on the current CPU
+ *
+ * You should call this only if cpu_has_svm() returned true.
+ */
+static inline void cpu_svm_disable(void)
+{
+ uint64_t efer;
+
+ wrmsrl(MSR_VM_HSAVE_PA, 0);
+ rdmsrl(MSR_EFER, efer);
+ wrmsrl(MSR_EFER, efer & ~MSR_EFER_SVME_MASK);
+}
+
#endif /* _ASM_X86_VIRTEX_H */
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 64241f5..7ded2ee 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -259,11 +259,7 @@ static int has_svm(void)

static void svm_hardware_disable(void *garbage)
{
- uint64_t efer;
-
- wrmsrl(MSR_VM_HSAVE_PA, 0);
- rdmsrl(MSR_EFER, efer);
- wrmsrl(MSR_EFER, efer & ~MSR_EFER_SVME_MASK);
+ cpu_svm_disable();
}

static void svm_hardware_enable(void *garbage)
--
1.5.5.GIT

2008-11-13 17:49:19

by Eduardo Habkost

[permalink] [raw]
Subject: [PATCH 09/11] x86: asm/virtext.h: create cpu_emergency_svm_disable()

This function can be used by the reboot or kdump code to forcibly
disable SVM on the CPU.

Signed-off-by: Eduardo Habkost <[email protected]>
---
arch/x86/include/asm/virtext.h | 8 ++++++++
1 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/arch/x86/include/asm/virtext.h b/arch/x86/include/asm/virtext.h
index 7281e10..e4f6bb0 100644
--- a/arch/x86/include/asm/virtext.h
+++ b/arch/x86/include/asm/virtext.h
@@ -142,4 +142,12 @@ static inline void cpu_svm_disable(void)
wrmsrl(MSR_EFER, efer & ~MSR_EFER_SVME_MASK);
}

+/** Makes sure SVM is disabled, if it is supported on the CPU
+ */
+static inline void cpu_emergency_svm_disable(void)
+{
+ if (cpu_has_svm(NULL))
+ cpu_svm_disable();
+}
+
#endif /* _ASM_X86_VIRTEX_H */
--
1.5.5.GIT

2008-11-13 17:49:38

by Eduardo Habkost

[permalink] [raw]
Subject: [PATCH 10/11] kdump: forcibly disable VMX and SVM on machine_crash_shutdown()

We need to disable virtualization extensions on all CPUs before booting
the kdump kernel, otherwise the kdump kernel booting will fail, and
rebooting after the kdump kernel did its task may also fail.

We do it using cpu_emergency_vmxoff() and cpu_emergency_svm_disable(),
that should always work, because those functions check if the CPUs
support SVM or VMX before doing their tasks.

Signed-off-by: Eduardo Habkost <[email protected]>
---
arch/x86/kernel/crash.c | 18 ++++++++++++++++++
1 files changed, 18 insertions(+), 0 deletions(-)

diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c
index d84a852..c689d19 100644
--- a/arch/x86/kernel/crash.c
+++ b/arch/x86/kernel/crash.c
@@ -26,6 +26,7 @@
#include <linux/kdebug.h>
#include <asm/smp.h>
#include <asm/reboot.h>
+#include <asm/virtext.h>

#include <mach_ipi.h>

@@ -49,6 +50,15 @@ static void kdump_nmi_callback(int cpu, struct die_args *args)
#endif
crash_save_cpu(regs, cpu);

+ /* Disable VMX or SVM if needed.
+ *
+ * We need to disable virtualization on all CPUs.
+ * Having VMX or SVM enabled on any CPU may break rebooting
+ * after the kdump kernel has finished its task.
+ */
+ cpu_emergency_vmxoff();
+ cpu_emergency_svm_disable();
+
disable_local_APIC();
}

@@ -80,6 +90,14 @@ void native_machine_crash_shutdown(struct pt_regs *regs)
local_irq_disable();

kdump_nmi_shootdown_cpus();
+
+ /* Booting kdump kernel with VMX or SVM enabled won't work,
+ * because (among other limitations) we can't disable paging
+ * with the virt flags.
+ */
+ cpu_emergency_vmxoff();
+ cpu_emergency_svm_disable();
+
lapic_shutdown();
#if defined(CONFIG_X86_IO_APIC)
disable_IO_APIC();
--
1.5.5.GIT

2008-11-16 07:59:04

by Avi Kivity

[permalink] [raw]
Subject: Re: [PATCH 00/11] x86: disable virt on kdump and emergency_restart (v3)

Eduardo Habkost wrote:
> Hi,
>
> This is a new spin of the series to disable vmx on kdump and on
> emergency_restart. Now we avoid doing the function pointer stuff by
> moving 4 small KVM functions to a header, as inline functions. The code
> looks much simpler now, but we have to be more careful because some
> additional code will run on kdump and reboot even when KVM is never
> loaded.
>
> I haven't tested the SVM changes on AMD CPUs. The changes are really
> simple, but some testing is welcome.
>
> This series is against tip.git#master, that already contains the
> nmi_shootdown_cpus() changes I've submitted previously.
>
>
>

Looks good. I am slightly uneasy about moving things away from vmx.h
and svm.h; can we keep them there and #include those headers directly?

--
error compiling committee.c: too many arguments to function

2008-11-17 15:06:22

by Eduardo Habkost

[permalink] [raw]
Subject: Re: [PATCH 00/11] x86: disable virt on kdump and emergency_restart (v3)

On Sun, Nov 16, 2008 at 09:57:55AM +0200, Avi Kivity wrote:
> Eduardo Habkost wrote:
>> Hi,
>>
>> This is a new spin of the series to disable vmx on kdump and on
>> emergency_restart. Now we avoid doing the function pointer stuff by
>> moving 4 small KVM functions to a header, as inline functions. The code
>> looks much simpler now, but we have to be more careful because some
>> additional code will run on kdump and reboot even when KVM is never
>> loaded.
>>
>> I haven't tested the SVM changes on AMD CPUs. The changes are really
>> simple, but some testing is welcome.
>>
>> This series is against tip.git#master, that already contains the
>> nmi_shootdown_cpus() changes I've submitted previously.
>>
>>
>>
>
> Looks good. I am slightly uneasy about moving things away from vmx.h
> and svm.h; can we keep them there and #include those headers directly?

I see them as bits of code that are being moved from KVM to the kernel
core. I think moving those bits outside arch/x86/kvm/ makes this more
clear: people can expect that code living in arch/x86/kvm/ is never
used if CONFIG_KVM was not set.

Because of their location, I thought svm.h and vmx.h had KVM-specific
code. Now I've noticed they are independent from KVM. May I move svm.h
and vmx.h to arch/x86/include/asm, then?

--
Eduardo

2008-11-17 15:13:15

by Avi Kivity

[permalink] [raw]
Subject: Re: [PATCH 00/11] x86: disable virt on kdump and emergency_restart (v3)

Eduardo Habkost wrote:
> Because of their location, I thought svm.h and vmx.h had KVM-specific
> code. Now I've noticed they are independent from KVM. May I move svm.h
> and vmx.h to arch/x86/include/asm, then?
>

Indeed the intent was to have these as hardware descriptions rather than
bits of code. So moving them to include/asm makes sense.

--
error compiling committee.c: too many arguments to function