Download raw body.
psp(4): Automatically load SEV firmware 3/3
Hi,
and the actual firmware loading.
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;
+ 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