mirror of
https://github.com/torvalds/linux.git
synced 2024-12-11 21:52:04 +00:00
400331f8ff
A microcode update on some Intel processors causes all TSX transactions to always abort by default[*]. Microcode also added functionality to re-enable TSX for development purposes. With this microcode loaded, if tsx=on was passed on the cmdline, and TSX development mode was already enabled before the kernel boot, it may make the system vulnerable to TSX Asynchronous Abort (TAA). To be on safer side, unconditionally disable TSX development mode during boot. If a viable use case appears, this can be revisited later. [*]: Intel TSX Disable Update for Selected Processors, doc ID: 643557 [ bp: Drop unstable web link, massage heavily. ] Suggested-by: Andrew Cooper <andrew.cooper3@citrix.com> Suggested-by: Borislav Petkov <bp@alien8.de> Signed-off-by: Pawan Gupta <pawan.kumar.gupta@linux.intel.com> Signed-off-by: Borislav Petkov <bp@suse.de> Tested-by: Neelima Krishnan <neelima.krishnan@intel.com> Cc: <stable@vger.kernel.org> Link: https://lore.kernel.org/r/347bd844da3a333a9793c6687d4e4eb3b2419a3e.1646943780.git.pawan.kumar.gupta@linux.intel.com
262 lines
7.3 KiB
C
262 lines
7.3 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Intel Transactional Synchronization Extensions (TSX) control.
|
|
*
|
|
* Copyright (C) 2019-2021 Intel Corporation
|
|
*
|
|
* Author:
|
|
* Pawan Gupta <pawan.kumar.gupta@linux.intel.com>
|
|
*/
|
|
|
|
#include <linux/cpufeature.h>
|
|
|
|
#include <asm/cmdline.h>
|
|
|
|
#include "cpu.h"
|
|
|
|
#undef pr_fmt
|
|
#define pr_fmt(fmt) "tsx: " fmt
|
|
|
|
enum tsx_ctrl_states tsx_ctrl_state __ro_after_init = TSX_CTRL_NOT_SUPPORTED;
|
|
|
|
static void tsx_disable(void)
|
|
{
|
|
u64 tsx;
|
|
|
|
rdmsrl(MSR_IA32_TSX_CTRL, tsx);
|
|
|
|
/* Force all transactions to immediately abort */
|
|
tsx |= TSX_CTRL_RTM_DISABLE;
|
|
|
|
/*
|
|
* Ensure TSX support is not enumerated in CPUID.
|
|
* This is visible to userspace and will ensure they
|
|
* do not waste resources trying TSX transactions that
|
|
* will always abort.
|
|
*/
|
|
tsx |= TSX_CTRL_CPUID_CLEAR;
|
|
|
|
wrmsrl(MSR_IA32_TSX_CTRL, tsx);
|
|
}
|
|
|
|
static void tsx_enable(void)
|
|
{
|
|
u64 tsx;
|
|
|
|
rdmsrl(MSR_IA32_TSX_CTRL, tsx);
|
|
|
|
/* Enable the RTM feature in the cpu */
|
|
tsx &= ~TSX_CTRL_RTM_DISABLE;
|
|
|
|
/*
|
|
* Ensure TSX support is enumerated in CPUID.
|
|
* This is visible to userspace and will ensure they
|
|
* can enumerate and use the TSX feature.
|
|
*/
|
|
tsx &= ~TSX_CTRL_CPUID_CLEAR;
|
|
|
|
wrmsrl(MSR_IA32_TSX_CTRL, tsx);
|
|
}
|
|
|
|
static bool tsx_ctrl_is_supported(void)
|
|
{
|
|
u64 ia32_cap = x86_read_arch_cap_msr();
|
|
|
|
/*
|
|
* TSX is controlled via MSR_IA32_TSX_CTRL. However, support for this
|
|
* MSR is enumerated by ARCH_CAP_TSX_MSR bit in MSR_IA32_ARCH_CAPABILITIES.
|
|
*
|
|
* TSX control (aka MSR_IA32_TSX_CTRL) is only available after a
|
|
* microcode update on CPUs that have their MSR_IA32_ARCH_CAPABILITIES
|
|
* bit MDS_NO=1. CPUs with MDS_NO=0 are not planned to get
|
|
* MSR_IA32_TSX_CTRL support even after a microcode update. Thus,
|
|
* tsx= cmdline requests will do nothing on CPUs without
|
|
* MSR_IA32_TSX_CTRL support.
|
|
*/
|
|
return !!(ia32_cap & ARCH_CAP_TSX_CTRL_MSR);
|
|
}
|
|
|
|
static enum tsx_ctrl_states x86_get_tsx_auto_mode(void)
|
|
{
|
|
if (boot_cpu_has_bug(X86_BUG_TAA))
|
|
return TSX_CTRL_DISABLE;
|
|
|
|
return TSX_CTRL_ENABLE;
|
|
}
|
|
|
|
/*
|
|
* Disabling TSX is not a trivial business.
|
|
*
|
|
* First of all, there's a CPUID bit: X86_FEATURE_RTM_ALWAYS_ABORT
|
|
* which says that TSX is practically disabled (all transactions are
|
|
* aborted by default). When that bit is set, the kernel unconditionally
|
|
* disables TSX.
|
|
*
|
|
* In order to do that, however, it needs to dance a bit:
|
|
*
|
|
* 1. The first method to disable it is through MSR_TSX_FORCE_ABORT and
|
|
* the MSR is present only when *two* CPUID bits are set:
|
|
*
|
|
* - X86_FEATURE_RTM_ALWAYS_ABORT
|
|
* - X86_FEATURE_TSX_FORCE_ABORT
|
|
*
|
|
* 2. The second method is for CPUs which do not have the above-mentioned
|
|
* MSR: those use a different MSR - MSR_IA32_TSX_CTRL and disable TSX
|
|
* through that one. Those CPUs can also have the initially mentioned
|
|
* CPUID bit X86_FEATURE_RTM_ALWAYS_ABORT set and for those the same strategy
|
|
* applies: TSX gets disabled unconditionally.
|
|
*
|
|
* When either of the two methods are present, the kernel disables TSX and
|
|
* clears the respective RTM and HLE feature flags.
|
|
*
|
|
* An additional twist in the whole thing presents late microcode loading
|
|
* which, when done, may cause for the X86_FEATURE_RTM_ALWAYS_ABORT CPUID
|
|
* bit to be set after the update.
|
|
*
|
|
* A subsequent hotplug operation on any logical CPU except the BSP will
|
|
* cause for the supported CPUID feature bits to get re-detected and, if
|
|
* RTM and HLE get cleared all of a sudden, but, userspace did consult
|
|
* them before the update, then funny explosions will happen. Long story
|
|
* short: the kernel doesn't modify CPUID feature bits after booting.
|
|
*
|
|
* That's why, this function's call in init_intel() doesn't clear the
|
|
* feature flags.
|
|
*/
|
|
static void tsx_clear_cpuid(void)
|
|
{
|
|
u64 msr;
|
|
|
|
/*
|
|
* MSR_TFA_TSX_CPUID_CLEAR bit is only present when both CPUID
|
|
* bits RTM_ALWAYS_ABORT and TSX_FORCE_ABORT are present.
|
|
*/
|
|
if (boot_cpu_has(X86_FEATURE_RTM_ALWAYS_ABORT) &&
|
|
boot_cpu_has(X86_FEATURE_TSX_FORCE_ABORT)) {
|
|
rdmsrl(MSR_TSX_FORCE_ABORT, msr);
|
|
msr |= MSR_TFA_TSX_CPUID_CLEAR;
|
|
wrmsrl(MSR_TSX_FORCE_ABORT, msr);
|
|
} else if (tsx_ctrl_is_supported()) {
|
|
rdmsrl(MSR_IA32_TSX_CTRL, msr);
|
|
msr |= TSX_CTRL_CPUID_CLEAR;
|
|
wrmsrl(MSR_IA32_TSX_CTRL, msr);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Disable TSX development mode
|
|
*
|
|
* When the microcode released in Feb 2022 is applied, TSX will be disabled by
|
|
* default on some processors. MSR 0x122 (TSX_CTRL) and MSR 0x123
|
|
* (IA32_MCU_OPT_CTRL) can be used to re-enable TSX for development, doing so is
|
|
* not recommended for production deployments. In particular, applying MD_CLEAR
|
|
* flows for mitigation of the Intel TSX Asynchronous Abort (TAA) transient
|
|
* execution attack may not be effective on these processors when Intel TSX is
|
|
* enabled with updated microcode.
|
|
*/
|
|
static void tsx_dev_mode_disable(void)
|
|
{
|
|
u64 mcu_opt_ctrl;
|
|
|
|
/* Check if RTM_ALLOW exists */
|
|
if (!boot_cpu_has_bug(X86_BUG_TAA) || !tsx_ctrl_is_supported() ||
|
|
!cpu_feature_enabled(X86_FEATURE_SRBDS_CTRL))
|
|
return;
|
|
|
|
rdmsrl(MSR_IA32_MCU_OPT_CTRL, mcu_opt_ctrl);
|
|
|
|
if (mcu_opt_ctrl & RTM_ALLOW) {
|
|
mcu_opt_ctrl &= ~RTM_ALLOW;
|
|
wrmsrl(MSR_IA32_MCU_OPT_CTRL, mcu_opt_ctrl);
|
|
setup_force_cpu_cap(X86_FEATURE_RTM_ALWAYS_ABORT);
|
|
}
|
|
}
|
|
|
|
void __init tsx_init(void)
|
|
{
|
|
char arg[5] = {};
|
|
int ret;
|
|
|
|
tsx_dev_mode_disable();
|
|
|
|
/*
|
|
* Hardware will always abort a TSX transaction when the CPUID bit
|
|
* RTM_ALWAYS_ABORT is set. In this case, it is better not to enumerate
|
|
* CPUID.RTM and CPUID.HLE bits. Clear them here.
|
|
*/
|
|
if (boot_cpu_has(X86_FEATURE_RTM_ALWAYS_ABORT)) {
|
|
tsx_ctrl_state = TSX_CTRL_RTM_ALWAYS_ABORT;
|
|
tsx_clear_cpuid();
|
|
setup_clear_cpu_cap(X86_FEATURE_RTM);
|
|
setup_clear_cpu_cap(X86_FEATURE_HLE);
|
|
return;
|
|
}
|
|
|
|
if (!tsx_ctrl_is_supported()) {
|
|
tsx_ctrl_state = TSX_CTRL_NOT_SUPPORTED;
|
|
return;
|
|
}
|
|
|
|
ret = cmdline_find_option(boot_command_line, "tsx", arg, sizeof(arg));
|
|
if (ret >= 0) {
|
|
if (!strcmp(arg, "on")) {
|
|
tsx_ctrl_state = TSX_CTRL_ENABLE;
|
|
} else if (!strcmp(arg, "off")) {
|
|
tsx_ctrl_state = TSX_CTRL_DISABLE;
|
|
} else if (!strcmp(arg, "auto")) {
|
|
tsx_ctrl_state = x86_get_tsx_auto_mode();
|
|
} else {
|
|
tsx_ctrl_state = TSX_CTRL_DISABLE;
|
|
pr_err("invalid option, defaulting to off\n");
|
|
}
|
|
} else {
|
|
/* tsx= not provided */
|
|
if (IS_ENABLED(CONFIG_X86_INTEL_TSX_MODE_AUTO))
|
|
tsx_ctrl_state = x86_get_tsx_auto_mode();
|
|
else if (IS_ENABLED(CONFIG_X86_INTEL_TSX_MODE_OFF))
|
|
tsx_ctrl_state = TSX_CTRL_DISABLE;
|
|
else
|
|
tsx_ctrl_state = TSX_CTRL_ENABLE;
|
|
}
|
|
|
|
if (tsx_ctrl_state == TSX_CTRL_DISABLE) {
|
|
tsx_disable();
|
|
|
|
/*
|
|
* tsx_disable() will change the state of the RTM and HLE CPUID
|
|
* bits. Clear them here since they are now expected to be not
|
|
* set.
|
|
*/
|
|
setup_clear_cpu_cap(X86_FEATURE_RTM);
|
|
setup_clear_cpu_cap(X86_FEATURE_HLE);
|
|
} else if (tsx_ctrl_state == TSX_CTRL_ENABLE) {
|
|
|
|
/*
|
|
* HW defaults TSX to be enabled at bootup.
|
|
* We may still need the TSX enable support
|
|
* during init for special cases like
|
|
* kexec after TSX is disabled.
|
|
*/
|
|
tsx_enable();
|
|
|
|
/*
|
|
* tsx_enable() will change the state of the RTM and HLE CPUID
|
|
* bits. Force them here since they are now expected to be set.
|
|
*/
|
|
setup_force_cpu_cap(X86_FEATURE_RTM);
|
|
setup_force_cpu_cap(X86_FEATURE_HLE);
|
|
}
|
|
}
|
|
|
|
void tsx_ap_init(void)
|
|
{
|
|
tsx_dev_mode_disable();
|
|
|
|
if (tsx_ctrl_state == TSX_CTRL_ENABLE)
|
|
tsx_enable();
|
|
else if (tsx_ctrl_state == TSX_CTRL_DISABLE)
|
|
tsx_disable();
|
|
else if (tsx_ctrl_state == TSX_CTRL_RTM_ALWAYS_ABORT)
|
|
/* See comment over that function for more details. */
|
|
tsx_clear_cpuid();
|
|
}
|