xen: add Xen microcode driver for Wheezy. (Closes: #693053)

This should go away and be replaced by the in-hypervisor pre-dom0 loader in
Jessie.

svn path=/dists/sid/linux/; revision=19497
This commit is contained in:
Ian Campbell 2012-11-12 16:54:04 +00:00
parent 17cceef83a
commit 12dd335c3c
3 changed files with 298 additions and 0 deletions

1
debian/changelog vendored
View File

@ -43,6 +43,7 @@ linux (3.2.33-1) UNRELEASED; urgency=low
* [x86] asus-laptop: Do not call HWRS on init (Closes: #692436)
* [x86] drm/i915: Only kick out vesafb if we takeover the fbcon with KMS
(Closes: #686284)
* [xen] add support for microcode updating. (Closes: #693053)
-- Ben Hutchings <ben@decadent.org.uk> Wed, 24 Oct 2012 14:15:57 +0100

View File

@ -0,0 +1,295 @@
From 23757fb5d6781bf945d21d1f5373aa71122cbea9 Mon Sep 17 00:00:00 2001
From: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
Date: Fri, 27 Mar 2009 17:39:15 -0700
Subject: [PATCH] xen: add CPU microcode update driver
Xen does all the hard work for us, including choosing the right update
method for this cpu type and actually doing it for all cpus. We just
need to supply it with the firmware blob.
Because Xen updates all CPUs (and the kernel's virtual cpu numbers have
no fixed relationship with the underlying physical cpus), we only bother
doing anything for cpu "0".
[ Impact: allow CPU microcode update in Xen dom0 ]
Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
---
Takes from git://git.kernel.org/pub/scm/linux/kernel/git/jeremy/xen.git#upstream/microcode
arch/x86/include/asm/microcode.h | 9 ++
arch/x86/kernel/Makefile | 1 +
arch/x86/kernel/microcode_core.c | 5 +-
arch/x86/kernel/microcode_xen.c | 198 ++++++++++++++++++++++++++++++++++++++
arch/x86/xen/Kconfig | 4 +
5 files changed, 216 insertions(+), 1 deletion(-)
create mode 100644 arch/x86/kernel/microcode_xen.c
Index: linux/arch/x86/include/asm/microcode.h
===================================================================
--- linux.orig/arch/x86/include/asm/microcode.h 2012-10-30 23:27:11.000000000 +0000
+++ linux/arch/x86/include/asm/microcode.h 2012-11-09 10:59:49.000000000 +0000
@@ -61,4 +61,13 @@
}
#endif
+#ifdef CONFIG_MICROCODE_XEN
+extern struct microcode_ops * __init init_xen_microcode(void);
+#else
+static inline struct microcode_ops * __init init_xen_microcode(void)
+{
+ return NULL;
+}
+#endif
+
#endif /* _ASM_X86_MICROCODE_H */
Index: linux/arch/x86/kernel/Makefile
===================================================================
--- linux.orig/arch/x86/kernel/Makefile 2012-10-30 23:27:11.000000000 +0000
+++ linux/arch/x86/kernel/Makefile 2012-11-09 10:59:49.000000000 +0000
@@ -92,6 +92,7 @@
microcode-y := microcode_core.o
microcode-$(CONFIG_MICROCODE_INTEL) += microcode_intel.o
microcode-$(CONFIG_MICROCODE_AMD) += microcode_amd.o
+microcode-$(CONFIG_MICROCODE_XEN) += microcode_xen.o
obj-$(CONFIG_MICROCODE) += microcode.o
obj-$(CONFIG_X86_CHECK_BIOS_CORRUPTION) += check.o
Index: linux/arch/x86/kernel/microcode_core.c
===================================================================
--- linux.orig/arch/x86/kernel/microcode_core.c 2012-11-09 10:18:15.000000000 +0000
+++ linux/arch/x86/kernel/microcode_core.c 2012-11-09 10:59:49.000000000 +0000
@@ -84,6 +84,7 @@
#include <linux/mm.h>
#include <linux/syscore_ops.h>
+#include <xen/xen.h>
#include <asm/microcode.h>
#include <asm/processor.h>
@@ -518,7 +519,9 @@
struct cpuinfo_x86 *c = &cpu_data(0);
int error;
- if (c->x86_vendor == X86_VENDOR_INTEL)
+ if (xen_pv_domain())
+ microcode_ops = init_xen_microcode();
+ else if (c->x86_vendor == X86_VENDOR_INTEL)
microcode_ops = init_intel_microcode();
else if (c->x86_vendor == X86_VENDOR_AMD)
microcode_ops = init_amd_microcode();
Index: linux/arch/x86/kernel/microcode_xen.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux/arch/x86/kernel/microcode_xen.c 2012-11-09 10:59:49.000000000 +0000
@@ -0,0 +1,198 @@
+/*
+ * Xen microcode update driver
+ *
+ * Xen does most of the work here. We just pass the whole blob into
+ * Xen, and it will apply it to all CPUs as appropriate. Xen will
+ * worry about how different CPU models are actually updated.
+ */
+#include <linux/sched.h>
+#include <linux/module.h>
+#include <linux/firmware.h>
+#include <linux/vmalloc.h>
+#include <linux/uaccess.h>
+
+#include <asm/microcode.h>
+
+#include <xen/xen.h>
+#include <xen/interface/platform.h>
+#include <xen/interface/xen.h>
+
+#include <asm/xen/hypercall.h>
+#include <asm/xen/hypervisor.h>
+
+MODULE_DESCRIPTION("Xen microcode update driver");
+MODULE_LICENSE("GPL");
+
+struct xen_microcode {
+ size_t len;
+ char data[0];
+};
+
+static int xen_microcode_update(int cpu)
+{
+ int err;
+ struct xen_platform_op op;
+ struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+ struct xen_microcode *uc = uci->mc;
+
+ if (uc == NULL || uc->len == 0) {
+ /*
+ * We do all cpus at once, so we don't need to do
+ * other cpus explicitly (besides, these vcpu numbers
+ * have no relationship to underlying physical cpus).
+ */
+ return 0;
+ }
+
+ op.cmd = XENPF_microcode_update;
+ set_xen_guest_handle(op.u.microcode.data, uc->data);
+ op.u.microcode.length = uc->len;
+
+ err = HYPERVISOR_dom0_op(&op);
+
+ if (err != 0)
+ printk(KERN_WARNING "microcode_xen: microcode update failed: %d\n", err);
+
+ return err;
+}
+
+static enum ucode_state xen_request_microcode_fw(int cpu, struct device *device)
+{
+ char name[30];
+ struct cpuinfo_x86 *c = &cpu_data(cpu);
+ const struct firmware *firmware;
+ struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+ enum ucode_state ret;
+ struct xen_microcode *uc;
+ size_t size;
+ int err;
+
+ switch (c->x86_vendor) {
+ case X86_VENDOR_INTEL:
+ snprintf(name, sizeof(name), "intel-ucode/%02x-%02x-%02x",
+ c->x86, c->x86_model, c->x86_mask);
+ break;
+
+ case X86_VENDOR_AMD:
+ snprintf(name, sizeof(name), "amd-ucode/microcode_amd.bin");
+ break;
+
+ default:
+ return UCODE_NFOUND;
+ }
+
+ err = request_firmware(&firmware, name, device);
+ if (err) {
+ pr_debug("microcode: data file %s load failed\n", name);
+ return UCODE_NFOUND;
+ }
+
+ /*
+ * Only bother getting real firmware for cpu 0; the others get
+ * dummy placeholders.
+ */
+ if (cpu == 0)
+ size = firmware->size;
+ else
+ size = 0;
+
+ if (uci->mc != NULL) {
+ vfree(uci->mc);
+ uci->mc = NULL;
+ }
+
+ ret = UCODE_ERROR;
+ uc = vmalloc(sizeof(*uc) + size);
+ if (uc == NULL)
+ goto out;
+
+ ret = UCODE_OK;
+ uc->len = size;
+ memcpy(uc->data, firmware->data, uc->len);
+
+ uci->mc = uc;
+
+out:
+ release_firmware(firmware);
+
+ return ret;
+}
+
+static enum ucode_state xen_request_microcode_user(int cpu,
+ const void __user *buf, size_t size)
+{
+ struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+ struct xen_microcode *uc;
+ enum ucode_state ret;
+ size_t unread;
+
+ if (cpu != 0) {
+ /* No real firmware for non-zero cpus; just store a
+ placeholder */
+ size = 0;
+ }
+
+ if (uci->mc != NULL) {
+ vfree(uci->mc);
+ uci->mc = NULL;
+ }
+
+ ret = UCODE_ERROR;
+ uc = vmalloc(sizeof(*uc) + size);
+ if (uc == NULL)
+ goto out;
+
+ uc->len = size;
+
+ ret = UCODE_NFOUND;
+
+ unread = copy_from_user(uc->data, buf, size);
+
+ if (unread != 0) {
+ printk(KERN_WARNING "failed to read %zd of %zd bytes at %p -> %p\n",
+ unread, size, buf, uc->data);
+ goto out;
+ }
+
+ ret = UCODE_OK;
+
+out:
+ if (ret == 0)
+ uci->mc = uc;
+ else
+ vfree(uc);
+
+ return ret;
+}
+
+static void xen_microcode_fini_cpu(int cpu)
+{
+ struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+
+ vfree(uci->mc);
+ uci->mc = NULL;
+}
+
+static int xen_collect_cpu_info(int cpu, struct cpu_signature *sig)
+{
+ sig->sig = 0;
+ sig->pf = 0;
+ sig->rev = 0;
+
+ return 0;
+}
+
+static struct microcode_ops microcode_xen_ops = {
+ .request_microcode_user = xen_request_microcode_user,
+ .request_microcode_fw = xen_request_microcode_fw,
+ .collect_cpu_info = xen_collect_cpu_info,
+ .apply_microcode = xen_microcode_update,
+ .microcode_fini_cpu = xen_microcode_fini_cpu,
+};
+
+struct microcode_ops * __init init_xen_microcode(void)
+{
+ if (!xen_initial_domain())
+ return NULL;
+ return &microcode_xen_ops;
+}
Index: linux/arch/x86/xen/Kconfig
===================================================================
--- linux.orig/arch/x86/xen/Kconfig 2012-10-30 23:27:11.000000000 +0000
+++ linux/arch/x86/xen/Kconfig 2012-11-09 11:00:42.000000000 +0000
@@ -48,3 +48,7 @@
help
Enable statistics output and various tuning options in debugfs.
Enabling this option may incur a significant performance overhead.
+
+config MICROCODE_XEN
+ def_bool y
+ depends on XEN_DOM0 && MICROCODE

View File

@ -406,3 +406,5 @@ bugfix/all/use-clamp_t-in-UNAME26-fix.patch
debian/fs-writeback-avoid-ABI-change-in-3.2.32.patch
bugfix/x86/asus-laptop-Do-not-call-HWRS-on-init.patch
bugfix/x86/drm-i915-Only-kick-out-vesafb-if-we-takeover-the-fbc.patch
features/all/xen/microcode.patch