Commit 9784edd7 authored by Linus Torvalds's avatar Linus Torvalds

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
parents a9251280 0c0fe08c
...@@ -1358,17 +1358,16 @@ config MICROCODE_AMD ...@@ -1358,17 +1358,16 @@ config MICROCODE_AMD
If you select this option, microcode patch loading support for AMD If you select this option, microcode patch loading support for AMD
processors will be enabled. processors will be enabled.
config MICROCODE_OLD_INTERFACE config MICROCODE_LATE_LOADING
bool "Ancient loading interface (DEPRECATED)" bool "Late microcode loading (DANGEROUS)"
default n default n
depends on MICROCODE depends on MICROCODE
help help
DO NOT USE THIS! This is the ancient /dev/cpu/microcode interface Loading microcode late, when the system is up and executing instructions
which was used by userspace tools like iucode_tool and microcode.ctl. is a tricky business and should be avoided if possible. Just the sequence
It is inadequate because it runs too late to be able to properly of synchronizing all cores and SMT threads is one fragile dance which does
load microcode on a machine and it needs special tools. Instead, you not guarantee that cores might not softlock after the loading. Therefore,
should've switched to the early loading method with the initrd or use this at your own risk. Late loading taints the kernel too.
builtin microcode by now: Documentation/x86/microcode.rst
config X86_MSR config X86_MSR
tristate "/dev/cpu/*/msr - Model-specific register support" tristate "/dev/cpu/*/msr - Model-specific register support"
......
...@@ -2222,6 +2222,7 @@ void cpu_init_secondary(void) ...@@ -2222,6 +2222,7 @@ void cpu_init_secondary(void)
} }
#endif #endif
#ifdef CONFIG_MICROCODE_LATE_LOADING
/* /*
* The microcode loader calls this upon late microcode load to recheck features, * The microcode loader calls this upon late microcode load to recheck features,
* only when microcode has been updated. Caller holds microcode_mutex and CPU * only when microcode has been updated. Caller holds microcode_mutex and CPU
...@@ -2251,6 +2252,7 @@ void microcode_check(void) ...@@ -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: 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"); 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 * Invoked from core CPU hotplug code after hotplug operations
......
...@@ -373,101 +373,10 @@ static int apply_microcode_on_target(int cpu) ...@@ -373,101 +373,10 @@ static int apply_microcode_on_target(int cpu)
return ret; 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 */ /* fake device for request_firmware */
static struct platform_device *microcode_pdev; static struct platform_device *microcode_pdev;
#ifdef CONFIG_MICROCODE_LATE_LOADING
/* /*
* Late loading dance. Why the heavy-handed stomp_machine effort? * Late loading dance. Why the heavy-handed stomp_machine effort?
* *
...@@ -584,6 +493,9 @@ static int microcode_reload_late(void) ...@@ -584,6 +493,9 @@ static int microcode_reload_late(void)
{ {
int ret; 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_in, 0);
atomic_set(&late_cpus_out, 0); atomic_set(&late_cpus_out, 0);
...@@ -632,9 +544,14 @@ static ssize_t reload_store(struct device *dev, ...@@ -632,9 +544,14 @@ static ssize_t reload_store(struct device *dev,
if (ret == 0) if (ret == 0)
ret = size; ret = size;
add_taint(TAINT_CPU_OUT_OF_SPEC, LOCKDEP_STILL_OK);
return ret; return ret;
} }
static DEVICE_ATTR_WO(reload);
#endif
static ssize_t version_show(struct device *dev, static ssize_t version_show(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
...@@ -651,7 +568,6 @@ static ssize_t pf_show(struct device *dev, ...@@ -651,7 +568,6 @@ static ssize_t pf_show(struct device *dev,
return sprintf(buf, "0x%x\n", uci->cpu_sig.pf); 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(version, 0444, version_show, NULL);
static DEVICE_ATTR(processor_flags, 0444, pf_show, NULL); static DEVICE_ATTR(processor_flags, 0444, pf_show, NULL);
...@@ -804,7 +720,9 @@ static int mc_cpu_down_prep(unsigned int cpu) ...@@ -804,7 +720,9 @@ static int mc_cpu_down_prep(unsigned int cpu)
} }
static struct attribute *cpu_root_microcode_attrs[] = { static struct attribute *cpu_root_microcode_attrs[] = {
#ifdef CONFIG_MICROCODE_LATE_LOADING
&dev_attr_reload.attr, &dev_attr_reload.attr,
#endif
NULL NULL
}; };
...@@ -838,10 +756,7 @@ static int __init microcode_init(void) ...@@ -838,10 +756,7 @@ static int __init microcode_init(void)
cpus_read_lock(); cpus_read_lock();
mutex_lock(&microcode_mutex); mutex_lock(&microcode_mutex);
error = subsys_interface_register(&mc_cpu_interface); error = subsys_interface_register(&mc_cpu_interface);
if (!error)
perf_check_microcode();
mutex_unlock(&microcode_mutex); mutex_unlock(&microcode_mutex);
cpus_read_unlock(); cpus_read_unlock();
...@@ -856,10 +771,6 @@ static int __init microcode_init(void) ...@@ -856,10 +771,6 @@ static int __init microcode_init(void)
goto out_driver; goto out_driver;
} }
error = microcode_dev_init();
if (error)
goto out_ucode_group;
register_syscore_ops(&mc_syscore_ops); register_syscore_ops(&mc_syscore_ops);
cpuhp_setup_state_nocalls(CPUHP_AP_MICROCODE_LOADER, "x86/microcode:starting", cpuhp_setup_state_nocalls(CPUHP_AP_MICROCODE_LOADER, "x86/microcode:starting",
mc_cpu_starting, NULL); mc_cpu_starting, NULL);
...@@ -870,10 +781,6 @@ static int __init microcode_init(void) ...@@ -870,10 +781,6 @@ static int __init microcode_init(void)
return 0; return 0;
out_ucode_group:
sysfs_remove_group(&cpu_subsys.dev_root->kobj,
&cpu_root_microcode_group);
out_driver: out_driver:
cpus_read_lock(); cpus_read_lock();
mutex_lock(&microcode_mutex); mutex_lock(&microcode_mutex);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment