Download raw body.
psp(4): Automatically load SEV firmware 3/3
On Fri, Oct 25, 2024 at 03:51:11PM +0200, Hans-Jörg Höxer wrote:
> Hi,
>
> and the actual firmware loading.
>
See 1 comment below, otherwise ok mlarkin.
> Take care,
> HJ.
> ---------------------------------------------------------------
> commit 9c4c3b5c92581546d9d0c1dda8e463715eeb5306
> Author: Hans-Joerg Hoexer <hshoexer@genua.de>
> Date: Tue Oct 1 18:49:01 2024 +0200
>
> psp(4): Automatically load SEV firmware
>
> When opening /dev/psp for the first time, load the SEV firmware.
> The firmware files will be provided as ports package. The relevant
> firmware file is determined by CPU family and model (ci_family and
> ci_model).
>
> If no firmware files are installed or the right file could be
> determined, the PSP will be initialized using the on-chip firmware.
>
> diff --git a/sys/dev/ic/psp.c b/sys/dev/ic/psp.c
> index 92459c9e06f..4836f3f69a5 100644
> --- a/sys/dev/ic/psp.c
> +++ b/sys/dev/ic/psp.c
> @@ -21,6 +21,7 @@
> #include <sys/device.h>
> #include <sys/pledge.h>
> #include <sys/rwlock.h>
> +#include <sys/malloc.h>
>
> #include <machine/bus.h>
>
> @@ -58,6 +59,11 @@ struct psp_softc {
>
> uint32_t sc_flags;
> #define PSPF_INITIALIZED 0x1
> +#define PSPF_UCODELOADED 0x2
> +#define PSPF_NOUCODE 0x4
> +
> + u_char *sc_ucodebuf;
> + size_t sc_ucodelen;
> };
>
> int psp_get_pstatus(struct psp_softc *, struct psp_platform_status *);
> @@ -65,6 +71,7 @@ int psp_init(struct psp_softc *, struct psp_init *);
> int psp_reinit(struct psp_softc *);
> int psp_match(struct device *, void *, void *);
> void psp_attach(struct device *, struct device *, void *);
> +void psp_load_ucode(struct psp_softc *);
>
> struct cfdriver psp_cd = {
> NULL, "psp", DV_DULL
> @@ -705,6 +712,10 @@ pspopen(dev_t dev, int flag, int mode, struct proc *p)
> if (sc == NULL)
> return (ENXIO);
>
> +#ifndef SMALL_KERNEL
> + psp_load_ucode(sc);
> +#endif
> +
> if (!(sc->sc_flags & PSPF_INITIALIZED))
> return (psp_reinit(sc));
>
> @@ -825,3 +836,65 @@ pspsubmatch(struct device *parent, void *match, void *aux)
> return (0);
> return ((*cf->cf_attach->ca_match)(parent, cf, aux));
> }
> +
> +#ifndef SMALL_KERNEL
> +struct ucode {
> + uint8_t family;
> + uint8_t model;
> + const char *uname;
> +} const psp_ucode_table[] = {
> + { 0x17, 0x0, "amdsev/amd_sev_fam17h_model0xh.sbin" },
> + { 0x17, 0x3, "amdsev/amd_sev_fam17h_model3xh.sbin" },
> + { 0x19, 0x0, "amdsev/amd_sev_fam19h_model0xh.sbin" },
> + { 0x19, 0x1, "amdsev/amd_sev_fam19h_model1xh.sbin" },
> + { 0, 0, NULL }
> +};
> +
> +void
> +psp_load_ucode(struct psp_softc *sc)
> +{
> + struct psp_downloadfirmware dlfw;
> + struct cpu_info *ci = &cpu_info_primary;
> + const struct ucode *uc;
> + int error;
> +
> + if (sc->sc_flags & PSPF_UCODELOADED || sc->sc_flags & PSPF_NOUCODE ||
> + sc->sc_flags & PSPF_INITIALIZED)
> + return;
> +
> + for (uc = psp_ucode_table; uc->uname; uc++)
> + if (ci->ci_family == uc->family &&
> + ((ci->ci_model & 0xf0) >> 4) == uc->model)
> + break;
> +
> + if (uc->uname == NULL) {
> + sc->sc_flags |= PSPF_NOUCODE;
Do you think it would be useful to print a message about not knowing about,
and/or having firmware for this family/model? We do that for example, for some
wireless devices.
> + return; /* no firmware found */
> + }
> +
> + error = loadfirmware(uc->uname, &sc->sc_ucodebuf, &sc->sc_ucodelen);
> + if (error) {
> + if (error != ENOENT) {
> + printf("%s: error %d, could not read firmware %s\n",
> + sc->sc_dev.dv_xname, error, uc->uname);
> + }
> + sc->sc_flags |= PSPF_NOUCODE;
> + return;
> + }
> +
> + bzero(&dlfw, sizeof(dlfw));
> + dlfw.fw_len = sc->sc_ucodelen;
> + dlfw.fw_paddr = (uint64_t)sc->sc_ucodebuf;
> +
> + if (psp_downloadfirmware(sc, &dlfw) < 0)
> + goto out;
> +
> + sc->sc_flags |= PSPF_UCODELOADED;
> +out:
> + if (sc->sc_ucodebuf) {
> + free(sc->sc_ucodebuf, M_DEVBUF, sc->sc_ucodelen);
> + sc->sc_ucodebuf = NULL;
> + sc->sc_ucodelen = 0;
> + }
> +}
> +#endif /* !SMALL_KERNEL */
psp(4): Automatically load SEV firmware 3/3