#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: cpu_ucode.c,v 1.13 2020/04/25 15:26:18 bouyer Exp $");
#if defined(_KERNEL_OPT)
#include "opt_cpu_ucode.h"
#include "opt_xen.h"
#endif
#include <sys/param.h>
#include <sys/cpuio.h>
#include <sys/cpu.h>
#include <dev/firmload.h>
#include <machine/cpuvar.h>
#include <machine/cputypes.h>
#include <x86/cpu_ucode.h>
#ifdef XEN
#include <xen/include/public/xen.h>
#include <xen/hypervisor.h>
#endif
static struct cpu_ucode_softc ucode_softc;
int
cpu_ucode_get_version(struct cpu_ucode_version *data)
{
union {
struct cpu_ucode_version_amd a;
struct cpu_ucode_version_intel1 i;
} v;
size_t l;
int error;
if (!data->data)
return 0;
switch (cpu_vendor) {
case CPUVENDOR_AMD:
l = sizeof(v.a);
error = cpu_ucode_amd_get_version(data, &v, l);
break;
case CPUVENDOR_INTEL:
l = sizeof(v.i);
error = cpu_ucode_intel_get_version(data, &v, l);
break;
default:
return EOPNOTSUPP;
}
if (error)
return error;
return copyout(&v, data->data, l);
}
int
cpu_ucode_md_open(firmware_handle_t *fwh, int loader_version, const char *fwname)
{
switch (cpu_vendor) {
case CPUVENDOR_AMD:
return cpu_ucode_amd_firmware_open(fwh, fwname);
case CPUVENDOR_INTEL:
return cpu_ucode_intel_firmware_open(fwh, fwname);
default:
return EOPNOTSUPP;
}
}
#ifndef XENPV
int
cpu_ucode_apply(const struct cpu_ucode *data)
{
struct cpu_ucode_softc *sc = &ucode_softc;
int error;
sc->loader_version = data->loader_version;
error = cpu_ucode_load(sc, data->fwname);
if (error)
return error;
switch (cpu_vendor) {
case CPUVENDOR_AMD:
error = cpu_ucode_amd_apply(sc, data->cpu_nr);
break;
case CPUVENDOR_INTEL:
error = cpu_ucode_intel_apply(sc, data->cpu_nr);
break;
default:
error = EOPNOTSUPP;
}
if (sc->sc_blob != NULL)
firmware_free(sc->sc_blob, sc->sc_blobsize);
sc->sc_blob = NULL;
sc->sc_blobsize = 0;
return error;
}
#else
int
cpu_ucode_apply(const struct cpu_ucode *data)
{
struct cpu_ucode_softc *sc = &ucode_softc;
struct xen_platform_op op;
int error;
if (data->cpu_nr != CPU_UCODE_ALL_CPUS)
return EOPNOTSUPP;
sc->loader_version = data->loader_version;
error = cpu_ucode_load(sc, data->fwname);
if (error)
return error;
op.cmd = XENPF_microcode_update;
set_xen_guest_handle(op.u.microcode.data, sc->sc_blob);
op.u.microcode.length = sc->sc_blobsize;
error = -HYPERVISOR_platform_op(&op);
if (sc->sc_blob)
firmware_free(sc->sc_blob, sc->sc_blobsize);
sc->sc_blob = NULL;
sc->sc_blobsize = 0;
return error;
}
#endif