Port-i386 archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

microcode update for Intel CPUs



Hi -

Here is a patch which implements microcode updates for Intel CPUs.
It mostly uses the framework added by Christoph Egger a while ago,
which is for AMD CPUs only.

I've extended the framework somewhat, to allow for MD data structures,
and to allow to keep complexity out of the kernel. In particular,
the newly added mode follows more the (Open)Solaris way -- it
constructs a path name from CPU version data and loads exactly
this particular image, without need to parse unrelated data.

Binary compatibility to previous userland cpuctl is provided. Don't
know whether it is needed, but it was easy.

I've tested with i386 on bare metal and amd64 as Xen Dom0. On the
former, each core is updated individually by "cpuctl" invocations.
On the latter, only one call is done to the hypervisor which seems
to take care of the rest.
The patch is not finished, but it might show how the kernel API
could look like. In particular the userland tool which parses
the firmware file distributed by Intel and extracts the binaries
for each CPU type is missing.

So, well, please comment. Sorry that I didn't take time to explain
design objectives. Please ask.

best regards
Matthias


------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------
Forschungszentrum Juelich GmbH
52425 Juelich
Sitz der Gesellschaft: Juelich
Eingetragen im Handelsregister des Amtsgerichts Dueren Nr. HR B 3498
Vorsitzender des Aufsichtsrats: MinDir Dr. Karl Eugen Huthmacher
Geschaeftsfuehrung: Prof. Dr. Achim Bachem (Vorsitzender),
Karsten Beneke (stellv. Vorsitzender), Prof. Dr.-Ing. Harald Bolt,
Prof. Dr. Sebastian M. Schmidt
------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------

Kennen Sie schon unsere app? http://www.fz-juelich.de/app
# HG changeset patch
# Parent 12f849b3af7257fe5574200a13b05e440d083234

diff -r 12f849b3af72 sys/arch/x86/conf/files.x86
--- a/sys/arch/x86/conf/files.x86       Mon Aug 13 16:59:42 2012 +0200
+++ b/sys/arch/x86/conf/files.x86       Mon Aug 13 22:30:26 2012 +0200
@@ -99,6 +99,7 @@
 
 file   arch/x86/x86/cpu_ucode.c        cpu_ucode needs-flag
 file   arch/x86/x86/cpu_ucode_amd.c    cpu_ucode needs-flag
+file   arch/x86/x86/cpu_ucode_intel.c  cpu_ucode needs-flag
 
 define lapic
 file   arch/x86/x86/lapic.c            lapic needs-flag
diff -r 12f849b3af72 sys/arch/x86/include/Makefile
--- a/sys/arch/x86/include/Makefile     Mon Aug 13 16:59:42 2012 +0200
+++ b/sys/arch/x86/include/Makefile     Mon Aug 13 22:30:26 2012 +0200
@@ -6,6 +6,7 @@
        bootinfo.h \
        cacheinfo.h \
        cpu.h \
+       cpu_ucode.h \
        cputypes.h \
        cpuvar.h \
        float.h \
diff -r 12f849b3af72 sys/arch/x86/include/cpu_ucode.h
--- a/sys/arch/x86/include/cpu_ucode.h  Mon Aug 13 16:59:42 2012 +0200
+++ b/sys/arch/x86/include/cpu_ucode.h  Mon Aug 13 22:30:26 2012 +0200
@@ -31,12 +31,57 @@
 #ifndef _X86_CPU_UCODE_H_
 #define _X86_CPU_UCODE_H_
 
+#define CPU_UCODE_LOADER_AMD 0
+struct cpu_ucode_version_amd {
+       uint64_t version;
+};
+
+#define CPU_UCODE_LOADER_INTEL1 1
+struct cpu_ucode_version_intel1 {
+       uint32_t ucodeversion;
+       int platformid;
+};
+
+#ifdef _KERNEL
 #include <sys/cpu.h>
 #include <sys/cpuio.h>
 #include <dev/firmload.h>
 
-int cpu_ucode_amd_get_version(struct cpu_ucode *);
+int cpu_ucode_amd_get_version(struct cpu_ucode_version *);
+/* XXX COMPAT */
+int compat6_cpu_ucode_amd_get_version(struct compat6_cpu_ucode *);
 int cpu_ucode_amd_firmware_open(firmware_handle_t *, const char *);
-int cpu_ucode_amd_apply(struct cpu_ucode_softc *);
+int cpu_ucode_amd_apply(struct cpu_ucode_softc *, int);
+
+int cpu_ucode_intel_get_version(struct cpu_ucode_version *);
+int cpu_ucode_intel_firmware_open(firmware_handle_t *, const char *);
+int cpu_ucode_intel_apply(struct cpu_ucode_softc *, int);
+#endif /* _KERNEL */
+
+struct intel_ucode_header {
+       uint32_t        uh_header_ver;
+       uint32_t        uh_rev;
+       uint32_t        uh_date;
+       uint32_t        uh_signature;
+       uint32_t        uh_checksum;
+       uint32_t        uh_loader_ver;
+       uint32_t        uh_proc_flags;
+       uint32_t        uh_body_size;
+       uint32_t        uh_total_size;
+       uint32_t        uh_reserved[3];
+};
+
+struct intel_ucode_proc_signature {
+       uint32_t        ups_signature;
+       uint32_t        ups_proc_flags;
+       uint32_t        ups_checksum;
+};
+
+struct intel_ucode_ext_table {
+       uint32_t        uet_count;
+       uint32_t        uet_checksum;
+       uint32_t        uet_reserved[3];
+       struct intel_ucode_proc_signature uet_proc_sig[1];
+};
 
 #endif
diff -r 12f849b3af72 sys/arch/x86/x86/cpu_ucode.c
--- a/sys/arch/x86/x86/cpu_ucode.c      Mon Aug 13 16:59:42 2012 +0200
+++ b/sys/arch/x86/x86/cpu_ucode.c      Mon Aug 13 22:30:26 2012 +0200
@@ -47,15 +47,30 @@
 static struct cpu_ucode_softc ucode_softc;
 
 int
-cpu_ucode_get_version(void *data)
+cpu_ucode_get_version(struct cpu_ucode_version *data)
 {
-       struct cpu_ucode *ucode = data;
 
        switch (cpu_vendor) {
        case CPUVENDOR_AMD:
-               return cpu_ucode_amd_get_version(ucode);
+               return cpu_ucode_amd_get_version(data);
+       case CPUVENDOR_INTEL:
+               return cpu_ucode_intel_get_version(data);
        default:
-               ucode->version = (uint64_t)-1;
+               return EOPNOTSUPP;
+       }
+
+       return 0;
+}
+
+/* XXX COMPAT */
+int
+compat6_cpu_ucode_get_version(struct compat6_cpu_ucode *data)
+{
+
+       switch (cpu_vendor) {
+       case CPUVENDOR_AMD:
+               return compat6_cpu_ucode_amd_get_version(data);
+       default:
                return EOPNOTSUPP;
        }
 
@@ -63,32 +78,36 @@
 }
 
 int
-cpu_ucode_md_open(firmware_handle_t *fwh, const char *fwname)
+cpu_ucode_md_open(firmware_handle_t *fwh, int loader_version, const char 
*fwname)
 {
        switch (cpu_vendor) {
        case CPUVENDOR_AMD:
                return cpu_ucode_amd_firmware_open(fwh, fwname);
        case CPUVENDOR_INTEL:
-               return EOPNOTSUPP; /* not yet supported */
+               return cpu_ucode_intel_firmware_open(fwh, fwname);
        default:
                return EOPNOTSUPP;
        }
 }
 
 int
-cpu_ucode_apply(void *data)
+cpu_ucode_apply(const struct cpu_ucode *data)
 {
-       struct cpu_ucode *ucode = data;
        struct cpu_ucode_softc *sc = &ucode_softc;
        int error;
 
-       error = cpu_ucode_load(sc, ucode->fwname);
+       sc->loader_version = data->loader_version;
+
+       error = cpu_ucode_load(sc, data->fwname);
        if (error)
                return error;
 
        switch (cpu_vendor) {
        case CPUVENDOR_AMD:
-               error = cpu_ucode_amd_apply(sc);
+               error = cpu_ucode_amd_apply(sc, data->cpu_nr);
+               break;
+       case CPUVENDOR_INTEL:
+               error = cpu_ucode_intel_apply(sc, data->cpu_nr);
                break;
        default:
                return EOPNOTSUPP;
@@ -100,3 +119,27 @@
        sc->sc_blobsize = 0;
        return error;
 }
+
+/* XXX COMPAT */
+int
+compat6_cpu_ucode_apply(const struct compat6_cpu_ucode *data)
+{
+       struct cpu_ucode_softc *sc = &ucode_softc;
+       int error;
+
+       if (cpu_vendor != CPUVENDOR_AMD)
+               return EOPNOTSUPP;
+
+       sc->loader_version = CPU_UCODE_LOADER_AMD;
+       error = cpu_ucode_load(sc, data->fwname);
+       if (error)
+               return error;
+
+       error = cpu_ucode_amd_apply(sc, CPU_UCODE_ALL_CPUS);
+
+       if (sc->sc_blob != NULL)
+               firmware_free(sc->sc_blob, 0);
+       sc->sc_blob = NULL;
+       sc->sc_blobsize = 0;
+       return error;
+}
diff -r 12f849b3af72 sys/arch/x86/x86/cpu_ucode_amd.c
--- a/sys/arch/x86/x86/cpu_ucode_amd.c  Mon Aug 13 16:59:42 2012 +0200
+++ b/sys/arch/x86/x86/cpu_ucode_amd.c  Mon Aug 13 22:30:26 2012 +0200
@@ -102,14 +102,29 @@
 }
 
 int
-cpu_ucode_amd_get_version(struct cpu_ucode *ucode)
+cpu_ucode_amd_get_version(struct cpu_ucode_version *ucode)
 {
-       if (amd_cpufamily() < 0x10) {
-               ucode->version = (uint64_t)-1;
+       struct cpu_ucode_version_amd data;
+
+       if (ucode->loader_version != CPU_UCODE_LOADER_AMD || amd_cpufamily() < 
0x10)
                return EOPNOTSUPP;
-       }
+       if (!ucode->data)
+               return 0;
 
-       ucode->version = rdmsr(MSR_UCODE_AMD_PATCHLEVEL);
+       data.version = rdmsr(MSR_UCODE_AMD_PATCHLEVEL);
+       return copyout(&data, ucode->data, sizeof(data));
+}
+
+int
+compat6_cpu_ucode_amd_get_version(struct compat6_cpu_ucode *ucode)
+{
+       uint64_t uclevel;
+
+       if (amd_cpufamily() < 0x10)
+               return EOPNOTSUPP;
+
+       uclevel = rdmsr(MSR_UCODE_AMD_PATCHLEVEL);
+       ucode->version = uclevel;
        return 0;
 }
 
@@ -227,7 +242,7 @@
 }
 
 int
-cpu_ucode_amd_apply(struct cpu_ucode_softc *sc)
+cpu_ucode_amd_apply(struct cpu_ucode_softc *sc, int cpuno)
 {
        int i, error = 0;
        uint32_t *magic;
@@ -236,6 +251,10 @@
        struct mc_buf mc;
        int where;
 
+       if (sc->loader_version != CPU_UCODE_LOADER_AMD
+           || cpuno != CPU_UCODE_ALL_CPUS)
+               return EINVAL;
+
        cpu_signature = curcpu()->ci_signature;
 
        KASSERT(sc->sc_blob != NULL);
diff -r 12f849b3af72 sys/arch/x86/x86/cpu_ucode_intel.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/arch/x86/x86/cpu_ucode_intel.c        Mon Aug 13 22:30:26 2012 +0200
@@ -0,0 +1,151 @@
+/* $NetBSD: cpu_ucode_amd.c,v 1.3 2012/05/10 12:35:53 cegger Exp $ */
+/*
+ * Copyright (c) 2012 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: cpu_ucode_amd.c,v 1.3 2012/05/10 12:35:53 cegger 
Exp $");
+
+#include "opt_xen.h"
+#include "opt_cpu_ucode.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>
+
+#define MSR_IA32_PLATFORM_ID 0x17
+#define MSR_IA32_BIOS_UPDT_TRIGGER 0x79
+#define MSR_IA32_BIOS_SIGN_ID 0x8b
+
+static void
+intel_getcurrentucode(uint32_t *ucodeversion, int *platformid)
+{
+       unsigned int unneeded_ids[4];
+       uint64_t msr;
+
+       kpreempt_disable();
+
+       wrmsr(MSR_IA32_BIOS_SIGN_ID, 0);
+       x86_cpuid(0, unneeded_ids);
+       msr = rdmsr(MSR_IA32_BIOS_SIGN_ID);
+       *ucodeversion = msr >> 32;
+
+       kpreempt_enable();
+
+       msr = rdmsr(MSR_IA32_PLATFORM_ID);
+       *platformid = ((int)(msr >> 50)) & 7;
+}
+
+int
+cpu_ucode_intel_get_version(struct cpu_ucode_version *ucode)
+{
+       struct cpu_info *ci = curcpu();
+       int cpu_family;
+       struct cpu_ucode_version_intel1 data;
+
+       if (ucode->loader_version != CPU_UCODE_LOADER_INTEL1)
+               return EOPNOTSUPP;
+       if (!ucode->data)
+               return 0;
+
+       cpu_family = CPUID2FAMILY(ci->ci_signature);
+       if (cpu_family < 6)
+               return EOPNOTSUPP;
+
+       intel_getcurrentucode(&data.ucodeversion, &data.platformid);
+
+       return copyout(&data, ucode->data, sizeof(data));
+}
+
+int
+cpu_ucode_intel_firmware_open(firmware_handle_t *fwh, const char *fwname)
+{
+       const char *fw_path = "cpu_x86_intel1";
+       uint32_t ucodeversion, cpu_signature;
+       int platformid;
+       char cpuspec[11];
+
+       if (fwname != NULL && fwname[0] != '\0')
+               return firmware_open(fw_path, fwname, fwh);
+
+       cpu_signature = curcpu()->ci_signature;
+       intel_getcurrentucode(&ucodeversion, &platformid);
+       sprintf(cpuspec, "%08x-%d", cpu_signature, platformid);
+
+       return firmware_open(fw_path, cpuspec, fwh);
+}
+
+#ifndef XEN
+int
+cpu_ucode_intel_apply(struct cpu_ucode_softc *sc, int cpuno)
+{
+       uint32_t cpu_signature;
+       uint32_t oucodeversion, nucodeversion;
+       int platformid;
+       struct intel_ucode_header *uh;
+
+       if (sc->loader_version != CPU_UCODE_LOADER_INTEL1
+           || cpuno != CPU_UCODE_CURRENT_CPU)
+               return EINVAL;
+
+       if ((uintptr_t)(sc->sc_blob) & 15) {
+               printf("ucode alignment bad\n");
+               return EINVAL;
+       }
+
+       uh = (struct intel_ucode_header *)(sc->sc_blob);
+
+       kpreempt_disable();
+
+       cpu_signature = curcpu()->ci_signature;
+       if (CPUID2FAMILY(cpu_signature) < 6) {
+               kpreempt_enable();
+               return EOPNOTSUPP;
+       }
+
+       intel_getcurrentucode(&oucodeversion, &platformid);
+
+       wrmsr(MSR_IA32_BIOS_UPDT_TRIGGER, (uintptr_t)(sc->sc_blob) + 48);
+
+       intel_getcurrentucode(&nucodeversion, &platformid);
+
+       kpreempt_enable();
+
+       printf("cpu %d: ucode 0x%x->0x%x, target 0x%x\n", curcpu()->ci_index,
+              oucodeversion, nucodeversion, uh->uh_rev);
+
+       return 0;
+}
+#endif
diff -r 12f849b3af72 sys/arch/xen/conf/files.xen
--- a/sys/arch/xen/conf/files.xen       Mon Aug 13 16:59:42 2012 +0200
+++ b/sys/arch/xen/conf/files.xen       Mon Aug 13 22:30:26 2012 +0200
@@ -96,6 +96,7 @@
 
 file   arch/xen/xen/xen_ucode.c        dom0ops | cpu_ucode needs-flag
 file   arch/x86/x86/cpu_ucode_amd.c    dom0ops | cpu_ucode needs-flag
+file   arch/x86/x86/cpu_ucode_intel.c  dom0ops | cpu_ucode needs-flag
 
 file   arch/xen/xen/xen_machdep.c
 file   arch/xen/xen/xen_debug.c
diff -r 12f849b3af72 sys/arch/xen/xen/xen_ucode.c
--- a/sys/arch/xen/xen/xen_ucode.c      Mon Aug 13 16:59:42 2012 +0200
+++ b/sys/arch/xen/xen/xen_ucode.c      Mon Aug 13 22:30:26 2012 +0200
@@ -47,15 +47,30 @@
 static struct cpu_ucode_softc ucode_softc;
 
 int
-cpu_ucode_get_version(void *data)
+cpu_ucode_get_version(struct cpu_ucode_version *data)
 {
-       struct cpu_ucode *ucode = data;
 
        switch (cpu_vendor) {
        case CPUVENDOR_AMD:
-               return cpu_ucode_amd_get_version(ucode);
+               return cpu_ucode_amd_get_version(data);
+       case CPUVENDOR_INTEL:
+               return cpu_ucode_intel_get_version(data);
        default:
-               ucode->version = (uint64_t)-1;
+               return EOPNOTSUPP;
+       }
+
+       return 0;
+}
+
+/* XXX COMPAT */
+int
+compat6_cpu_ucode_get_version(struct compat6_cpu_ucode *data)
+{
+
+       switch (cpu_vendor) {
+       case CPUVENDOR_AMD:
+               return compat6_cpu_ucode_amd_get_version(data);
+       default:
                return EOPNOTSUPP;
        }
 
@@ -63,27 +78,31 @@
 }
 
 int
-cpu_ucode_md_open(firmware_handle_t *fwh, const char *fwname)
+cpu_ucode_md_open(firmware_handle_t *fwh, int loader_version, const char 
*fwname)
 {
        switch (cpu_vendor) {
        case CPUVENDOR_AMD:
                return cpu_ucode_amd_firmware_open(fwh, fwname);
        case CPUVENDOR_INTEL:
-               return EOPNOTSUPP; /* not yet supported */
+               return cpu_ucode_intel_firmware_open(fwh, fwname);
        default:
                return EOPNOTSUPP;
        }
 }
 
 int
-cpu_ucode_apply(void *data)
+cpu_ucode_apply(const struct cpu_ucode *data)
 {
-       struct cpu_ucode *ucode = data;
        struct cpu_ucode_softc *sc = &ucode_softc;
        struct xen_platform_op op;
        int error;
 
-       error = cpu_ucode_load(sc, ucode->fwname);
+       /* Xen updates all??? */
+       if (data->cpu_nr != CPU_UCODE_ALL_CPUS)
+               return EOPNOTSUPP;
+
+       sc->loader_version = data->loader_version;
+       error = cpu_ucode_load(sc, data->fwname);
        if (error)
                return error;
 
@@ -99,3 +118,28 @@
        sc->sc_blobsize = 0;
        return error;
 }
+
+int
+compat6_cpu_ucode_apply(const struct compat6_cpu_ucode *data)
+{
+       struct cpu_ucode_softc *sc = &ucode_softc;
+       struct xen_platform_op op;
+       int error;
+
+       sc->loader_version = CPU_UCODE_LOADER_AMD;
+       error = cpu_ucode_load(sc, data->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 != NULL)
+               firmware_free(sc->sc_blob, 0);
+       sc->sc_blob = NULL;
+       sc->sc_blobsize = 0;
+       return error;
+}
diff -r 12f849b3af72 sys/compat/sys/cpuio.h
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/compat/sys/cpuio.h    Mon Aug 13 22:30:26 2012 +0200
@@ -0,0 +1,9 @@
+/* $NetBSD$ */
+
+struct compat6_cpu_ucode {
+       uint64_t version;
+       char fwname[PATH_MAX];
+};
+
+#define OIOC_CPU_UCODE_GET_VERSION      _IOR('c', 4, struct compat6_cpu_ucode)
+#define OIOC_CPU_UCODE_APPLY            _IOW('c', 5, struct compat6_cpu_ucode)
diff -r 12f849b3af72 sys/kern/kern_cpu.c
--- a/sys/kern/kern_cpu.c       Mon Aug 13 16:59:42 2012 +0200
+++ b/sys/kern/kern_cpu.c       Mon Aug 13 22:30:26 2012 +0200
@@ -59,6 +59,7 @@
 __KERNEL_RCSID(0, "$NetBSD: kern_cpu.c,v 1.56 2012/06/13 23:00:05 joerg Exp 
$");
 
 #include "opt_cpu_ucode.h"
+#include "opt_compat_netbsd.h"
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -265,7 +266,12 @@
 
 #ifdef CPU_UCODE
        case IOC_CPU_UCODE_GET_VERSION:
-               error = cpu_ucode_get_version(data);
+               error = cpu_ucode_get_version((struct cpu_ucode_version *)data);
+               break;
+
+       /* XXX ifdef COMPAT */
+       case OIOC_CPU_UCODE_GET_VERSION:
+               error = compat6_cpu_ucode_get_version((struct compat6_cpu_ucode 
*)data);
                break;
 
        case IOC_CPU_UCODE_APPLY:
@@ -274,7 +280,17 @@
                    NULL, NULL, NULL, NULL);
                if (error != 0)
                        break;
-               error = cpu_ucode_apply(data);
+               error = cpu_ucode_apply((const struct cpu_ucode *)data);
+               break;
+
+       /* XXX ifdef COMPAT */
+       case OIOC_CPU_UCODE_APPLY:
+               error = kauth_authorize_machdep(l->l_cred,
+                   KAUTH_MACHDEP_CPU_UCODE_APPLY,
+                   NULL, NULL, NULL, NULL);
+               if (error != 0)
+                       break;
+               error = compat6_cpu_ucode_apply((const struct compat6_cpu_ucode 
*)data);
                break;
 #endif
 
@@ -554,7 +570,7 @@
                sc->sc_blobsize = 0;
        }
 
-       error = cpu_ucode_md_open(&fwh, fwname);
+       error = cpu_ucode_md_open(&fwh, sc->loader_version, fwname);
        if (error != 0) {
                aprint_error("ucode: firmware_open failed: %i\n", error);
                goto err0;
diff -r 12f849b3af72 sys/sys/cpu.h
--- a/sys/sys/cpu.h     Mon Aug 13 16:59:42 2012 +0200
+++ b/sys/sys/cpu.h     Mon Aug 13 22:30:26 2012 +0200
@@ -43,7 +43,11 @@
 #endif
 
 #ifdef CPU_UCODE
+#include <sys/cpuio.h>
 #include <dev/firmload.h>
+
+/* XXX ifdef COMPAT */
+#include <compat/sys/cpuio.h>
 #endif
 
 /*
@@ -110,14 +114,19 @@
 
 #ifdef CPU_UCODE
 struct cpu_ucode_softc {
+       int loader_version;
        char *sc_blob;
        off_t sc_blobsize;
 };
 
-int cpu_ucode_get_version(void *);
-int cpu_ucode_apply(void *);
+int cpu_ucode_get_version(struct cpu_ucode_version *);
+/* XXX ifdef COMPAT */
+int compat6_cpu_ucode_get_version(struct compat6_cpu_ucode *);
+int cpu_ucode_apply(const struct cpu_ucode *);
+/* XXX ifdef COMPAT */
+int compat6_cpu_ucode_apply(const struct compat6_cpu_ucode *);
 int cpu_ucode_load(struct cpu_ucode_softc *, const char *);
-int cpu_ucode_md_open(firmware_handle_t *, const char *);
+int cpu_ucode_md_open(firmware_handle_t *, int, const char *);
 #endif
 
 #endif
diff -r 12f849b3af72 sys/sys/cpuio.h
--- a/sys/sys/cpuio.h   Mon Aug 13 16:59:42 2012 +0200
+++ b/sys/sys/cpuio.h   Mon Aug 13 22:30:26 2012 +0200
@@ -62,13 +62,22 @@
 #define        IOC_CPU_GETSTATE        _IOWR('c', 1, cpustate_t)
 #define        IOC_CPU_GETCOUNT        _IOR('c', 2, int)
 #define        IOC_CPU_MAPID           _IOWR('c', 3, int)
+/* 4 and 5 reserved for compat nb6 x86 amd ucode loader */
+
+struct cpu_ucode_version {
+       int loader_version;     /* IN: md version number */
+       void *data;             /* OUT: CPU ID data */
+};
 
 struct cpu_ucode {
-       uint64_t version;
+       int loader_version;     /* md version number */
+       int cpu_nr;             /* CPU index or special value below */
+#define CPU_UCODE_ALL_CPUS (-1)
+#define CPU_UCODE_CURRENT_CPU (-2)
        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)
+#define IOC_CPU_UCODE_GET_VERSION      _IOWR('c', 6, struct cpu_ucode_version)
+#define IOC_CPU_UCODE_APPLY            _IOW('c', 7, struct cpu_ucode)
 
 #endif /* !_SYS_CPUIO_H_ */
diff -r 12f849b3af72 usr.sbin/cpuctl/arch/i386.c
--- a/usr.sbin/cpuctl/arch/i386.c       Mon Aug 13 16:59:42 2012 +0200
+++ b/usr.sbin/cpuctl/arch/i386.c       Mon Aug 13 22:30:26 2012 +0200
@@ -64,6 +64,7 @@
 #include <sys/param.h>
 #include <sys/bitops.h>
 #include <sys/sysctl.h>
+#include <sys/cpuio.h>
 
 #include <string.h>
 #include <stdio.h>
@@ -79,6 +80,7 @@
 #include <x86/cpuvar.h>
 #include <x86/cputypes.h>
 #include <x86/cacheinfo.h>
+#include <x86/cpu_ucode.h>
 
 #include "../cpuctl.h"
 
@@ -1233,7 +1235,7 @@
 }
 
 void
-identifycpu(const char *cpuname)
+identifycpu(int fd, const char *cpuname)
 {
        const char *name = "", *modifier, *vendorname, *brand = "";
        int class = CPUCLASS_386, i, xmax;
@@ -1248,6 +1250,11 @@
        size_t sz;
        char buf[512];
        char *bp;
+       struct cpu_ucode_version ucode;
+       union {
+               struct cpu_ucode_version_amd amd;
+               struct cpu_ucode_version_intel1 intel1;
+       } ucvers;
 
        ci = &cistore;
        memset(ci, 0, sizeof(*ci));
@@ -1519,6 +1526,21 @@
            CPUID2FAMILY(ci->ci_signature), CPUID2MODEL(ci->ci_signature),
            CPUID2EXTFAMILY(ci->ci_signature), CPUID2EXTMODEL(ci->ci_signature),
            CPUID2STEPPING(ci->ci_signature));
+
+       if (cpu_vendor == CPUVENDOR_AMD)
+               ucode.loader_version = CPU_UCODE_LOADER_AMD;
+       else if (cpu_vendor == CPUVENDOR_INTEL)
+               ucode.loader_version = CPU_UCODE_LOADER_INTEL1;
+       else
+               return;
+       ucode.data = &ucvers;
+       if (ioctl(fd, IOC_CPU_UCODE_GET_VERSION, &ucode) < 0)
+               return;
+       if (cpu_vendor == CPUVENDOR_AMD)
+               printf("%s: UCode version: 0x%"PRIx64"\n", cpuname, 
ucvers.amd.version);
+       else if (cpu_vendor == CPUVENDOR_INTEL)
+               printf("%s: microcode version 0x%x, platform ID %d\n", cpuname,
+                      ucvers.intel1.ucodeversion, ucvers.intel1.platformid);
 }
 
 static const char *
@@ -1996,3 +2018,49 @@
        aprint_normal_dev(ci->ci_dev, "AMD Power Management features: %s\n",
            buf);
 }
+
+int
+ucodeupdate_check(int fd, struct cpu_ucode *uc)
+{
+       struct cpu_info ci;
+       int loader_version, res;
+       struct cpu_ucode_version versreq;
+       extern int cpu_info_level;
+
+       x86_identify();
+       ci.ci_cpuid_level = cpu_info_level;
+       cpu_probe_base_features(&ci);
+       if (!strcmp((char *)ci.ci_vendor, "AuthenticAMD"))
+               loader_version = CPU_UCODE_LOADER_AMD;
+       else if (!strcmp((char *)ci.ci_vendor, "GenuineIntel"))
+               loader_version = CPU_UCODE_LOADER_INTEL1;
+       else
+               return -1;
+
+       /* check whether the kernel understands this loader version */
+       versreq.loader_version = loader_version;
+       versreq.data = 0;
+       res = ioctl(fd, IOC_CPU_UCODE_GET_VERSION, &versreq);
+       if (res)
+               return -1;
+
+       switch (loader_version) {
+       case CPU_UCODE_LOADER_AMD:
+               if (uc->cpu_nr != -1) {
+                       /* printf? */
+                       return -1;
+               }
+               uc->cpu_nr = CPU_UCODE_ALL_CPUS;
+               break;
+       case CPU_UCODE_LOADER_INTEL1:
+               if (uc->cpu_nr == -1)
+                       uc->cpu_nr = CPU_UCODE_ALL_CPUS; /* for Xen */
+               else
+                       uc->cpu_nr = CPU_UCODE_CURRENT_CPU;
+               break;
+       default: /* can't happen */
+               return -1;
+       }
+       uc->loader_version = loader_version;
+       return 0;
+}
diff -r 12f849b3af72 usr.sbin/cpuctl/arch/noarch.c
--- a/usr.sbin/cpuctl/arch/noarch.c     Mon Aug 13 16:59:42 2012 +0200
+++ b/usr.sbin/cpuctl/arch/noarch.c     Mon Aug 13 22:30:26 2012 +0200
@@ -38,8 +38,15 @@
 #include "../cpuctl.h"
 
 void
-identifycpu(const char *cpuname)
+identifycpu(int fd, const char *cpuname)
 {
 
        printf("CPU identification not implemented for this architecture.\n");
 }
+
+int
+ucodeupdate_check(int, struct cpu_ucode *uc)
+{
+
+       return 0;
+}
diff -r 12f849b3af72 usr.sbin/cpuctl/cpuctl.c
--- a/usr.sbin/cpuctl/cpuctl.c  Mon Aug 13 16:59:42 2012 +0200
+++ b/usr.sbin/cpuctl/cpuctl.c  Mon Aug 13 22:30:26 2012 +0200
@@ -192,12 +192,38 @@
 {
        int error;
        struct cpu_ucode uc;
+       unsigned long id = 0; /* gcc */
+       char *ep;
+       cpuset_t *cpuset;
 
+       uc.cpu_nr = -1;
+       if (argv[0] != NULL) {
+               id = strtoul(argv[0], &ep, 0);
+               if (id != ULONG_MAX && *ep == '\0') {
+                       uc.cpu_nr = id;
+                       argv++;
+               }
+       }
        if (argv[0] != NULL)
                strlcpy(uc.fwname, argv[0], sizeof(uc.fwname));
        else
                memset(uc.fwname, '\0', sizeof(uc.fwname));
 
+       error = ucodeupdate_check(fd, &uc);
+       if (error)
+               errx(EXIT_FAILURE, "unsupported");
+
+       if (uc.cpu_nr == CPU_UCODE_CURRENT_CPU) {
+               cpuset = cpuset_create();
+               if (cpuset == NULL)
+                       err(EXIT_FAILURE, "cpuset_create");
+               cpuset_zero(cpuset);
+               cpuset_set(id, cpuset);
+               if (_sched_setaffinity(0, 0, cpuset_size(cpuset), cpuset) < 0) {
+                       err(EXIT_FAILURE, "_sched_setaffinity");
+               }
+               cpuset_destroy(cpuset);
+       }
        error = ioctl(fd, IOC_CPU_UCODE_APPLY, &uc);
        if (error < 0) {
                if (uc.fwname[0])
@@ -214,8 +240,6 @@
        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);
@@ -238,17 +262,7 @@
                }
                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);
+       identifycpu(fd, name);
 }
 
 static u_int
diff -r 12f849b3af72 usr.sbin/cpuctl/cpuctl.h
--- a/usr.sbin/cpuctl/cpuctl.h  Mon Aug 13 16:59:42 2012 +0200
+++ b/usr.sbin/cpuctl/cpuctl.h  Mon Aug 13 22:30:26 2012 +0200
@@ -33,4 +33,5 @@
 int    aprint_verbose_dev(const char *, const char *, ...) __printflike(2, 3);
 int    aprint_error_dev(const char *, const char *, ...) __printflike(2, 3);
 
-void   identifycpu(const char *);
+void   identifycpu(int, const char *);
+int    ucodeupdate_check(int, struct cpu_ucode *);


Home | Main Index | Thread Index | Old Index