xref: /openbsd/sys/dev/ic/psp.c (revision 45c4fed2)
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