Port-xen archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: RFC: cpu microcode loading support
On 12/15/11 18:43, Christoph Egger wrote:
Hi,
Support cpu microcode loading for AMD CPUs with NetBSD/amd64,
NetBSD/i386 and NetBSD/Xen.
Get the microcode patch from http://www.amd64.org/support/microcode.html
and put the extracted microcode_amd.bin file into
/libdata/firmware/x86/amd/
Then run cpuctl identify 0 and you should see something like this:
cpu0: UCode version: 0x1000080
After applying the microcode patch with
'cpuctl ucode'
you can see with cpuctl identify 0 that the patch got applied:
cpu0: UCode version: 0x1000083
The patch is a draft for review/comments and not yet for committing.
For x86 I need to make use of xc_broadcast(9) to apply the microcode
on all cpus.
kauth(9) is implemented as requested from tls@ and also
uses xc_broadcast(9) to automatically apply the ucode patch on all cpus.
This version is intended to get committed. Please review.
Christoph
Index: sys/arch/amd64/include/types.h
===================================================================
RCS file: /cvsroot/src/sys/arch/amd64/include/types.h,v
retrieving revision 1.40
diff -u -p -r1.40 types.h
--- sys/arch/amd64/include/types.h 4 Dec 2011 16:24:13 -0000 1.40
+++ sys/arch/amd64/include/types.h 16 Dec 2011 15:07:02 -0000
@@ -108,4 +108,10 @@ typedef volatile unsigned char __cpu_si
#endif /* __x86_64__ */
+#if defined(XEN) && defined(DOM0OPS)
+#define __HAVE_CPU_MICROCODE
+#elif !defined(XEN)
+#define __HAVE_CPU_MICROCODE
+#endif
+
#endif /* _X86_64_MACHTYPES_H_ */
Index: sys/arch/i386/include/types.h
===================================================================
RCS file: /cvsroot/src/sys/arch/i386/include/types.h,v
retrieving revision 1.74
diff -u -p -r1.74 types.h
--- sys/arch/i386/include/types.h 6 Jul 2011 18:46:04 -0000 1.74
+++ sys/arch/i386/include/types.h 16 Dec 2011 15:07:02 -0000
@@ -121,4 +121,10 @@ typedef volatile unsigned char __cpu_si
#define __HAVE_RAS
#endif
+#if defined(XEN) && defined(DOM0OPS)
+#define __HAVE_CPU_MICROCODE
+#elif !defined(XEN)
+#define __HAVE_CPU_MICROCODE
+#endif
+
#endif /* _I386_MACHTYPES_H_ */
Index: sys/arch/x86/conf/files.x86
===================================================================
RCS file: /cvsroot/src/sys/arch/x86/conf/files.x86,v
retrieving revision 1.75
diff -u -p -r1.75 files.x86
--- sys/arch/x86/conf/files.x86 19 Oct 2011 05:22:25 -0000 1.75
+++ sys/arch/x86/conf/files.x86 16 Dec 2011 15:07:02 -0000
@@ -92,6 +92,8 @@ file arch/x86/x86/vm_machdep.c
file arch/x86/x86/x86_autoconf.c
file arch/x86/x86/x86_userconf.c userconf
file arch/x86/x86/x86_machdep.c
+file arch/x86/x86/cpu_ucode.c
+file arch/x86/x86/cpu_ucode_amd.c
define lapic
file arch/x86/x86/lapic.c lapic needs-flag
Index: sys/arch/x86/include/cpu_ucode.h
===================================================================
RCS file: sys/arch/x86/include/cpu_ucode.h
diff -N sys/arch/x86/include/cpu_ucode.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ sys/arch/x86/include/cpu_ucode.h 16 Dec 2011 15:07:02 -0000
@@ -0,0 +1,46 @@
+/* $NetBSD: $ */
+/*
+ * Copyright (c) 2011 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christoph Egger.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _X86_CPU_UCODE_H_
+#define _X86_CPU_UCODE_H_
+
+#include <sys/cpuio.h>
+#include <dev/firmload.h>
+
+struct mc_softc {
+ char *sc_blob;
+ off_t sc_blobsize;
+};
+
+int cpu_ucode_amd_get_version(struct cpu_ucode *);
+int cpu_ucode_amd_firmware_open(firmware_handle_t *fwh);
+int cpu_ucode_amd_apply(struct mc_softc *);
+
+#endif
Index: sys/arch/xen/conf/files.xen
===================================================================
RCS file: /cvsroot/src/sys/arch/xen/conf/files.xen,v
retrieving revision 1.123
diff -u -p -r1.123 files.xen
--- sys/arch/xen/conf/files.xen 22 Sep 2011 23:02:34 -0000 1.123
+++ sys/arch/xen/conf/files.xen 16 Dec 2011 15:07:02 -0000
@@ -92,6 +92,8 @@ file arch/xen/x86/x86_xpmap.c
file arch/xen/x86/xen_pmap.c
file arch/xen/x86/xen_intr.c
file arch/xen/x86/xenfunc.c
+file arch/xen/xen/xen_ucode.c dom0ops
+file arch/x86/x86/cpu_ucode_amd.c dom0ops
file arch/xen/xen/xen_machdep.c
file arch/xen/xen/xen_debug.c
Index: sys/arch/xen/xen/xen_ucode.c
===================================================================
RCS file: sys/arch/xen/xen/xen_ucode.c
diff -N sys/arch/xen/xen/xen_ucode.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ sys/arch/xen/xen/xen_ucode.c 16 Dec 2011 15:07:02 -0000
@@ -0,0 +1,140 @@
+/* $NetBSD: $ */
+/*
+ * Copyright (c) 2011 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christoph Egger.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: $");
+
+#include <sys/param.h>
+#include <sys/cpuio.h>
+#include <sys/cpu.h>
+
+#include <dev/firmload.h>
+
+#include <machine/cpuvar.h>
+#include <machine/cputypes.h>
+
+#include <x86/cpu_ucode.h>
+
+static struct mc_softc ucode_softc;
+
+int
+cpu_ucode_get_version(void *data)
+{
+ struct cpu_ucode *ucode = data;
+
+ switch (cpu_vendor) {
+ case CPUVENDOR_AMD:
+ return cpu_ucode_amd_get_version(ucode);
+ default:
+ ucode->version = (uint64_t)-1;
+ return ENOTSUP;
+ }
+
+ return 0;
+}
+
+static int
+cpu_ucode_load(const char *fwname)
+{
+ struct mc_softc *sc = &ucode_softc;
+ firmware_handle_t fwh;
+ int error;
+ off_t size;
+
+ if (sc->sc_blob != NULL) {
+ firmware_free(sc->sc_blob, 0);
+ sc->sc_blob = NULL;
+ }
+
+ switch (cpu_vendor) {
+ case CPUVENDOR_AMD:
+ error = cpu_ucode_amd_firmware_open(&fwh);
+ break;
+ case CPUVENDOR_INTEL:
+ /* fw_path = "x86/intel"; */
+ return ENOTSUP;
+ default:
+ return ENOTSUP;
+ }
+
+ if (error) {
+ aprint_error("ucode: firmware_open failed: %i\n", error);
+ goto err0;
+ }
+
+ sc->sc_blobsize = size = firmware_get_size(fwh);
+
+ sc->sc_blob = firmware_malloc(size);
+ if (sc->sc_blob == NULL) {
+ error = ENOMEM;
+ firmware_close(fwh);
+ goto err0;
+ }
+
+ error = firmware_read(fwh, 0, sc->sc_blob, size);
+ firmware_close(fwh);
+ if (error != 0)
+ goto err1;
+
+ sc->sc_blobsize = size;
+ return 0;
+
+err1:
+ firmware_free(sc->sc_blob, 0);
+ sc->sc_blob = NULL;
+ sc->sc_blobsize = 0;
+err0:
+ return error;
+}
+
+int
+cpu_ucode_apply(void *data)
+{
+ struct cpu_ucode *ucode = data;
+ struct mc_softc *sc = &ucode_softc;
+ struct xen_platform_op op;
+ int error;
+
+ error = cpu_ucode_load(ucode->fwname);
+ if (error)
+ return error;
+
+ op.cmd = XENPF_microcode_update;
+ set_xen_guest_handle(op.u.microcode.data, sc->sc_blob);
+ op.u.microcode.length = sc->sc_blobsize;
+
+ error = -HYPERVISOR_platform_op(&op);
+
+ if (sc->sc_blob)
+ firmware_free(sc->sc_blob, 0);
+ sc->sc_blob = NULL;
+ sc->sc_blobsize = 0;
+ return error;
+}
Index: sys/arch/x86/x86/cpu_ucode.c
===================================================================
RCS file: sys/arch/x86/x86/cpu_ucode.c
diff -N sys/arch/x86/x86/cpu_ucode.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ sys/arch/x86/x86/cpu_ucode.c 16 Dec 2011 15:07:02 -0000
@@ -0,0 +1,149 @@
+/* $NetBSD: $ */
+/*
+ * Copyright (c) 2011 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christoph Egger.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: $");
+
+#include <sys/param.h>
+#include <sys/cpuio.h>
+#include <sys/cpu.h>
+
+#include <dev/firmload.h>
+
+#include <machine/cpuvar.h>
+#include <machine/cputypes.h>
+
+#include <x86/cpu_ucode.h>
+
+static struct mc_softc ucode_softc;
+
+int
+cpu_ucode_get_version(void *data)
+{
+ struct cpu_ucode *ucode = data;
+
+ switch (cpu_vendor) {
+ case CPUVENDOR_AMD:
+ return cpu_ucode_amd_get_version(ucode);
+ default:
+ ucode->version = (uint64_t)-1;
+ return ENOTSUP;
+ }
+
+ return 0;
+}
+
+static int
+cpu_ucode_load(struct mc_softc *sc, const char *fwname)
+{
+ firmware_handle_t fwh = NULL;
+ int error;
+ off_t size;
+
+ if (sc->sc_blob != NULL) {
+ firmware_free(sc->sc_blob, 0);
+ sc->sc_blob = NULL;
+ sc->sc_blobsize = 0;
+ }
+
+ switch (cpu_vendor) {
+ case CPUVENDOR_AMD:
+ error = cpu_ucode_amd_firmware_open(&fwh);
+ break;
+ case CPUVENDOR_INTEL:
+ /* fw_path = "x86/intel"; */
+ return ENOTSUP; /* not yet supported */
+ default:
+ return ENOTSUP;
+ }
+
+ if (error) {
+ aprint_error("ucode: firmware_open failed: %i\n", error);
+ goto err0;
+ }
+
+ sc->sc_blobsize = size = firmware_get_size(fwh);
+#if 0
+ if (size < sizeof(struct microcode_amd_header)) {
+ aprint_error("ucode: image '%s' has no header\n",
+ fwname);
+ error = EIO;
+ goto err0;
+ }
+#endif
+
+ sc->sc_blob = firmware_malloc(size);
+ if (sc->sc_blob == NULL) {
+ error = ENOMEM;
+ firmware_close(fwh);
+ goto err0;
+ }
+
+ error = firmware_read(fwh, 0, sc->sc_blob, size);
+ firmware_close(fwh);
+ if (error != 0)
+ goto err1;
+
+ sc->sc_blobsize = size;
+ return 0;
+
+err1:
+ firmware_free(sc->sc_blob, 0);
+err0:
+ sc->sc_blob = NULL;
+ sc->sc_blobsize = 0;
+ return error;
+}
+
+int
+cpu_ucode_apply(void *data)
+{
+ struct cpu_ucode *ucode = data;
+ struct mc_softc *sc = &ucode_softc;
+ int error;
+
+ error = cpu_ucode_load(sc, ucode->fwname);
+ if (error)
+ return error;
+
+ switch (cpu_vendor) {
+ case CPUVENDOR_AMD:
+ error = cpu_ucode_amd_apply(sc);
+ break;
+ default:
+ return ENOTSUP;
+ }
+
+ if (sc->sc_blob)
+ firmware_free(sc->sc_blob, 0);
+ sc->sc_blob = NULL;
+ sc->sc_blobsize = 0;
+ return error;
+}
Index: sys/arch/x86/x86/cpu_ucode_amd.c
===================================================================
RCS file: sys/arch/x86/x86/cpu_ucode_amd.c
diff -N sys/arch/x86/x86/cpu_ucode_amd.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ sys/arch/x86/x86/cpu_ucode_amd.c 16 Dec 2011 15:07:02 -0000
@@ -0,0 +1,288 @@
+/* $NetBSD: $ */
+/*
+ * Copyright (c) 2011 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christoph Egger.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: $");
+
+#include "opt_xen.h"
+
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/cpuio.h>
+#include <sys/cpu.h>
+#include <sys/kmem.h>
+#include <sys/xcall.h>
+
+#include <machine/cpufunc.h>
+#include <machine/specialreg.h>
+#include <x86/cpu_ucode.h>
+
+struct microcode_amd_header {
+ uint32_t ah_data_code;
+ uint32_t ah_patch_id;
+ uint8_t ah_patch_data_id[2];
+ uint8_t ah_patch_data_len;
+ uint8_t ah_init_flag;
+ uint32_t ah_patch_data_checksum;
+ uint32_t ah_nb_dev_id;
+ uint32_t ah_sb_dev_id;
+ uint16_t ah_processor_rev_id;
+ uint8_t ah_nb_rev_id;
+ uint8_t ah_sb_rev_id;
+ uint8_t ah_bios_api_rev;
+ uint8_t ah_reserved[3];
+ uint32_t ah_match_reg[8];
+} __packed;
+
+/* equivalence cpu table */
+struct microcode_amd_equiv_cpu_table {
+ uint32_t ect_installed_cpu;
+ uint32_t ect_fixed_errata_mask;
+ uint32_t ect_fixed_errata_compare;
+ uint16_t ect_equiv_cpu;
+ uint16_t ect_reserved;
+};
+
+#define UCODE_MAGIC 0x00414d44
+
+struct microcode_amd {
+ uint8_t *mpb; /* microcode patch block */
+ size_t mpb_size;
+ struct microcode_amd_equiv_cpu_table *ect;
+ size_t ect_size;
+};
+
+struct mpbhdr {
+#define UCODE_TYPE_EQUIV 0
+#define UCODE_TYPE_PATCH 1
+ uint32_t mpb_type;
+ uint32_t mpb_len;
+ uint32_t mpb_data[];
+};
+
+static uint32_t
+amd_cpufamily(void)
+{
+ uint32_t family;
+ struct cpu_info *ci = curcpu();
+
+ family = CPUID2FAMILY(ci->ci_signature);
+ if (family == 0xf)
+ family += CPUID2EXTFAMILY(ci->ci_signature);
+
+ return family;
+}
+
+int
+cpu_ucode_amd_get_version(struct cpu_ucode *ucode)
+{
+ if (amd_cpufamily() < 0x10) {
+ ucode->version = (uint64_t)-1;
+ return ENOTSUP;
+ }
+
+ ucode->version = rdmsr(MSR_UCODE_AMD_PATCHLEVEL);
+ return 0;
+}
+
+int
+cpu_ucode_amd_firmware_open(firmware_handle_t *fwh)
+{
+ const char *fw_path = "x86/amd";
+ char fwname[32];
+ int error;
+
+ snprintf(fwname, sizeof(fwname), "microcode_amd_fam%xh.bin",
+ amd_cpufamily());
+
+ error = firmware_open(fw_path, fwname, fwh);
+ if (error == 0)
+ return 0;
+
+ return firmware_open(fw_path, "microcode_amd.bin", fwh);
+}
+
+#ifndef XEN
+struct mc_buf {
+ uint8_t *mc_buf;
+ uint32_t mc_equiv_cpuid;
+ struct mpbhdr *mc_mpbuf;
+ struct microcode_amd *mc_amd;
+ int mc_error;
+};
+
+static void
+cpu_apply_cb(void *arg0, void *arg1)
+{
+ int error = 0;
+ const struct mc_softc *sc = arg0;
+ struct microcode_amd mc_amd;
+ struct mc_buf mc;
+ device_t dev;
+
+ memcpy(&mc, arg1, sizeof(mc));
+ mc_amd.mpb = mc.mc_amd->mpb;
+ mc_amd.mpb_size = mc.mc_amd->mpb_size;
+
+ dev = curcpu()->ci_dev;
+
+ do {
+ uint64_t patchlevel;
+ struct microcode_amd_header *hdr;
+
+ if (mc.mc_mpbuf->mpb_type != UCODE_TYPE_PATCH) {
+ aprint_debug_dev(dev, "ucode: patch type expected\n");
+ goto next;
+ }
+
+ hdr = (struct microcode_amd_header *)mc_amd.mpb;
+ if (hdr->ah_processor_rev_id != mc.mc_equiv_cpuid) {
+ aprint_debug_dev(dev, "ucode: patch does not"
+ "match this cpu "
+ "(patch is for cpu id %x, cpu id is %x)\n",
+ hdr->ah_processor_rev_id, mc.mc_equiv_cpuid);
+ goto next;
+ }
+
+ patchlevel = rdmsr(MSR_UCODE_AMD_PATCHLEVEL);
+ if (hdr->ah_patch_id <= patchlevel)
+ goto next;
+
+ /* found matching microcode update */
+ wrmsr(MSR_UCODE_AMD_PATCHLOADER, (u_long)hdr);
+
+ /* check current patch id and patch's id for match */
+ if (patchlevel == rdmsr(MSR_UCODE_AMD_PATCHLEVEL)) {
+ aprint_debug_dev(dev, "ucode: update from revision "
+ "0x%"PRIx64" to 0x%x failed\n",
+ patchlevel, hdr->ah_patch_id);
+ error = EIO;
+ goto out;
+ } else {
+ /* Success */
+ error = 0;
+ goto out;
+ }
+
+next:
+ mc.mc_buf += mc.mc_mpbuf->mpb_len +
+ sizeof(mc.mc_mpbuf->mpb_type) +
+ sizeof(mc.mc_mpbuf->mpb_len);
+ mc.mc_mpbuf = (struct mpbhdr *)mc.mc_buf;
+ mc_amd.mpb = (uint8_t *)mc.mc_mpbuf->mpb_data;
+ mc_amd.mpb_size = mc.mc_mpbuf->mpb_len;
+
+ } while ((uintptr_t)((mc.mc_buf) - (uint8_t *)sc->sc_blob) <
sc->sc_blobsize);
+ aprint_error_dev(dev, "ucode: No newer patch available "
+ "for this cpu than is already installed.\n");
+ error = ENOENT;
+
+out:
+ if (error)
+ ((struct mc_buf *)(arg1))->mc_error = error;
+}
+
+int
+cpu_ucode_amd_apply(struct mc_softc *sc)
+{
+ int i, error = 0;
+ uint32_t *magic;
+ uint32_t cpu_signature;
+ uint32_t equiv_cpuid = 0;
+ struct mc_buf mc;
+ int where;
+
+ cpu_signature = curcpu()->ci_signature;
+
+ KASSERT(sc->sc_blob != NULL);
+ magic = (uint32_t *)sc->sc_blob;
+ if (*magic != UCODE_MAGIC) {
+ aprint_error("ucode: wrong file magic\n");
+ return EINVAL;
+ }
+
+ mc.mc_buf = &sc->sc_blob[sizeof(*magic)];
+ mc.mc_mpbuf = (struct mpbhdr *)mc.mc_buf;
+
+ /* equivalence table is expected to come first */
+ if (mc.mc_mpbuf->mpb_type != UCODE_TYPE_EQUIV) {
+ aprint_error("ucode: missing equivalence table\n");
+ return EINVAL;
+ }
+
+ mc.mc_amd = kmem_zalloc(sizeof(*mc.mc_amd), KM_NOSLEEP);
+ if (mc.mc_amd == NULL)
+ return ENOMEM;
+
+ mc.mc_amd->ect = kmem_alloc(mc.mc_mpbuf->mpb_len, KM_NOSLEEP);
+ if (mc.mc_amd->ect == NULL) {
+ error = ENOMEM;
+ goto err0;
+ }
+
+ memcpy(mc.mc_amd->ect, mc.mc_mpbuf->mpb_data, mc.mc_mpbuf->mpb_len);
+ mc.mc_amd->ect_size = mc.mc_mpbuf->mpb_len;
+
+ /* check if there is a patch for this cpu present */
+ for (i = 0; mc.mc_amd->ect[i].ect_installed_cpu != 0; i++) {
+ if (cpu_signature == mc.mc_amd->ect[i].ect_installed_cpu) {
+ /* keep extended family and extended model */
+ equiv_cpuid = mc.mc_amd->ect[i].ect_equiv_cpu & 0xffff;
+ break;
+ }
+ }
+ if (equiv_cpuid == 0) {
+ aprint_error("ucode: No patch available for this cpu\n");
+ error = ENOENT;
+ goto err1;
+ }
+
+ mc.mc_equiv_cpuid = equiv_cpuid;
+ mc.mc_buf += mc.mc_mpbuf->mpb_len + sizeof(mc.mc_mpbuf->mpb_type) +
+ sizeof(mc.mc_mpbuf->mpb_len);
+ mc.mc_mpbuf = (struct mpbhdr *)mc.mc_buf;
+ mc.mc_amd->mpb = (uint8_t *)mc.mc_mpbuf->mpb_data;
+ mc.mc_amd->mpb_size = mc.mc_mpbuf->mpb_len;
+
+ /* Apply it on all cpus */
+ mc.mc_error = 0;
+ where = xc_broadcast(XC_HIGHPRI, cpu_apply_cb, sc, &mc);
+
+ /* Wait for completion */
+ xc_wait(where);
+ error = mc.mc_error;
+
+err1:
+ kmem_free(mc.mc_amd->ect, mc.mc_amd->ect_size);
+err0:
+ kmem_free(mc.mc_amd, sizeof(*mc.mc_amd));
+ return error;
+}
+#endif
Index: sys/kern/kern_cpu.c
===================================================================
RCS file: /cvsroot/src/sys/kern/kern_cpu.c,v
retrieving revision 1.52
diff -u -p -r1.52 kern_cpu.c
--- sys/kern/kern_cpu.c 29 Oct 2011 11:41:32 -0000 1.52
+++ sys/kern/kern_cpu.c 16 Dec 2011 15:07:02 -0000
@@ -245,6 +245,21 @@ cpuctl_ioctl(dev_t dev, u_long cmd, void
*(int *)data = ncpu;
break;
+#ifdef __HAVE_CPU_MICROCODE
+ case IOC_CPU_UCODE_GET_VERSION:
+ error = cpu_ucode_get_version(data);
+ break;
+
+ case IOC_CPU_UCODE_APPLY:
+ error = kauth_authorize_system(l->l_cred,
+ KAUTH_SYSTEM_CPU, KAUTH_REQ_SYSTEM_CPU_UCODE_APPLY,
+ data, NULL, NULL);
+ if (error != 0)
+ break;
+ error = cpu_ucode_apply(data);
+ break;
+#endif
+
default:
error = ENOTTY;
break;
Index: sys/secmodel/suser/secmodel_suser.c
===================================================================
RCS file: /cvsroot/src/sys/secmodel/suser/secmodel_suser.c,v
retrieving revision 1.36
diff -u -p -r1.36 secmodel_suser.c
--- sys/secmodel/suser/secmodel_suser.c 4 Dec 2011 19:25:01 -0000 1.36
+++ sys/secmodel/suser/secmodel_suser.c 16 Dec 2011 15:07:02 -0000
@@ -248,6 +248,7 @@ secmodel_suser_system_cb(kauth_cred_t cr
case KAUTH_SYSTEM_CPU:
switch (req) {
case KAUTH_REQ_SYSTEM_CPU_SETSTATE:
+ case KAUTH_REQ_SYSTEM_CPU_UCODE_APPLY:
if (isroot)
result = KAUTH_RESULT_ALLOW;
Index: sys/sys/cpu.h
===================================================================
RCS file: /cvsroot/src/sys/sys/cpu.h,v
retrieving revision 1.33
diff -u -p -r1.33 cpu.h
--- sys/sys/cpu.h 7 Aug 2011 13:33:02 -0000 1.33
+++ sys/sys/cpu.h 16 Dec 2011 15:07:02 -0000
@@ -102,6 +102,12 @@ cpu_name(struct cpu_info *ci)
{
return ci->ci_data.cpu_name;
}
+
+#ifdef __HAVE_CPU_MICROCODE
+int cpu_ucode_get_version(void *);
+int cpu_ucode_apply(void *);
+#endif
+
#endif
#endif /* !_LOCORE */
Index: sys/sys/cpuio.h
===================================================================
RCS file: /cvsroot/src/sys/sys/cpuio.h,v
retrieving revision 1.5
diff -u -p -r1.5 cpuio.h
--- sys/sys/cpuio.h 11 Sep 2011 14:54:49 -0000 1.5
+++ sys/sys/cpuio.h 16 Dec 2011 15:07:02 -0000
@@ -62,4 +62,12 @@ typedef struct cpustate {
#define IOC_CPU_GETCOUNT _IOR('c', 2, int)
#define IOC_CPU_MAPID _IOWR('c', 3, int)
+struct cpu_ucode {
+ uint64_t version;
+ char fwname[PATH_MAX];
+};
+
+#define IOC_CPU_UCODE_GET_VERSION _IOR('c', 4, struct cpu_ucode)
+#define IOC_CPU_UCODE_APPLY _IOW('c', 5, struct cpu_ucode)
+
#endif /* !_SYS_CPUIO_H_ */
Index: sys/sys/kauth.h
===================================================================
RCS file: /cvsroot/src/sys/sys/kauth.h,v
retrieving revision 1.66
diff -u -p -r1.66 kauth.h
--- sys/sys/kauth.h 4 Dec 2011 19:25:01 -0000 1.66
+++ sys/sys/kauth.h 16 Dec 2011 15:07:02 -0000
@@ -109,6 +109,7 @@ enum kauth_system_req {
KAUTH_REQ_SYSTEM_CHROOT_CHROOT=1,
KAUTH_REQ_SYSTEM_CHROOT_FCHROOT,
KAUTH_REQ_SYSTEM_CPU_SETSTATE,
+ KAUTH_REQ_SYSTEM_CPU_UCODE_APPLY,
KAUTH_REQ_SYSTEM_DEBUG_IPKDB,
KAUTH_REQ_SYSTEM_MOUNT_GET,
KAUTH_REQ_SYSTEM_MOUNT_NEW,
Index: usr.sbin/cpuctl/cpuctl.c
===================================================================
RCS file: /cvsroot/src/usr.sbin/cpuctl/cpuctl.c,v
retrieving revision 1.19
diff -u -p -r1.19 cpuctl.c
--- usr.sbin/cpuctl/cpuctl.c 27 Sep 2011 11:24:21 -0000 1.19
+++ usr.sbin/cpuctl/cpuctl.c 16 Dec 2011 15:07:02 -0000
@@ -63,6 +63,7 @@ static void cpu_offline(char **);
static void cpu_online(char **);
static void cpu_intr(char **);
static void cpu_nointr(char **);
+static void cpu_ucode(char **);
static struct cmdtab {
const char *label;
@@ -75,6 +76,7 @@ static struct cmdtab {
{ "online", 1, cpu_online },
{ "intr", 1, cpu_intr },
{ "nointr", 1, cpu_nointr },
+ { "ucode", 0, cpu_ucode },
{ NULL, 0, NULL },
};
@@ -119,6 +121,7 @@ usage(void)
fprintf(stderr, " %s online cpuno\n", progname);
fprintf(stderr, " %s intr cpuno\n", progname);
fprintf(stderr, " %s nointr cpuno\n", progname);
+ fprintf(stderr, " %s ucode [file]\n", progname);
exit(EXIT_FAILURE);
/* NOTREACHED */
}
@@ -181,11 +184,28 @@ cpu_nointr(char **argv)
}
static void
+cpu_ucode(char **argv)
+{
+ int error;
+ struct cpu_ucode uc;
+
+ if (argv[0] != NULL)
+ strlcpy(uc.fwname, argv[0], sizeof(uc.fwname));
+
+ error = ioctl(fd, IOC_CPU_UCODE_APPLY, &uc);
+ if (error < 0)
+ err(EXIT_FAILURE, "IOC_CPU_UCODE_APPLY");
+}
+
+
+static void
cpu_identify(char **argv)
{
char name[32];
unsigned int id, np;
cpuset_t *cpuset;
+ struct cpu_ucode ucode;
+ char ucbuf[16];
np = sysconf(_SC_NPROCESSORS_CONF);
id = getcpuid(argv);
@@ -209,6 +229,16 @@ cpu_identify(char **argv)
cpuset_destroy(cpuset);
}
identifycpu(name);
+
+ if (ioctl(fd, IOC_CPU_UCODE_GET_VERSION, &ucode) < 0)
+ ucode.version = (uint64_t)-1;
+ if (ucode.version == (uint64_t)-1)
+ strcpy(ucbuf, "?");
+ else
+ snprintf(ucbuf, sizeof(ucbuf), "0x%"PRIx64,
+ ucode.version);
+
+ printf("%s: UCode version: %s\n", name, ucbuf);
}
static u_int
@@ -242,7 +272,7 @@ cpu_list(char **argv)
err(EXIT_FAILURE, "IOC_CPU_GETCOUNT");
printf(
-"Num HwId Unbound LWPs Interrupts Last change #Intr\n"
+"Num HwId Unbound LWPs Interrupts Last change #Intr \n"
"---- ---- ------------ ---------- ------------------------ -----\n");
for (i = 0; i < cnt; i++) {
@@ -263,11 +293,13 @@ cpu_list(char **argv)
strcpy(ibuf, "?");
else
snprintf(ibuf, sizeof(ibuf), "%d", cs.cs_intrcnt - 1);
+
lastmod = (time_t)cs.cs_lastmod |
((time_t)cs.cs_lastmodhi << 32);
ts = asctime(localtime(&lastmod));
ts[strlen(ts) - 1] = '\0';
- printf("%-4d %-4x %-12s %-10s %s %s\n", i, cs.cs_hwid, state,
+ printf("%-4d %-4x %-12s %-10s %s %-5s\n",
+ i, cs.cs_hwid, state,
intr, ts, ibuf);
}
}
Home |
Main Index |
Thread Index |
Old Index