From b4ccf14a1737e02e6ff8c00d848e6d132b880b0d Mon Sep 17 00:00:00 2001 From: patrick Date: Tue, 6 Feb 2018 01:09:17 +0000 Subject: [PATCH] Load the Intel microcode much earlier. So far we had loaded it after 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 | 34 ++++----------- sys/arch/amd64/amd64/machdep.c | 11 ++++- sys/arch/amd64/amd64/ucode.c | 50 ++++++++++----------- sys/arch/amd64/include/biosvar.h | 9 +++- sys/arch/amd64/include/cpufunc.h | 5 +-- sys/arch/amd64/stand/boot/conf.c | 4 +- sys/arch/amd64/stand/cdboot/conf.c | 4 +- sys/arch/amd64/stand/efiboot/conf.c | 4 +- sys/arch/amd64/stand/libsa/exec_i386.c | 60 +++++++++++++++++++++++++- sys/arch/amd64/stand/pxeboot/conf.c | 4 +- 10 files changed, 118 insertions(+), 67 deletions(-) diff --git a/sys/arch/amd64/amd64/cpu.c b/sys/arch/amd64/amd64/cpu.c index 8a779aa65eb..c8727f583b0 100644 --- a/sys/arch/amd64/amd64/cpu.c +++ b/sys/arch/amd64/amd64/cpu.c @@ -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); - } -} diff --git a/sys/arch/amd64/amd64/machdep.c b/sys/arch/amd64/amd64/machdep.c index 33d1d38395b..a1d5e02f340 100644 --- a/sys/arch/amd64/amd64/machdep.c +++ b/sys/arch/amd64/amd64/machdep.c @@ -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, diff --git a/sys/arch/amd64/amd64/ucode.c b/sys/arch/amd64/amd64/ucode.c index ceec53dafea..232a1a6d081 100644 --- a/sys/arch/amd64/amd64/ucode.c +++ b/sys/arch/amd64/amd64/ucode.c @@ -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 * Copyright (c) 2018 Patrick Wildt @@ -19,10 +19,14 @@ #include #include #include +#include + +#include #include #include #include +#include /* #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; diff --git a/sys/arch/amd64/include/biosvar.h b/sys/arch/amd64/include/biosvar.h index dcb59d766ca..14de16baf31 100644 --- a/sys/arch/amd64/include/biosvar.h +++ b/sys/arch/amd64/include/biosvar.h @@ -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 */ diff --git a/sys/arch/amd64/include/cpufunc.h b/sys/arch/amd64/include/cpufunc.h index a86ac711a80..b52e4b3d2ae 100644 --- a/sys/arch/amd64/include/cpufunc.h +++ b/sys/arch/amd64/include/cpufunc.h @@ -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 */ diff --git a/sys/arch/amd64/stand/boot/conf.c b/sys/arch/amd64/stand/boot/conf.c index 6bb7271de00..50cb3b92e9d 100644 --- a/sys/arch/amd64/stand/boot/conf.c +++ b/sys/arch/amd64/stand/boot/conf.c @@ -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 #include -const char version[] = "3.33"; +const char version[] = "3.34"; int debug = 1; diff --git a/sys/arch/amd64/stand/cdboot/conf.c b/sys/arch/amd64/stand/cdboot/conf.c index 29088565aa8..dc54f04658e 100644 --- a/sys/arch/amd64/stand/cdboot/conf.c +++ b/sys/arch/amd64/stand/cdboot/conf.c @@ -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 #include -const char version[] = "3.28"; +const char version[] = "3.29"; int debug = 1; diff --git a/sys/arch/amd64/stand/efiboot/conf.c b/sys/arch/amd64/stand/efiboot/conf.c index b91d7485dea..7c9d692c717 100644 --- a/sys/arch/amd64/stand/efiboot/conf.c +++ b/sys/arch/amd64/stand/efiboot/conf.c @@ -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; diff --git a/sys/arch/amd64/stand/libsa/exec_i386.c b/sys/arch/amd64/stand/libsa/exec_i386.c index eecefb2c2d8..b4abf181240 100644 --- a/sys/arch/amd64/stand/libsa/exec_i386.c +++ b/sys/arch/amd64/stand/libsa/exec_i386.c @@ -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 @@ -33,8 +33,10 @@ #include #include #include +#include #include +#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); +} diff --git a/sys/arch/amd64/stand/pxeboot/conf.c b/sys/arch/amd64/stand/pxeboot/conf.c index 4e2484374c3..05524fab91c 100644 --- a/sys/arch/amd64/stand/pxeboot/conf.c +++ b/sys/arch/amd64/stand/pxeboot/conf.c @@ -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; -- 2.20.1