1 /* $NetBSD: cpu_ucode.c,v 1.13 2020/04/25 15:26:18 bouyer Exp $ */ 2 /* 3 * Copyright (c) 2012 The NetBSD Foundation, Inc. 4 * All rights reserved. 5 * 6 * This code is derived from software contributed to The NetBSD Foundation 7 * by Christoph Egger. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 20 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include <sys/cdefs.h> 32 __KERNEL_RCSID(0, "$NetBSD: cpu_ucode.c,v 1.13 2020/04/25 15:26:18 bouyer Exp $"); 33 34 #if defined(_KERNEL_OPT) 35 #include "opt_cpu_ucode.h" 36 #include "opt_xen.h" 37 #endif 38 39 #include <sys/param.h> 40 #include <sys/cpuio.h> 41 #include <sys/cpu.h> 42 43 #include <dev/firmload.h> 44 45 #include <machine/cpuvar.h> 46 #include <machine/cputypes.h> 47 48 #include <x86/cpu_ucode.h> 49 50 #ifdef XEN 51 #include <xen/include/public/xen.h> 52 #include <xen/hypervisor.h> 53 #endif 54 55 static struct cpu_ucode_softc ucode_softc; 56 57 int 58 cpu_ucode_get_version(struct cpu_ucode_version *data) 59 { 60 union { 61 struct cpu_ucode_version_amd a; 62 struct cpu_ucode_version_intel1 i; 63 } v; 64 size_t l; 65 int error; 66 67 if (!data->data) 68 return 0; 69 70 switch (cpu_vendor) { 71 case CPUVENDOR_AMD: 72 l = sizeof(v.a); 73 error = cpu_ucode_amd_get_version(data, &v, l); 74 break; 75 case CPUVENDOR_INTEL: 76 l = sizeof(v.i); 77 error = cpu_ucode_intel_get_version(data, &v, l); 78 break; 79 default: 80 return EOPNOTSUPP; 81 } 82 83 if (error) 84 return error; 85 86 return copyout(&v, data->data, l); 87 } 88 89 int 90 cpu_ucode_md_open(firmware_handle_t *fwh, int loader_version, const char *fwname) 91 { 92 switch (cpu_vendor) { 93 case CPUVENDOR_AMD: 94 return cpu_ucode_amd_firmware_open(fwh, fwname); 95 case CPUVENDOR_INTEL: 96 return cpu_ucode_intel_firmware_open(fwh, fwname); 97 default: 98 return EOPNOTSUPP; 99 } 100 } 101 102 #ifndef XENPV 103 int 104 cpu_ucode_apply(const struct cpu_ucode *data) 105 { 106 struct cpu_ucode_softc *sc = &ucode_softc; 107 int error; 108 109 sc->loader_version = data->loader_version; 110 111 error = cpu_ucode_load(sc, data->fwname); 112 if (error) 113 return error; 114 115 switch (cpu_vendor) { 116 case CPUVENDOR_AMD: 117 error = cpu_ucode_amd_apply(sc, data->cpu_nr); 118 break; 119 case CPUVENDOR_INTEL: 120 error = cpu_ucode_intel_apply(sc, data->cpu_nr); 121 break; 122 default: 123 error = EOPNOTSUPP; 124 } 125 126 if (sc->sc_blob != NULL) 127 firmware_free(sc->sc_blob, sc->sc_blobsize); 128 sc->sc_blob = NULL; 129 sc->sc_blobsize = 0; 130 return error; 131 } 132 #else 133 int 134 cpu_ucode_apply(const struct cpu_ucode *data) 135 { 136 struct cpu_ucode_softc *sc = &ucode_softc; 137 struct xen_platform_op op; 138 int error; 139 140 /* Xen updates all??? */ 141 if (data->cpu_nr != CPU_UCODE_ALL_CPUS) 142 return EOPNOTSUPP; 143 144 sc->loader_version = data->loader_version; 145 error = cpu_ucode_load(sc, data->fwname); 146 if (error) 147 return error; 148 149 op.cmd = XENPF_microcode_update; 150 set_xen_guest_handle(op.u.microcode.data, sc->sc_blob); 151 op.u.microcode.length = sc->sc_blobsize; 152 153 error = -HYPERVISOR_platform_op(&op); 154 155 if (sc->sc_blob) 156 firmware_free(sc->sc_blob, sc->sc_blobsize); 157 sc->sc_blob = NULL; 158 sc->sc_blobsize = 0; 159 return error; 160 } 161 #endif /* XEN */ 162