xref: /openbsd/sys/dev/ic/psp.c (revision 7989dc90)
1*7989dc90Sjsg /*	$OpenBSD: psp.c,v 1.4 2024/09/04 08:14:18 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>
220b9f4c66Sjsg #include <sys/pledge.h>
238eadc5ecSjsg #include <sys/rwlock.h>
240b9f4c66Sjsg 
250b9f4c66Sjsg #include <machine/bus.h>
260b9f4c66Sjsg 
270b9f4c66Sjsg #include <sys/proc.h>
280b9f4c66Sjsg #include <uvm/uvm.h>
290b9f4c66Sjsg #include <crypto/xform.h>
300b9f4c66Sjsg 
310b9f4c66Sjsg #include <dev/ic/ccpvar.h>
320b9f4c66Sjsg #include <dev/ic/pspvar.h>
330b9f4c66Sjsg 
348eadc5ecSjsg struct psp_softc {
358eadc5ecSjsg 	struct device		sc_dev;
368eadc5ecSjsg 	bus_space_tag_t		sc_iot;
378eadc5ecSjsg 	bus_space_handle_t	sc_ioh;
380b9f4c66Sjsg 
398eadc5ecSjsg 	bus_dma_tag_t		sc_dmat;
408eadc5ecSjsg 	uint32_t		sc_capabilities;
418eadc5ecSjsg 
428eadc5ecSjsg 	bus_dmamap_t		sc_cmd_map;
438eadc5ecSjsg 	bus_dma_segment_t	sc_cmd_seg;
448eadc5ecSjsg 	size_t			sc_cmd_size;
458eadc5ecSjsg 	caddr_t			sc_cmd_kva;
468eadc5ecSjsg 
478eadc5ecSjsg 	bus_dmamap_t		sc_tmr_map;
488eadc5ecSjsg 	bus_dma_segment_t	sc_tmr_seg;
498eadc5ecSjsg 	size_t			sc_tmr_size;
508eadc5ecSjsg 	caddr_t			sc_tmr_kva;
518eadc5ecSjsg 
528eadc5ecSjsg 	struct rwlock		sc_lock;
538eadc5ecSjsg };
548eadc5ecSjsg 
558eadc5ecSjsg int	psp_get_pstatus(struct psp_softc *, struct psp_platform_status *);
568eadc5ecSjsg int	psp_init(struct psp_softc *, struct psp_init *);
578eadc5ecSjsg int	psp_match(struct device *, void *, void *);
588eadc5ecSjsg void	psp_attach(struct device *, struct device *, void *);
598eadc5ecSjsg 
608eadc5ecSjsg struct cfdriver psp_cd = {
618eadc5ecSjsg 	NULL, "psp", DV_DULL
628eadc5ecSjsg };
638eadc5ecSjsg 
648eadc5ecSjsg const struct cfattach psp_ca = {
658eadc5ecSjsg 	sizeof(struct psp_softc),
668eadc5ecSjsg 	psp_match,
678eadc5ecSjsg 	psp_attach
688eadc5ecSjsg };
690b9f4c66Sjsg 
700b9f4c66Sjsg int
718eadc5ecSjsg psp_sev_intr(void *arg)
720b9f4c66Sjsg {
738eadc5ecSjsg 	struct ccp_softc *csc = arg;
748eadc5ecSjsg 	struct psp_softc *sc = (struct psp_softc *)csc->sc_psp;
758eadc5ecSjsg 	uint32_t status;
768eadc5ecSjsg 
778eadc5ecSjsg 	status = bus_space_read_4(sc->sc_iot, sc->sc_ioh, PSP_REG_INTSTS);
788eadc5ecSjsg 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, PSP_REG_INTSTS, status);
798eadc5ecSjsg 
800b9f4c66Sjsg 	if (!(status & PSP_CMDRESP_COMPLETE))
810b9f4c66Sjsg 		return (0);
820b9f4c66Sjsg 
830b9f4c66Sjsg 	wakeup(sc);
840b9f4c66Sjsg 
850b9f4c66Sjsg 	return (1);
860b9f4c66Sjsg }
870b9f4c66Sjsg 
880b9f4c66Sjsg int
898eadc5ecSjsg psp_match(struct device *parent, void *match, void *aux)
900b9f4c66Sjsg {
918eadc5ecSjsg 	return (1);
928eadc5ecSjsg }
938eadc5ecSjsg 
948eadc5ecSjsg void
958eadc5ecSjsg psp_attach(struct device *parent, struct device *self, void *aux)
968eadc5ecSjsg {
978eadc5ecSjsg 	struct psp_softc		*sc = (struct psp_softc *)self;
988eadc5ecSjsg 	struct psp_attach_args		*arg = aux;
990b9f4c66Sjsg 	struct psp_platform_status	pst;
1000b9f4c66Sjsg 	struct psp_init			init;
1010b9f4c66Sjsg 	size_t				size;
1020b9f4c66Sjsg 	int				nsegs;
1030b9f4c66Sjsg 
1048eadc5ecSjsg 	sc->sc_iot = arg->iot;
1058eadc5ecSjsg 	sc->sc_ioh = arg->ioh;
1068eadc5ecSjsg 	sc->sc_dmat = arg->dmat;
1078eadc5ecSjsg 	sc->sc_capabilities = arg->capabilities;
1080b9f4c66Sjsg 
1098eadc5ecSjsg 	rw_init(&sc->sc_lock, "psp_lock");
1100b9f4c66Sjsg 
1110b9f4c66Sjsg 	/* create and map SEV command buffer */
1120b9f4c66Sjsg 	sc->sc_cmd_size = size = PAGE_SIZE;
1130b9f4c66Sjsg 	if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
1140b9f4c66Sjsg 	    BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW | BUS_DMA_64BIT,
1150b9f4c66Sjsg 	    &sc->sc_cmd_map) != 0)
1168eadc5ecSjsg 		return;
1170b9f4c66Sjsg 
1180b9f4c66Sjsg 	if (bus_dmamem_alloc(sc->sc_dmat, size, 0, 0, &sc->sc_cmd_seg, 1,
1190b9f4c66Sjsg 	    &nsegs, BUS_DMA_WAITOK | BUS_DMA_ZERO) != 0)
1200b9f4c66Sjsg 		goto fail_0;
1210b9f4c66Sjsg 
1220b9f4c66Sjsg 	if (bus_dmamem_map(sc->sc_dmat, &sc->sc_cmd_seg, nsegs, size,
1230b9f4c66Sjsg 	    &sc->sc_cmd_kva, BUS_DMA_WAITOK) != 0)
1240b9f4c66Sjsg 		goto fail_1;
1250b9f4c66Sjsg 
1260b9f4c66Sjsg 	if (bus_dmamap_load(sc->sc_dmat, sc->sc_cmd_map, sc->sc_cmd_kva,
1270b9f4c66Sjsg 	    size, NULL, BUS_DMA_WAITOK) != 0)
1280b9f4c66Sjsg 		goto fail_2;
1290b9f4c66Sjsg 
1308eadc5ecSjsg 	if (psp_get_pstatus(sc, &pst) || pst.state != 0)
1310b9f4c66Sjsg 		goto fail_3;
1320b9f4c66Sjsg 
1330b9f4c66Sjsg 	/*
1340b9f4c66Sjsg          * create and map Trusted Memory Region (TMR); size 1 Mbyte,
1350b9f4c66Sjsg          * needs to be aligned to 1 Mbyte.
1360b9f4c66Sjsg 	 */
1370b9f4c66Sjsg 	sc->sc_tmr_size = size = PSP_TMR_SIZE;
1380b9f4c66Sjsg 	if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
1390b9f4c66Sjsg 	    BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW | BUS_DMA_64BIT,
1400b9f4c66Sjsg 	    &sc->sc_tmr_map) != 0)
1410b9f4c66Sjsg 		goto fail_3;
1420b9f4c66Sjsg 
1430b9f4c66Sjsg 	if (bus_dmamem_alloc(sc->sc_dmat, size, size, 0, &sc->sc_tmr_seg, 1,
1440b9f4c66Sjsg 	    &nsegs, BUS_DMA_WAITOK | BUS_DMA_ZERO) != 0)
1450b9f4c66Sjsg 		goto fail_4;
1460b9f4c66Sjsg 
1470b9f4c66Sjsg 	if (bus_dmamem_map(sc->sc_dmat, &sc->sc_tmr_seg, nsegs, size,
1480b9f4c66Sjsg 	    &sc->sc_tmr_kva, BUS_DMA_WAITOK) != 0)
1490b9f4c66Sjsg 		goto fail_5;
1500b9f4c66Sjsg 
1510b9f4c66Sjsg 	if (bus_dmamap_load(sc->sc_dmat, sc->sc_tmr_map, sc->sc_tmr_kva,
1520b9f4c66Sjsg 	    size, NULL, BUS_DMA_WAITOK) != 0)
1530b9f4c66Sjsg 		goto fail_6;
1540b9f4c66Sjsg 
1550b9f4c66Sjsg 	memset(&init, 0, sizeof(init));
1560b9f4c66Sjsg 	init.enable_es = 1;
1570b9f4c66Sjsg 	init.tmr_length = PSP_TMR_SIZE;
1580b9f4c66Sjsg 	init.tmr_paddr = sc->sc_tmr_map->dm_segs[0].ds_addr;
1598eadc5ecSjsg 	if (psp_init(sc, &init))
1600b9f4c66Sjsg 		goto fail_7;
1610b9f4c66Sjsg 
1628eadc5ecSjsg 	printf(": SEV");
1630b9f4c66Sjsg 
1648eadc5ecSjsg 	psp_get_pstatus(sc, &pst);
1650b9f4c66Sjsg 	if ((pst.state == 1) && (pst.cfges_build & 0x1))
1660b9f4c66Sjsg 		printf(", SEV-ES");
1670b9f4c66Sjsg 
1688eadc5ecSjsg 	printf("\n");
1690b9f4c66Sjsg 
1708eadc5ecSjsg 	return;
1710b9f4c66Sjsg 
1720b9f4c66Sjsg fail_7:
1730b9f4c66Sjsg 	bus_dmamap_unload(sc->sc_dmat, sc->sc_tmr_map);
1740b9f4c66Sjsg fail_6:
1750b9f4c66Sjsg 	bus_dmamem_unmap(sc->sc_dmat, sc->sc_tmr_kva, size);
1760b9f4c66Sjsg fail_5:
1770b9f4c66Sjsg 	bus_dmamem_free(sc->sc_dmat, &sc->sc_tmr_seg, 1);
1780b9f4c66Sjsg fail_4:
1790b9f4c66Sjsg 	bus_dmamap_destroy(sc->sc_dmat, sc->sc_tmr_map);
1800b9f4c66Sjsg fail_3:
1810b9f4c66Sjsg 	bus_dmamap_unload(sc->sc_dmat, sc->sc_cmd_map);
1820b9f4c66Sjsg fail_2:
1830b9f4c66Sjsg 	bus_dmamem_unmap(sc->sc_dmat, sc->sc_cmd_kva, size);
1840b9f4c66Sjsg fail_1:
1850b9f4c66Sjsg 	bus_dmamem_free(sc->sc_dmat, &sc->sc_cmd_seg, 1);
1860b9f4c66Sjsg fail_0:
1870b9f4c66Sjsg 	bus_dmamap_destroy(sc->sc_dmat, sc->sc_cmd_map);
1880b9f4c66Sjsg 
1898eadc5ecSjsg 	printf("\n");
1900b9f4c66Sjsg 
1918eadc5ecSjsg 	return;
1920b9f4c66Sjsg }
1930b9f4c66Sjsg 
1940b9f4c66Sjsg static int
1958eadc5ecSjsg ccp_wait(struct psp_softc *sc, uint32_t *status, int poll)
1960b9f4c66Sjsg {
1970b9f4c66Sjsg 	uint32_t	cmdword;
1980b9f4c66Sjsg 	int		count;
1990b9f4c66Sjsg 
2000b9f4c66Sjsg 	if (poll) {
2010b9f4c66Sjsg 		count = 0;
2020b9f4c66Sjsg 		while (count++ < 10) {
2030b9f4c66Sjsg 			cmdword = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
2040b9f4c66Sjsg 			    PSP_REG_CMDRESP);
2050b9f4c66Sjsg 			if (cmdword & PSP_CMDRESP_RESPONSE)
2060b9f4c66Sjsg 				goto done;
2070b9f4c66Sjsg 			delay(5000);
2080b9f4c66Sjsg 		}
2090b9f4c66Sjsg 
2100b9f4c66Sjsg 		/* timeout */
2110b9f4c66Sjsg 		return (1);
2120b9f4c66Sjsg 	}
2130b9f4c66Sjsg 
2140b9f4c66Sjsg 	if (tsleep_nsec(sc, PWAIT, "psp", SEC_TO_NSEC(1)) == EWOULDBLOCK)
2150b9f4c66Sjsg 		return (1);
2160b9f4c66Sjsg 
2170b9f4c66Sjsg done:
2180b9f4c66Sjsg 	if (status) {
2190b9f4c66Sjsg 		*status = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
2200b9f4c66Sjsg 		    PSP_REG_CMDRESP);
2210b9f4c66Sjsg 	}
2220b9f4c66Sjsg 
2230b9f4c66Sjsg 	return (0);
2240b9f4c66Sjsg }
2250b9f4c66Sjsg 
2260b9f4c66Sjsg static int
2278eadc5ecSjsg ccp_docmd(struct psp_softc *sc, int cmd, uint64_t paddr)
2280b9f4c66Sjsg {
2290b9f4c66Sjsg 	uint32_t	plo, phi, cmdword, status;
2300b9f4c66Sjsg 
2310b9f4c66Sjsg 	plo = ((paddr >> 0) & 0xffffffff);
2320b9f4c66Sjsg 	phi = ((paddr >> 32) & 0xffffffff);
2330b9f4c66Sjsg 	cmdword = (cmd & 0x3ff) << 16;
2340b9f4c66Sjsg 	if (!cold)
2350b9f4c66Sjsg 		cmdword |= PSP_CMDRESP_IOC;
2360b9f4c66Sjsg 
2370b9f4c66Sjsg 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, PSP_REG_ADDRLO, plo);
2380b9f4c66Sjsg 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, PSP_REG_ADDRHI, phi);
2390b9f4c66Sjsg 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, PSP_REG_CMDRESP, cmdword);
2400b9f4c66Sjsg 
2410b9f4c66Sjsg 	if (ccp_wait(sc, &status, cold))
2420b9f4c66Sjsg 		return (1);
2430b9f4c66Sjsg 
2440b9f4c66Sjsg 	/* Did PSP sent a response code? */
2450b9f4c66Sjsg 	if (status & PSP_CMDRESP_RESPONSE) {
2460b9f4c66Sjsg 		if ((status & PSP_STATUS_MASK) != PSP_STATUS_SUCCESS)
2470b9f4c66Sjsg 			return (1);
2480b9f4c66Sjsg 	}
2490b9f4c66Sjsg 
2500b9f4c66Sjsg 	return (0);
2510b9f4c66Sjsg }
2520b9f4c66Sjsg 
2530b9f4c66Sjsg int
2548eadc5ecSjsg psp_init(struct psp_softc *sc, struct psp_init *uinit)
2550b9f4c66Sjsg {
2560b9f4c66Sjsg 	struct psp_init		*init;
2570b9f4c66Sjsg 	int			 ret;
2580b9f4c66Sjsg 
2590b9f4c66Sjsg 	init = (struct psp_init *)sc->sc_cmd_kva;
2600b9f4c66Sjsg 	bzero(init, sizeof(*init));
2610b9f4c66Sjsg 
2620b9f4c66Sjsg 	init->enable_es = uinit->enable_es;
2630b9f4c66Sjsg 	init->tmr_paddr = uinit->tmr_paddr;
2640b9f4c66Sjsg 	init->tmr_length = uinit->tmr_length;
2650b9f4c66Sjsg 
2660b9f4c66Sjsg 	ret = ccp_docmd(sc, PSP_CMD_INIT, sc->sc_cmd_map->dm_segs[0].ds_addr);
2670b9f4c66Sjsg 	if (ret != 0)
2680b9f4c66Sjsg 		return (EIO);
2690b9f4c66Sjsg 
2700b9f4c66Sjsg 	wbinvd_on_all_cpus();
2710b9f4c66Sjsg 
2720b9f4c66Sjsg 	return (0);
2730b9f4c66Sjsg }
2740b9f4c66Sjsg 
2750b9f4c66Sjsg int
2768eadc5ecSjsg psp_get_pstatus(struct psp_softc *sc, struct psp_platform_status *ustatus)
2770b9f4c66Sjsg {
2780b9f4c66Sjsg 	struct psp_platform_status *status;
2790b9f4c66Sjsg 	int			 ret;
2800b9f4c66Sjsg 
2810b9f4c66Sjsg 	status = (struct psp_platform_status *)sc->sc_cmd_kva;
2820b9f4c66Sjsg 	bzero(status, sizeof(*status));
2830b9f4c66Sjsg 
2840b9f4c66Sjsg 	ret = ccp_docmd(sc, PSP_CMD_PLATFORMSTATUS,
2850b9f4c66Sjsg 	    sc->sc_cmd_map->dm_segs[0].ds_addr);
2860b9f4c66Sjsg 
2870b9f4c66Sjsg 	if (ret != 0)
2880b9f4c66Sjsg 		return (EIO);
2890b9f4c66Sjsg 
2900b9f4c66Sjsg 	bcopy(status, ustatus, sizeof(*ustatus));
2910b9f4c66Sjsg 
2920b9f4c66Sjsg 	return (0);
2930b9f4c66Sjsg }
2940b9f4c66Sjsg 
2950b9f4c66Sjsg int
2968eadc5ecSjsg psp_df_flush(struct psp_softc *sc)
2970b9f4c66Sjsg {
2980b9f4c66Sjsg 	int			 ret;
2990b9f4c66Sjsg 
3000b9f4c66Sjsg 	wbinvd_on_all_cpus();
3010b9f4c66Sjsg 
3020b9f4c66Sjsg 	ret = ccp_docmd(sc, PSP_CMD_DF_FLUSH, 0x0);
3030b9f4c66Sjsg 
3040b9f4c66Sjsg 	if (ret != 0)
3050b9f4c66Sjsg 		return (EIO);
3060b9f4c66Sjsg 
3070b9f4c66Sjsg 	return (0);
3080b9f4c66Sjsg }
3090b9f4c66Sjsg 
3100b9f4c66Sjsg int
3118eadc5ecSjsg psp_decommission(struct psp_softc *sc, struct psp_decommission *udecom)
3120b9f4c66Sjsg {
3130b9f4c66Sjsg 	struct psp_decommission	*decom;
3140b9f4c66Sjsg 	int			 ret;
3150b9f4c66Sjsg 
3160b9f4c66Sjsg 	decom = (struct psp_decommission *)sc->sc_cmd_kva;
3170b9f4c66Sjsg 	bzero(decom, sizeof(*decom));
3180b9f4c66Sjsg 
3190b9f4c66Sjsg 	decom->handle = udecom->handle;
3200b9f4c66Sjsg 
3210b9f4c66Sjsg 	ret = ccp_docmd(sc, PSP_CMD_DECOMMISSION,
3220b9f4c66Sjsg 	    sc->sc_cmd_map->dm_segs[0].ds_addr);
3230b9f4c66Sjsg 
3240b9f4c66Sjsg 	if (ret != 0)
3250b9f4c66Sjsg 		return (EIO);
3260b9f4c66Sjsg 
3270b9f4c66Sjsg 	return (0);
3280b9f4c66Sjsg }
3290b9f4c66Sjsg 
3300b9f4c66Sjsg int
3318eadc5ecSjsg psp_get_gstatus(struct psp_softc *sc, struct psp_guest_status *ustatus)
3320b9f4c66Sjsg {
3330b9f4c66Sjsg 	struct psp_guest_status	*status;
3340b9f4c66Sjsg 	int			 ret;
3350b9f4c66Sjsg 
3360b9f4c66Sjsg 	status = (struct psp_guest_status *)sc->sc_cmd_kva;
3370b9f4c66Sjsg 	bzero(status, sizeof(*status));
3380b9f4c66Sjsg 
3390b9f4c66Sjsg 	status->handle = ustatus->handle;
3400b9f4c66Sjsg 
3410b9f4c66Sjsg 	ret = ccp_docmd(sc, PSP_CMD_GUESTSTATUS,
3420b9f4c66Sjsg 	    sc->sc_cmd_map->dm_segs[0].ds_addr);
3430b9f4c66Sjsg 
3440b9f4c66Sjsg 	if (ret != 0)
3450b9f4c66Sjsg 		return (EIO);
3460b9f4c66Sjsg 
3470b9f4c66Sjsg 	ustatus->policy = status->policy;
3480b9f4c66Sjsg 	ustatus->asid = status->asid;
3490b9f4c66Sjsg 	ustatus->state = status->state;
3500b9f4c66Sjsg 
3510b9f4c66Sjsg 	return (0);
3520b9f4c66Sjsg }
3530b9f4c66Sjsg 
3540b9f4c66Sjsg int
3558eadc5ecSjsg psp_launch_start(struct psp_softc *sc, struct psp_launch_start *ustart)
3560b9f4c66Sjsg {
3570b9f4c66Sjsg 	struct psp_launch_start	*start;
3580b9f4c66Sjsg 	int			 ret;
3590b9f4c66Sjsg 
3600b9f4c66Sjsg 	start = (struct psp_launch_start *)sc->sc_cmd_kva;
3610b9f4c66Sjsg 	bzero(start, sizeof(*start));
3620b9f4c66Sjsg 
3630b9f4c66Sjsg 	start->handle = ustart->handle;
3640b9f4c66Sjsg 	start->policy = ustart->policy;
3650b9f4c66Sjsg 
3660b9f4c66Sjsg 	ret = ccp_docmd(sc, PSP_CMD_LAUNCH_START,
3670b9f4c66Sjsg 	    sc->sc_cmd_map->dm_segs[0].ds_addr);
3680b9f4c66Sjsg 
3690b9f4c66Sjsg 	if (ret != 0)
3700b9f4c66Sjsg 		return (EIO);
3710b9f4c66Sjsg 
3720b9f4c66Sjsg 	/* If requested, return new handle. */
3730b9f4c66Sjsg 	if (ustart->handle == 0)
3740b9f4c66Sjsg 		ustart->handle = start->handle;
3750b9f4c66Sjsg 
3760b9f4c66Sjsg 	return (0);
3770b9f4c66Sjsg }
3780b9f4c66Sjsg 
3790b9f4c66Sjsg int
380*7989dc90Sjsg psp_launch_update_data(struct psp_softc *sc,
381*7989dc90Sjsg     struct psp_launch_update_data *ulud, struct proc *p)
3820b9f4c66Sjsg {
3830b9f4c66Sjsg 	struct psp_launch_update_data	*ludata;
3840b9f4c66Sjsg 	pmap_t				 pmap;
3850b9f4c66Sjsg 	vaddr_t				 v, next, end;
3860b9f4c66Sjsg 	size_t				 size, len, off;
3870b9f4c66Sjsg 	int				 ret;
3880b9f4c66Sjsg 
3890b9f4c66Sjsg 	/* Ensure AES_XTS_BLOCKSIZE alignment and multiplicity. */
3900b9f4c66Sjsg 	if ((ulud->paddr & (AES_XTS_BLOCKSIZE - 1)) != 0 ||
3910b9f4c66Sjsg 	    (ulud->length % AES_XTS_BLOCKSIZE) != 0)
3920b9f4c66Sjsg 		return (EINVAL);
3930b9f4c66Sjsg 
3940b9f4c66Sjsg 	ludata = (struct psp_launch_update_data *)sc->sc_cmd_kva;
3950b9f4c66Sjsg 	bzero(ludata, sizeof(*ludata));
3960b9f4c66Sjsg 
3970b9f4c66Sjsg 	ludata->handle = ulud->handle;
3980b9f4c66Sjsg 
3990b9f4c66Sjsg 	/* Drain caches before we encrypt memory. */
4000b9f4c66Sjsg 	wbinvd_on_all_cpus();
4010b9f4c66Sjsg 
4020b9f4c66Sjsg 	/*
4030b9f4c66Sjsg 	 * Launch update one physical page at a time.  We could
4040b9f4c66Sjsg 	 * optimise this for contiguous pages of physical memory.
4050b9f4c66Sjsg 	 *
4060b9f4c66Sjsg 	 * vmd(8) provides the guest physical address, thus convert
4070b9f4c66Sjsg 	 * to system physical address.
4080b9f4c66Sjsg 	 */
4090b9f4c66Sjsg 	pmap = vm_map_pmap(&p->p_vmspace->vm_map);
4100b9f4c66Sjsg 	size = ulud->length;
4110b9f4c66Sjsg 	end = ulud->paddr + ulud->length;
4120b9f4c66Sjsg 	for (v = ulud->paddr; v < end; v = next) {
4130b9f4c66Sjsg 		off = v & PAGE_MASK;
4140b9f4c66Sjsg 
4150b9f4c66Sjsg 		len = MIN(PAGE_SIZE - off, size);
4160b9f4c66Sjsg 
4170b9f4c66Sjsg 		/* Wire mapping. */
4180b9f4c66Sjsg 		if (uvm_map_pageable(&p->p_vmspace->vm_map, v, v+len, FALSE, 0))
4190b9f4c66Sjsg 			return (EINVAL);
4200b9f4c66Sjsg 		if (!pmap_extract(pmap, v, (paddr_t *)&ludata->paddr))
4210b9f4c66Sjsg 			return (EINVAL);
4220b9f4c66Sjsg 		ludata->length = len;
4230b9f4c66Sjsg 
4240b9f4c66Sjsg 		ret = ccp_docmd(sc, PSP_CMD_LAUNCH_UPDATE_DATA,
4250b9f4c66Sjsg 		    sc->sc_cmd_map->dm_segs[0].ds_addr);
4260b9f4c66Sjsg 
4270b9f4c66Sjsg 		if (ret != 0)
4280b9f4c66Sjsg 			return (EIO);
4290b9f4c66Sjsg 
4300b9f4c66Sjsg 		size -= len;
4310b9f4c66Sjsg 		next = v + len;
4320b9f4c66Sjsg 	}
4330b9f4c66Sjsg 
4340b9f4c66Sjsg 	return (0);
4350b9f4c66Sjsg }
4360b9f4c66Sjsg 
4370b9f4c66Sjsg int
4388eadc5ecSjsg psp_launch_measure(struct psp_softc *sc, struct psp_launch_measure *ulm)
4390b9f4c66Sjsg {
4400b9f4c66Sjsg 	struct psp_launch_measure *lm;
4410b9f4c66Sjsg 	int			 ret;
4420b9f4c66Sjsg 	uint64_t		 paddr;
4430b9f4c66Sjsg 
4440b9f4c66Sjsg 	if (ulm->measure_len != sizeof(ulm->psp_measure))
4450b9f4c66Sjsg 		return (EINVAL);
4460b9f4c66Sjsg 
4470b9f4c66Sjsg 	lm = (struct psp_launch_measure *)sc->sc_cmd_kva;
4480b9f4c66Sjsg 	bzero(lm, sizeof(*lm));
4490b9f4c66Sjsg 
4500b9f4c66Sjsg 	lm->handle = ulm->handle;
4510b9f4c66Sjsg 	paddr = sc->sc_cmd_map->dm_segs[0].ds_addr;
4520b9f4c66Sjsg 	lm->measure_paddr =
4530b9f4c66Sjsg 	    paddr + offsetof(struct psp_launch_measure, psp_measure);
4540b9f4c66Sjsg 	lm->measure_len = sizeof(lm->psp_measure);
4550b9f4c66Sjsg 
4560b9f4c66Sjsg 	ret = ccp_docmd(sc, PSP_CMD_LAUNCH_MEASURE, paddr);
4570b9f4c66Sjsg 
4580b9f4c66Sjsg 	if (ret != 0 || lm->measure_len != ulm->measure_len)
4590b9f4c66Sjsg 		return (EIO);
4600b9f4c66Sjsg 
4610b9f4c66Sjsg 	bcopy(&lm->psp_measure, &ulm->psp_measure, ulm->measure_len);
4620b9f4c66Sjsg 
4630b9f4c66Sjsg 	return (0);
4640b9f4c66Sjsg }
4650b9f4c66Sjsg 
4660b9f4c66Sjsg int
4678eadc5ecSjsg psp_launch_finish(struct psp_softc *sc, struct psp_launch_finish *ulf)
4680b9f4c66Sjsg {
4690b9f4c66Sjsg 	struct psp_launch_finish *lf;
4700b9f4c66Sjsg 	int			 ret;
4710b9f4c66Sjsg 
4720b9f4c66Sjsg 	lf = (struct psp_launch_finish *)sc->sc_cmd_kva;
4730b9f4c66Sjsg 	bzero(lf, sizeof(*lf));
4740b9f4c66Sjsg 
4750b9f4c66Sjsg 	lf->handle = ulf->handle;
4760b9f4c66Sjsg 
4770b9f4c66Sjsg 	ret = ccp_docmd(sc, PSP_CMD_LAUNCH_FINISH,
4780b9f4c66Sjsg 	    sc->sc_cmd_map->dm_segs[0].ds_addr);
4790b9f4c66Sjsg 
4800b9f4c66Sjsg 	if (ret != 0)
4810b9f4c66Sjsg 		return (EIO);
4820b9f4c66Sjsg 
4830b9f4c66Sjsg 	return (0);
4840b9f4c66Sjsg }
4850b9f4c66Sjsg 
4860b9f4c66Sjsg int
4878eadc5ecSjsg psp_attestation(struct psp_softc *sc, struct psp_attestation *uat)
4880b9f4c66Sjsg {
4890b9f4c66Sjsg 	struct psp_attestation	*at;
4900b9f4c66Sjsg 	int			 ret;
4910b9f4c66Sjsg 	uint64_t		 paddr;
4920b9f4c66Sjsg 
4930b9f4c66Sjsg 	if (uat->attest_len != sizeof(uat->psp_report))
4940b9f4c66Sjsg 		return (EINVAL);
4950b9f4c66Sjsg 
4960b9f4c66Sjsg 	at = (struct psp_attestation *)sc->sc_cmd_kva;
4970b9f4c66Sjsg 	bzero(at, sizeof(*at));
4980b9f4c66Sjsg 
4990b9f4c66Sjsg 	at->handle = uat->handle;
5000b9f4c66Sjsg 	paddr = sc->sc_cmd_map->dm_segs[0].ds_addr;
5010b9f4c66Sjsg 	at->attest_paddr =
5020b9f4c66Sjsg 	    paddr + offsetof(struct psp_attestation, psp_report);
5030b9f4c66Sjsg 	bcopy(uat->attest_nonce, at->attest_nonce, sizeof(at->attest_nonce));
5040b9f4c66Sjsg 	at->attest_len = sizeof(at->psp_report);
5050b9f4c66Sjsg 
5060b9f4c66Sjsg 	ret = ccp_docmd(sc, PSP_CMD_ATTESTATION, paddr);
5070b9f4c66Sjsg 
5080b9f4c66Sjsg 	if (ret != 0 || at->attest_len != uat->attest_len)
5090b9f4c66Sjsg 		return (EIO);
5100b9f4c66Sjsg 
5110b9f4c66Sjsg 	bcopy(&at->psp_report, &uat->psp_report, uat->attest_len);
5120b9f4c66Sjsg 
5130b9f4c66Sjsg 	return (0);
5140b9f4c66Sjsg }
5150b9f4c66Sjsg 
5160b9f4c66Sjsg int
5178eadc5ecSjsg psp_activate(struct psp_softc *sc, struct psp_activate *uact)
5180b9f4c66Sjsg {
5190b9f4c66Sjsg 	struct psp_activate	*act;
5200b9f4c66Sjsg 	int			 ret;
5210b9f4c66Sjsg 
5220b9f4c66Sjsg 	act = (struct psp_activate *)sc->sc_cmd_kva;
5230b9f4c66Sjsg 	bzero(act, sizeof(*act));
5240b9f4c66Sjsg 
5250b9f4c66Sjsg 	act->handle = uact->handle;
5260b9f4c66Sjsg 	act->asid = uact->asid;
5270b9f4c66Sjsg 
5280b9f4c66Sjsg 	ret = ccp_docmd(sc, PSP_CMD_ACTIVATE,
5290b9f4c66Sjsg 	    sc->sc_cmd_map->dm_segs[0].ds_addr);
5300b9f4c66Sjsg 
5310b9f4c66Sjsg 	if (ret != 0)
5320b9f4c66Sjsg 		return (EIO);
5330b9f4c66Sjsg 
5340b9f4c66Sjsg 	return (0);
5350b9f4c66Sjsg }
5360b9f4c66Sjsg 
5370b9f4c66Sjsg int
5388eadc5ecSjsg psp_deactivate(struct psp_softc *sc, struct psp_deactivate *udeact)
5390b9f4c66Sjsg {
5400b9f4c66Sjsg 	struct psp_deactivate	*deact;
5410b9f4c66Sjsg 	int			 ret;
5420b9f4c66Sjsg 
5430b9f4c66Sjsg 	deact = (struct psp_deactivate *)sc->sc_cmd_kva;
5440b9f4c66Sjsg 	bzero(deact, sizeof(*deact));
5450b9f4c66Sjsg 
5460b9f4c66Sjsg 	deact->handle = udeact->handle;
5470b9f4c66Sjsg 
5480b9f4c66Sjsg 	ret = ccp_docmd(sc, PSP_CMD_DEACTIVATE,
5490b9f4c66Sjsg 	    sc->sc_cmd_map->dm_segs[0].ds_addr);
5500b9f4c66Sjsg 
5510b9f4c66Sjsg 	if (ret != 0)
5520b9f4c66Sjsg 		return (EIO);
5530b9f4c66Sjsg 
5540b9f4c66Sjsg 	return (0);
5550b9f4c66Sjsg }
5560b9f4c66Sjsg 
5570b9f4c66Sjsg int
5588eadc5ecSjsg psp_guest_shutdown(struct psp_softc *sc, struct psp_guest_shutdown *ugshutdown)
5590b9f4c66Sjsg {
5600b9f4c66Sjsg 	struct psp_deactivate	deact;
5610b9f4c66Sjsg 	struct psp_decommission	decom;
5620b9f4c66Sjsg 	int			ret;
5630b9f4c66Sjsg 
5640b9f4c66Sjsg 	bzero(&deact, sizeof(deact));
5650b9f4c66Sjsg 	deact.handle = ugshutdown->handle;
5668eadc5ecSjsg 	if ((ret = psp_deactivate(sc, &deact)) != 0)
5670b9f4c66Sjsg 		return (ret);
5680b9f4c66Sjsg 
5698eadc5ecSjsg 	if ((ret = psp_df_flush(sc)) != 0)
5700b9f4c66Sjsg 		return (ret);
5710b9f4c66Sjsg 
5720b9f4c66Sjsg 	bzero(&decom, sizeof(decom));
5730b9f4c66Sjsg 	decom.handle = ugshutdown->handle;
5748eadc5ecSjsg 	if ((ret = psp_decommission(sc, &decom)) != 0)
5750b9f4c66Sjsg 		return (ret);
5760b9f4c66Sjsg 
5770b9f4c66Sjsg 	return (0);
5780b9f4c66Sjsg }
5790b9f4c66Sjsg 
5800b9f4c66Sjsg int
581*7989dc90Sjsg psp_snp_get_pstatus(struct psp_softc *sc,
582*7989dc90Sjsg     struct psp_snp_platform_status *ustatus)
5830b9f4c66Sjsg {
5840b9f4c66Sjsg 	struct psp_snp_platform_status *status;
5850b9f4c66Sjsg 	int			 ret;
5860b9f4c66Sjsg 
5870b9f4c66Sjsg 	status = (struct psp_snp_platform_status *)sc->sc_cmd_kva;
5880b9f4c66Sjsg 	bzero(status, sizeof(*status));
5890b9f4c66Sjsg 
5900b9f4c66Sjsg 	ret = ccp_docmd(sc, PSP_CMD_SNP_PLATFORMSTATUS,
5910b9f4c66Sjsg 	    sc->sc_cmd_map->dm_segs[0].ds_addr);
5920b9f4c66Sjsg 
5930b9f4c66Sjsg 	if (ret != 0)
5940b9f4c66Sjsg 		return (EIO);
5950b9f4c66Sjsg 
5960b9f4c66Sjsg 	bcopy(status, ustatus, sizeof(*ustatus));
5970b9f4c66Sjsg 
5980b9f4c66Sjsg 	return (0);
5990b9f4c66Sjsg }
6000b9f4c66Sjsg 
6010b9f4c66Sjsg int
6020b9f4c66Sjsg pspopen(dev_t dev, int flag, int mode, struct proc *p)
6030b9f4c66Sjsg {
6048eadc5ecSjsg 	struct psp_softc *sc;
6058eadc5ecSjsg 
6068eadc5ecSjsg 	sc = (struct psp_softc *)device_lookup(&psp_cd, minor(dev));
6078eadc5ecSjsg 	if (sc == NULL)
6088eadc5ecSjsg 		return (ENXIO);
6090b9f4c66Sjsg 
6100b9f4c66Sjsg 	return (0);
6110b9f4c66Sjsg }
6120b9f4c66Sjsg 
6130b9f4c66Sjsg int
6140b9f4c66Sjsg pspclose(dev_t dev, int flag, int mode, struct proc *p)
6150b9f4c66Sjsg {
6168eadc5ecSjsg 	struct psp_softc *sc;
6178eadc5ecSjsg 
6188eadc5ecSjsg 	sc = (struct psp_softc *)device_lookup(&psp_cd, minor(dev));
6198eadc5ecSjsg 	if (sc == NULL)
6208eadc5ecSjsg 		return (ENXIO);
6218eadc5ecSjsg 
6220b9f4c66Sjsg 	return (0);
6230b9f4c66Sjsg }
6240b9f4c66Sjsg 
6250b9f4c66Sjsg int
6260b9f4c66Sjsg pspioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
6270b9f4c66Sjsg {
6288eadc5ecSjsg 	struct psp_softc *sc;
6290b9f4c66Sjsg 	int ret;
6300b9f4c66Sjsg 
6318eadc5ecSjsg 	sc = (struct psp_softc *)device_lookup(&psp_cd, minor(dev));
6328eadc5ecSjsg 	if (sc == NULL)
6338eadc5ecSjsg 		return (ENXIO);
6348eadc5ecSjsg 
6358eadc5ecSjsg 	rw_enter_write(&sc->sc_lock);
6360b9f4c66Sjsg 
6370b9f4c66Sjsg 	switch (cmd) {
6380b9f4c66Sjsg 	case PSP_IOC_GET_PSTATUS:
6398eadc5ecSjsg 		ret = psp_get_pstatus(sc, (struct psp_platform_status *)data);
6400b9f4c66Sjsg 		break;
6410b9f4c66Sjsg 	case PSP_IOC_DF_FLUSH:
6428eadc5ecSjsg 		ret = psp_df_flush(sc);
6430b9f4c66Sjsg 		break;
6440b9f4c66Sjsg 	case PSP_IOC_DECOMMISSION:
6458eadc5ecSjsg 		ret = psp_decommission(sc, (struct psp_decommission *)data);
6460b9f4c66Sjsg 		break;
6470b9f4c66Sjsg 	case PSP_IOC_GET_GSTATUS:
6488eadc5ecSjsg 		ret = psp_get_gstatus(sc, (struct psp_guest_status *)data);
6490b9f4c66Sjsg 		break;
6500b9f4c66Sjsg 	case PSP_IOC_LAUNCH_START:
6518eadc5ecSjsg 		ret = psp_launch_start(sc, (struct psp_launch_start *)data);
6520b9f4c66Sjsg 		break;
6530b9f4c66Sjsg 	case PSP_IOC_LAUNCH_UPDATE_DATA:
6548eadc5ecSjsg 		ret = psp_launch_update_data(sc,
6550b9f4c66Sjsg 		    (struct psp_launch_update_data *)data, p);
6560b9f4c66Sjsg 		break;
6570b9f4c66Sjsg 	case PSP_IOC_LAUNCH_MEASURE:
6588eadc5ecSjsg 		ret = psp_launch_measure(sc, (struct psp_launch_measure *)data);
6590b9f4c66Sjsg 		break;
6600b9f4c66Sjsg 	case PSP_IOC_LAUNCH_FINISH:
6618eadc5ecSjsg 		ret = psp_launch_finish(sc, (struct psp_launch_finish *)data);
6620b9f4c66Sjsg 		break;
6630b9f4c66Sjsg 	case PSP_IOC_ATTESTATION:
6648eadc5ecSjsg 		ret = psp_attestation(sc, (struct psp_attestation *)data);
6650b9f4c66Sjsg 		break;
6660b9f4c66Sjsg 	case PSP_IOC_ACTIVATE:
6678eadc5ecSjsg 		ret = psp_activate(sc, (struct psp_activate *)data);
6680b9f4c66Sjsg 		break;
6690b9f4c66Sjsg 	case PSP_IOC_DEACTIVATE:
6708eadc5ecSjsg 		ret = psp_deactivate(sc, (struct psp_deactivate *)data);
6710b9f4c66Sjsg 		break;
6720b9f4c66Sjsg 	case PSP_IOC_GUEST_SHUTDOWN:
6738eadc5ecSjsg 		ret = psp_guest_shutdown(sc, (struct psp_guest_shutdown *)data);
6740b9f4c66Sjsg 		break;
6750b9f4c66Sjsg 	case PSP_IOC_SNP_GET_PSTATUS:
6768eadc5ecSjsg 		ret = psp_snp_get_pstatus(sc,
6778eadc5ecSjsg 		    (struct psp_snp_platform_status *)data);
6780b9f4c66Sjsg 		break;
6790b9f4c66Sjsg 	default:
6800b9f4c66Sjsg 		ret = ENOTTY;
6810b9f4c66Sjsg 		break;
6820b9f4c66Sjsg 	}
6830b9f4c66Sjsg 
6848eadc5ecSjsg 	rw_exit_write(&sc->sc_lock);
6850b9f4c66Sjsg 
6860b9f4c66Sjsg 	return (ret);
6870b9f4c66Sjsg }
6880b9f4c66Sjsg 
6890b9f4c66Sjsg int
6900b9f4c66Sjsg pledge_ioctl_psp(struct proc *p, long com)
6910b9f4c66Sjsg {
6920b9f4c66Sjsg 	switch (com) {
6930b9f4c66Sjsg 	case PSP_IOC_GET_PSTATUS:
6940b9f4c66Sjsg 	case PSP_IOC_DF_FLUSH:
6950b9f4c66Sjsg 	case PSP_IOC_GET_GSTATUS:
6960b9f4c66Sjsg 	case PSP_IOC_LAUNCH_START:
6970b9f4c66Sjsg 	case PSP_IOC_LAUNCH_UPDATE_DATA:
6980b9f4c66Sjsg 	case PSP_IOC_LAUNCH_MEASURE:
6990b9f4c66Sjsg 	case PSP_IOC_LAUNCH_FINISH:
7000b9f4c66Sjsg 	case PSP_IOC_ACTIVATE:
7010b9f4c66Sjsg 	case PSP_IOC_GUEST_SHUTDOWN:
7020b9f4c66Sjsg 		return (0);
7030b9f4c66Sjsg 	default:
7040b9f4c66Sjsg 		return (pledge_fail(p, EPERM, PLEDGE_VMM));
7050b9f4c66Sjsg 	}
7060b9f4c66Sjsg }
7078eadc5ecSjsg 
7088eadc5ecSjsg int
7098eadc5ecSjsg pspprint(void *aux, const char *pnp)
7108eadc5ecSjsg {
7118eadc5ecSjsg 	return QUIET;
7128eadc5ecSjsg }
7138eadc5ecSjsg 
7148eadc5ecSjsg int
7158eadc5ecSjsg pspsubmatch(struct device *parent, void *match, void *aux)
7168eadc5ecSjsg {
7178eadc5ecSjsg 	struct psp_attach_args *arg = aux;
7188eadc5ecSjsg 	struct cfdata *cf = match;
7198eadc5ecSjsg 
7208eadc5ecSjsg 	if (!(arg->capabilities & PSP_CAP_SEV))
7218eadc5ecSjsg 		return (0);
7228eadc5ecSjsg 	return ((*cf->cf_attach->ca_match)(parent, cf, aux));
7238eadc5ecSjsg }
724