summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2022-06-05 10:55:23 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2022-06-05 10:55:23 -0700
commit9784edd73a08ea08d0ce5606e1f0f729df688c59 (patch)
treea9247155727c093f98a62af876a476db1a69219f
parenta925128092d8dd5c2ea8644e1dddd510b7ebc9c7 (diff)
parent0c0fe08c76485fe0178ebb0fa1a2052c727abe94 (diff)
Merge tag 'x86-microcode-2022-06-05' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 microcode updates from Thomas Gleixner: - Disable late microcode loading by default. Unless the HW people get their act together and provide a required minimum version in the microcode header for making a halfways informed decision its just lottery and broken. - Warn and taint the kernel when microcode is loaded late - Remove the old unused microcode loader interface - Remove a redundant perf callback from the microcode loader * tag 'x86-microcode-2022-06-05' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86/microcode: Remove unnecessary perf callback x86/microcode: Taint and warn on late loading x86/microcode: Default-disable late loading x86/microcode: Rip out the OLD_INTERFACE
-rw-r--r--arch/x86/Kconfig15
-rw-r--r--arch/x86/kernel/cpu/common.c2
-rw-r--r--arch/x86/kernel/cpu/microcode/core.c115
3 files changed, 20 insertions, 112 deletions
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 7df2a9ef3662..9783ebc4e021 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -1358,17 +1358,16 @@ config MICROCODE_AMD
If you select this option, microcode patch loading support for AMD
processors will be enabled.
-config MICROCODE_OLD_INTERFACE
- bool "Ancient loading interface (DEPRECATED)"
+config MICROCODE_LATE_LOADING
+ bool "Late microcode loading (DANGEROUS)"
default n
depends on MICROCODE
help
- DO NOT USE THIS! This is the ancient /dev/cpu/microcode interface
- which was used by userspace tools like iucode_tool and microcode.ctl.
- It is inadequate because it runs too late to be able to properly
- load microcode on a machine and it needs special tools. Instead, you
- should've switched to the early loading method with the initrd or
- builtin microcode by now: Documentation/x86/microcode.rst
+ Loading microcode late, when the system is up and executing instructions
+ is a tricky business and should be avoided if possible. Just the sequence
+ of synchronizing all cores and SMT threads is one fragile dance which does
+ not guarantee that cores might not softlock after the loading. Therefore,
+ use this at your own risk. Late loading taints the kernel too.
config X86_MSR
tristate "/dev/cpu/*/msr - Model-specific register support"
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index 2e9142797c99..c296cb1c0113 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -2222,6 +2222,7 @@ void cpu_init_secondary(void)
}
#endif
+#ifdef CONFIG_MICROCODE_LATE_LOADING
/*
* The microcode loader calls this upon late microcode load to recheck features,
* only when microcode has been updated. Caller holds microcode_mutex and CPU
@@ -2251,6 +2252,7 @@ void microcode_check(void)
pr_warn("x86/CPU: CPU features have changed after loading microcode, but might not take effect.\n");
pr_warn("x86/CPU: Please consider either early loading through initrd/built-in or a potential BIOS update.\n");
}
+#endif
/*
* Invoked from core CPU hotplug code after hotplug operations
diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c
index 239ff5fcec6a..ad57e0e4d674 100644
--- a/arch/x86/kernel/cpu/microcode/core.c
+++ b/arch/x86/kernel/cpu/microcode/core.c
@@ -373,101 +373,10 @@ static int apply_microcode_on_target(int cpu)
return ret;
}
-#ifdef CONFIG_MICROCODE_OLD_INTERFACE
-static int do_microcode_update(const void __user *buf, size_t size)
-{
- int error = 0;
- int cpu;
-
- for_each_online_cpu(cpu) {
- struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
- enum ucode_state ustate;
-
- if (!uci->valid)
- continue;
-
- ustate = microcode_ops->request_microcode_user(cpu, buf, size);
- if (ustate == UCODE_ERROR) {
- error = -1;
- break;
- } else if (ustate == UCODE_NEW) {
- apply_microcode_on_target(cpu);
- }
- }
-
- return error;
-}
-
-static int microcode_open(struct inode *inode, struct file *file)
-{
- return capable(CAP_SYS_RAWIO) ? stream_open(inode, file) : -EPERM;
-}
-
-static ssize_t microcode_write(struct file *file, const char __user *buf,
- size_t len, loff_t *ppos)
-{
- ssize_t ret = -EINVAL;
- unsigned long nr_pages = totalram_pages();
-
- if ((len >> PAGE_SHIFT) > nr_pages) {
- pr_err("too much data (max %ld pages)\n", nr_pages);
- return ret;
- }
-
- cpus_read_lock();
- mutex_lock(&microcode_mutex);
-
- if (do_microcode_update(buf, len) == 0)
- ret = (ssize_t)len;
-
- if (ret > 0)
- perf_check_microcode();
-
- mutex_unlock(&microcode_mutex);
- cpus_read_unlock();
-
- return ret;
-}
-
-static const struct file_operations microcode_fops = {
- .owner = THIS_MODULE,
- .write = microcode_write,
- .open = microcode_open,
- .llseek = no_llseek,
-};
-
-static struct miscdevice microcode_dev = {
- .minor = MICROCODE_MINOR,
- .name = "microcode",
- .nodename = "cpu/microcode",
- .fops = &microcode_fops,
-};
-
-static int __init microcode_dev_init(void)
-{
- int error;
-
- error = misc_register(&microcode_dev);
- if (error) {
- pr_err("can't misc_register on minor=%d\n", MICROCODE_MINOR);
- return error;
- }
-
- return 0;
-}
-
-static void __exit microcode_dev_exit(void)
-{
- misc_deregister(&microcode_dev);
-}
-#else
-#define microcode_dev_init() 0
-#define microcode_dev_exit() do { } while (0)
-#endif
-
/* fake device for request_firmware */
static struct platform_device *microcode_pdev;
+#ifdef CONFIG_MICROCODE_LATE_LOADING
/*
* Late loading dance. Why the heavy-handed stomp_machine effort?
*
@@ -584,6 +493,9 @@ static int microcode_reload_late(void)
{
int ret;
+ pr_err("Attempting late microcode loading - it is dangerous and taints the kernel.\n");
+ pr_err("You should switch to early loading, if possible.\n");
+
atomic_set(&late_cpus_in, 0);
atomic_set(&late_cpus_out, 0);
@@ -632,9 +544,14 @@ put:
if (ret == 0)
ret = size;
+ add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_STILL_OK);
+
return ret;
}
+static DEVICE_ATTR_WO(reload);
+#endif
+
static ssize_t version_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -651,7 +568,6 @@ static ssize_t pf_show(struct device *dev,
return sprintf(buf, "0x%x\n", uci->cpu_sig.pf);
}
-static DEVICE_ATTR_WO(reload);
static DEVICE_ATTR(version, 0444, version_show, NULL);
static DEVICE_ATTR(processor_flags, 0444, pf_show, NULL);
@@ -804,7 +720,9 @@ static int mc_cpu_down_prep(unsigned int cpu)
}
static struct attribute *cpu_root_microcode_attrs[] = {
+#ifdef CONFIG_MICROCODE_LATE_LOADING
&dev_attr_reload.attr,
+#endif
NULL
};
@@ -838,10 +756,7 @@ static int __init microcode_init(void)
cpus_read_lock();
mutex_lock(&microcode_mutex);
-
error = subsys_interface_register(&mc_cpu_interface);
- if (!error)
- perf_check_microcode();
mutex_unlock(&microcode_mutex);
cpus_read_unlock();
@@ -856,10 +771,6 @@ static int __init microcode_init(void)
goto out_driver;
}
- error = microcode_dev_init();
- if (error)
- goto out_ucode_group;
-
register_syscore_ops(&mc_syscore_ops);
cpuhp_setup_state_nocalls(CPUHP_AP_MICROCODE_LOADER, "x86/microcode:starting",
mc_cpu_starting, NULL);
@@ -870,10 +781,6 @@ static int __init microcode_init(void)
return 0;
- out_ucode_group:
- sysfs_remove_group(&cpu_subsys.dev_root->kobj,
- &cpu_root_microcode_group);
-
out_driver:
cpus_read_lock();
mutex_lock(&microcode_mutex);