From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail.linutronix.de (193.142.43.55:993) by crypto-ml.lab.linutronix.de with IMAP4-SSL for ; 05 Oct 2019 06:40:16 -0000 Received: from mga07.intel.com ([134.134.136.100]) by Galois.linutronix.de with esmtps (TLS1.2:DHE_RSA_AES_256_CBC_SHA256:256) (Exim 4.80) (envelope-from ) id 1iGdjj-0007xk-0D for speck@linutronix.de; Sat, 05 Oct 2019 08:40:15 +0200 Date: Fri, 4 Oct 2019 23:34:31 -0700 From: Pawan Gupta Subject: [MODERATED] [PATCH v5 09/11] TAAv5 9 Message-ID: =?utf-8?q?=3C359ce9cf9388518b5b18a0d79583cb97063c2f80=2E157025?= =?utf-8?q?5065=2Egit=2Epawan=2Ekumar=2Egupta=40linux=2Eintel=2Ecom=3E?= References: MIME-Version: 1.0 In-Reply-To: Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit To: speck@linutronix.de List-ID: Transactional Synchronization Extensions (TSX) is an extension to the x86 instruction set architecture (ISA) that adds Hardware Transactional Memory (HTM) support. Changing TSX state currently requires a reboot. This may not be desirable when rebooting imposes a huge penalty. Add support to control TSX feature via a new sysfs file: /sys/devices/system/cpu/hw_tx_mem - Writing 0|off|N|n to this file disables TSX feature on all the CPUs. This is equivalent to boot parameter tsx=off. - Writing 1|on|Y|y to this file enables TSX feature on all the CPUs. This is equivalent to boot parameter tsx=on. - Reading from this returns the status of TSX feature. - When TSX control is not supported this interface is not visible in sysfs. Changing the TSX state from this interface also updates CPUID.RTM feature bit. From the kernel side, this feature bit doesn't result in any ALTERNATIVE code patching. No memory allocations are done to save/restore user state. No code paths in outside of the tests for vulnerability to TAA are dependent on the value of the feature bit. In general the kernel doesn't care whether RTM is present or not. Applications typically look at CPUID bits once at startup (or when first calling into a library that uses the feature). So we have a couple of cases to cover: 1) An application started and saw that RTM was enabled, so began to use it. Then TSX was disabled. Net result in this case is that the application will keep trying to use RTM, but every xbegin() will immediately abort the transaction. This has a performance impact to the application, but it doesn't affect correctness because all users of RTM must have a fallback path for when the transaction aborts. Note that even if an application is in the middle of a transaction when we disable RTM, we are safe. The XPI that we use to update the TSX_CTRL MSR will abort the transaction (just as any interrupt would abort a transaction). 2) An application starts and sees RTM is not available. So it will always use alternative paths. Even if TSX is enabled and RTM is set, applications in general do not re-evaluate their choice so will continue to run in non-TSX mode. Signed-off-by: Pawan Gupta Reviewed-by: Mark Gross Reviewed-by: Tony Luck Tested-by: Neelima Krishnan --- .../ABI/testing/sysfs-devices-system-cpu | 23 ++++ arch/x86/kernel/cpu/tsx.c | 103 ++++++++++++++++++ drivers/base/cpu.c | 32 +++++- include/linux/cpu.h | 6 + 4 files changed, 163 insertions(+), 1 deletion(-) diff --git a/Documentation/ABI/testing/sysfs-devices-system-cpu b/Documentation/ABI/testing/sysfs-devices-system-cpu index 5f7d7b14fa44..0c3c8c462285 100644 --- a/Documentation/ABI/testing/sysfs-devices-system-cpu +++ b/Documentation/ABI/testing/sysfs-devices-system-cpu @@ -562,3 +562,26 @@ Description: Umwait control or C0.2 state. The time is an unsigned 32-bit number. Note that a value of zero means there is no limit. Low order two bits must be zero. + +What: /sys/devices/system/cpu/hw_tx_mem +Date: August 2019 +Contact: Pawan Gupta + Linux kernel mailing list +Description: Hardware Transactional Memory (HTM) control. + + Read/write interface to control HTM feature for all the CPUs in + the system. This interface is only present on platforms that + support HTM control. HTM is a hardware feature to speed up the + execution of multi-threaded software through lock elision. An + example of HTM implementation is Intel Transactional + Synchronization Extensions (TSX). + + Read returns the status of HTM feature. + + 0: HTM is disabled + 1: HTM is enabled + + Write sets the state of HTM feature. + + 0: Disables HTM + 1: Enables HTM diff --git a/arch/x86/kernel/cpu/tsx.c b/arch/x86/kernel/cpu/tsx.c index 73a0e5af3720..2cea038fdcba 100644 --- a/arch/x86/kernel/cpu/tsx.c +++ b/arch/x86/kernel/cpu/tsx.c @@ -10,9 +10,12 @@ #include #include +#include #include "cpu.h" +static DEFINE_MUTEX(tsx_mutex); + static enum tsx_ctrl_states { TSX_CTRL_ENABLE, TSX_CTRL_DISABLE, @@ -150,3 +153,103 @@ void tsx_init(struct cpuinfo_x86 *c) setup_force_cpu_cap(X86_FEATURE_RTM); } } + +static void tsx_update_this_cpu(void *arg) +{ + struct cpuinfo_x86 *c = &cpu_data(smp_processor_id()); + unsigned long enable = (unsigned long)arg; + + if (enable) { + tsx_enable(); + set_cpu_cap(c, X86_FEATURE_RTM); + setup_force_cpu_cap(X86_FEATURE_RTM); + } else { + tsx_disable(); + clear_cpu_cap(c, X86_FEATURE_RTM); + setup_clear_cpu_cap(X86_FEATURE_RTM); + } +} + +static void tsx_update_on_each_cpu(bool val) +{ + get_online_cpus(); + on_each_cpu(tsx_update_this_cpu, (void *)val, 1); + put_online_cpus(); +} + +ssize_t hw_tx_mem_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%d\n", tsx_ctrl_state == TSX_CTRL_ENABLE ? 1 : 0); +} + +ssize_t hw_tx_mem_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + enum tsx_ctrl_states requested_state; + ssize_t ret; + bool val; + + ret = kstrtobool(buf, &val); + if (ret) + return ret; + + mutex_lock(&tsx_mutex); + + if (val) { + tsx_user_cmd = TSX_USER_CMD_ON; + requested_state = TSX_CTRL_ENABLE; + } else { + tsx_user_cmd = TSX_USER_CMD_OFF; + requested_state = TSX_CTRL_DISABLE; + } + + /* Current state is same as the reqested state, do nothing */ + if (tsx_ctrl_state == requested_state) + goto exit; + + tsx_ctrl_state = requested_state; + + /* + * Changing the TSX state from this interface also updates CPUID.RTM + * feature bit. From the kernel side, this feature bit doesn't result + * in any ALTERNATIVE code patching. No memory allocations are done to + * save/restore user state. No code paths in outside of the tests for + * vulnerability to TAA are dependent on the value of the feature bit. + * In general the kernel doesn't care whether RTM is present or not. + * + * From the user side it is a bit fuzzier. Applications typically look + * at CPUID bits once at startup (or when first calling into a library + * that uses the feature). So we have a couple of cases to cover: + * + * 1) An application started and saw that RTM was enabled, so began + * to use it. Then TSX was disabled. Net result in this case is + * that the application will keep trying to use RTM, but every + * xbegin() will immediately abort the transaction. This has a + * performance impact to the application, but it doesn't affect + * correctness because all users of RTM must have a fallback path + * for when the transaction aborts. Note that even if an application + * is in the middle of a transaction when we disable RTM, we are + * safe. The XPI that we use to update the TSX_CTRL MSR will abort + * the transaction (just as any interrupt would abort a + * transaction). + * + * 2) An application starts and sees RTM is not available. So it will + * always use alternative paths. Even if TSX is enabled and RTM is + * set, applications in general do not re-evaluate their choice so + * will continue to run in non-TSX mode. + */ + tsx_update_on_each_cpu(val); +exit: + mutex_unlock(&tsx_mutex); + + return count; +} + +umode_t hw_tx_mem_is_visible(void) +{ + if (tsx_ctrl_state == TSX_CTRL_NOT_SUPPORTED) + return 0; + + return 0644; +} diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index 0fccd8c0312e..2148e974ab0a 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -460,6 +460,34 @@ struct device *cpu_device_create(struct device *parent, void *drvdata, } EXPORT_SYMBOL_GPL(cpu_device_create); +ssize_t __weak hw_tx_mem_show(struct device *dev, struct device_attribute *a, + char *buf) +{ + return -ENODEV; +} + +ssize_t __weak hw_tx_mem_store(struct device *dev, struct device_attribute *a, + const char *buf, size_t count) +{ + return -ENODEV; +} + +DEVICE_ATTR_RW(hw_tx_mem); + +umode_t __weak hw_tx_mem_is_visible(void) +{ + return 0; +} + +static umode_t cpu_root_attrs_is_visible(struct kobject *kobj, + struct attribute *attr, int index) +{ + if (attr == &dev_attr_hw_tx_mem.attr) + return hw_tx_mem_is_visible(); + + return attr->mode; +} + #ifdef CONFIG_GENERIC_CPU_AUTOPROBE static DEVICE_ATTR(modalias, 0444, print_cpu_modalias, NULL); #endif @@ -481,11 +509,13 @@ static struct attribute *cpu_root_attrs[] = { #ifdef CONFIG_GENERIC_CPU_AUTOPROBE &dev_attr_modalias.attr, #endif + &dev_attr_hw_tx_mem.attr, NULL }; static struct attribute_group cpu_root_attr_group = { - .attrs = cpu_root_attrs, + .attrs = cpu_root_attrs, + .is_visible = cpu_root_attrs_is_visible, }; static const struct attribute_group *cpu_root_attr_groups[] = { diff --git a/include/linux/cpu.h b/include/linux/cpu.h index 1872b15bda75..820fda85fc71 100644 --- a/include/linux/cpu.h +++ b/include/linux/cpu.h @@ -63,6 +63,12 @@ extern ssize_t cpu_show_tsx_async_abort(struct device *dev, struct device_attribute *attr, char *buf); +extern ssize_t hw_tx_mem_show(struct device *dev, struct device_attribute *a, + char *buf); +extern ssize_t hw_tx_mem_store(struct device *dev, struct device_attribute *a, + const char *buf, size_t count); +extern umode_t hw_tx_mem_is_visible(void); + extern __printf(4, 5) struct device *cpu_device_create(struct device *parent, void *drvdata, const struct attribute_group **groups, -- 2.20.1