From: jsg Date: Thu, 23 Aug 2018 14:47:52 +0000 (+0000) Subject: port the amd64 code for loading intel microcode on boot to i386 X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=4a222fdfd23ce026d1d1a301b821dfc392dc6770;p=openbsd port the amd64 code for loading intel microcode on boot to i386 ok deraadt@ mlarkin@ --- 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 * @@ -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 + * Copyright (c) 2018 Patrick Wildt + * + * 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 +#include +#include +#include + +#include + +#include +#include +#include +#include + +/* #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 #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 #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 #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 @@ -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;