1*45c4fed2Sjsg /* $OpenBSD: psp.c,v 1.14 2024/11/10 06:51:59 jsg Exp $ */
20b9f4c66Sjsg
30b9f4c66Sjsg /*
40b9f4c66Sjsg * Copyright (c) 2023, 2024 Hans-Joerg Hoexer <hshoexer@genua.de>
50b9f4c66Sjsg *
60b9f4c66Sjsg * Permission to use, copy, modify, and distribute this software for any
70b9f4c66Sjsg * purpose with or without fee is hereby granted, provided that the above
80b9f4c66Sjsg * copyright notice and this permission notice appear in all copies.
90b9f4c66Sjsg *
100b9f4c66Sjsg * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
110b9f4c66Sjsg * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
120b9f4c66Sjsg * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
130b9f4c66Sjsg * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
140b9f4c66Sjsg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
150b9f4c66Sjsg * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
160b9f4c66Sjsg * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
170b9f4c66Sjsg */
180b9f4c66Sjsg
190b9f4c66Sjsg #include <sys/param.h>
200b9f4c66Sjsg #include <sys/systm.h>
210b9f4c66Sjsg #include <sys/device.h>
223c6d599cSbluhm #include <sys/malloc.h>
238f8d81e9Sbluhm #include <sys/mutex.h>
240b9f4c66Sjsg #include <sys/pledge.h>
258f8d81e9Sbluhm #include <sys/proc.h>
268eadc5ecSjsg #include <sys/rwlock.h>
270b9f4c66Sjsg
280b9f4c66Sjsg #include <machine/bus.h>
290b9f4c66Sjsg
30*45c4fed2Sjsg #include <uvm/uvm_extern.h>
310b9f4c66Sjsg #include <crypto/xform.h>
320b9f4c66Sjsg
330b9f4c66Sjsg #include <dev/ic/ccpvar.h>
340b9f4c66Sjsg #include <dev/ic/pspvar.h>
350b9f4c66Sjsg
368eadc5ecSjsg struct psp_softc {
378eadc5ecSjsg struct device sc_dev;
388eadc5ecSjsg bus_space_tag_t sc_iot;
398eadc5ecSjsg bus_space_handle_t sc_ioh;
400b9f4c66Sjsg
418eadc5ecSjsg bus_dma_tag_t sc_dmat;
4238923a19Sbluhm
4338923a19Sbluhm bus_size_t sc_reg_inten;
4438923a19Sbluhm bus_size_t sc_reg_intsts;
4538923a19Sbluhm bus_size_t sc_reg_cmdresp;
4638923a19Sbluhm bus_size_t sc_reg_addrlo;
4738923a19Sbluhm bus_size_t sc_reg_addrhi;
488eadc5ecSjsg
498eadc5ecSjsg bus_dmamap_t sc_cmd_map;
508eadc5ecSjsg bus_dma_segment_t sc_cmd_seg;
518eadc5ecSjsg size_t sc_cmd_size;
528eadc5ecSjsg caddr_t sc_cmd_kva;
538eadc5ecSjsg
548eadc5ecSjsg bus_dmamap_t sc_tmr_map;
558eadc5ecSjsg bus_dma_segment_t sc_tmr_seg;
568eadc5ecSjsg size_t sc_tmr_size;
578eadc5ecSjsg caddr_t sc_tmr_kva;
588eadc5ecSjsg
598eadc5ecSjsg struct rwlock sc_lock;
608f8d81e9Sbluhm struct mutex psp_lock;
61ff28563eSbluhm
62ff28563eSbluhm uint32_t sc_flags;
63ff28563eSbluhm #define PSPF_INITIALIZED 0x1
643c6d599cSbluhm #define PSPF_UCODELOADED 0x2
653c6d599cSbluhm #define PSPF_NOUCODE 0x4
663c6d599cSbluhm
673c6d599cSbluhm u_char *sc_ucodebuf;
683c6d599cSbluhm size_t sc_ucodelen;
698eadc5ecSjsg };
708eadc5ecSjsg
718eadc5ecSjsg int psp_get_pstatus(struct psp_softc *, struct psp_platform_status *);
728eadc5ecSjsg int psp_init(struct psp_softc *, struct psp_init *);
73ff28563eSbluhm int psp_reinit(struct psp_softc *);
748eadc5ecSjsg int psp_match(struct device *, void *, void *);
758eadc5ecSjsg void psp_attach(struct device *, struct device *, void *);
763c6d599cSbluhm void psp_load_ucode(struct psp_softc *);
778eadc5ecSjsg
788eadc5ecSjsg struct cfdriver psp_cd = {
798eadc5ecSjsg NULL, "psp", DV_DULL
808eadc5ecSjsg };
818eadc5ecSjsg
828eadc5ecSjsg const struct cfattach psp_ca = {
838eadc5ecSjsg sizeof(struct psp_softc),
848eadc5ecSjsg psp_match,
858eadc5ecSjsg psp_attach
868eadc5ecSjsg };
870b9f4c66Sjsg
880b9f4c66Sjsg int
psp_sev_intr(void * arg)898eadc5ecSjsg psp_sev_intr(void *arg)
900b9f4c66Sjsg {
918eadc5ecSjsg struct ccp_softc *csc = arg;
928eadc5ecSjsg struct psp_softc *sc = (struct psp_softc *)csc->sc_psp;
938eadc5ecSjsg uint32_t status;
948eadc5ecSjsg
958f8d81e9Sbluhm mtx_enter(&sc->psp_lock);
9638923a19Sbluhm status = bus_space_read_4(sc->sc_iot, sc->sc_ioh, sc->sc_reg_intsts);
9738923a19Sbluhm bus_space_write_4(sc->sc_iot, sc->sc_ioh, sc->sc_reg_intsts, status);
988f8d81e9Sbluhm mtx_leave(&sc->psp_lock);
998eadc5ecSjsg
1000b9f4c66Sjsg if (!(status & PSP_CMDRESP_COMPLETE))
1010b9f4c66Sjsg return (0);
1020b9f4c66Sjsg
1030b9f4c66Sjsg wakeup(sc);
1040b9f4c66Sjsg
1050b9f4c66Sjsg return (1);
1060b9f4c66Sjsg }
1070b9f4c66Sjsg
1080b9f4c66Sjsg int
psp_match(struct device * parent,void * match,void * aux)1098eadc5ecSjsg psp_match(struct device *parent, void *match, void *aux)
1100b9f4c66Sjsg {
1118eadc5ecSjsg return (1);
1128eadc5ecSjsg }
1138eadc5ecSjsg
1148eadc5ecSjsg void
psp_attach(struct device * parent,struct device * self,void * aux)1158eadc5ecSjsg psp_attach(struct device *parent, struct device *self, void *aux)
1168eadc5ecSjsg {
1178eadc5ecSjsg struct psp_softc *sc = (struct psp_softc *)self;
1188eadc5ecSjsg struct psp_attach_args *arg = aux;
1190b9f4c66Sjsg struct psp_platform_status pst;
1200b9f4c66Sjsg size_t size;
1210b9f4c66Sjsg int nsegs;
1220b9f4c66Sjsg
12338923a19Sbluhm printf(":");
1248eadc5ecSjsg sc->sc_iot = arg->iot;
1258eadc5ecSjsg sc->sc_ioh = arg->ioh;
1268eadc5ecSjsg sc->sc_dmat = arg->dmat;
12738923a19Sbluhm if (arg->version == 1) {
12838923a19Sbluhm sc->sc_reg_inten = PSPV1_REG_INTEN;
12938923a19Sbluhm sc->sc_reg_intsts = PSPV1_REG_INTSTS;
13038923a19Sbluhm sc->sc_reg_cmdresp = PSPV1_REG_CMDRESP;
13138923a19Sbluhm sc->sc_reg_addrlo = PSPV1_REG_ADDRLO;
13238923a19Sbluhm sc->sc_reg_addrhi = PSPV1_REG_ADDRHI;
13338923a19Sbluhm } else {
13438923a19Sbluhm sc->sc_reg_inten = PSP_REG_INTEN;
13538923a19Sbluhm sc->sc_reg_intsts = PSP_REG_INTSTS;
13638923a19Sbluhm sc->sc_reg_cmdresp = PSP_REG_CMDRESP;
13738923a19Sbluhm sc->sc_reg_addrlo = PSP_REG_ADDRLO;
13838923a19Sbluhm sc->sc_reg_addrhi = PSP_REG_ADDRHI;
13938923a19Sbluhm }
14038923a19Sbluhm if (arg->version)
14138923a19Sbluhm printf(" vers %d,", arg->version);
1420b9f4c66Sjsg
1438eadc5ecSjsg rw_init(&sc->sc_lock, "psp_lock");
1448f8d81e9Sbluhm mtx_init(&sc->psp_lock, IPL_BIO);
1450b9f4c66Sjsg
1460b9f4c66Sjsg /* create and map SEV command buffer */
1470b9f4c66Sjsg sc->sc_cmd_size = size = PAGE_SIZE;
1480b9f4c66Sjsg if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
1490b9f4c66Sjsg BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW | BUS_DMA_64BIT,
1500b9f4c66Sjsg &sc->sc_cmd_map) != 0)
1518eadc5ecSjsg return;
1520b9f4c66Sjsg
1530b9f4c66Sjsg if (bus_dmamem_alloc(sc->sc_dmat, size, 0, 0, &sc->sc_cmd_seg, 1,
1540b9f4c66Sjsg &nsegs, BUS_DMA_WAITOK | BUS_DMA_ZERO) != 0)
1550b9f4c66Sjsg goto fail_0;
1560b9f4c66Sjsg
1570b9f4c66Sjsg if (bus_dmamem_map(sc->sc_dmat, &sc->sc_cmd_seg, nsegs, size,
1580b9f4c66Sjsg &sc->sc_cmd_kva, BUS_DMA_WAITOK) != 0)
1590b9f4c66Sjsg goto fail_1;
1600b9f4c66Sjsg
1610b9f4c66Sjsg if (bus_dmamap_load(sc->sc_dmat, sc->sc_cmd_map, sc->sc_cmd_kva,
1620b9f4c66Sjsg size, NULL, BUS_DMA_WAITOK) != 0)
1630b9f4c66Sjsg goto fail_2;
1640b9f4c66Sjsg
16538923a19Sbluhm if (psp_get_pstatus(sc, &pst)) {
16638923a19Sbluhm printf(" platform status");
1670b9f4c66Sjsg goto fail_3;
16838923a19Sbluhm }
16938923a19Sbluhm if (pst.state != PSP_PSTATE_UNINIT) {
17038923a19Sbluhm printf(" uninitialized state");
17138923a19Sbluhm goto fail_3;
17238923a19Sbluhm }
173ff28563eSbluhm printf(" api %u.%u, build %u, SEV, SEV-ES",
17438923a19Sbluhm pst.api_major, pst.api_minor, pst.cfges_build >> 24);
1750b9f4c66Sjsg
17638923a19Sbluhm /* enable interrupts */
17738923a19Sbluhm bus_space_write_4(sc->sc_iot, sc->sc_ioh, sc->sc_reg_inten, -1);
17838923a19Sbluhm
1798eadc5ecSjsg printf("\n");
1800b9f4c66Sjsg
1818eadc5ecSjsg return;
1820b9f4c66Sjsg
1830b9f4c66Sjsg fail_3:
1840b9f4c66Sjsg bus_dmamap_unload(sc->sc_dmat, sc->sc_cmd_map);
1850b9f4c66Sjsg fail_2:
1860b9f4c66Sjsg bus_dmamem_unmap(sc->sc_dmat, sc->sc_cmd_kva, size);
1870b9f4c66Sjsg fail_1:
1880b9f4c66Sjsg bus_dmamem_free(sc->sc_dmat, &sc->sc_cmd_seg, 1);
1890b9f4c66Sjsg fail_0:
1900b9f4c66Sjsg bus_dmamap_destroy(sc->sc_dmat, sc->sc_cmd_map);
1910b9f4c66Sjsg
19238923a19Sbluhm printf(" failed\n");
1930b9f4c66Sjsg
1948eadc5ecSjsg return;
1950b9f4c66Sjsg }
1960b9f4c66Sjsg
1970b9f4c66Sjsg static int
ccp_wait(struct psp_softc * sc,uint32_t * status,int poll)1988eadc5ecSjsg ccp_wait(struct psp_softc *sc, uint32_t *status, int poll)
1990b9f4c66Sjsg {
2000b9f4c66Sjsg uint32_t cmdword;
2010b9f4c66Sjsg int count;
2020b9f4c66Sjsg
2038f8d81e9Sbluhm MUTEX_ASSERT_LOCKED(&sc->psp_lock);
2048f8d81e9Sbluhm
2050b9f4c66Sjsg if (poll) {
2060b9f4c66Sjsg count = 0;
20738923a19Sbluhm while (count++ < 400) {
2080b9f4c66Sjsg cmdword = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
20938923a19Sbluhm sc->sc_reg_cmdresp);
2100b9f4c66Sjsg if (cmdword & PSP_CMDRESP_RESPONSE)
2110b9f4c66Sjsg goto done;
2120b9f4c66Sjsg delay(5000);
2130b9f4c66Sjsg }
2140b9f4c66Sjsg
2150b9f4c66Sjsg /* timeout */
2160b9f4c66Sjsg return (1);
2170b9f4c66Sjsg }
2180b9f4c66Sjsg
2198f8d81e9Sbluhm if (msleep_nsec(sc, &sc->psp_lock, PWAIT, "psp", SEC_TO_NSEC(2))
2208f8d81e9Sbluhm == EWOULDBLOCK)
2210b9f4c66Sjsg return (1);
2220b9f4c66Sjsg
22338923a19Sbluhm cmdword = bus_space_read_4(sc->sc_iot, sc->sc_ioh, sc->sc_reg_cmdresp);
2240b9f4c66Sjsg done:
22538923a19Sbluhm if (status != NULL)
22638923a19Sbluhm *status = cmdword;
2270b9f4c66Sjsg return (0);
2280b9f4c66Sjsg }
2290b9f4c66Sjsg
2300b9f4c66Sjsg static int
ccp_docmd(struct psp_softc * sc,int cmd,uint64_t paddr)2318eadc5ecSjsg ccp_docmd(struct psp_softc *sc, int cmd, uint64_t paddr)
2320b9f4c66Sjsg {
2330b9f4c66Sjsg uint32_t plo, phi, cmdword, status;
2348f8d81e9Sbluhm int ret;
2350b9f4c66Sjsg
2360b9f4c66Sjsg plo = ((paddr >> 0) & 0xffffffff);
2370b9f4c66Sjsg phi = ((paddr >> 32) & 0xffffffff);
2380b9f4c66Sjsg cmdword = (cmd & 0x3ff) << 16;
2390b9f4c66Sjsg if (!cold)
2400b9f4c66Sjsg cmdword |= PSP_CMDRESP_IOC;
2410b9f4c66Sjsg
2428f8d81e9Sbluhm mtx_enter(&sc->psp_lock);
24338923a19Sbluhm bus_space_write_4(sc->sc_iot, sc->sc_ioh, sc->sc_reg_addrlo, plo);
24438923a19Sbluhm bus_space_write_4(sc->sc_iot, sc->sc_ioh, sc->sc_reg_addrhi, phi);
24538923a19Sbluhm bus_space_write_4(sc->sc_iot, sc->sc_ioh, sc->sc_reg_cmdresp, cmdword);
2460b9f4c66Sjsg
2478f8d81e9Sbluhm ret = ccp_wait(sc, &status, cold);
2488f8d81e9Sbluhm mtx_leave(&sc->psp_lock);
2498f8d81e9Sbluhm if (ret)
2500b9f4c66Sjsg return (1);
2510b9f4c66Sjsg
2520b9f4c66Sjsg /* Did PSP sent a response code? */
2530b9f4c66Sjsg if (status & PSP_CMDRESP_RESPONSE) {
2540b9f4c66Sjsg if ((status & PSP_STATUS_MASK) != PSP_STATUS_SUCCESS)
2550b9f4c66Sjsg return (1);
2560b9f4c66Sjsg }
2570b9f4c66Sjsg
2580b9f4c66Sjsg return (0);
2590b9f4c66Sjsg }
2600b9f4c66Sjsg
2610b9f4c66Sjsg int
psp_init(struct psp_softc * sc,struct psp_init * uinit)2628eadc5ecSjsg psp_init(struct psp_softc *sc, struct psp_init *uinit)
2630b9f4c66Sjsg {
2640b9f4c66Sjsg struct psp_init *init;
2650b9f4c66Sjsg int ret;
2660b9f4c66Sjsg
2670b9f4c66Sjsg init = (struct psp_init *)sc->sc_cmd_kva;
2680b9f4c66Sjsg bzero(init, sizeof(*init));
2690b9f4c66Sjsg
2700b9f4c66Sjsg init->enable_es = uinit->enable_es;
2710b9f4c66Sjsg init->tmr_paddr = uinit->tmr_paddr;
2720b9f4c66Sjsg init->tmr_length = uinit->tmr_length;
2730b9f4c66Sjsg
2740b9f4c66Sjsg ret = ccp_docmd(sc, PSP_CMD_INIT, sc->sc_cmd_map->dm_segs[0].ds_addr);
2750b9f4c66Sjsg if (ret != 0)
2760b9f4c66Sjsg return (EIO);
2770b9f4c66Sjsg
278305d28e7Sbluhm wbinvd_on_all_cpus_acked();
2790b9f4c66Sjsg
280ff28563eSbluhm sc->sc_flags |= PSPF_INITIALIZED;
281ff28563eSbluhm
2820b9f4c66Sjsg return (0);
2830b9f4c66Sjsg }
2840b9f4c66Sjsg
2850b9f4c66Sjsg int
psp_reinit(struct psp_softc * sc)286ff28563eSbluhm psp_reinit(struct psp_softc *sc)
287ff28563eSbluhm {
288ff28563eSbluhm struct psp_init init;
289ff28563eSbluhm size_t size;
290ff28563eSbluhm int nsegs;
291ff28563eSbluhm
292ff28563eSbluhm if (sc->sc_flags & PSPF_INITIALIZED) {
293ff28563eSbluhm printf("%s: invalid flags 0x%x\n", __func__, sc->sc_flags);
294ff28563eSbluhm return (EINVAL);
295ff28563eSbluhm }
296ff28563eSbluhm
297ff28563eSbluhm if (sc->sc_tmr_map != NULL)
298ff28563eSbluhm return (EINVAL);
299ff28563eSbluhm
300ff28563eSbluhm /*
301ff28563eSbluhm * create and map Trusted Memory Region (TMR); size 1 Mbyte,
302ff28563eSbluhm * needs to be aligend to 1 Mbyte.
303ff28563eSbluhm */
304ff28563eSbluhm sc->sc_tmr_size = size = PSP_TMR_SIZE;
305ff28563eSbluhm if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
306ff28563eSbluhm BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW | BUS_DMA_64BIT,
307ff28563eSbluhm &sc->sc_tmr_map) != 0)
308ff28563eSbluhm return (ENOMEM);
309ff28563eSbluhm
310ff28563eSbluhm if (bus_dmamem_alloc(sc->sc_dmat, size, size, 0, &sc->sc_tmr_seg, 1,
311ff28563eSbluhm &nsegs, BUS_DMA_WAITOK | BUS_DMA_ZERO) != 0)
312ff28563eSbluhm goto fail_0;
313ff28563eSbluhm
314ff28563eSbluhm if (bus_dmamem_map(sc->sc_dmat, &sc->sc_tmr_seg, nsegs, size,
315ff28563eSbluhm &sc->sc_tmr_kva, BUS_DMA_WAITOK) != 0)
316ff28563eSbluhm goto fail_1;
317ff28563eSbluhm
318ff28563eSbluhm if (bus_dmamap_load(sc->sc_dmat, sc->sc_tmr_map, sc->sc_tmr_kva,
319ff28563eSbluhm size, NULL, BUS_DMA_WAITOK) != 0)
320ff28563eSbluhm goto fail_2;
321ff28563eSbluhm
322ff28563eSbluhm memset(&init, 0, sizeof(init));
323ff28563eSbluhm init.enable_es = 1;
324ff28563eSbluhm init.tmr_length = PSP_TMR_SIZE;
325ff28563eSbluhm init.tmr_paddr = sc->sc_tmr_map->dm_segs[0].ds_addr;
326ff28563eSbluhm if (psp_init(sc, &init))
327ff28563eSbluhm goto fail_3;
328ff28563eSbluhm
329ff28563eSbluhm return (0);
330ff28563eSbluhm
331ff28563eSbluhm fail_3:
332ff28563eSbluhm bus_dmamap_unload(sc->sc_dmat, sc->sc_tmr_map);
333ff28563eSbluhm fail_2:
334ff28563eSbluhm bus_dmamem_unmap(sc->sc_dmat, sc->sc_tmr_kva, size);
335ff28563eSbluhm fail_1:
336ff28563eSbluhm bus_dmamem_free(sc->sc_dmat, &sc->sc_tmr_seg, 1);
337ff28563eSbluhm fail_0:
338ff28563eSbluhm bus_dmamap_destroy(sc->sc_dmat, sc->sc_tmr_map);
339ff28563eSbluhm
340ff28563eSbluhm return (ENOMEM);
341ff28563eSbluhm }
342ff28563eSbluhm
343ff28563eSbluhm int
psp_shutdown(struct psp_softc * sc)344b25bc4b2Sbluhm psp_shutdown(struct psp_softc *sc)
345b25bc4b2Sbluhm {
346b25bc4b2Sbluhm int ret;
347b25bc4b2Sbluhm
348b25bc4b2Sbluhm if (sc->sc_tmr_map == NULL)
349b25bc4b2Sbluhm return (EINVAL);
350b25bc4b2Sbluhm
351b25bc4b2Sbluhm ret = ccp_docmd(sc, PSP_CMD_SHUTDOWN, 0x0);
352b25bc4b2Sbluhm
353b25bc4b2Sbluhm if (ret != 0)
354b25bc4b2Sbluhm return (EIO);
355b25bc4b2Sbluhm
356b25bc4b2Sbluhm /* wbinvd right after SHUTDOWN */
357305d28e7Sbluhm wbinvd_on_all_cpus_acked();
358b25bc4b2Sbluhm
359b25bc4b2Sbluhm /* release TMR */
360b25bc4b2Sbluhm bus_dmamap_unload(sc->sc_dmat, sc->sc_tmr_map);
361b25bc4b2Sbluhm bus_dmamem_unmap(sc->sc_dmat, sc->sc_tmr_kva, sc->sc_tmr_size);
362b25bc4b2Sbluhm bus_dmamem_free(sc->sc_dmat, &sc->sc_tmr_seg, 1);
363b25bc4b2Sbluhm bus_dmamap_destroy(sc->sc_dmat, sc->sc_tmr_map);
364b25bc4b2Sbluhm sc->sc_tmr_map = NULL;
365b25bc4b2Sbluhm
366b25bc4b2Sbluhm /* reset flags */
367b25bc4b2Sbluhm sc->sc_flags = 0;
368b25bc4b2Sbluhm
369b25bc4b2Sbluhm return (0);
370b25bc4b2Sbluhm }
371b25bc4b2Sbluhm
372b25bc4b2Sbluhm int
psp_get_pstatus(struct psp_softc * sc,struct psp_platform_status * ustatus)3738eadc5ecSjsg psp_get_pstatus(struct psp_softc *sc, struct psp_platform_status *ustatus)
3740b9f4c66Sjsg {
3750b9f4c66Sjsg struct psp_platform_status *status;
3760b9f4c66Sjsg int ret;
3770b9f4c66Sjsg
3780b9f4c66Sjsg status = (struct psp_platform_status *)sc->sc_cmd_kva;
3790b9f4c66Sjsg bzero(status, sizeof(*status));
3800b9f4c66Sjsg
3810b9f4c66Sjsg ret = ccp_docmd(sc, PSP_CMD_PLATFORMSTATUS,
3820b9f4c66Sjsg sc->sc_cmd_map->dm_segs[0].ds_addr);
3830b9f4c66Sjsg
3840b9f4c66Sjsg if (ret != 0)
3850b9f4c66Sjsg return (EIO);
3860b9f4c66Sjsg
3870b9f4c66Sjsg bcopy(status, ustatus, sizeof(*ustatus));
3880b9f4c66Sjsg
3890b9f4c66Sjsg return (0);
3900b9f4c66Sjsg }
3910b9f4c66Sjsg
3920b9f4c66Sjsg int
psp_df_flush(struct psp_softc * sc)3938eadc5ecSjsg psp_df_flush(struct psp_softc *sc)
3940b9f4c66Sjsg {
3950b9f4c66Sjsg int ret;
3960b9f4c66Sjsg
397305d28e7Sbluhm wbinvd_on_all_cpus_acked();
3980b9f4c66Sjsg
3990b9f4c66Sjsg ret = ccp_docmd(sc, PSP_CMD_DF_FLUSH, 0x0);
4000b9f4c66Sjsg
4010b9f4c66Sjsg if (ret != 0)
4020b9f4c66Sjsg return (EIO);
4030b9f4c66Sjsg
4040b9f4c66Sjsg return (0);
4050b9f4c66Sjsg }
4060b9f4c66Sjsg
4070b9f4c66Sjsg int
psp_decommission(struct psp_softc * sc,struct psp_decommission * udecom)4088eadc5ecSjsg psp_decommission(struct psp_softc *sc, struct psp_decommission *udecom)
4090b9f4c66Sjsg {
4100b9f4c66Sjsg struct psp_decommission *decom;
4110b9f4c66Sjsg int ret;
4120b9f4c66Sjsg
4130b9f4c66Sjsg decom = (struct psp_decommission *)sc->sc_cmd_kva;
4140b9f4c66Sjsg bzero(decom, sizeof(*decom));
4150b9f4c66Sjsg
4160b9f4c66Sjsg decom->handle = udecom->handle;
4170b9f4c66Sjsg
4180b9f4c66Sjsg ret = ccp_docmd(sc, PSP_CMD_DECOMMISSION,
4190b9f4c66Sjsg sc->sc_cmd_map->dm_segs[0].ds_addr);
4200b9f4c66Sjsg
4210b9f4c66Sjsg if (ret != 0)
4220b9f4c66Sjsg return (EIO);
4230b9f4c66Sjsg
4240b9f4c66Sjsg return (0);
4250b9f4c66Sjsg }
4260b9f4c66Sjsg
4270b9f4c66Sjsg int
psp_get_gstatus(struct psp_softc * sc,struct psp_guest_status * ustatus)4288eadc5ecSjsg psp_get_gstatus(struct psp_softc *sc, struct psp_guest_status *ustatus)
4290b9f4c66Sjsg {
4300b9f4c66Sjsg struct psp_guest_status *status;
4310b9f4c66Sjsg int ret;
4320b9f4c66Sjsg
4330b9f4c66Sjsg status = (struct psp_guest_status *)sc->sc_cmd_kva;
4340b9f4c66Sjsg bzero(status, sizeof(*status));
4350b9f4c66Sjsg
4360b9f4c66Sjsg status->handle = ustatus->handle;
4370b9f4c66Sjsg
4380b9f4c66Sjsg ret = ccp_docmd(sc, PSP_CMD_GUESTSTATUS,
4390b9f4c66Sjsg sc->sc_cmd_map->dm_segs[0].ds_addr);
4400b9f4c66Sjsg
4410b9f4c66Sjsg if (ret != 0)
4420b9f4c66Sjsg return (EIO);
4430b9f4c66Sjsg
4440b9f4c66Sjsg ustatus->policy = status->policy;
4450b9f4c66Sjsg ustatus->asid = status->asid;
4460b9f4c66Sjsg ustatus->state = status->state;
4470b9f4c66Sjsg
4480b9f4c66Sjsg return (0);
4490b9f4c66Sjsg }
4500b9f4c66Sjsg
4510b9f4c66Sjsg int
psp_launch_start(struct psp_softc * sc,struct psp_launch_start * ustart)4528eadc5ecSjsg psp_launch_start(struct psp_softc *sc, struct psp_launch_start *ustart)
4530b9f4c66Sjsg {
4540b9f4c66Sjsg struct psp_launch_start *start;
4550b9f4c66Sjsg int ret;
4560b9f4c66Sjsg
4570b9f4c66Sjsg start = (struct psp_launch_start *)sc->sc_cmd_kva;
4580b9f4c66Sjsg bzero(start, sizeof(*start));
4590b9f4c66Sjsg
4600b9f4c66Sjsg start->handle = ustart->handle;
4610b9f4c66Sjsg start->policy = ustart->policy;
4620b9f4c66Sjsg
4630b9f4c66Sjsg ret = ccp_docmd(sc, PSP_CMD_LAUNCH_START,
4640b9f4c66Sjsg sc->sc_cmd_map->dm_segs[0].ds_addr);
4650b9f4c66Sjsg
4660b9f4c66Sjsg if (ret != 0)
4670b9f4c66Sjsg return (EIO);
4680b9f4c66Sjsg
4690b9f4c66Sjsg /* If requested, return new handle. */
4700b9f4c66Sjsg if (ustart->handle == 0)
4710b9f4c66Sjsg ustart->handle = start->handle;
4720b9f4c66Sjsg
4730b9f4c66Sjsg return (0);
4740b9f4c66Sjsg }
4750b9f4c66Sjsg
4760b9f4c66Sjsg int
psp_launch_update_data(struct psp_softc * sc,struct psp_launch_update_data * ulud,struct proc * p)4777989dc90Sjsg psp_launch_update_data(struct psp_softc *sc,
4787989dc90Sjsg struct psp_launch_update_data *ulud, struct proc *p)
4790b9f4c66Sjsg {
4800b9f4c66Sjsg struct psp_launch_update_data *ludata;
4810b9f4c66Sjsg pmap_t pmap;
482a061ddb5Sbluhm vaddr_t v, next, start, end;
4830b9f4c66Sjsg size_t size, len, off;
4840b9f4c66Sjsg int ret;
4850b9f4c66Sjsg
4860b9f4c66Sjsg /* Ensure AES_XTS_BLOCKSIZE alignment and multiplicity. */
4870b9f4c66Sjsg if ((ulud->paddr & (AES_XTS_BLOCKSIZE - 1)) != 0 ||
4880b9f4c66Sjsg (ulud->length % AES_XTS_BLOCKSIZE) != 0)
4890b9f4c66Sjsg return (EINVAL);
4900b9f4c66Sjsg
4910b9f4c66Sjsg ludata = (struct psp_launch_update_data *)sc->sc_cmd_kva;
4920b9f4c66Sjsg bzero(ludata, sizeof(*ludata));
4930b9f4c66Sjsg
4940b9f4c66Sjsg ludata->handle = ulud->handle;
4950b9f4c66Sjsg
4960b9f4c66Sjsg /* Drain caches before we encrypt memory. */
497305d28e7Sbluhm wbinvd_on_all_cpus_acked();
4980b9f4c66Sjsg
4990b9f4c66Sjsg /*
5000b9f4c66Sjsg * Launch update one physical page at a time. We could
5010b9f4c66Sjsg * optimise this for contiguous pages of physical memory.
5020b9f4c66Sjsg *
5030b9f4c66Sjsg * vmd(8) provides the guest physical address, thus convert
5040b9f4c66Sjsg * to system physical address.
5050b9f4c66Sjsg */
5060b9f4c66Sjsg pmap = vm_map_pmap(&p->p_vmspace->vm_map);
507a061ddb5Sbluhm start = ulud->paddr;
5080b9f4c66Sjsg size = ulud->length;
509a061ddb5Sbluhm end = start + size;
510a061ddb5Sbluhm
511a061ddb5Sbluhm ret = EINVAL;
512a061ddb5Sbluhm
513a061ddb5Sbluhm /* Wire mapping. */
514a061ddb5Sbluhm if (uvm_map_pageable(&p->p_vmspace->vm_map, start, end, FALSE, 0))
515a061ddb5Sbluhm goto out;
516a061ddb5Sbluhm
5170b9f4c66Sjsg for (v = ulud->paddr; v < end; v = next) {
5180b9f4c66Sjsg off = v & PAGE_MASK;
5190b9f4c66Sjsg
5200b9f4c66Sjsg len = MIN(PAGE_SIZE - off, size);
5210b9f4c66Sjsg
5220b9f4c66Sjsg if (!pmap_extract(pmap, v, (paddr_t *)&ludata->paddr))
523a061ddb5Sbluhm goto out;
5240b9f4c66Sjsg ludata->length = len;
5250b9f4c66Sjsg
5260b9f4c66Sjsg ret = ccp_docmd(sc, PSP_CMD_LAUNCH_UPDATE_DATA,
5270b9f4c66Sjsg sc->sc_cmd_map->dm_segs[0].ds_addr);
5280b9f4c66Sjsg
529a061ddb5Sbluhm if (ret != 0) {
530a061ddb5Sbluhm ret = EIO;
531a061ddb5Sbluhm goto out;
532a061ddb5Sbluhm }
5330b9f4c66Sjsg
5340b9f4c66Sjsg size -= len;
5350b9f4c66Sjsg next = v + len;
5360b9f4c66Sjsg }
5370b9f4c66Sjsg
538a061ddb5Sbluhm out:
539a061ddb5Sbluhm /* Unwire again. */
540a061ddb5Sbluhm if (uvm_map_pageable(&p->p_vmspace->vm_map, start, end, TRUE, 0))
541a061ddb5Sbluhm return (EINVAL);
542a061ddb5Sbluhm
543a061ddb5Sbluhm return (ret);
5440b9f4c66Sjsg }
5450b9f4c66Sjsg
5460b9f4c66Sjsg int
psp_launch_measure(struct psp_softc * sc,struct psp_launch_measure * ulm)5478eadc5ecSjsg psp_launch_measure(struct psp_softc *sc, struct psp_launch_measure *ulm)
5480b9f4c66Sjsg {
5490b9f4c66Sjsg struct psp_launch_measure *lm;
5500b9f4c66Sjsg int ret;
5510b9f4c66Sjsg uint64_t paddr;
5520b9f4c66Sjsg
5530b9f4c66Sjsg if (ulm->measure_len != sizeof(ulm->psp_measure))
5540b9f4c66Sjsg return (EINVAL);
5550b9f4c66Sjsg
5560b9f4c66Sjsg lm = (struct psp_launch_measure *)sc->sc_cmd_kva;
5570b9f4c66Sjsg bzero(lm, sizeof(*lm));
5580b9f4c66Sjsg
5590b9f4c66Sjsg lm->handle = ulm->handle;
5600b9f4c66Sjsg paddr = sc->sc_cmd_map->dm_segs[0].ds_addr;
5610b9f4c66Sjsg lm->measure_paddr =
5620b9f4c66Sjsg paddr + offsetof(struct psp_launch_measure, psp_measure);
5630b9f4c66Sjsg lm->measure_len = sizeof(lm->psp_measure);
5640b9f4c66Sjsg
5650b9f4c66Sjsg ret = ccp_docmd(sc, PSP_CMD_LAUNCH_MEASURE, paddr);
5660b9f4c66Sjsg
5670b9f4c66Sjsg if (ret != 0 || lm->measure_len != ulm->measure_len)
5680b9f4c66Sjsg return (EIO);
5690b9f4c66Sjsg
5700b9f4c66Sjsg bcopy(&lm->psp_measure, &ulm->psp_measure, ulm->measure_len);
5710b9f4c66Sjsg
5720b9f4c66Sjsg return (0);
5730b9f4c66Sjsg }
5740b9f4c66Sjsg
5750b9f4c66Sjsg int
psp_launch_finish(struct psp_softc * sc,struct psp_launch_finish * ulf)5768eadc5ecSjsg psp_launch_finish(struct psp_softc *sc, struct psp_launch_finish *ulf)
5770b9f4c66Sjsg {
5780b9f4c66Sjsg struct psp_launch_finish *lf;
5790b9f4c66Sjsg int ret;
5800b9f4c66Sjsg
5810b9f4c66Sjsg lf = (struct psp_launch_finish *)sc->sc_cmd_kva;
5820b9f4c66Sjsg bzero(lf, sizeof(*lf));
5830b9f4c66Sjsg
5840b9f4c66Sjsg lf->handle = ulf->handle;
5850b9f4c66Sjsg
5860b9f4c66Sjsg ret = ccp_docmd(sc, PSP_CMD_LAUNCH_FINISH,
5870b9f4c66Sjsg sc->sc_cmd_map->dm_segs[0].ds_addr);
5880b9f4c66Sjsg
5890b9f4c66Sjsg if (ret != 0)
5900b9f4c66Sjsg return (EIO);
5910b9f4c66Sjsg
5920b9f4c66Sjsg return (0);
5930b9f4c66Sjsg }
5940b9f4c66Sjsg
5950b9f4c66Sjsg int
psp_attestation(struct psp_softc * sc,struct psp_attestation * uat)5968eadc5ecSjsg psp_attestation(struct psp_softc *sc, struct psp_attestation *uat)
5970b9f4c66Sjsg {
5980b9f4c66Sjsg struct psp_attestation *at;
5990b9f4c66Sjsg int ret;
6000b9f4c66Sjsg uint64_t paddr;
6010b9f4c66Sjsg
6020b9f4c66Sjsg if (uat->attest_len != sizeof(uat->psp_report))
6030b9f4c66Sjsg return (EINVAL);
6040b9f4c66Sjsg
6050b9f4c66Sjsg at = (struct psp_attestation *)sc->sc_cmd_kva;
6060b9f4c66Sjsg bzero(at, sizeof(*at));
6070b9f4c66Sjsg
6080b9f4c66Sjsg at->handle = uat->handle;
6090b9f4c66Sjsg paddr = sc->sc_cmd_map->dm_segs[0].ds_addr;
6100b9f4c66Sjsg at->attest_paddr =
6110b9f4c66Sjsg paddr + offsetof(struct psp_attestation, psp_report);
6120b9f4c66Sjsg bcopy(uat->attest_nonce, at->attest_nonce, sizeof(at->attest_nonce));
6130b9f4c66Sjsg at->attest_len = sizeof(at->psp_report);
6140b9f4c66Sjsg
6150b9f4c66Sjsg ret = ccp_docmd(sc, PSP_CMD_ATTESTATION, paddr);
6160b9f4c66Sjsg
6170b9f4c66Sjsg if (ret != 0 || at->attest_len != uat->attest_len)
6180b9f4c66Sjsg return (EIO);
6190b9f4c66Sjsg
6200b9f4c66Sjsg bcopy(&at->psp_report, &uat->psp_report, uat->attest_len);
6210b9f4c66Sjsg
6220b9f4c66Sjsg return (0);
6230b9f4c66Sjsg }
6240b9f4c66Sjsg
6250b9f4c66Sjsg int
psp_activate(struct psp_softc * sc,struct psp_activate * uact)6268eadc5ecSjsg psp_activate(struct psp_softc *sc, struct psp_activate *uact)
6270b9f4c66Sjsg {
6280b9f4c66Sjsg struct psp_activate *act;
6290b9f4c66Sjsg int ret;
6300b9f4c66Sjsg
6310b9f4c66Sjsg act = (struct psp_activate *)sc->sc_cmd_kva;
6320b9f4c66Sjsg bzero(act, sizeof(*act));
6330b9f4c66Sjsg
6340b9f4c66Sjsg act->handle = uact->handle;
6350b9f4c66Sjsg act->asid = uact->asid;
6360b9f4c66Sjsg
6370b9f4c66Sjsg ret = ccp_docmd(sc, PSP_CMD_ACTIVATE,
6380b9f4c66Sjsg sc->sc_cmd_map->dm_segs[0].ds_addr);
6390b9f4c66Sjsg
6400b9f4c66Sjsg if (ret != 0)
6410b9f4c66Sjsg return (EIO);
6420b9f4c66Sjsg
6430b9f4c66Sjsg return (0);
6440b9f4c66Sjsg }
6450b9f4c66Sjsg
6460b9f4c66Sjsg int
psp_deactivate(struct psp_softc * sc,struct psp_deactivate * udeact)6478eadc5ecSjsg psp_deactivate(struct psp_softc *sc, struct psp_deactivate *udeact)
6480b9f4c66Sjsg {
6490b9f4c66Sjsg struct psp_deactivate *deact;
6500b9f4c66Sjsg int ret;
6510b9f4c66Sjsg
6520b9f4c66Sjsg deact = (struct psp_deactivate *)sc->sc_cmd_kva;
6530b9f4c66Sjsg bzero(deact, sizeof(*deact));
6540b9f4c66Sjsg
6550b9f4c66Sjsg deact->handle = udeact->handle;
6560b9f4c66Sjsg
6570b9f4c66Sjsg ret = ccp_docmd(sc, PSP_CMD_DEACTIVATE,
6580b9f4c66Sjsg sc->sc_cmd_map->dm_segs[0].ds_addr);
6590b9f4c66Sjsg
6600b9f4c66Sjsg if (ret != 0)
6610b9f4c66Sjsg return (EIO);
6620b9f4c66Sjsg
6630b9f4c66Sjsg return (0);
6640b9f4c66Sjsg }
6650b9f4c66Sjsg
6660b9f4c66Sjsg int
psp_downloadfirmware(struct psp_softc * sc,struct psp_downloadfirmware * udlfw)66752c926a1Sbluhm psp_downloadfirmware(struct psp_softc *sc, struct psp_downloadfirmware *udlfw)
66852c926a1Sbluhm {
66952c926a1Sbluhm struct psp_downloadfirmware *dlfw;
67052c926a1Sbluhm bus_dmamap_t map;
67152c926a1Sbluhm bus_dma_segment_t seg;
67252c926a1Sbluhm caddr_t kva;
67352c926a1Sbluhm int nsegs;
67452c926a1Sbluhm int ret;
67552c926a1Sbluhm
67652c926a1Sbluhm dlfw = (struct psp_downloadfirmware *)sc->sc_cmd_kva;
67752c926a1Sbluhm bzero(dlfw, sizeof(*dlfw));
67852c926a1Sbluhm
67952c926a1Sbluhm ret = ENOMEM;
68052c926a1Sbluhm if (bus_dmamap_create(sc->sc_dmat, udlfw->fw_len, 1, udlfw->fw_len, 0,
68152c926a1Sbluhm BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW | BUS_DMA_64BIT, &map) != 0)
68252c926a1Sbluhm return (ret);
68352c926a1Sbluhm if (bus_dmamem_alloc(sc->sc_dmat, udlfw->fw_len, 0, 0, &seg, 1,
68452c926a1Sbluhm &nsegs, BUS_DMA_WAITOK | BUS_DMA_ZERO) != 0 || nsegs != 1)
68552c926a1Sbluhm goto fail_0;
68652c926a1Sbluhm if (bus_dmamem_map(sc->sc_dmat, &seg, nsegs, udlfw->fw_len, &kva,
68752c926a1Sbluhm BUS_DMA_WAITOK) != 0)
68852c926a1Sbluhm goto fail_1;
68952c926a1Sbluhm if (bus_dmamap_load(sc->sc_dmat, map, kva, udlfw->fw_len, NULL,
69052c926a1Sbluhm BUS_DMA_WAITOK) != 0)
69152c926a1Sbluhm goto fail_2;
69252c926a1Sbluhm
69352c926a1Sbluhm bcopy((void *)udlfw->fw_paddr, kva, udlfw->fw_len);
69452c926a1Sbluhm
69552c926a1Sbluhm dlfw->fw_paddr = map->dm_segs[0].ds_addr;
69652c926a1Sbluhm dlfw->fw_len = map->dm_segs[0].ds_len;
69752c926a1Sbluhm
69852c926a1Sbluhm ret = ccp_docmd(sc, PSP_CMD_DOWNLOADFIRMWARE,
69952c926a1Sbluhm sc->sc_cmd_map->dm_segs[0].ds_addr);
70052c926a1Sbluhm
70152c926a1Sbluhm if (ret != 0)
70252c926a1Sbluhm ret = EIO;
70352c926a1Sbluhm
70452c926a1Sbluhm bus_dmamap_unload(sc->sc_dmat, map);
70552c926a1Sbluhm fail_2:
70652c926a1Sbluhm bus_dmamem_unmap(sc->sc_dmat, kva, udlfw->fw_len);
70752c926a1Sbluhm fail_1:
70852c926a1Sbluhm bus_dmamem_free(sc->sc_dmat, &seg, 1);
70952c926a1Sbluhm fail_0:
71052c926a1Sbluhm bus_dmamap_destroy(sc->sc_dmat, map);
71152c926a1Sbluhm
71252c926a1Sbluhm return (ret);
71352c926a1Sbluhm }
71452c926a1Sbluhm
71552c926a1Sbluhm int
psp_guest_shutdown(struct psp_softc * sc,struct psp_guest_shutdown * ugshutdown)7168eadc5ecSjsg psp_guest_shutdown(struct psp_softc *sc, struct psp_guest_shutdown *ugshutdown)
7170b9f4c66Sjsg {
7180b9f4c66Sjsg struct psp_deactivate deact;
7190b9f4c66Sjsg struct psp_decommission decom;
7200b9f4c66Sjsg int ret;
7210b9f4c66Sjsg
7220b9f4c66Sjsg bzero(&deact, sizeof(deact));
7230b9f4c66Sjsg deact.handle = ugshutdown->handle;
7248eadc5ecSjsg if ((ret = psp_deactivate(sc, &deact)) != 0)
7250b9f4c66Sjsg return (ret);
7260b9f4c66Sjsg
7278eadc5ecSjsg if ((ret = psp_df_flush(sc)) != 0)
7280b9f4c66Sjsg return (ret);
7290b9f4c66Sjsg
7300b9f4c66Sjsg bzero(&decom, sizeof(decom));
7310b9f4c66Sjsg decom.handle = ugshutdown->handle;
7328eadc5ecSjsg if ((ret = psp_decommission(sc, &decom)) != 0)
7330b9f4c66Sjsg return (ret);
7340b9f4c66Sjsg
7350b9f4c66Sjsg return (0);
7360b9f4c66Sjsg }
7370b9f4c66Sjsg
7380b9f4c66Sjsg int
psp_snp_get_pstatus(struct psp_softc * sc,struct psp_snp_platform_status * ustatus)7397989dc90Sjsg psp_snp_get_pstatus(struct psp_softc *sc,
7407989dc90Sjsg struct psp_snp_platform_status *ustatus)
7410b9f4c66Sjsg {
7420b9f4c66Sjsg struct psp_snp_platform_status *status;
7430b9f4c66Sjsg int ret;
7440b9f4c66Sjsg
7450b9f4c66Sjsg status = (struct psp_snp_platform_status *)sc->sc_cmd_kva;
7460b9f4c66Sjsg bzero(status, sizeof(*status));
7470b9f4c66Sjsg
7480b9f4c66Sjsg ret = ccp_docmd(sc, PSP_CMD_SNP_PLATFORMSTATUS,
7490b9f4c66Sjsg sc->sc_cmd_map->dm_segs[0].ds_addr);
7500b9f4c66Sjsg
7510b9f4c66Sjsg if (ret != 0)
7520b9f4c66Sjsg return (EIO);
7530b9f4c66Sjsg
7540b9f4c66Sjsg bcopy(status, ustatus, sizeof(*ustatus));
7550b9f4c66Sjsg
7560b9f4c66Sjsg return (0);
7570b9f4c66Sjsg }
7580b9f4c66Sjsg
7590b9f4c66Sjsg int
pspopen(dev_t dev,int flag,int mode,struct proc * p)7600b9f4c66Sjsg pspopen(dev_t dev, int flag, int mode, struct proc *p)
7610b9f4c66Sjsg {
7628eadc5ecSjsg struct psp_softc *sc;
7638eadc5ecSjsg
7648eadc5ecSjsg sc = (struct psp_softc *)device_lookup(&psp_cd, minor(dev));
7658eadc5ecSjsg if (sc == NULL)
7668eadc5ecSjsg return (ENXIO);
7670b9f4c66Sjsg
7683c6d599cSbluhm psp_load_ucode(sc);
7693c6d599cSbluhm
770ff28563eSbluhm if (!(sc->sc_flags & PSPF_INITIALIZED))
771ff28563eSbluhm return (psp_reinit(sc));
772ff28563eSbluhm
7730b9f4c66Sjsg return (0);
7740b9f4c66Sjsg }
7750b9f4c66Sjsg
7760b9f4c66Sjsg int
pspclose(dev_t dev,int flag,int mode,struct proc * p)7770b9f4c66Sjsg pspclose(dev_t dev, int flag, int mode, struct proc *p)
7780b9f4c66Sjsg {
7798eadc5ecSjsg struct psp_softc *sc;
7808eadc5ecSjsg
7818eadc5ecSjsg sc = (struct psp_softc *)device_lookup(&psp_cd, minor(dev));
7828eadc5ecSjsg if (sc == NULL)
7838eadc5ecSjsg return (ENXIO);
7848eadc5ecSjsg
7850b9f4c66Sjsg return (0);
7860b9f4c66Sjsg }
7870b9f4c66Sjsg
7880b9f4c66Sjsg int
pspioctl(dev_t dev,u_long cmd,caddr_t data,int flag,struct proc * p)7890b9f4c66Sjsg pspioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
7900b9f4c66Sjsg {
7918eadc5ecSjsg struct psp_softc *sc;
7920b9f4c66Sjsg int ret;
7930b9f4c66Sjsg
7948eadc5ecSjsg sc = (struct psp_softc *)device_lookup(&psp_cd, minor(dev));
7958eadc5ecSjsg if (sc == NULL)
7968eadc5ecSjsg return (ENXIO);
7978eadc5ecSjsg
7988f8d81e9Sbluhm KERNEL_UNLOCK();
7998f8d81e9Sbluhm
8008eadc5ecSjsg rw_enter_write(&sc->sc_lock);
8010b9f4c66Sjsg
8020b9f4c66Sjsg switch (cmd) {
803ff28563eSbluhm case PSP_IOC_INIT:
804ff28563eSbluhm ret = psp_reinit(sc);
805ff28563eSbluhm break;
806b25bc4b2Sbluhm case PSP_IOC_SHUTDOWN:
807b25bc4b2Sbluhm ret = psp_shutdown(sc);
808b25bc4b2Sbluhm break;
8090b9f4c66Sjsg case PSP_IOC_GET_PSTATUS:
8108eadc5ecSjsg ret = psp_get_pstatus(sc, (struct psp_platform_status *)data);
8110b9f4c66Sjsg break;
8120b9f4c66Sjsg case PSP_IOC_DF_FLUSH:
8138eadc5ecSjsg ret = psp_df_flush(sc);
8140b9f4c66Sjsg break;
8150b9f4c66Sjsg case PSP_IOC_DECOMMISSION:
8168eadc5ecSjsg ret = psp_decommission(sc, (struct psp_decommission *)data);
8170b9f4c66Sjsg break;
8180b9f4c66Sjsg case PSP_IOC_GET_GSTATUS:
8198eadc5ecSjsg ret = psp_get_gstatus(sc, (struct psp_guest_status *)data);
8200b9f4c66Sjsg break;
8210b9f4c66Sjsg case PSP_IOC_LAUNCH_START:
8228eadc5ecSjsg ret = psp_launch_start(sc, (struct psp_launch_start *)data);
8230b9f4c66Sjsg break;
8240b9f4c66Sjsg case PSP_IOC_LAUNCH_UPDATE_DATA:
8258eadc5ecSjsg ret = psp_launch_update_data(sc,
8260b9f4c66Sjsg (struct psp_launch_update_data *)data, p);
8270b9f4c66Sjsg break;
8280b9f4c66Sjsg case PSP_IOC_LAUNCH_MEASURE:
8298eadc5ecSjsg ret = psp_launch_measure(sc, (struct psp_launch_measure *)data);
8300b9f4c66Sjsg break;
8310b9f4c66Sjsg case PSP_IOC_LAUNCH_FINISH:
8328eadc5ecSjsg ret = psp_launch_finish(sc, (struct psp_launch_finish *)data);
8330b9f4c66Sjsg break;
8340b9f4c66Sjsg case PSP_IOC_ATTESTATION:
8358eadc5ecSjsg ret = psp_attestation(sc, (struct psp_attestation *)data);
8360b9f4c66Sjsg break;
8370b9f4c66Sjsg case PSP_IOC_ACTIVATE:
8388eadc5ecSjsg ret = psp_activate(sc, (struct psp_activate *)data);
8390b9f4c66Sjsg break;
8400b9f4c66Sjsg case PSP_IOC_DEACTIVATE:
8418eadc5ecSjsg ret = psp_deactivate(sc, (struct psp_deactivate *)data);
8420b9f4c66Sjsg break;
8430b9f4c66Sjsg case PSP_IOC_GUEST_SHUTDOWN:
8448eadc5ecSjsg ret = psp_guest_shutdown(sc, (struct psp_guest_shutdown *)data);
8450b9f4c66Sjsg break;
8460b9f4c66Sjsg case PSP_IOC_SNP_GET_PSTATUS:
8478eadc5ecSjsg ret = psp_snp_get_pstatus(sc,
8488eadc5ecSjsg (struct psp_snp_platform_status *)data);
8490b9f4c66Sjsg break;
8500b9f4c66Sjsg default:
8510b9f4c66Sjsg ret = ENOTTY;
8520b9f4c66Sjsg break;
8530b9f4c66Sjsg }
8540b9f4c66Sjsg
8558eadc5ecSjsg rw_exit_write(&sc->sc_lock);
8560b9f4c66Sjsg
8578f8d81e9Sbluhm KERNEL_LOCK();
8588f8d81e9Sbluhm
8590b9f4c66Sjsg return (ret);
8600b9f4c66Sjsg }
8610b9f4c66Sjsg
8620b9f4c66Sjsg int
pledge_ioctl_psp(struct proc * p,long com)8630b9f4c66Sjsg pledge_ioctl_psp(struct proc *p, long com)
8640b9f4c66Sjsg {
8650b9f4c66Sjsg switch (com) {
8660b9f4c66Sjsg case PSP_IOC_GET_PSTATUS:
8670b9f4c66Sjsg case PSP_IOC_DF_FLUSH:
8680b9f4c66Sjsg case PSP_IOC_GET_GSTATUS:
8690b9f4c66Sjsg case PSP_IOC_LAUNCH_START:
8700b9f4c66Sjsg case PSP_IOC_LAUNCH_UPDATE_DATA:
8710b9f4c66Sjsg case PSP_IOC_LAUNCH_MEASURE:
8720b9f4c66Sjsg case PSP_IOC_LAUNCH_FINISH:
8730b9f4c66Sjsg case PSP_IOC_ACTIVATE:
8740b9f4c66Sjsg case PSP_IOC_GUEST_SHUTDOWN:
8750b9f4c66Sjsg return (0);
8760b9f4c66Sjsg default:
8770b9f4c66Sjsg return (pledge_fail(p, EPERM, PLEDGE_VMM));
8780b9f4c66Sjsg }
8790b9f4c66Sjsg }
8808eadc5ecSjsg
8818eadc5ecSjsg int
pspprint(void * aux,const char * pnp)8828eadc5ecSjsg pspprint(void *aux, const char *pnp)
8838eadc5ecSjsg {
8848eadc5ecSjsg return QUIET;
8858eadc5ecSjsg }
8868eadc5ecSjsg
8878eadc5ecSjsg int
pspsubmatch(struct device * parent,void * match,void * aux)8888eadc5ecSjsg pspsubmatch(struct device *parent, void *match, void *aux)
8898eadc5ecSjsg {
8908eadc5ecSjsg struct psp_attach_args *arg = aux;
8918eadc5ecSjsg struct cfdata *cf = match;
8928eadc5ecSjsg
8938eadc5ecSjsg if (!(arg->capabilities & PSP_CAP_SEV))
8948eadc5ecSjsg return (0);
8958eadc5ecSjsg return ((*cf->cf_attach->ca_match)(parent, cf, aux));
8968eadc5ecSjsg }
8973c6d599cSbluhm
8983c6d599cSbluhm struct ucode {
8993c6d599cSbluhm uint8_t family;
9003c6d599cSbluhm uint8_t model;
9013c6d599cSbluhm const char *uname;
9023c6d599cSbluhm } const psp_ucode_table[] = {
9033c6d599cSbluhm { 0x17, 0x0, "amdsev/amd_sev_fam17h_model0xh.sbin" },
9043c6d599cSbluhm { 0x17, 0x3, "amdsev/amd_sev_fam17h_model3xh.sbin" },
9053c6d599cSbluhm { 0x19, 0x0, "amdsev/amd_sev_fam19h_model0xh.sbin" },
9063c6d599cSbluhm { 0x19, 0x1, "amdsev/amd_sev_fam19h_model1xh.sbin" },
9073c6d599cSbluhm { 0, 0, NULL }
9083c6d599cSbluhm };
9093c6d599cSbluhm
9103c6d599cSbluhm void
psp_load_ucode(struct psp_softc * sc)9113c6d599cSbluhm psp_load_ucode(struct psp_softc *sc)
9123c6d599cSbluhm {
9133c6d599cSbluhm struct psp_downloadfirmware dlfw;
9143c6d599cSbluhm struct cpu_info *ci = &cpu_info_primary;
9153c6d599cSbluhm const struct ucode *uc;
9163c6d599cSbluhm uint8_t family, model;
9173c6d599cSbluhm int error;
9183c6d599cSbluhm
9193c6d599cSbluhm if ((sc->sc_flags & PSPF_UCODELOADED) ||
9203c6d599cSbluhm (sc->sc_flags & PSPF_NOUCODE) ||
9213c6d599cSbluhm (sc->sc_flags & PSPF_INITIALIZED))
9223c6d599cSbluhm return;
9233c6d599cSbluhm
9243c6d599cSbluhm family = ci->ci_family;
9253c6d599cSbluhm model = (ci->ci_model & 0xf0) >> 4;
9263c6d599cSbluhm
9273c6d599cSbluhm for (uc = psp_ucode_table; uc->uname; uc++) {
9283c6d599cSbluhm if ((uc->family == family) && (uc->model == model))
9293c6d599cSbluhm break;
9303c6d599cSbluhm }
9313c6d599cSbluhm
9323c6d599cSbluhm if (uc->uname == NULL) {
9333c6d599cSbluhm printf("%s: no firmware found, CPU family 0x%x model 0x%x\n",
9343c6d599cSbluhm sc->sc_dev.dv_xname, family, model);
9353c6d599cSbluhm sc->sc_flags |= PSPF_NOUCODE;
9363c6d599cSbluhm return;
9373c6d599cSbluhm }
9383c6d599cSbluhm
9393c6d599cSbluhm error = loadfirmware(uc->uname, &sc->sc_ucodebuf, &sc->sc_ucodelen);
9403c6d599cSbluhm if (error) {
9413c6d599cSbluhm if (error != ENOENT) {
9423c6d599cSbluhm printf("%s: error %d, could not read firmware %s\n",
9433c6d599cSbluhm sc->sc_dev.dv_xname, error, uc->uname);
9443c6d599cSbluhm }
9453c6d599cSbluhm sc->sc_flags |= PSPF_NOUCODE;
9463c6d599cSbluhm return;
9473c6d599cSbluhm }
9483c6d599cSbluhm
9493c6d599cSbluhm bzero(&dlfw, sizeof(dlfw));
9503c6d599cSbluhm dlfw.fw_len = sc->sc_ucodelen;
9513c6d599cSbluhm dlfw.fw_paddr = (uint64_t)sc->sc_ucodebuf;
9523c6d599cSbluhm
9533c6d599cSbluhm if (psp_downloadfirmware(sc, &dlfw) < 0)
9543c6d599cSbluhm goto out;
9553c6d599cSbluhm
9563c6d599cSbluhm sc->sc_flags |= PSPF_UCODELOADED;
9573c6d599cSbluhm out:
9583c6d599cSbluhm if (sc->sc_ucodebuf) {
9593c6d599cSbluhm free(sc->sc_ucodebuf, M_DEVBUF, sc->sc_ucodelen);
9603c6d599cSbluhm sc->sc_ucodebuf = NULL;
9613c6d599cSbluhm sc->sc_ucodelen = 0;
9623c6d599cSbluhm }
9633c6d599cSbluhm }
964