aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2018-07-13 16:23:16 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2018-08-15 17:37:29 +0200
commit8fc95fe3fe601e48f719d10ff63e32142e86db05 (patch)
treec23fb65df708dc0377924e72e5e8ded98c92088c
parent8e5e7a09889ada21077936c51ca3b2b17cec9e34 (diff)
downloadlinux-8fc95fe3fe601e48f719d10ff63e32142e86db05.tar.gz
x86/litf: Introduce vmx status variable
commit 72c6d2db64fa18c996ece8f06e499509e6c9a37e upstream. Store the effective mitigation of VMX in a status variable and use it to report the VMX state in the l1tf sysfs file. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Tested-by: Jiri Kosina <jkosina@suse.cz> Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Reviewed-by: Josh Poimboeuf <jpoimboe@redhat.com> Link: https://lkml.kernel.org/r/20180713142322.433098358@linutronix.de Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--arch/x86/include/asm/vmx.h9
-rw-r--r--arch/x86/kernel/cpu/bugs.c36
-rw-r--r--arch/x86/kvm/vmx.c22
3 files changed, 54 insertions, 13 deletions
diff --git a/arch/x86/include/asm/vmx.h b/arch/x86/include/asm/vmx.h
index 6aa8499e1f6204..6439f01d2ff290 100644
--- a/arch/x86/include/asm/vmx.h
+++ b/arch/x86/include/asm/vmx.h
@@ -576,4 +576,13 @@ enum vm_instruction_error_number {
VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID = 28,
};
+enum vmx_l1d_flush_state {
+ VMENTER_L1D_FLUSH_AUTO,
+ VMENTER_L1D_FLUSH_NEVER,
+ VMENTER_L1D_FLUSH_COND,
+ VMENTER_L1D_FLUSH_ALWAYS,
+};
+
+extern enum vmx_l1d_flush_state l1tf_vmx_mitigation;
+
#endif
diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c
index c07a9ee43e9fad..b053382e863f7f 100644
--- a/arch/x86/kernel/cpu/bugs.c
+++ b/arch/x86/kernel/cpu/bugs.c
@@ -22,6 +22,7 @@
#include <asm/processor-flags.h>
#include <asm/fpu/internal.h>
#include <asm/msr.h>
+#include <asm/vmx.h>
#include <asm/paravirt.h>
#include <asm/alternative.h>
#include <asm/pgtable.h>
@@ -636,6 +637,12 @@ void x86_spec_ctrl_setup_ap(void)
#undef pr_fmt
#define pr_fmt(fmt) "L1TF: " fmt
+
+#if IS_ENABLED(CONFIG_KVM_INTEL)
+enum vmx_l1d_flush_state l1tf_vmx_mitigation __ro_after_init = VMENTER_L1D_FLUSH_AUTO;
+EXPORT_SYMBOL_GPL(l1tf_vmx_mitigation);
+#endif
+
static void __init l1tf_select_mitigation(void)
{
u64 half_pa;
@@ -665,6 +672,32 @@ static void __init l1tf_select_mitigation(void)
#ifdef CONFIG_SYSFS
+#define L1TF_DEFAULT_MSG "Mitigation: PTE Inversion"
+
+#if IS_ENABLED(CONFIG_KVM_INTEL)
+static const char *l1tf_vmx_states[] = {
+ [VMENTER_L1D_FLUSH_AUTO] = "auto",
+ [VMENTER_L1D_FLUSH_NEVER] = "vulnerable",
+ [VMENTER_L1D_FLUSH_COND] = "conditional cache flushes",
+ [VMENTER_L1D_FLUSH_ALWAYS] = "cache flushes",
+};
+
+static ssize_t l1tf_show_state(char *buf)
+{
+ if (l1tf_vmx_mitigation == VMENTER_L1D_FLUSH_AUTO)
+ return sprintf(buf, "%s\n", L1TF_DEFAULT_MSG);
+
+ return sprintf(buf, "%s; VMX: SMT %s, L1D %s\n", L1TF_DEFAULT_MSG,
+ cpu_smt_control == CPU_SMT_ENABLED ? "vulnerable" : "disabled",
+ l1tf_vmx_states[l1tf_vmx_mitigation]);
+}
+#else
+static ssize_t l1tf_show_state(char *buf)
+{
+ return sprintf(buf, "%s\n", L1TF_DEFAULT_MSG);
+}
+#endif
+
static ssize_t cpu_show_common(struct device *dev, struct device_attribute *attr,
char *buf, unsigned int bug)
{
@@ -695,9 +728,8 @@ static ssize_t cpu_show_common(struct device *dev, struct device_attribute *attr
case X86_BUG_L1TF:
if (boot_cpu_has(X86_FEATURE_L1TF_PTEINV))
- return sprintf(buf, "Mitigation: Page Table Inversion\n");
+ return l1tf_show_state(buf);
break;
-
default:
break;
}
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index e6f6da2a89b078..05a5b4d637ff93 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -193,19 +193,13 @@ extern const ulong vmx_return;
static DEFINE_STATIC_KEY_FALSE(vmx_l1d_should_flush);
-/* These MUST be in sync with vmentry_l1d_param order. */
-enum vmx_l1d_flush_state {
- VMENTER_L1D_FLUSH_NEVER,
- VMENTER_L1D_FLUSH_COND,
- VMENTER_L1D_FLUSH_ALWAYS,
-};
-
static enum vmx_l1d_flush_state __read_mostly vmentry_l1d_flush = VMENTER_L1D_FLUSH_COND;
static const struct {
const char *option;
enum vmx_l1d_flush_state cmd;
} vmentry_l1d_param[] = {
+ {"auto", VMENTER_L1D_FLUSH_AUTO},
{"never", VMENTER_L1D_FLUSH_NEVER},
{"cond", VMENTER_L1D_FLUSH_COND},
{"always", VMENTER_L1D_FLUSH_ALWAYS},
@@ -13323,8 +13317,12 @@ static int __init vmx_setup_l1d_flush(void)
{
struct page *page;
+ if (!boot_cpu_has_bug(X86_BUG_L1TF))
+ return 0;
+
+ l1tf_vmx_mitigation = vmentry_l1d_flush;
+
if (vmentry_l1d_flush == VMENTER_L1D_FLUSH_NEVER ||
- !boot_cpu_has_bug(X86_BUG_L1TF) ||
vmx_l1d_use_msr_save_list())
return 0;
@@ -13339,12 +13337,14 @@ static int __init vmx_setup_l1d_flush(void)
return 0;
}
-static void vmx_free_l1d_flush_pages(void)
+static void vmx_cleanup_l1d_flush(void)
{
if (vmx_l1d_flush_pages) {
free_pages((unsigned long)vmx_l1d_flush_pages, L1D_CACHE_ORDER);
vmx_l1d_flush_pages = NULL;
}
+ /* Restore state so sysfs ignores VMX */
+ l1tf_vmx_mitigation = VMENTER_L1D_FLUSH_AUTO;
}
static int __init vmx_init(void)
@@ -13387,7 +13387,7 @@ static int __init vmx_init(void)
r = kvm_init(&vmx_x86_ops, sizeof(struct vcpu_vmx),
__alignof__(struct vcpu_vmx), THIS_MODULE);
if (r) {
- vmx_free_l1d_flush_pages();
+ vmx_cleanup_l1d_flush();
return r;
}
@@ -13431,7 +13431,7 @@ static void __exit vmx_exit(void)
static_branch_disable(&enable_evmcs);
}
#endif
- vmx_free_l1d_flush_pages();
+ vmx_cleanup_l1d_flush();
}
module_init(vmx_init)