X86 microcode updates:

- 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
 -----BEGIN PGP SIGNATURE-----
 
 iQJHBAABCgAxFiEEQp8+kY+LLUocC4bMphj1TA10mKEFAmKcdjETHHRnbHhAbGlu
 dXRyb25peC5kZQAKCRCmGPVMDXSYoUUTD/92cLMB0g7XP8yFN+ZiHl7uoaDtE0UR
 WfapnMNL3tKKVnuwEMg83AjtyQ+O1JNZ6iS5K8jmiBnBByg6EQccz8pfe3jUQ6Ar
 gOLWV1F4tRbJD2NqqiWOo/l5qs5hJaz/QeE+oyCP0fvw6DOZixepG5RzveFSSwAa
 G2Q03GsGEu84SXlVAjagMSU6tYlBnlZBfKRB8NiNxkW8CLcJY0NfDCunbN6icEbH
 AQHXeviM3GWMKJA9R9DeSvYq9PbN5o2UVmcFQWsDAzZ8Ne2qCqskjoGNjuQ9s+72
 G35fm5d7dtIcrYg4PSJN0JDJP4HbcfSjhUrbdH4iAClTkGnNQERfuDV9O92/lYJE
 hd9c8yCegD0NWQ4dMNNrM5PSbWbQK7ajqRYVvqqouJZpH+IDtajA1jxEe+1msB8P
 xmXQDcdSMOyVs+Bw3Djf3tt8Qqhu4jxnf3y711oLklPwwh9lq9SvaWiX9ZFoYgdn
 1HVtQUAOdgDmncs5BQ8dpuwtoYXH5p31n0wh57emyFXl7wA93eWouuFczQ6mSol9
 LLdd9c+q9mBFIo0ult+fVhEOTDJF+27s3YXOpge6BAqei/SQIU4c5oq51CukV7ap
 TPzWAayq0lsAwXn1k6r86Zkewh1C2SQTyk1J3zMehZlSVpwSWbEQASYlKywmh6YB
 N+6/0XtHDAVK5Q==
 =DQjr
 -----END PGP SIGNATURE-----

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
This commit is contained in:
Linus Torvalds 2022-06-05 10:55:23 -07:00
commit 9784edd73a
3 changed files with 20 additions and 112 deletions

View File

@ -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"

View File

@ -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)
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

View File

@ -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)
{ {
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 @@ put:
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,
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)
} }
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)
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)
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)
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);