From 12dd335c3c106f7d6a2741fa91e69109cc06f2cf Mon Sep 17 00:00:00 2001 From: Ian Campbell Date: Mon, 12 Nov 2012 16:54:04 +0000 Subject: [PATCH] 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 --- debian/changelog | 1 + .../patches/features/all/xen/microcode.patch | 295 ++++++++++++++++++ debian/patches/series | 2 + 3 files changed, 298 insertions(+) create mode 100644 debian/patches/features/all/xen/microcode.patch diff --git a/debian/changelog b/debian/changelog index 4f3f95039..cf78213de 100644 --- a/debian/changelog +++ b/debian/changelog @@ -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 Wed, 24 Oct 2012 14:15:57 +0100 diff --git a/debian/patches/features/all/xen/microcode.patch b/debian/patches/features/all/xen/microcode.patch new file mode 100644 index 000000000..e1bcdd39b --- /dev/null +++ b/debian/patches/features/all/xen/microcode.patch @@ -0,0 +1,295 @@ +From 23757fb5d6781bf945d21d1f5373aa71122cbea9 Mon Sep 17 00:00:00 2001 +From: Jeremy Fitzhardinge +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 +--- + +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 + #include + ++#include + #include + #include + +@@ -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 ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include ++#include ++ ++#include ++#include ++ ++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 µcode_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 diff --git a/debian/patches/series b/debian/patches/series index e2577480d..db9262141 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -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