1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
75
76#include <linux/platform_device.h>
77#include <linux/miscdevice.h>
78#include <linux/capability.h>
79#include <linux/kernel.h>
80#include <linux/module.h>
81#include <linux/mutex.h>
82#include <linux/cpu.h>
83#include <linux/fs.h>
84#include <linux/mm.h>
85#include <linux/syscore_ops.h>
86
87#include <asm/microcode.h>
88#include <asm/processor.h>
89#include <asm/cpu_device_id.h>
90#include <asm/perf_event.h>
91
92MODULE_DESCRIPTION("Microcode Update Driver");
93MODULE_AUTHOR("Tigran Aivazian <tigran@aivazian.fsnet.co.uk>");
94MODULE_LICENSE("GPL");
95
96#define MICROCODE_VERSION "2.00"
97
98static struct microcode_ops *microcode_ops;
99
100bool dis_ucode_ldr;
101module_param(dis_ucode_ldr, bool, 0);
102
103
104
105
106
107
108
109
110
111
112
113
114
115static DEFINE_MUTEX(microcode_mutex);
116
117struct ucode_cpu_info ucode_cpu_info[NR_CPUS];
118EXPORT_SYMBOL_GPL(ucode_cpu_info);
119
120
121
122
123
124struct cpu_info_ctx {
125 struct cpu_signature *cpu_sig;
126 int err;
127};
128
129static void collect_cpu_info_local(void *arg)
130{
131 struct cpu_info_ctx *ctx = arg;
132
133 ctx->err = microcode_ops->collect_cpu_info(smp_processor_id(),
134 ctx->cpu_sig);
135}
136
137static int collect_cpu_info_on_target(int cpu, struct cpu_signature *cpu_sig)
138{
139 struct cpu_info_ctx ctx = { .cpu_sig = cpu_sig, .err = 0 };
140 int ret;
141
142 ret = smp_call_function_single(cpu, collect_cpu_info_local, &ctx, 1);
143 if (!ret)
144 ret = ctx.err;
145
146 return ret;
147}
148
149static int collect_cpu_info(int cpu)
150{
151 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
152 int ret;
153
154 memset(uci, 0, sizeof(*uci));
155
156 ret = collect_cpu_info_on_target(cpu, &uci->cpu_sig);
157 if (!ret)
158 uci->valid = 1;
159
160 return ret;
161}
162
163struct apply_microcode_ctx {
164 int err;
165};
166
167static void apply_microcode_local(void *arg)
168{
169 struct apply_microcode_ctx *ctx = arg;
170
171 ctx->err = microcode_ops->apply_microcode(smp_processor_id());
172}
173
174static int apply_microcode_on_target(int cpu)
175{
176 struct apply_microcode_ctx ctx = { .err = 0 };
177 int ret;
178
179 ret = smp_call_function_single(cpu, apply_microcode_local, &ctx, 1);
180 if (!ret)
181 ret = ctx.err;
182
183 return ret;
184}
185
186#ifdef CONFIG_MICROCODE_OLD_INTERFACE
187static int do_microcode_update(const void __user *buf, size_t size)
188{
189 int error = 0;
190 int cpu;
191
192 for_each_online_cpu(cpu) {
193 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
194 enum ucode_state ustate;
195
196 if (!uci->valid)
197 continue;
198
199 ustate = microcode_ops->request_microcode_user(cpu, buf, size);
200 if (ustate == UCODE_ERROR) {
201 error = -1;
202 break;
203 } else if (ustate == UCODE_OK)
204 apply_microcode_on_target(cpu);
205 }
206
207 return error;
208}
209
210static int microcode_open(struct inode *inode, struct file *file)
211{
212 return capable(CAP_SYS_RAWIO) ? nonseekable_open(inode, file) : -EPERM;
213}
214
215static ssize_t microcode_write(struct file *file, const char __user *buf,
216 size_t len, loff_t *ppos)
217{
218 ssize_t ret = -EINVAL;
219
220 if ((len >> PAGE_SHIFT) > totalram_pages) {
221 pr_err("too much data (max %ld pages)\n", totalram_pages);
222 return ret;
223 }
224
225 get_online_cpus();
226 mutex_lock(µcode_mutex);
227
228 if (do_microcode_update(buf, len) == 0)
229 ret = (ssize_t)len;
230
231 if (ret > 0)
232 perf_check_microcode();
233
234 mutex_unlock(µcode_mutex);
235 put_online_cpus();
236
237 return ret;
238}
239
240static const struct file_operations microcode_fops = {
241 .owner = THIS_MODULE,
242 .write = microcode_write,
243 .open = microcode_open,
244 .llseek = no_llseek,
245};
246
247static struct miscdevice microcode_dev = {
248 .minor = MICROCODE_MINOR,
249 .name = "microcode",
250 .nodename = "cpu/microcode",
251 .fops = µcode_fops,
252};
253
254static int __init microcode_dev_init(void)
255{
256 int error;
257
258 error = misc_register(µcode_dev);
259 if (error) {
260 pr_err("can't misc_register on minor=%d\n", MICROCODE_MINOR);
261 return error;
262 }
263
264 return 0;
265}
266
267static void __exit microcode_dev_exit(void)
268{
269 misc_deregister(µcode_dev);
270}
271
272MODULE_ALIAS_MISCDEV(MICROCODE_MINOR);
273MODULE_ALIAS("devname:cpu/microcode");
274#else
275#define microcode_dev_init() 0
276#define microcode_dev_exit() do { } while (0)
277#endif
278
279
280static struct platform_device *microcode_pdev;
281
282static int reload_for_cpu(int cpu)
283{
284 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
285 enum ucode_state ustate;
286 int err = 0;
287
288 if (!uci->valid)
289 return err;
290
291 ustate = microcode_ops->request_microcode_fw(cpu, µcode_pdev->dev, true);
292 if (ustate == UCODE_OK)
293 apply_microcode_on_target(cpu);
294 else
295 if (ustate == UCODE_ERROR)
296 err = -EINVAL;
297 return err;
298}
299
300static ssize_t reload_store(struct device *dev,
301 struct device_attribute *attr,
302 const char *buf, size_t size)
303{
304 unsigned long val;
305 int cpu;
306 ssize_t ret = 0, tmp_ret;
307
308 ret = kstrtoul(buf, 0, &val);
309 if (ret)
310 return ret;
311
312 if (val != 1)
313 return size;
314
315 get_online_cpus();
316 mutex_lock(µcode_mutex);
317 for_each_online_cpu(cpu) {
318 tmp_ret = reload_for_cpu(cpu);
319 if (tmp_ret != 0)
320 pr_warn("Error reloading microcode on CPU %d\n", cpu);
321
322
323 if (!ret)
324 ret = tmp_ret;
325 }
326 if (!ret)
327 perf_check_microcode();
328 mutex_unlock(µcode_mutex);
329 put_online_cpus();
330
331 if (!ret)
332 ret = size;
333
334 return ret;
335}
336
337static ssize_t version_show(struct device *dev,
338 struct device_attribute *attr, char *buf)
339{
340 struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
341
342 return sprintf(buf, "0x%x\n", uci->cpu_sig.rev);
343}
344
345static ssize_t pf_show(struct device *dev,
346 struct device_attribute *attr, char *buf)
347{
348 struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
349
350 return sprintf(buf, "0x%x\n", uci->cpu_sig.pf);
351}
352
353static DEVICE_ATTR(reload, 0200, NULL, reload_store);
354static DEVICE_ATTR(version, 0400, version_show, NULL);
355static DEVICE_ATTR(processor_flags, 0400, pf_show, NULL);
356
357static struct attribute *mc_default_attrs[] = {
358 &dev_attr_version.attr,
359 &dev_attr_processor_flags.attr,
360 NULL
361};
362
363static struct attribute_group mc_attr_group = {
364 .attrs = mc_default_attrs,
365 .name = "microcode",
366};
367
368static void microcode_fini_cpu(int cpu)
369{
370 microcode_ops->microcode_fini_cpu(cpu);
371}
372
373static enum ucode_state microcode_resume_cpu(int cpu)
374{
375 pr_debug("CPU%d updated upon resume\n", cpu);
376
377 if (apply_microcode_on_target(cpu))
378 return UCODE_ERROR;
379
380 return UCODE_OK;
381}
382
383static enum ucode_state microcode_init_cpu(int cpu, bool refresh_fw)
384{
385 enum ucode_state ustate;
386 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
387
388 if (uci && uci->valid)
389 return UCODE_OK;
390
391 if (collect_cpu_info(cpu))
392 return UCODE_ERROR;
393
394
395 if (system_state != SYSTEM_RUNNING)
396 return UCODE_NFOUND;
397
398 ustate = microcode_ops->request_microcode_fw(cpu, µcode_pdev->dev,
399 refresh_fw);
400
401 if (ustate == UCODE_OK) {
402 pr_debug("CPU%d updated upon init\n", cpu);
403 apply_microcode_on_target(cpu);
404 }
405
406 return ustate;
407}
408
409static enum ucode_state microcode_update_cpu(int cpu)
410{
411 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
412
413 if (uci->valid)
414 return microcode_resume_cpu(cpu);
415
416 return microcode_init_cpu(cpu, false);
417}
418
419static int mc_device_add(struct device *dev, struct subsys_interface *sif)
420{
421 int err, cpu = dev->id;
422
423 if (!cpu_online(cpu))
424 return 0;
425
426 pr_debug("CPU%d added\n", cpu);
427
428 err = sysfs_create_group(&dev->kobj, &mc_attr_group);
429 if (err)
430 return err;
431
432 if (microcode_init_cpu(cpu, true) == UCODE_ERROR)
433 return -EINVAL;
434
435 return err;
436}
437
438static int mc_device_remove(struct device *dev, struct subsys_interface *sif)
439{
440 int cpu = dev->id;
441
442 if (!cpu_online(cpu))
443 return 0;
444
445 pr_debug("CPU%d removed\n", cpu);
446 microcode_fini_cpu(cpu);
447 sysfs_remove_group(&dev->kobj, &mc_attr_group);
448 return 0;
449}
450
451static struct subsys_interface mc_cpu_interface = {
452 .name = "microcode",
453 .subsys = &cpu_subsys,
454 .add_dev = mc_device_add,
455 .remove_dev = mc_device_remove,
456};
457
458
459
460
461static void mc_bp_resume(void)
462{
463 int cpu = smp_processor_id();
464 struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
465
466 if (uci->valid && uci->mc)
467 microcode_ops->apply_microcode(cpu);
468 else if (!uci->mc)
469 reload_early_microcode();
470}
471
472static struct syscore_ops mc_syscore_ops = {
473 .resume = mc_bp_resume,
474};
475
476static int
477mc_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu)
478{
479 unsigned int cpu = (unsigned long)hcpu;
480 struct device *dev;
481
482 dev = get_cpu_device(cpu);
483
484 switch (action & ~CPU_TASKS_FROZEN) {
485 case CPU_ONLINE:
486 microcode_update_cpu(cpu);
487 pr_debug("CPU%d added\n", cpu);
488
489
490
491
492
493 case CPU_DOWN_FAILED:
494 if (sysfs_create_group(&dev->kobj, &mc_attr_group))
495 pr_err("Failed to create group for CPU%d\n", cpu);
496 break;
497
498 case CPU_DOWN_PREPARE:
499
500 sysfs_remove_group(&dev->kobj, &mc_attr_group);
501 pr_debug("CPU%d removed\n", cpu);
502 break;
503
504
505
506
507
508
509
510
511
512 }
513
514
515 if (action == CPU_UP_CANCELED_FROZEN)
516 microcode_fini_cpu(cpu);
517
518 return NOTIFY_OK;
519}
520
521static struct notifier_block __refdata mc_cpu_notifier = {
522 .notifier_call = mc_cpu_callback,
523};
524
525#ifdef MODULE
526
527static const struct x86_cpu_id __initconst microcode_id[] = {
528#ifdef CONFIG_MICROCODE_INTEL
529 { X86_VENDOR_INTEL, X86_FAMILY_ANY, X86_MODEL_ANY, },
530#endif
531#ifdef CONFIG_MICROCODE_AMD
532 { X86_VENDOR_AMD, X86_FAMILY_ANY, X86_MODEL_ANY, },
533#endif
534 {}
535};
536MODULE_DEVICE_TABLE(x86cpu, microcode_id);
537#endif
538
539static struct attribute *cpu_root_microcode_attrs[] = {
540 &dev_attr_reload.attr,
541 NULL
542};
543
544static struct attribute_group cpu_root_microcode_group = {
545 .name = "microcode",
546 .attrs = cpu_root_microcode_attrs,
547};
548
549static int __init microcode_init(void)
550{
551 struct cpuinfo_x86 *c = &cpu_data(0);
552 int error;
553
554 if (paravirt_enabled() || dis_ucode_ldr)
555 return -EINVAL;
556
557 if (c->x86_vendor == X86_VENDOR_INTEL)
558 microcode_ops = init_intel_microcode();
559 else if (c->x86_vendor == X86_VENDOR_AMD)
560 microcode_ops = init_amd_microcode();
561 else
562 pr_err("no support for this CPU vendor\n");
563
564 if (!microcode_ops)
565 return -ENODEV;
566
567 microcode_pdev = platform_device_register_simple("microcode", -1,
568 NULL, 0);
569 if (IS_ERR(microcode_pdev))
570 return PTR_ERR(microcode_pdev);
571
572 get_online_cpus();
573 mutex_lock(µcode_mutex);
574
575 error = subsys_interface_register(&mc_cpu_interface);
576 if (!error)
577 perf_check_microcode();
578 mutex_unlock(µcode_mutex);
579 put_online_cpus();
580
581 if (error)
582 goto out_pdev;
583
584 error = sysfs_create_group(&cpu_subsys.dev_root->kobj,
585 &cpu_root_microcode_group);
586
587 if (error) {
588 pr_err("Error creating microcode group!\n");
589 goto out_driver;
590 }
591
592 error = microcode_dev_init();
593 if (error)
594 goto out_ucode_group;
595
596 register_syscore_ops(&mc_syscore_ops);
597 register_hotcpu_notifier(&mc_cpu_notifier);
598
599 pr_info("Microcode Update Driver: v" MICROCODE_VERSION
600 " <tigran@aivazian.fsnet.co.uk>, Peter Oruba\n");
601
602 return 0;
603
604 out_ucode_group:
605 sysfs_remove_group(&cpu_subsys.dev_root->kobj,
606 &cpu_root_microcode_group);
607
608 out_driver:
609 get_online_cpus();
610 mutex_lock(µcode_mutex);
611
612 subsys_interface_unregister(&mc_cpu_interface);
613
614 mutex_unlock(µcode_mutex);
615 put_online_cpus();
616
617 out_pdev:
618 platform_device_unregister(microcode_pdev);
619 return error;
620
621}
622module_init(microcode_init);
623
624static void __exit microcode_exit(void)
625{
626 struct cpuinfo_x86 *c = &cpu_data(0);
627
628 microcode_dev_exit();
629
630 unregister_hotcpu_notifier(&mc_cpu_notifier);
631 unregister_syscore_ops(&mc_syscore_ops);
632
633 sysfs_remove_group(&cpu_subsys.dev_root->kobj,
634 &cpu_root_microcode_group);
635
636 get_online_cpus();
637 mutex_lock(µcode_mutex);
638
639 subsys_interface_unregister(&mc_cpu_interface);
640
641 mutex_unlock(µcode_mutex);
642 put_online_cpus();
643
644 platform_device_unregister(microcode_pdev);
645
646 microcode_ops = NULL;
647
648 if (c->x86_vendor == X86_VENDOR_AMD)
649 exit_amd_microcode();
650
651 pr_info("Microcode Update Driver: v" MICROCODE_VERSION " removed.\n");
652}
653module_exit(microcode_exit);
654