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