This is a note to let you know that I've just added the patch titled intel_idle: Disable IBRS during long idle to the 5.4-stable tree which can be found at: http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary The filename of the patch is: intel_idle-disable-ibrs-during-long-idle.patch and it can be found in the queue-5.4 subdirectory. If you, or anyone else, feels it should not be added to the stable tree, please let <stable@xxxxxxxxxxxxxxx> know about it. >From foo@baz Wed Oct 5 12:28:43 PM CEST 2022 From: Thadeu Lima de Souza Cascardo <cascardo@xxxxxxxxxxxxx> Date: Mon, 3 Oct 2022 10:10:18 -0300 Subject: intel_idle: Disable IBRS during long idle To: stable@xxxxxxxxxxxxxxx Cc: x86@xxxxxxxxxx, kvm@xxxxxxxxxxxxxxx, bp@xxxxxxxxx, pbonzini@xxxxxxxxxx, peterz@xxxxxxxxxxxxx, jpoimboe@xxxxxxxxxx Message-ID: <20221003131038.12645-18-cascardo@xxxxxxxxxxxxx> From: Peter Zijlstra <peterz@xxxxxxxxxxxxx> commit bf5835bcdb9635c97f85120dba9bfa21e111130f upstream. Having IBRS enabled while the SMT sibling is idle unnecessarily slows down the running sibling. OTOH, disabling IBRS around idle takes two MSR writes, which will increase the idle latency. Therefore, only disable IBRS around deeper idle states. Shallow idle states are bounded by the tick in duration, since NOHZ is not allowed for them by virtue of their short target residency. Only do this for mwait-driven idle, since that keeps interrupts disabled across idle, which makes disabling IBRS vs IRQ-entry a non-issue. Note: C6 is a random threshold, most importantly C1 probably shouldn't disable IBRS, benchmarking needed. Suggested-by: Tim Chen <tim.c.chen@xxxxxxxxxxxxxxx> Signed-off-by: Peter Zijlstra (Intel) <peterz@xxxxxxxxxxxxx> Signed-off-by: Borislav Petkov <bp@xxxxxxx> Reviewed-by: Josh Poimboeuf <jpoimboe@xxxxxxxxxx> Signed-off-by: Borislav Petkov <bp@xxxxxxx> [cascardo: no CPUIDLE_FLAG_IRQ_ENABLE] Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@xxxxxxxxxxxxx> Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx> [cascardo: context adjustments] Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@xxxxxxxxxxxxx> Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx> --- arch/x86/include/asm/nospec-branch.h | 1 arch/x86/kernel/cpu/bugs.c | 6 ++++ drivers/idle/intel_idle.c | 43 ++++++++++++++++++++++++++++++----- 3 files changed, 44 insertions(+), 6 deletions(-) --- a/arch/x86/include/asm/nospec-branch.h +++ b/arch/x86/include/asm/nospec-branch.h @@ -299,6 +299,7 @@ static inline void indirect_branch_predi /* The Intel SPEC CTRL MSR base value cache */ extern u64 x86_spec_ctrl_base; extern void write_spec_ctrl_current(u64 val, bool force); +extern u64 spec_ctrl_current(void); /* * With retpoline, we must use IBRS to restrict branch prediction --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -77,6 +77,12 @@ void write_spec_ctrl_current(u64 val, bo wrmsrl(MSR_IA32_SPEC_CTRL, val); } +u64 spec_ctrl_current(void) +{ + return this_cpu_read(x86_spec_ctrl_current); +} +EXPORT_SYMBOL_GPL(spec_ctrl_current); + /* * The vendor and possibly platform specific bits which can be modified in * x86_spec_ctrl_base. --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c @@ -46,11 +46,13 @@ #include <linux/tick.h> #include <trace/events/power.h> #include <linux/sched.h> +#include <linux/sched/smt.h> #include <linux/notifier.h> #include <linux/cpu.h> #include <linux/moduleparam.h> #include <asm/cpu_device_id.h> #include <asm/intel-family.h> +#include <asm/nospec-branch.h> #include <asm/mwait.h> #include <asm/msr.h> @@ -98,6 +100,12 @@ static struct cpuidle_state *cpuidle_sta #define CPUIDLE_FLAG_TLB_FLUSHED 0x10000 /* + * Disable IBRS across idle (when KERNEL_IBRS), is exclusive vs IRQ_ENABLE + * above. + */ +#define CPUIDLE_FLAG_IBRS BIT(16) + +/* * MWAIT takes an 8-bit "hint" in EAX "suggesting" * the C-state (top nibble) and sub-state (bottom nibble) * 0x00 means "MWAIT(C1)", 0x10 means "MWAIT(C2)" etc. @@ -107,6 +115,24 @@ static struct cpuidle_state *cpuidle_sta #define flg2MWAIT(flags) (((flags) >> 24) & 0xFF) #define MWAIT2flg(eax) ((eax & 0xFF) << 24) +static __cpuidle int intel_idle_ibrs(struct cpuidle_device *dev, + struct cpuidle_driver *drv, int index) +{ + bool smt_active = sched_smt_active(); + u64 spec_ctrl = spec_ctrl_current(); + int ret; + + if (smt_active) + wrmsrl(MSR_IA32_SPEC_CTRL, 0); + + ret = intel_idle(dev, drv, index); + + if (smt_active) + wrmsrl(MSR_IA32_SPEC_CTRL, spec_ctrl); + + return ret; +} + /* * States are indexed by the cstate number, * which is also the index into the MWAIT hint array. @@ -605,7 +631,7 @@ static struct cpuidle_state skl_cstates[ { .name = "C6", .desc = "MWAIT 0x20", - .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED, + .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED | CPUIDLE_FLAG_IBRS, .exit_latency = 85, .target_residency = 200, .enter = &intel_idle, @@ -613,7 +639,7 @@ static struct cpuidle_state skl_cstates[ { .name = "C7s", .desc = "MWAIT 0x33", - .flags = MWAIT2flg(0x33) | CPUIDLE_FLAG_TLB_FLUSHED, + .flags = MWAIT2flg(0x33) | CPUIDLE_FLAG_TLB_FLUSHED | CPUIDLE_FLAG_IBRS, .exit_latency = 124, .target_residency = 800, .enter = &intel_idle, @@ -621,7 +647,7 @@ static struct cpuidle_state skl_cstates[ { .name = "C8", .desc = "MWAIT 0x40", - .flags = MWAIT2flg(0x40) | CPUIDLE_FLAG_TLB_FLUSHED, + .flags = MWAIT2flg(0x40) | CPUIDLE_FLAG_TLB_FLUSHED | CPUIDLE_FLAG_IBRS, .exit_latency = 200, .target_residency = 800, .enter = &intel_idle, @@ -629,7 +655,7 @@ static struct cpuidle_state skl_cstates[ { .name = "C9", .desc = "MWAIT 0x50", - .flags = MWAIT2flg(0x50) | CPUIDLE_FLAG_TLB_FLUSHED, + .flags = MWAIT2flg(0x50) | CPUIDLE_FLAG_TLB_FLUSHED | CPUIDLE_FLAG_IBRS, .exit_latency = 480, .target_residency = 5000, .enter = &intel_idle, @@ -637,7 +663,7 @@ static struct cpuidle_state skl_cstates[ { .name = "C10", .desc = "MWAIT 0x60", - .flags = MWAIT2flg(0x60) | CPUIDLE_FLAG_TLB_FLUSHED, + .flags = MWAIT2flg(0x60) | CPUIDLE_FLAG_TLB_FLUSHED | CPUIDLE_FLAG_IBRS, .exit_latency = 890, .target_residency = 5000, .enter = &intel_idle, @@ -666,7 +692,7 @@ static struct cpuidle_state skx_cstates[ { .name = "C6", .desc = "MWAIT 0x20", - .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED, + .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED | CPUIDLE_FLAG_IBRS, .exit_latency = 133, .target_residency = 600, .enter = &intel_idle, @@ -1370,6 +1396,11 @@ static void __init intel_idle_cpuidle_dr drv->states[drv->state_count] = /* structure copy */ cpuidle_state_table[cstate]; + if (cpu_feature_enabled(X86_FEATURE_KERNEL_IBRS) && + cpuidle_state_table[cstate].flags & CPUIDLE_FLAG_IBRS) { + drv->states[drv->state_count].enter = intel_idle_ibrs; + } + drv->state_count += 1; } Patches currently in stable-queue which might be from cascardo@xxxxxxxxxxxxx are queue-5.4/x86-speculation-disable-rrsba-behavior.patch queue-5.4/kvm-vmx-flatten-__vmx_vcpu_run.patch queue-5.4/x86-kvm-vmx-make-noinstr-clean.patch queue-5.4/revert-x86-speculation-add-rsb-vm-exit-protections.patch queue-5.4/kvm-vmx-fix-ibrs-handling-after-vmexit.patch queue-5.4/kvm-vmx-prevent-guest-rsb-poisoning-attacks-with-eibrs.patch queue-5.4/kvm-nvmx-use-__vmx_vcpu_run-in-nested_vmx_check_vmentry_hw.patch queue-5.4/x86-bugs-keep-a-per-cpu-ia32_spec_ctrl-value.patch queue-5.4/x86-cpu-amd-enumerate-btc_no.patch queue-5.4/x86-speculation-fix-firmware-entry-spec_ctrl-handling.patch queue-5.4/x86-speculation-add-spectre_v2-ibrs-option-to-support-kernel-ibrs.patch queue-5.4/x86-cpu-add-consistent-cpu-match-macros.patch queue-5.4/x86-speculation-remove-x86_spec_ctrl_mask.patch queue-5.4/x86-bugs-add-cannon-lake-to-retbleed-affected-cpu-list.patch queue-5.4/x86-bugs-warn-when-ibrs-mitigation-is-selected-on-enhanced-ibrs-parts.patch queue-5.4/x86-speculation-fill-rsb-on-vmexit-for-ibrs.patch queue-5.4/x86-cpu-add-a-steppings-field-to-struct-x86_cpu_id.patch queue-5.4/kvm-vmx-convert-launched-argument-to-flags.patch queue-5.4/x86-common-stamp-out-the-stepping-madness.patch queue-5.4/x86-bugs-split-spectre_v2_select_mitigation-and-spectre_v2_user_select_mitigation.patch queue-5.4/x86-bugs-report-intel-retbleed-vulnerability.patch queue-5.4/x86-speculation-change-fill_return_buffer-to-work-with-objtool.patch queue-5.4/x86-cpufeatures-move-retpoline-flags-to-word-11.patch queue-5.4/x86-speculation-fix-spec_ctrl-write-on-smt-state-change.patch queue-5.4/kvm-vmx-use-test-reg-reg-instead-of-cmp-0-reg-in-vmenter.s.patch queue-5.4/x86-bugs-optimize-spec_ctrl-msr-writes.patch queue-5.4/x86-bugs-report-amd-retbleed-vulnerability.patch queue-5.4/x86-speculation-fix-rsb-filling-with-config_retpoline-n.patch queue-5.4/intel_idle-disable-ibrs-during-long-idle.patch queue-5.4/x86-speculation-use-declare_per_cpu-for-x86_spec_ctrl_current.patch queue-5.4/x86-entry-remove-skip_r11rcx.patch queue-5.4/x86-speculation-use-cached-host-spec_ctrl-value-for-guest-entry-exit.patch queue-5.4/x86-devicetable-move-x86-specific-macro-out-of-generic-code.patch queue-5.4/x86-bugs-add-amd-retbleed-boot-parameter.patch queue-5.4/x86-entry-add-kernel-ibrs-implementation.patch queue-5.4/revert-x86-cpu-add-a-steppings-field-to-struct-x86_cpu_id.patch queue-5.4/x86-speculation-add-rsb-vm-exit-protections.patch