Skip to content

Commit

Permalink
Merge tag 'x86-microcode-2022-06-05' of git://git.kernel.org/pub/scm/…
Browse files Browse the repository at this point in the history
…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
  • Loading branch information
Linus Torvalds committed Jun 5, 2022
2 parents a925128 + 0c0fe08 commit 9784edd
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 112 deletions.
15 changes: 7 additions & 8 deletions arch/x86/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
2 changes: 2 additions & 0 deletions arch/x86/kernel/cpu/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
115 changes: 11 additions & 104 deletions arch/x86/kernel/cpu/microcode/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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?
*
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -632,9 +544,14 @@ static ssize_t reload_store(struct device *dev,
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)
{
Expand All @@ -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);

Expand Down Expand Up @@ -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
};

Expand Down Expand Up @@ -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();

Expand All @@ -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);
Expand All @@ -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);
Expand Down

0 comments on commit 9784edd

Please sign in to comment.