Load the Intel microcode much earlier. So far we had loaded it after
authorpatrick <patrick@openbsd.org>
Tue, 6 Feb 2018 01:09:17 +0000 (01:09 +0000)
committerpatrick <patrick@openbsd.org>
Tue, 6 Feb 2018 01:09:17 +0000 (01:09 +0000)
the CPUs identified and then we had to update the CPU flags afterwards.
As microcode updates can add/remove instructions and features, we need
to load it earlier.  Thus, make the bootloader look for the microcode
and supply it to the kernel as another bootarg.  This way we can update
the cores' microcode before we identify them.

ok deraadt@

sys/arch/amd64/amd64/cpu.c
sys/arch/amd64/amd64/machdep.c
sys/arch/amd64/amd64/ucode.c
sys/arch/amd64/include/biosvar.h
sys/arch/amd64/include/cpufunc.h
sys/arch/amd64/stand/boot/conf.c
sys/arch/amd64/stand/cdboot/conf.c
sys/arch/amd64/stand/efiboot/conf.c
sys/arch/amd64/stand/libsa/exec_i386.c
sys/arch/amd64/stand/pxeboot/conf.c

index 8a779aa..c8727f5 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: cpu.c,v 1.110 2018/01/12 20:14:20 deraadt Exp $       */
+/*     $OpenBSD: cpu.c,v 1.111 2018/02/06 01:09:17 patrick Exp $       */
 /* $NetBSD: cpu.c,v 1.1 2003/04/26 18:39:26 fvdl Exp $ */
 
 /*-
@@ -406,21 +406,24 @@ cpu_attach(struct device *parent, struct device *self, void *aux)
                printf("(uniprocessor)\n");
                ci->ci_flags |= CPUF_PRESENT | CPUF_SP | CPUF_PRIMARY;
                cpu_intr_init(ci);
+#ifndef SMALL_KERNEL
+               cpu_ucode_apply(ci);
+#endif
                identifycpu(ci);
 #ifdef MTRR
                mem_range_attach();
 #endif /* MTRR */
                cpu_init(ci);
                cpu_init_mwait(sc);
-#ifndef SMALL_KERNEL
-               config_mountroot(NULL, cpu_ucode_attachhook);
-#endif
                break;
 
        case CPU_ROLE_BP:
                printf("apid %d (boot processor)\n", caa->cpu_apicid);
                ci->ci_flags |= CPUF_PRESENT | CPUF_BSP | CPUF_PRIMARY;
                cpu_intr_init(ci);
+#ifndef SMALL_KERNEL
+               cpu_ucode_apply(ci);
+#endif
                identifycpu(ci);
 #ifdef MTRR
                mem_range_attach();
@@ -438,9 +441,6 @@ cpu_attach(struct device *parent, struct device *self, void *aux)
                ioapic_bsp_id = caa->cpu_apicid;
 #endif
                cpu_init_mwait(sc);
-#ifndef SMALL_KERNEL
-               config_mountroot(NULL, cpu_ucode_attachhook);
-#endif
                break;
 
        case CPU_ROLE_AP:
@@ -698,6 +698,7 @@ cpu_hatch(void *v)
 
        lapic_enable();
        lapic_startclock();
+       cpu_ucode_apply(ci);
 
        if ((ci->ci_flags & CPUF_IDENTIFIED) == 0) {
                /*
@@ -738,8 +739,6 @@ cpu_hatch(void *v)
        lldt(0);
 
        cpu_init(ci);
-       cpu_ucode_apply(ci);
-       cpu_flags_update(ci);
 #if NPVBUS > 0
        pvbus_init_cpu();
 #endif
@@ -939,20 +938,3 @@ cpu_activate(struct device *self, int act)
 
        return (0);
 }
-
-void
-cpu_flags_update(struct cpu_info *ci)
-{
-       uint32_t dummy;
-
-       /* XXX this update is much later than we want it to be */
-       if (cpuid_level >= 0x07) {
-               CPUID_LEAF(0x7, 0, dummy, dummy, dummy,
-                   ci->ci_feature_sefflags_edx);
-       }
-       if (!strcmp(cpu_vendor, "AuthenticAMD") &&
-           ci->ci_pnfeatset >= 0x80000008) {
-               CPUID(0x80000008, dummy, ci->ci_feature_amdspec_ebx,
-                   dummy, dummy);
-       }
-}
index 33d1d38..a1d5e02 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: machdep.c,v 1.237 2018/01/06 22:03:12 guenther Exp $  */
+/*     $OpenBSD: machdep.c,v 1.238 2018/02/06 01:09:17 patrick Exp $   */
 /*     $NetBSD: machdep.c,v 1.3 2003/05/07 22:58:18 fvdl Exp $ */
 
 /*-
@@ -241,6 +241,7 @@ bios_diskinfo_t     *bios_diskinfo;
 bios_memmap_t  *bios_memmap;
 u_int32_t      bios_cksumlen;
 bios_efiinfo_t *bios_efiinfo;
+bios_ucode_t   *bios_ucode;
 
 /*
  * Size of memory segments, before any memory is stolen.
@@ -308,6 +309,10 @@ cpu_startup(void)
 
        /* Safe for i/o port / memory space allocation to use malloc now. */
        x86_bus_space_mallocok();
+
+#ifndef SMALL_KERNEL
+       cpu_ucode_setup();
+#endif
 }
 
 /*
@@ -1886,6 +1891,10 @@ getbootinfo(char *bootinfo, int bootinfo_size)
                                docninit++;
                        break;
 
+               case BOOTARG_UCODE:
+                       bios_ucode = (bios_ucode_t *)q->ba_arg;
+                       break;
+
                default:
 #ifdef BOOTINFO_DEBUG
                        printf(" unsupported arg (%d) %p", q->ba_type,
index ceec53d..232a1a6 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ucode.c,v 1.3 2018/01/14 20:15:37 bluhm Exp $ */
+/*     $OpenBSD: ucode.c,v 1.4 2018/02/06 01:09:17 patrick Exp $       */
 /*
  * Copyright (c) 2018 Stefan Fritsch <fritsch@genua.de>
  * Copyright (c) 2018 Patrick Wildt <patrick@blueri.se>
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/mutex.h>
+#include <sys/malloc.h>
+
+#include <uvm/uvm_extern.h>
 
 #include <machine/cpu.h>
 #include <machine/cpufunc.h>
 #include <machine/specialreg.h>
+#include <machine/biosvar.h>
 
 /* #define UCODE_DEBUG */
 #ifdef UCODE_DEBUG
@@ -65,7 +69,7 @@ struct intel_ucode_ext_sig {
 char *  cpu_ucode_data;
 size_t  cpu_ucode_size;
 
-void    cpu_ucode_setup(struct cpu_info *);
+void    cpu_ucode_setup(void);
 void    cpu_ucode_apply(struct cpu_info *);
 
 /* Intel */
@@ -81,32 +85,18 @@ struct intel_ucode_header   *cpu_ucode_intel_applied;
 struct mutex                    cpu_ucode_intel_mtx = MUTEX_INITIALIZER(IPL_HIGH);
 
 void
-cpu_ucode_attachhook(struct device *dv)
+cpu_ucode_setup(void)
 {
-       struct cpu_info *ci = curcpu();
-
-       cpu_ucode_setup(ci);
-       cpu_ucode_apply(ci);
-       cpu_flags_update(ci);
-}
-
-void
-cpu_ucode_setup(struct cpu_info *ci)
-{
-       char name[128];
-       u_char *ucode;
-       size_t size;
-
-       snprintf(name, sizeof(name), "intel/%02x-%02x-%02x", ci->ci_family,
-           ci->ci_model, (ci->ci_signature >> 0) & 0x0f);
+       if (bios_ucode == NULL)
+               return;
 
-       if (loadfirmware(name, &ucode, &size) != 0) {
-               DPRINTF(("%s: no microcode found: %s\n", __func__, name));
+       if (!bios_ucode->uc_addr || !bios_ucode->uc_size)
                return;
-       }
 
-       cpu_ucode_data = ucode;
-       cpu_ucode_size = size;
+       cpu_ucode_size = bios_ucode->uc_size;
+       cpu_ucode_data = malloc(cpu_ucode_size, M_DEVBUF, M_WAITOK);
+       memcpy(cpu_ucode_data, (void *)PMAP_DIRECT_MAP(bios_ucode->uc_addr),
+           cpu_ucode_size);
 }
 
 /*
@@ -126,8 +116,10 @@ cpu_ucode_intel_apply(struct cpu_info *ci)
        uint32_t old_rev, new_rev;
        paddr_t data;
 
-       if (cpu_ucode_data == NULL || cpu_ucode_size == 0)
+       if (cpu_ucode_data == NULL || cpu_ucode_size == 0) {
+               DPRINTF(("%s: no microcode provided\n", __func__));
                return;
+       }
 
        /*
         * Grab a mutex, because we are not allowed to run updates
@@ -140,10 +132,14 @@ cpu_ucode_intel_apply(struct cpu_info *ci)
        if (update == NULL)
                update = cpu_ucode_intel_find(cpu_ucode_data,
                    cpu_ucode_size, old_rev);
-       if (update == NULL)
+       if (update == NULL) {
+               DPRINTF(("%s: no microcode update found\n", __func__));
                goto out;
-       if (update->update_revision == old_rev)
+       }
+       if (update->update_revision == old_rev) {
+               DPRINTF(("%s: microcode already up-to-date\n", __func__));
                goto out;
+       }
 
        /* Apply microcode. */
        data = (paddr_t)update;
index dcb59d7..14de16b 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: biosvar.h,v 1.24 2017/06/20 12:39:20 tom Exp $        */
+/*     $OpenBSD: biosvar.h,v 1.25 2018/02/06 01:09:17 patrick Exp $    */
 
 /*
  * Copyright (c) 1997-1999 Michael Shalayeff
@@ -206,6 +206,12 @@ typedef struct _bios_efiinfo {
        uint32_t        fb_reserved_mask;
 } __packed bios_efiinfo_t;
 
+#define        BOOTARG_UCODE 12
+typedef struct _bios_ucode {
+       uint64_t        uc_addr;
+       uint64_t        uc_size;
+} __packed bios_ucode_t;
+
 #if defined(_KERNEL) || defined (_STANDALONE)
 
 #ifdef _LOCORE
@@ -254,6 +260,7 @@ bios_diskinfo_t *bios_getdiskinfo(dev_t);
 extern u_int bootapiver;
 extern bios_memmap_t *bios_memmap;
 extern bios_efiinfo_t *bios_efiinfo;
+extern bios_ucode_t *bios_ucode;
 
 #endif /* _KERNEL */
 #endif /* _LOCORE */
index a86ac71..b52e4b3 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: cpufunc.h,v 1.22 2018/01/11 22:31:09 patrick Exp $    */
+/*     $OpenBSD: cpufunc.h,v 1.23 2018/02/06 01:09:17 patrick Exp $    */
 /*     $NetBSD: cpufunc.h,v 1.3 2003/05/08 10:27:43 fvdl Exp $ */
 
 /*-
@@ -314,9 +314,8 @@ breakpoint(void)
 }
 
 void amd64_errata(struct cpu_info *);
-void cpu_flags_update(struct cpu_info *);
+void cpu_ucode_setup(void);
 void cpu_ucode_apply(struct cpu_info *);
-void cpu_ucode_attachhook(struct device *);
 
 #endif /* _KERNEL */
 
index 6bb7271..50cb3b9 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: conf.c,v 1.38 2017/09/08 05:36:51 deraadt Exp $       */
+/*     $OpenBSD: conf.c,v 1.39 2018/02/06 01:09:17 patrick Exp $       */
 
 /*
  * Copyright (c) 1996 Michael Shalayeff
@@ -40,7 +40,7 @@
 #include <biosdev.h>
 #include <dev/cons.h>
 
-const char version[] = "3.33";
+const char version[] = "3.34";
 int    debug = 1;
 
 
index 2908856..dc54f04 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: conf.c,v 1.33 2017/09/08 05:36:51 deraadt Exp $       */
+/*     $OpenBSD: conf.c,v 1.34 2018/02/06 01:09:17 patrick Exp $       */
 
 /*
  * Copyright (c) 2004 Tom Cosgrove
@@ -41,7 +41,7 @@
 #include <biosdev.h>
 #include <dev/cons.h>
 
-const char version[] = "3.28";
+const char version[] = "3.29";
 int    debug = 1;
 
 
index b91d748..7c9d692 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: conf.c,v 1.13 2018/01/30 20:19:06 naddy Exp $ */
+/*     $OpenBSD: conf.c,v 1.14 2018/02/06 01:09:17 patrick Exp $       */
 
 /*
  * Copyright (c) 1996 Michael Shalayeff
@@ -39,7 +39,7 @@
 #include "efidev.h"
 #include "efipxe.h"
 
-const char version[] = "3.37";
+const char version[] = "3.38";
 
 #ifdef EFI_DEBUG
 int    debug = 0;
index eecefb2..b4abf18 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: exec_i386.c,v 1.19 2017/07/06 11:27:56 mlarkin Exp $  */
+/*     $OpenBSD: exec_i386.c,v 1.20 2018/02/06 01:09:17 patrick Exp $  */
 
 /*
  * Copyright (c) 1997-1998 Michael Shalayeff
 #include <dev/cons.h>
 #include <lib/libsa/loadfile.h>
 #include <machine/biosvar.h>
+#include <machine/specialreg.h>
 #include <stand/boot/bootarg.h>
 
+#include "cmd.h"
 #include "disk.h"
 #include "libsa.h"
 
@@ -51,6 +53,9 @@
 typedef void (*startfuncp)(int, int, int, int, int, int, int, int)
     __attribute__ ((noreturn));
 
+void ucode_load(void);
+extern struct cmd_state cmd;
+
 char *bootmac = NULL;
 
 void
@@ -102,6 +107,8 @@ run_loadfile(u_long *marks, int howto)
        bcopy(bootdev_dip->disklabel.d_uid, &bootduid.duid, sizeof(bootduid));
        addbootarg(BOOTARG_BOOTDUID, sizeof(bootduid), &bootduid);
 
+       ucode_load();
+
 #ifdef SOFTRAID
        if (bootdev_dip->sr_vol != NULL) {
                bv = bootdev_dip->sr_vol;
@@ -160,3 +167,54 @@ run_loadfile(u_long *marks, int howto)
 #endif
        /* not reached */
 }
+
+void
+ucode_load(void)
+{
+       uint32_t model, family, stepping;
+       uint32_t dummy, signature;
+       uint32_t vendor[4];
+       bios_ucode_t uc;
+       struct stat sb;
+       char path[128];
+       size_t buflen;
+       char *buf;
+       int fd;
+
+       CPUID(0, dummy, vendor[0], vendor[2], vendor[1]);
+       vendor[3] = 0; /* NULL-terminate */
+       if (strcmp((char *)vendor, "GenuineIntel") != 0)
+               return;
+
+       CPUID(1, signature, dummy, dummy, dummy);
+       family = (signature >> 8) & 0x0f;
+       model = (signature >> 4) & 0x0f;
+       if (family == 0x6 || family == 0xf) {
+               family += (signature >> 20) & 0xff;
+               model += ((signature >> 16) & 0x0f) << 4;
+       }
+       stepping = (signature >> 0) & 0x0f;
+
+       snprintf(path, sizeof(path), "%s:/etc/firmware/intel/%02x-%02x-%02x",
+           cmd.bootdev, family, model, stepping);
+
+       fd = open(path, 0);
+       if (fd == -1)
+               return;
+
+       if (fstat(fd, &sb) == -1)
+               return;
+
+       buflen = sb.st_size;
+       if ((buf = alloc(buflen)) == NULL)
+               return;
+
+       if (read(fd, buf, buflen) != buflen) {
+               free(buf, buflen);
+               return;
+       }
+
+       uc.uc_addr = (uint64_t)buf;
+       uc.uc_size = (uint64_t)buflen;
+       addbootarg(BOOTARG_UCODE, sizeof(uc), &uc);
+}
index 4e24843..05524fa 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: conf.c,v 1.37 2017/09/08 05:36:51 deraadt Exp $       */
+/*     $OpenBSD: conf.c,v 1.38 2018/02/06 01:09:17 patrick Exp $       */
 
 /*
  * Copyright (c) 2004 Tom Cosgrove
@@ -43,7 +43,7 @@
 #include "pxeboot.h"
 #include "pxe_net.h"
 
-const char version[] = "3.28";
+const char version[] = "3.29";
 int    debug = 0;
 
 void (*sa_cleanup)(void) = pxe_shutdown;