Module Name: src Committed By: drochner Date: Wed Aug 29 17:13:23 UTC 2012
Modified Files: src/distrib/sets/lists/comp: md.amd64 md.i386 src/sys/arch/x86/conf: files.x86 src/sys/arch/x86/include: Makefile cpu_ucode.h src/sys/arch/x86/x86: cpu_ucode.c cpu_ucode_amd.c src/sys/arch/xen/conf: files.xen src/sys/arch/xen/xen: xen_ucode.c src/sys/kern: kern_cpu.c src/sys/sys: cpu.h cpuio.h src/usr.sbin/cpuctl: cpuctl.c cpuctl.h src/usr.sbin/cpuctl/arch: i386.c noarch.c Added Files: src/sys/arch/x86/x86: cpu_ucode_intel.c src/sys/compat/sys: cpuio.h Log Message: Extend the CPU microcode update framework to support Intel x86 CPUs. Contrary to the AMD implementation, it doesn't use xcalls to distribute the update to all CPUs but relies on cpuctl(8) to bind itself to the right CPU -- to keep it simple and avoid possible problems with hyperthreading. Also, it doesn't parse the vendor supplied file to pick the right part for the present CPU model but relies on userland to prepare files with specific filenames. I'll commit a pkg for this in a minute (pkgsrc/sysutils/intel-microcode). The ioctl interface changed; compatibility is provided (should be limited to COMPAT_NETBSD6 as soon as this is available). To generate a diff of this commit: cvs rdiff -u -r1.175 -r1.176 src/distrib/sets/lists/comp/md.amd64 cvs rdiff -u -r1.126 -r1.127 src/distrib/sets/lists/comp/md.i386 cvs rdiff -u -r1.78 -r1.79 src/sys/arch/x86/conf/files.x86 cvs rdiff -u -r1.16 -r1.17 src/sys/arch/x86/include/Makefile cvs rdiff -u -r1.1 -r1.2 src/sys/arch/x86/include/cpu_ucode.h cvs rdiff -u -r1.1 -r1.2 src/sys/arch/x86/x86/cpu_ucode.c cvs rdiff -u -r1.3 -r1.4 src/sys/arch/x86/x86/cpu_ucode_amd.c cvs rdiff -u -r0 -r1.1 src/sys/arch/x86/x86/cpu_ucode_intel.c cvs rdiff -u -r1.127 -r1.128 src/sys/arch/xen/conf/files.xen cvs rdiff -u -r1.1 -r1.2 src/sys/arch/xen/xen/xen_ucode.c cvs rdiff -u -r0 -r1.4 src/sys/compat/sys/cpuio.h cvs rdiff -u -r1.56 -r1.57 src/sys/kern/kern_cpu.c cvs rdiff -u -r1.35 -r1.36 src/sys/sys/cpu.h cvs rdiff -u -r1.7 -r1.8 src/sys/sys/cpuio.h cvs rdiff -u -r1.20 -r1.21 src/usr.sbin/cpuctl/cpuctl.c cvs rdiff -u -r1.3 -r1.4 src/usr.sbin/cpuctl/cpuctl.h cvs rdiff -u -r1.31 -r1.32 src/usr.sbin/cpuctl/arch/i386.c cvs rdiff -u -r1.2 -r1.3 src/usr.sbin/cpuctl/arch/noarch.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/distrib/sets/lists/comp/md.amd64 diff -u src/distrib/sets/lists/comp/md.amd64:1.175 src/distrib/sets/lists/comp/md.amd64:1.176 --- src/distrib/sets/lists/comp/md.amd64:1.175 Fri Aug 10 16:22:33 2012 +++ src/distrib/sets/lists/comp/md.amd64 Wed Aug 29 17:13:21 2012 @@ -1,4 +1,4 @@ -# $NetBSD: md.amd64,v 1.175 2012/08/10 16:22:33 joerg Exp $ +# $NetBSD: md.amd64,v 1.176 2012/08/29 17:13:21 drochner Exp $ ./usr/include/amd64 comp-c-include ./usr/include/amd64/ansi.h comp-c-include ./usr/include/amd64/aout_machdep.h comp-c-include @@ -283,6 +283,7 @@ ./usr/include/x86/bus.h comp-obsolete obsolete ./usr/include/x86/cacheinfo.h comp-c-include ./usr/include/x86/cpu.h comp-c-include +./usr/include/x86/cpu_ucode.h comp-c-include ./usr/include/x86/cputypes.h comp-c-include ./usr/include/x86/cpuvar.h comp-c-include ./usr/include/x86/float.h comp-c-include Index: src/distrib/sets/lists/comp/md.i386 diff -u src/distrib/sets/lists/comp/md.i386:1.126 src/distrib/sets/lists/comp/md.i386:1.127 --- src/distrib/sets/lists/comp/md.i386:1.126 Wed Aug 8 18:37:51 2012 +++ src/distrib/sets/lists/comp/md.i386 Wed Aug 29 17:13:21 2012 @@ -1,4 +1,4 @@ -# $NetBSD: md.i386,v 1.126 2012/08/08 18:37:51 drochner Exp $ +# $NetBSD: md.i386,v 1.127 2012/08/29 17:13:21 drochner Exp $ ./usr/include/clang-3.0/avxintrin.h comp-obsolete obsolete ./usr/include/clang-3.0/avx2intrin.h comp-obsolete obsolete ./usr/include/clang-3.0/bmi2intrin.h comp-obsolete obsolete @@ -165,6 +165,7 @@ ./usr/include/x86/bus.h comp-obsolete obsolete ./usr/include/x86/cacheinfo.h comp-c-include ./usr/include/x86/cpu.h comp-c-include +./usr/include/x86/cpu_ucode.h comp-c-include ./usr/include/x86/cputypes.h comp-c-include ./usr/include/x86/cpuvar.h comp-c-include ./usr/include/x86/float.h comp-c-include Index: src/sys/arch/x86/conf/files.x86 diff -u src/sys/arch/x86/conf/files.x86:1.78 src/sys/arch/x86/conf/files.x86:1.79 --- src/sys/arch/x86/conf/files.x86:1.78 Mon May 7 17:45:29 2012 +++ src/sys/arch/x86/conf/files.x86 Wed Aug 29 17:13:21 2012 @@ -1,4 +1,4 @@ -# $NetBSD: files.x86,v 1.78 2012/05/07 17:45:29 jym Exp $ +# $NetBSD: files.x86,v 1.79 2012/08/29 17:13:21 drochner Exp $ # options for MP configuration through the MP spec defflag opt_mpbios.h MPBIOS MPVERBOSE MPDEBUG MPBIOS_SCANPCI @@ -96,6 +96,7 @@ file arch/x86/x86/x86_machdep.c 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 Index: src/sys/arch/x86/include/Makefile diff -u src/sys/arch/x86/include/Makefile:1.16 src/sys/arch/x86/include/Makefile:1.17 --- src/sys/arch/x86/include/Makefile:1.16 Sun Jul 17 23:38:32 2011 +++ src/sys/arch/x86/include/Makefile Wed Aug 29 17:13:22 2012 @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.16 2011/07/17 23:38:32 dyoung Exp $ +# $NetBSD: Makefile,v 1.17 2012/08/29 17:13:22 drochner Exp $ INCSDIR=/usr/include/x86 @@ -6,6 +6,7 @@ INCS= aout_machdep.h \ bootinfo.h \ cacheinfo.h \ cpu.h \ + cpu_ucode.h \ cputypes.h \ cpuvar.h \ float.h \ Index: src/sys/arch/x86/include/cpu_ucode.h diff -u src/sys/arch/x86/include/cpu_ucode.h:1.1 src/sys/arch/x86/include/cpu_ucode.h:1.2 --- src/sys/arch/x86/include/cpu_ucode.h:1.1 Fri Jan 13 16:05:14 2012 +++ src/sys/arch/x86/include/cpu_ucode.h Wed Aug 29 17:13:22 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: cpu_ucode.h,v 1.1 2012/01/13 16:05:14 cegger Exp $ */ +/* $NetBSD: cpu_ucode.h,v 1.2 2012/08/29 17:13:22 drochner Exp $ */ /* * Copyright (c) 2012 The NetBSD Foundation, Inc. * All rights reserved. @@ -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 intel1_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_rev; + uint32_t uh_proc_flags; + uint32_t uh_data_size; + uint32_t uh_total_size; + uint32_t uh_reserved[3]; +}; + +struct intel1_ucode_proc_signature { + uint32_t ups_signature; + uint32_t ups_proc_flags; + uint32_t ups_checksum; +}; + +struct intel1_ucode_ext_table { + uint32_t uet_count; + uint32_t uet_checksum; + uint32_t uet_reserved[3]; + struct intel1_ucode_proc_signature uet_proc_sig[1]; +}; #endif Index: src/sys/arch/x86/x86/cpu_ucode.c diff -u src/sys/arch/x86/x86/cpu_ucode.c:1.1 src/sys/arch/x86/x86/cpu_ucode.c:1.2 --- src/sys/arch/x86/x86/cpu_ucode.c:1.1 Fri Jan 13 16:05:15 2012 +++ src/sys/arch/x86/x86/cpu_ucode.c Wed Aug 29 17:13:22 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: cpu_ucode.c,v 1.1 2012/01/13 16:05:15 cegger Exp $ */ +/* $NetBSD: cpu_ucode.c,v 1.2 2012/08/29 17:13:22 drochner Exp $ */ /* * Copyright (c) 2012 The NetBSD Foundation, Inc. * All rights reserved. @@ -29,7 +29,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: cpu_ucode.c,v 1.1 2012/01/13 16:05:15 cegger Exp $"); +__KERNEL_RCSID(0, "$NetBSD: cpu_ucode.c,v 1.2 2012/08/29 17:13:22 drochner Exp $"); #include "opt_cpu_ucode.h" @@ -47,48 +47,67 @@ __KERNEL_RCSID(0, "$NetBSD: cpu_ucode.c, 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 -cpu_ucode_md_open(firmware_handle_t *fwh, const char *fwname) +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; + } + + return 0; +} + +int +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 @@ cpu_ucode_apply(void *data) 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; +} Index: src/sys/arch/x86/x86/cpu_ucode_amd.c diff -u src/sys/arch/x86/x86/cpu_ucode_amd.c:1.3 src/sys/arch/x86/x86/cpu_ucode_amd.c:1.4 --- src/sys/arch/x86/x86/cpu_ucode_amd.c:1.3 Thu May 10 12:35:53 2012 +++ src/sys/arch/x86/x86/cpu_ucode_amd.c Wed Aug 29 17:13:22 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: cpu_ucode_amd.c,v 1.3 2012/05/10 12:35:53 cegger Exp $ */ +/* $NetBSD: cpu_ucode_amd.c,v 1.4 2012/08/29 17:13:22 drochner Exp $ */ /* * Copyright (c) 2012 The NetBSD Foundation, Inc. * All rights reserved. @@ -29,7 +29,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: cpu_ucode_amd.c,v 1.3 2012/05/10 12:35:53 cegger Exp $"); +__KERNEL_RCSID(0, "$NetBSD: cpu_ucode_amd.c,v 1.4 2012/08/29 17:13:22 drochner Exp $"); #include "opt_xen.h" #include "opt_cpu_ucode.h" @@ -102,14 +102,29 @@ amd_cpufamily(void) } 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; + + 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; - } - ucode->version = rdmsr(MSR_UCODE_AMD_PATCHLEVEL); + uclevel = rdmsr(MSR_UCODE_AMD_PATCHLEVEL); + ucode->version = uclevel; return 0; } @@ -227,7 +242,7 @@ out: } 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 @@ cpu_ucode_amd_apply(struct cpu_ucode_sof 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); Index: src/sys/arch/xen/conf/files.xen diff -u src/sys/arch/xen/conf/files.xen:1.127 src/sys/arch/xen/conf/files.xen:1.128 --- src/sys/arch/xen/conf/files.xen:1.127 Wed Jun 27 00:37:09 2012 +++ src/sys/arch/xen/conf/files.xen Wed Aug 29 17:13:22 2012 @@ -1,4 +1,4 @@ -# $NetBSD: files.xen,v 1.127 2012/06/27 00:37:09 jym Exp $ +# $NetBSD: files.xen,v 1.128 2012/08/29 17:13:22 drochner Exp $ # NetBSD: files.x86,v 1.10 2003/10/08 17:30:00 bouyer Exp # NetBSD: files.i386,v 1.254 2004/03/25 23:32:10 jmc Exp @@ -94,6 +94,7 @@ file arch/xen/x86/xenfunc.c 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 Index: src/sys/arch/xen/xen/xen_ucode.c diff -u src/sys/arch/xen/xen/xen_ucode.c:1.1 src/sys/arch/xen/xen/xen_ucode.c:1.2 --- src/sys/arch/xen/xen/xen_ucode.c:1.1 Fri Jan 13 16:05:15 2012 +++ src/sys/arch/xen/xen/xen_ucode.c Wed Aug 29 17:13:22 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: xen_ucode.c,v 1.1 2012/01/13 16:05:15 cegger Exp $ */ +/* $NetBSD: xen_ucode.c,v 1.2 2012/08/29 17:13:22 drochner Exp $ */ /* * Copyright (c) 2012 The NetBSD Foundation, Inc. * All rights reserved. @@ -29,7 +29,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: xen_ucode.c,v 1.1 2012/01/13 16:05:15 cegger Exp $"); +__KERNEL_RCSID(0, "$NetBSD: xen_ucode.c,v 1.2 2012/08/29 17:13:22 drochner Exp $"); #include "opt_cpu_ucode.h" @@ -47,15 +47,30 @@ __KERNEL_RCSID(0, "$NetBSD: xen_ucode.c, 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: + 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: - ucode->version = (uint64_t)-1; return EOPNOTSUPP; } @@ -63,27 +78,31 @@ cpu_ucode_get_version(void *data) } 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 @@ cpu_ucode_apply(void *data) 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; +} Index: src/sys/kern/kern_cpu.c diff -u src/sys/kern/kern_cpu.c:1.56 src/sys/kern/kern_cpu.c:1.57 --- src/sys/kern/kern_cpu.c:1.56 Wed Jun 13 23:00:05 2012 +++ src/sys/kern/kern_cpu.c Wed Aug 29 17:13:21 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: kern_cpu.c,v 1.56 2012/06/13 23:00:05 joerg Exp $ */ +/* $NetBSD: kern_cpu.c,v 1.57 2012/08/29 17:13:21 drochner Exp $ */ /*- * Copyright (c) 2007, 2008, 2009, 2010, 2012 The NetBSD Foundation, Inc. @@ -56,9 +56,10 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: kern_cpu.c,v 1.56 2012/06/13 23:00:05 joerg Exp $"); +__KERNEL_RCSID(0, "$NetBSD: kern_cpu.c,v 1.57 2012/08/29 17:13:21 drochner Exp $"); #include "opt_cpu_ucode.h" +#include "opt_compat_netbsd.h" #include <sys/param.h> #include <sys/systm.h> @@ -265,7 +266,12 @@ cpuctl_ioctl(dev_t dev, u_long cmd, void #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 @@ cpuctl_ioctl(dev_t dev, u_long cmd, void 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 @@ cpu_ucode_load(struct cpu_ucode_softc *s 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; Index: src/sys/sys/cpu.h diff -u src/sys/sys/cpu.h:1.35 src/sys/sys/cpu.h:1.36 --- src/sys/sys/cpu.h:1.35 Sun Jan 29 22:55:40 2012 +++ src/sys/sys/cpu.h Wed Aug 29 17:13:22 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: cpu.h,v 1.35 2012/01/29 22:55:40 rmind Exp $ */ +/* $NetBSD: cpu.h,v 1.36 2012/08/29 17:13:22 drochner Exp $ */ /*- * Copyright (c) 2007 YAMAMOTO Takashi, @@ -43,7 +43,11 @@ void cpu_idle(void); #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 @@ cpu_name(struct cpu_info *ci) #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 Index: src/sys/sys/cpuio.h diff -u src/sys/sys/cpuio.h:1.7 src/sys/sys/cpuio.h:1.8 --- src/sys/sys/cpuio.h:1.7 Mon Jan 16 10:36:16 2012 +++ src/sys/sys/cpuio.h Wed Aug 29 17:13:22 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: cpuio.h,v 1.7 2012/01/16 10:36:16 cegger Exp $ */ +/* $NetBSD: cpuio.h,v 1.8 2012/08/29 17:13:22 drochner Exp $ */ /*- * Copyright (c) 2007, 2009, 2012 The NetBSD Foundation, Inc. @@ -62,13 +62,22 @@ typedef struct cpustate { #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_ */ Index: src/usr.sbin/cpuctl/cpuctl.c diff -u src/usr.sbin/cpuctl/cpuctl.c:1.20 src/usr.sbin/cpuctl/cpuctl.c:1.21 --- src/usr.sbin/cpuctl/cpuctl.c:1.20 Fri Jan 13 16:05:16 2012 +++ src/usr.sbin/cpuctl/cpuctl.c Wed Aug 29 17:13:22 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: cpuctl.c,v 1.20 2012/01/13 16:05:16 cegger Exp $ */ +/* $NetBSD: cpuctl.c,v 1.21 2012/08/29 17:13:22 drochner Exp $ */ /*- * Copyright (c) 2007, 2008, 2009, 2012 The NetBSD Foundation, Inc. @@ -31,7 +31,7 @@ #ifndef lint #include <sys/cdefs.h> -__RCSID("$NetBSD: cpuctl.c,v 1.20 2012/01/13 16:05:16 cegger Exp $"); +__RCSID("$NetBSD: cpuctl.c,v 1.21 2012/08/29 17:13:22 drochner Exp $"); #endif /* not lint */ #include <sys/param.h> @@ -192,12 +192,38 @@ cpu_ucode(char **argv) { 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 @@ 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); @@ -238,17 +262,7 @@ 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); + identifycpu(fd, name); } static u_int Index: src/usr.sbin/cpuctl/cpuctl.h diff -u src/usr.sbin/cpuctl/cpuctl.h:1.3 src/usr.sbin/cpuctl/cpuctl.h:1.4 --- src/usr.sbin/cpuctl/cpuctl.h:1.3 Thu Mar 15 02:02:23 2012 +++ src/usr.sbin/cpuctl/cpuctl.h Wed Aug 29 17:13:23 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: cpuctl.h,v 1.3 2012/03/15 02:02:23 joerg Exp $ */ +/* $NetBSD: cpuctl.h,v 1.4 2012/08/29 17:13:23 drochner Exp $ */ /*- * Copyright (c) 2008 The NetBSD Foundation, Inc. @@ -33,4 +33,5 @@ int aprint_normal_dev(const char *, cons 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 *); Index: src/usr.sbin/cpuctl/arch/i386.c diff -u src/usr.sbin/cpuctl/arch/i386.c:1.31 src/usr.sbin/cpuctl/arch/i386.c:1.32 --- src/usr.sbin/cpuctl/arch/i386.c:1.31 Tue Apr 17 13:00:09 2012 +++ src/usr.sbin/cpuctl/arch/i386.c Wed Aug 29 17:13:23 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: i386.c,v 1.31 2012/04/17 13:00:09 cegger Exp $ */ +/* $NetBSD: i386.c,v 1.32 2012/08/29 17:13:23 drochner Exp $ */ /*- * Copyright (c) 1999, 2000, 2001, 2006, 2007, 2008 The NetBSD Foundation, Inc. @@ -57,13 +57,14 @@ #include <sys/cdefs.h> #ifndef lint -__RCSID("$NetBSD: i386.c,v 1.31 2012/04/17 13:00:09 cegger Exp $"); +__RCSID("$NetBSD: i386.c,v 1.32 2012/08/29 17:13:23 drochner Exp $"); #endif /* not lint */ #include <sys/types.h> #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 @@ __RCSID("$NetBSD: i386.c,v 1.31 2012/04/ #include <x86/cpuvar.h> #include <x86/cputypes.h> #include <x86/cacheinfo.h> +#include <x86/cpu_ucode.h> #include "../cpuctl.h" @@ -1233,7 +1235,7 @@ transmeta_cpu_info(struct cpu_info *ci) } 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 @@ identifycpu(const char *cpuname) 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 @@ identifycpu(const char *cpuname) 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 @@ powernow_probe(struct cpu_info *ci) 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; +} Index: src/usr.sbin/cpuctl/arch/noarch.c diff -u src/usr.sbin/cpuctl/arch/noarch.c:1.2 src/usr.sbin/cpuctl/arch/noarch.c:1.3 --- src/usr.sbin/cpuctl/arch/noarch.c:1.2 Tue May 6 09:10:25 2008 +++ src/usr.sbin/cpuctl/arch/noarch.c Wed Aug 29 17:13:23 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: noarch.c,v 1.2 2008/05/06 09:10:25 skrll Exp $ */ +/* $NetBSD: noarch.c,v 1.3 2012/08/29 17:13:23 drochner Exp $ */ /*- * Copyright (c) 2008 The NetBSD Foundation, Inc. @@ -30,7 +30,7 @@ #include <sys/types.h> #ifndef lint -__RCSID("$NetBSD: noarch.c,v 1.2 2008/05/06 09:10:25 skrll Exp $"); +__RCSID("$NetBSD: noarch.c,v 1.3 2012/08/29 17:13:23 drochner Exp $"); #endif /* not lint */ #include <stdio.h> @@ -38,8 +38,15 @@ __RCSID("$NetBSD: noarch.c,v 1.2 2008/05 #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; +} Added files: Index: src/sys/arch/x86/x86/cpu_ucode_intel.c diff -u /dev/null src/sys/arch/x86/x86/cpu_ucode_intel.c:1.1 --- /dev/null Wed Aug 29 17:13:23 2012 +++ src/sys/arch/x86/x86/cpu_ucode_intel.c Wed Aug 29 17:13:22 2012 @@ -0,0 +1,152 @@ +/* $NetBSD: cpu_ucode_intel.c,v 1.1 2012/08/29 17:13:22 drochner Exp $ */ +/* + * Copyright (c) 2012 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Matthias Drochner. + * + * 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_intel.c,v 1.1 2012/08/29 17:13:22 drochner 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(); + struct cpu_ucode_version_intel1 data; + + if (ucode->loader_version != CPU_UCODE_LOADER_INTEL1 || + CPUID2FAMILY(ci->ci_signature) < 6) + return EOPNOTSUPP; + if (!ucode->data) + return 0; + + 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; + if (CPUID2FAMILY(cpu_signature) < 6) + return EOPNOTSUPP; + + 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 ucodetarget, oucodeversion, nucodeversion; + int platformid; + struct intel1_ucode_header *uh; + + if (sc->loader_version != CPU_UCODE_LOADER_INTEL1 + || cpuno != CPU_UCODE_CURRENT_CPU) + return EINVAL; + + /* XXX relies on malloc alignment */ + if ((uintptr_t)(sc->sc_blob) & 15) { + printf("ucode alignment bad\n"); + return EINVAL; + } + + uh = (struct intel1_ucode_header *)(sc->sc_blob); + if (uh->uh_header_ver != 1 || uh->uh_loader_rev != 1) + return EINVAL; + ucodetarget = uh->uh_rev; + + kpreempt_disable(); + + intel_getcurrentucode(&oucodeversion, &platformid); + if (oucodeversion >= ucodetarget) { + kpreempt_enable(); + return EEXIST; /* ??? */ + } + wrmsr(MSR_IA32_BIOS_UPDT_TRIGGER, (uintptr_t)(sc->sc_blob) + 48); + intel_getcurrentucode(&nucodeversion, &platformid); + + kpreempt_enable(); + + if (nucodeversion != ucodetarget) + return EIO; + + printf("cpu %d: ucode 0x%x->0x%x\n", curcpu()->ci_index, + oucodeversion, nucodeversion); + + return 0; +} +#endif Index: src/sys/compat/sys/cpuio.h diff -u /dev/null src/sys/compat/sys/cpuio.h:1.4 --- /dev/null Wed Aug 29 17:13:23 2012 +++ src/sys/compat/sys/cpuio.h Wed Aug 29 17:13:22 2012 @@ -0,0 +1,9 @@ +/* $NetBSD: cpuio.h,v 1.4 2012/08/29 17:13:22 drochner Exp $ */ + +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)