summaryrefslogtreecommitdiff
path: root/sys/arch
diff options
context:
space:
mode:
authorJonathan Gray <jsg@cvs.openbsd.org>2018-08-23 14:47:53 +0000
committerJonathan Gray <jsg@cvs.openbsd.org>2018-08-23 14:47:53 +0000
commitf686e54fb037fc379c9127f0d54e077831f38e81 (patch)
treef09382a8fa0ed6e865518a6b2c40626c0931fafd /sys/arch
parentfc469ea850621ad85ab19d7482c03478fc263bcb (diff)
port the amd64 code for loading intel microcode on boot to i386
ok deraadt@ mlarkin@
Diffstat (limited to 'sys/arch')
-rw-r--r--sys/arch/i386/conf/files.i3863
-rw-r--r--sys/arch/i386/i386/acpi_machdep.c3
-rw-r--r--sys/arch/i386/i386/bios.c7
-rw-r--r--sys/arch/i386/i386/cpu.c11
-rw-r--r--sys/arch/i386/i386/machdep.c6
-rw-r--r--sys/arch/i386/i386/ucode.c328
-rw-r--r--sys/arch/i386/include/biosvar.h9
-rw-r--r--sys/arch/i386/include/cpufunc.h4
-rw-r--r--sys/arch/i386/include/specialreg.h3
-rw-r--r--sys/arch/i386/stand/boot/conf.c4
-rw-r--r--sys/arch/i386/stand/cdboot/conf.c4
-rw-r--r--sys/arch/i386/stand/libsa/exec_i386.c64
-rw-r--r--sys/arch/i386/stand/pxeboot/conf.c4
13 files changed, 435 insertions, 15 deletions
diff --git a/sys/arch/i386/conf/files.i386 b/sys/arch/i386/conf/files.i386
index ccc0b1206bc..e44323853ea 100644
--- a/sys/arch/i386/conf/files.i386
+++ b/sys/arch/i386/conf/files.i386
@@ -1,4 +1,4 @@
-# $OpenBSD: files.i386,v 1.242 2018/08/21 18:06:12 anton Exp $
+# $OpenBSD: files.i386,v 1.243 2018/08/23 14:47:52 jsg Exp $
#
# new style config file for i386 architecture
#
@@ -26,6 +26,7 @@ file arch/i386/i386/via.c
file arch/i386/i386/locore.s
file arch/i386/i386/amd64errata.c !small_kernel
file arch/i386/i386/longrun.c !small_kernel
+file arch/i386/i386/ucode.c !small_kernel
file arch/i386/i386/mem.c
file arch/i386/i386/i686_mem.c mtrr
file arch/i386/i386/k6_mem.c mtrr
diff --git a/sys/arch/i386/i386/acpi_machdep.c b/sys/arch/i386/i386/acpi_machdep.c
index 163f46388bb..bdc97fa8288 100644
--- a/sys/arch/i386/i386/acpi_machdep.c
+++ b/sys/arch/i386/i386/acpi_machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: acpi_machdep.c,v 1.69 2018/08/19 08:23:47 kettenis Exp $ */
+/* $OpenBSD: acpi_machdep.c,v 1.70 2018/08/23 14:47:52 jsg Exp $ */
/*
* Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com>
*
@@ -445,6 +445,7 @@ acpi_resume_cpu(struct acpi_softc *sc)
npxinit(&cpu_info_primary);
cpu_init(&cpu_info_primary);
+ cpu_ucode_apply(&cpu_info_primary);
/* Re-initialise memory range handling on BSP */
if (mem_range_softc.mr_op != NULL)
diff --git a/sys/arch/i386/i386/bios.c b/sys/arch/i386/i386/bios.c
index a6c3752fd0e..58e7ce436c9 100644
--- a/sys/arch/i386/i386/bios.c
+++ b/sys/arch/i386/i386/bios.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: bios.c,v 1.118 2018/04/28 15:44:59 jasper Exp $ */
+/* $OpenBSD: bios.c,v 1.119 2018/08/23 14:47:52 jsg Exp $ */
/*
* Copyright (c) 1997-2001 Michael Shalayeff
@@ -122,6 +122,7 @@ bios_bootmac_t *bios_bootmac;
#ifdef DDB
extern int db_console;
#endif
+bios_ucode_t *bios_ucode;
void smbios_info(char*);
@@ -608,6 +609,10 @@ bios_getopt(void)
explicit_bzero(bios_bootsr, sizeof(bios_bootsr_t));
break;
+ case BOOTARG_UCODE:
+ bios_ucode = (bios_ucode_t *)q->ba_arg;
+ break;
+
default:
#ifdef BIOS_DEBUG
printf(" unsupported arg (%d) %p", q->ba_type,
diff --git a/sys/arch/i386/i386/cpu.c b/sys/arch/i386/i386/cpu.c
index 54964560d0b..ded91fc64aa 100644
--- a/sys/arch/i386/i386/cpu.c
+++ b/sys/arch/i386/i386/cpu.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cpu.c,v 1.94 2018/07/30 14:19:12 kettenis Exp $ */
+/* $OpenBSD: cpu.c,v 1.95 2018/08/23 14:47:52 jsg Exp $ */
/* $NetBSD: cpu.c,v 1.1.2.7 2000/06/26 02:04:05 sommerfeld Exp $ */
/*-
@@ -317,6 +317,9 @@ cpu_attach(struct device *parent, struct device *self, void *aux)
case CPU_ROLE_SP:
printf("(uniprocessor)\n");
ci->ci_flags |= CPUF_PRESENT | CPUF_SP | CPUF_PRIMARY;
+#ifndef SMALL_KERNEL
+ cpu_ucode_apply(ci);
+#endif
identifycpu(ci);
#ifdef MTRR
mem_range_attach();
@@ -328,6 +331,9 @@ cpu_attach(struct device *parent, struct device *self, void *aux)
case CPU_ROLE_BP:
printf("apid %d (boot processor)\n", caa->cpu_apicid);
ci->ci_flags |= CPUF_PRESENT | CPUF_BSP | CPUF_PRIMARY;
+#ifndef SMALL_KERNEL
+ cpu_ucode_apply(ci);
+#endif
identifycpu(ci);
#ifdef MTRR
mem_range_attach();
@@ -356,6 +362,9 @@ cpu_attach(struct device *parent, struct device *self, void *aux)
#ifdef MULTIPROCESSOR
gdt_alloc_cpu(ci);
ci->ci_flags |= CPUF_PRESENT | CPUF_AP;
+#ifndef SMALL_KERNEL
+ cpu_ucode_apply(ci);
+#endif
identifycpu(ci);
sched_init_cpu(ci);
ci->ci_next = cpu_info_list->ci_next;
diff --git a/sys/arch/i386/i386/machdep.c b/sys/arch/i386/i386/machdep.c
index 57dfb38289f..b3c20696113 100644
--- a/sys/arch/i386/i386/machdep.c
+++ b/sys/arch/i386/i386/machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: machdep.c,v 1.625 2018/08/21 12:44:13 jsg Exp $ */
+/* $OpenBSD: machdep.c,v 1.626 2018/08/23 14:47:52 jsg Exp $ */
/* $NetBSD: machdep.c,v 1.214 1996/11/10 03:16:17 thorpej Exp $ */
/*-
@@ -422,6 +422,10 @@ cpu_startup(void)
}
ioport_malloc_safe = 1;
+#ifndef SMALL_KERNEL
+ cpu_ucode_setup();
+#endif
+
/* enter the IDT and trampoline code in the u-k maps */
enter_shared_special_pages();
diff --git a/sys/arch/i386/i386/ucode.c b/sys/arch/i386/i386/ucode.c
new file mode 100644
index 00000000000..a5c10da35af
--- /dev/null
+++ b/sys/arch/i386/i386/ucode.c
@@ -0,0 +1,328 @@
+/* $OpenBSD: ucode.c,v 1.1 2018/08/23 14:47:52 jsg Exp $ */
+/*
+ * Copyright (c) 2018 Stefan Fritsch <fritsch@genua.de>
+ * Copyright (c) 2018 Patrick Wildt <patrick@blueri.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#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
+#define DPRINTF(x) do { if (cpu_ucode_debug > 0) printf x; } while (0)
+#define DPRINTFN(n, x) do { if (cpu_ucode_debug >= (n)) printf x; } while (0)
+int cpu_ucode_debug = 1;
+#else
+#define DPRINTF(x) do { ; } while (0)
+#define DPRINTFN(n, x) do { ; } while (0)
+#endif
+
+struct intel_ucode_header {
+ uint32_t header_version;
+ uint32_t update_revision;
+ uint32_t date;
+ uint32_t processor_sig;
+ uint32_t checksum;
+ uint32_t loader_rev;
+ uint32_t processor_flags;
+ uint32_t data_size;
+ uint32_t total_size;
+ uint32_t reserved[3];
+};
+
+struct intel_ucode_ext_sig_header {
+ uint32_t ext_sig_count;
+ uint32_t checksum;
+ uint32_t reserved[3];
+};
+
+struct intel_ucode_ext_sig {
+ uint32_t processor_sig;
+ uint32_t processor_flags;
+ uint32_t checksum;
+};
+
+#define INTEL_UCODE_DEFAULT_DATA_SIZE 2000
+
+/* Generic */
+char * cpu_ucode_data;
+size_t cpu_ucode_size;
+
+void cpu_ucode_setup(void);
+void cpu_ucode_apply(struct cpu_info *);
+
+/* Intel */
+void cpu_ucode_intel_apply(struct cpu_info *);
+struct intel_ucode_header *
+ cpu_ucode_intel_find(char *, size_t, uint32_t);
+int cpu_ucode_intel_verify(struct intel_ucode_header *);
+int cpu_ucode_intel_match(struct intel_ucode_header *, uint32_t, uint32_t,
+ uint32_t);
+uint32_t cpu_ucode_intel_rev(void);
+
+struct intel_ucode_header *cpu_ucode_intel_applied;
+struct mutex cpu_ucode_intel_mtx = MUTEX_INITIALIZER(IPL_HIGH);
+
+void
+cpu_ucode_setup(void)
+{
+ vaddr_t va;
+ paddr_t pa;
+ int i, npages;
+ size_t size;
+
+ if (bios_ucode == NULL)
+ return;
+
+ if (!bios_ucode->uc_addr || !bios_ucode->uc_size)
+ return;
+
+ cpu_ucode_size = bios_ucode->uc_size;
+ size = round_page(bios_ucode->uc_size);
+ npages = size / PAGE_SIZE;
+
+ va = uvm_km_valloc(kernel_map, size);
+ if (va == 0)
+ return;
+ for (i = 0; i < npages; i++) {
+ pa = bios_ucode->uc_addr + (i * PAGE_SIZE);
+ pmap_enter(pmap_kernel(), va + (i * PAGE_SIZE), pa,
+ PROT_READ,
+ PROT_READ | PMAP_WIRED);
+ pmap_update(pmap_kernel());
+ }
+
+ cpu_ucode_data = malloc(cpu_ucode_size, M_DEVBUF, M_WAITOK);
+
+ memcpy((void *)cpu_ucode_data, (void *)va, cpu_ucode_size);
+
+ pmap_remove(pmap_kernel(), va, va + size);
+ pmap_update(pmap_kernel());
+ uvm_km_free(kernel_map, va, size);
+}
+
+/*
+ * Called per-CPU.
+ */
+void
+cpu_ucode_apply(struct cpu_info *ci)
+{
+ if (strcmp(cpu_vendor, "GenuineIntel") == 0)
+ cpu_ucode_intel_apply(ci);
+}
+
+void
+cpu_ucode_intel_apply(struct cpu_info *ci)
+{
+ struct intel_ucode_header *update;
+ uint32_t old_rev, new_rev;
+ paddr_t data;
+
+ 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
+ * simultaneously on HT siblings.
+ */
+ mtx_enter(&cpu_ucode_intel_mtx);
+
+ old_rev = cpu_ucode_intel_rev();
+ update = cpu_ucode_intel_applied;
+ if (update == NULL)
+ update = cpu_ucode_intel_find(cpu_ucode_data,
+ cpu_ucode_size, old_rev);
+ if (update == NULL) {
+ DPRINTF(("%s: no microcode update found\n", __func__));
+ goto out;
+ }
+ if (update->update_revision == old_rev) {
+ DPRINTF(("%s: microcode already up-to-date\n", __func__));
+ goto out;
+ }
+
+ /* Apply microcode. */
+ data = (paddr_t)update;
+ data += sizeof(struct intel_ucode_header);
+ wrmsr(MSR_BIOS_UPDT_TRIG, data);
+
+ new_rev = cpu_ucode_intel_rev();
+ if (new_rev != old_rev) {
+ DPRINTF(("%s: microcode updated cpu %ld rev %#x->%#x (%x)\n",
+ __func__, ci->ci_cpuid, old_rev, new_rev, update->date));
+ if (cpu_ucode_intel_applied == NULL)
+ cpu_ucode_intel_applied = update;
+ } else {
+ DPRINTF(("%s: microcode update failed cpu %ld rev %#x->%#x != %#x\n",
+ __func__, ci->ci_cpuid, old_rev, update->update_revision, new_rev));
+ }
+
+out:
+ mtx_leave(&cpu_ucode_intel_mtx);
+}
+
+struct intel_ucode_header *
+cpu_ucode_intel_find(char *data, size_t left, uint32_t current)
+{
+ uint64_t platform_id = (rdmsr(MSR_PLATFORM_ID) >> 50) & 0xff;
+ uint32_t sig, dummy1, dummy2, dummy3;
+ uint32_t mask = 1UL << platform_id;
+ struct intel_ucode_header *hdr;
+ uint32_t total_size;
+ int n = 0;
+
+ CPUID(1, sig, dummy1, dummy2, dummy3);
+
+ while (left > 0) {
+ hdr = (struct intel_ucode_header *)data;
+ if (left < sizeof(struct intel_ucode_header)) {
+ DPRINTF(("%s:%d: not enough data for header (%zd)\n",
+ __func__, n, left));
+ break;
+ }
+ /*
+ * Older microcode has an empty length. In that case we
+ * have to use the default length of 2000.
+ */
+ if (hdr->data_size)
+ total_size = hdr->total_size;
+ else
+ total_size = INTEL_UCODE_DEFAULT_DATA_SIZE +
+ sizeof(struct intel_ucode_header);
+ if (total_size > left) {
+ DPRINTF(("%s:%d: size %u out of range (%zd)\n",
+ __func__, n, total_size, left));
+ break;
+ }
+ if (cpu_ucode_intel_verify(hdr)) {
+ DPRINTF(("%s:%d: broken data\n", __func__, n));
+ break;
+ }
+ if (cpu_ucode_intel_match(hdr, sig, mask, current))
+ return hdr;
+ n++;
+ left -= total_size;
+ data += total_size;
+ }
+ DPRINTF(("%s: no update found\n", __func__));
+ return NULL;
+}
+
+int
+cpu_ucode_intel_verify(struct intel_ucode_header *hdr)
+{
+ uint32_t *data = (uint32_t *)hdr;
+ size_t total_size;
+ uint32_t sum;
+ int i;
+
+ CTASSERT(sizeof(struct intel_ucode_header) == 48);
+
+ if ((paddr_t)data % 16 != 0) {
+ DPRINTF(("%s: misaligned microcode update\n", __func__));
+ return 1;
+ }
+ if (hdr->loader_rev != 1) {
+ DPRINTF(("%s: unsupported loader rev\n", __func__));
+ return 1;
+ }
+
+ if (hdr->data_size)
+ total_size = hdr->total_size;
+ else
+ total_size = INTEL_UCODE_DEFAULT_DATA_SIZE +
+ sizeof(struct intel_ucode_header);
+ if (total_size % 4 != 0) {
+ DPRINTF(("%s: inconsistent size\n", __func__));
+ return 1;
+ }
+
+ sum = 0;
+ for (i = 0; i < total_size / 4; i++)
+ sum += data[i];
+ if (sum != 0) {
+ DPRINTF(("%s: wrong checksum (%#x)\n", __func__, sum));
+ return 1;
+ }
+
+ return 0;
+}
+
+int
+cpu_ucode_intel_match(struct intel_ucode_header *hdr,
+ uint32_t processor_sig, uint32_t processor_mask,
+ uint32_t ucode_revision)
+{
+ struct intel_ucode_ext_sig_header *ehdr;
+ struct intel_ucode_ext_sig *esig;
+ uint32_t data_size, total_size;
+ unsigned i;
+
+ data_size = hdr->data_size;
+ total_size = hdr->total_size;
+
+ /*
+ * Older microcode has an empty length. In that case we
+ * have to use the default length of 2000.
+ */
+ if (!data_size) {
+ data_size = INTEL_UCODE_DEFAULT_DATA_SIZE;
+ total_size = INTEL_UCODE_DEFAULT_DATA_SIZE +
+ sizeof(struct intel_ucode_header);
+ }
+
+ if (ucode_revision > hdr->update_revision)
+ return 0;
+ if (hdr->processor_sig == processor_sig &&
+ (hdr->processor_flags & processor_mask))
+ return 1;
+ if (total_size <= sizeof(struct intel_ucode_header) +
+ data_size + sizeof(struct intel_ucode_ext_sig_header))
+ return 0;
+
+ ehdr = (void *)((char *)hdr + sizeof(struct intel_ucode_header) +
+ data_size);
+ esig = (void *)&ehdr[1];
+ for (i = 0; i < ehdr->ext_sig_count; i++) {
+ if (esig[i].processor_sig == processor_sig &&
+ (esig[i].processor_flags & processor_mask))
+ return 1;
+ }
+
+ return 0;
+}
+
+uint32_t
+cpu_ucode_intel_rev(void)
+{
+ uint32_t eax, ebx, ecx, edx;
+ uint64_t rev;
+
+ wrmsr(MSR_BIOS_SIGN, 0);
+ CPUID(1, eax, ebx, ecx, edx);
+ rev = rdmsr(MSR_BIOS_SIGN);
+ return rev >> 32;
+}
diff --git a/sys/arch/i386/include/biosvar.h b/sys/arch/i386/include/biosvar.h
index df903be32b3..94a7df3140f 100644
--- a/sys/arch/i386/include/biosvar.h
+++ b/sys/arch/i386/include/biosvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: biosvar.h,v 1.66 2017/06/20 12:39:20 tom Exp $ */
+/* $OpenBSD: biosvar.h,v 1.67 2018/08/23 14:47:52 jsg Exp $ */
/*
* Copyright (c) 1997-1999 Michael Shalayeff
@@ -238,6 +238,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
@@ -289,6 +295,7 @@ void bios32_cleanup(void);
extern u_int bootapiver;
extern bios_memmap_t *bios_memmap;
extern bios_efiinfo_t *bios_efiinfo;
+extern bios_ucode_t *bios_ucode;
extern void *bios_smpinfo;
extern bios_pciinfo_t *bios_pciinfo;
diff --git a/sys/arch/i386/include/cpufunc.h b/sys/arch/i386/include/cpufunc.h
index 4f52ffb6fdd..78d368d9186 100644
--- a/sys/arch/i386/include/cpufunc.h
+++ b/sys/arch/i386/include/cpufunc.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: cpufunc.h,v 1.30 2018/07/30 14:19:12 kettenis Exp $ */
+/* $OpenBSD: cpufunc.h,v 1.31 2018/08/23 14:47:52 jsg Exp $ */
/* $NetBSD: cpufunc.h,v 1.8 1994/10/27 04:15:59 cgd Exp $ */
/*
@@ -280,6 +280,8 @@ breakpoint(void)
}
void amd64_errata(struct cpu_info *);
+void cpu_ucode_setup(void);
+void cpu_ucode_apply(struct cpu_info *);
struct cpu_info_full;
void cpu_enter_pages(struct cpu_info_full *);
diff --git a/sys/arch/i386/include/specialreg.h b/sys/arch/i386/include/specialreg.h
index d9d61910933..edef12caf3d 100644
--- a/sys/arch/i386/include/specialreg.h
+++ b/sys/arch/i386/include/specialreg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: specialreg.h,v 1.70 2018/08/21 12:44:13 jsg Exp $ */
+/* $OpenBSD: specialreg.h,v 1.71 2018/08/23 14:47:52 jsg Exp $ */
/* $NetBSD: specialreg.h,v 1.7 1994/10/27 04:16:26 cgd Exp $ */
/*-
@@ -329,6 +329,7 @@
#define P5MSR_CTRSEL 0x011 /* P5 only (trap on P6) */
#define P5MSR_CTR0 0x012 /* P5 only (trap on P6) */
#define P5MSR_CTR1 0x013 /* P5 only (trap on P6) */
+#define MSR_PLATFORM_ID 0x017 /* Platform ID for microcode */
#define MSR_APICBASE 0x01b
#define APICBASE_BSP 0x100
#define APICBASE_ENABLE_X2APIC 0x400
diff --git a/sys/arch/i386/stand/boot/conf.c b/sys/arch/i386/stand/boot/conf.c
index b1ef8d8ea57..4bb6d6ba32e 100644
--- a/sys/arch/i386/stand/boot/conf.c
+++ b/sys/arch/i386/stand/boot/conf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: conf.c,v 1.64 2018/08/10 16:43:54 jsing Exp $ */
+/* $OpenBSD: conf.c,v 1.65 2018/08/23 14:47:52 jsg Exp $ */
/*
* Copyright (c) 1996 Michael Shalayeff
@@ -41,7 +41,7 @@
#include <dev/cons.h>
#include "debug.h"
-const char version[] = "3.33";
+const char version[] = "3.34";
int debug = 1;
diff --git a/sys/arch/i386/stand/cdboot/conf.c b/sys/arch/i386/stand/cdboot/conf.c
index df50d2e23e0..909fd604f0a 100644
--- a/sys/arch/i386/stand/cdboot/conf.c
+++ b/sys/arch/i386/stand/cdboot/conf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: conf.c,v 1.32 2018/07/11 18:08:05 mlarkin Exp $ */
+/* $OpenBSD: conf.c,v 1.33 2018/08/23 14:47:52 jsg Exp $ */
/*
* Copyright (c) 2004 Tom Cosgrove
@@ -42,7 +42,7 @@
#include <dev/cons.h>
#include "debug.h"
-const char version[] = "3.29";
+const char version[] = "3.30";
int debug = 1;
void (*sa_cleanup)(void) = NULL;
diff --git a/sys/arch/i386/stand/libsa/exec_i386.c b/sys/arch/i386/stand/libsa/exec_i386.c
index 4364a3c0295..4049f8b74f0 100644
--- a/sys/arch/i386/stand/libsa/exec_i386.c
+++ b/sys/arch/i386/stand/libsa/exec_i386.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: exec_i386.c,v 1.44 2016/09/11 17:52:47 jsing Exp $ */
+/* $OpenBSD: exec_i386.c,v 1.45 2018/08/23 14:47:52 jsg Exp $ */
/*
* Copyright (c) 1997-1998 Michael Shalayeff
@@ -33,8 +33,10 @@
#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
@@ -99,6 +104,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;
@@ -144,3 +151,58 @@ run_loadfile(u_long *marks, int howto)
/* not reached */
#endif
}
+
+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 (buflen > 128*1024) {
+ printf("ucode too large\n");
+ return;
+ }
+
+ buf = (char *)(1*1024*1024);
+
+ 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/i386/stand/pxeboot/conf.c b/sys/arch/i386/stand/pxeboot/conf.c
index 2ffe11c1adc..8872e6a281a 100644
--- a/sys/arch/i386/stand/pxeboot/conf.c
+++ b/sys/arch/i386/stand/pxeboot/conf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: conf.c,v 1.37 2018/07/11 18:08:05 mlarkin Exp $ */
+/* $OpenBSD: conf.c,v 1.38 2018/08/23 14:47:52 jsg Exp $ */
/*
* Copyright (c) 2004 Tom Cosgrove
@@ -44,7 +44,7 @@
#include "pxeboot.h"
#include "pxe_net.h"
-const char version[] = "3.29";
+const char version[] = "3.30";
int debug = 1;
void (*sa_cleanup)(void) = pxe_shutdown;