xref: /openbsd-src/sys/dev/ic/psp.c (revision e283d8fbe4710b00487a897b3ac59307fdc34b04)
1*e283d8fbSbluhm /*	$OpenBSD: psp.c,v 1.15 2024/11/20 13:36:55 bluhm 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 
3045c4fed2Sjsg #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 *);
76*e283d8fbSbluhm int	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
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
1098eadc5ecSjsg psp_match(struct device *parent, void *match, void *aux)
1100b9f4c66Sjsg {
1118eadc5ecSjsg 	return (1);
1128eadc5ecSjsg }
1138eadc5ecSjsg 
1148eadc5ecSjsg void
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;
121*e283d8fbSbluhm 	int				nsegs, error;
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;
148*e283d8fbSbluhm 	error = bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
149*e283d8fbSbluhm 	    BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW | BUS_DMA_64BIT, &sc->sc_cmd_map);
150*e283d8fbSbluhm 	if (error)
1510b9f4c66Sjsg 		goto fail_0;
1520b9f4c66Sjsg 
153*e283d8fbSbluhm 	error = bus_dmamem_alloc(sc->sc_dmat, size, 0, 0, &sc->sc_cmd_seg, 1,
154*e283d8fbSbluhm 	    &nsegs, BUS_DMA_WAITOK | BUS_DMA_ZERO);
155*e283d8fbSbluhm 	if (error)
1560b9f4c66Sjsg 		goto fail_1;
1570b9f4c66Sjsg 
158*e283d8fbSbluhm 	error = bus_dmamem_map(sc->sc_dmat, &sc->sc_cmd_seg, nsegs, size,
159*e283d8fbSbluhm 	    &sc->sc_cmd_kva, BUS_DMA_WAITOK);
160*e283d8fbSbluhm 	if (error)
1610b9f4c66Sjsg 		goto fail_2;
1620b9f4c66Sjsg 
163*e283d8fbSbluhm 	error = bus_dmamap_load(sc->sc_dmat, sc->sc_cmd_map, sc->sc_cmd_kva,
164*e283d8fbSbluhm 	    size, NULL, BUS_DMA_WAITOK);
165*e283d8fbSbluhm 	if (error)
166*e283d8fbSbluhm 		goto fail_3;
167*e283d8fbSbluhm 
16838923a19Sbluhm 	if (psp_get_pstatus(sc, &pst)) {
16938923a19Sbluhm 		printf(" platform status");
170*e283d8fbSbluhm 		goto fail_4;
17138923a19Sbluhm 	}
17238923a19Sbluhm 	if (pst.state != PSP_PSTATE_UNINIT) {
17338923a19Sbluhm 		printf(" uninitialized state");
174*e283d8fbSbluhm 		goto fail_4;
17538923a19Sbluhm 	}
176ff28563eSbluhm 	printf(" api %u.%u, build %u, SEV, SEV-ES",
17738923a19Sbluhm 	    pst.api_major, pst.api_minor, pst.cfges_build >> 24);
1780b9f4c66Sjsg 
17938923a19Sbluhm 	/* enable interrupts */
18038923a19Sbluhm 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, sc->sc_reg_inten, -1);
18138923a19Sbluhm 
1828eadc5ecSjsg 	printf("\n");
1830b9f4c66Sjsg 
1848eadc5ecSjsg 	return;
1850b9f4c66Sjsg 
186*e283d8fbSbluhm fail_4:
1870b9f4c66Sjsg 	bus_dmamap_unload(sc->sc_dmat, sc->sc_cmd_map);
188*e283d8fbSbluhm fail_3:
1890b9f4c66Sjsg 	bus_dmamem_unmap(sc->sc_dmat, sc->sc_cmd_kva, size);
190*e283d8fbSbluhm fail_2:
191*e283d8fbSbluhm 	bus_dmamem_free(sc->sc_dmat, &sc->sc_cmd_seg, nsegs);
1920b9f4c66Sjsg fail_1:
1930b9f4c66Sjsg 	bus_dmamap_destroy(sc->sc_dmat, sc->sc_cmd_map);
194*e283d8fbSbluhm fail_0:
19538923a19Sbluhm 	printf(" failed\n");
1960b9f4c66Sjsg }
1970b9f4c66Sjsg 
1980b9f4c66Sjsg static int
1998eadc5ecSjsg ccp_wait(struct psp_softc *sc, uint32_t *status, int poll)
2000b9f4c66Sjsg {
2010b9f4c66Sjsg 	uint32_t	cmdword;
202*e283d8fbSbluhm 	int		count, error;
2030b9f4c66Sjsg 
2048f8d81e9Sbluhm 	MUTEX_ASSERT_LOCKED(&sc->psp_lock);
2058f8d81e9Sbluhm 
2060b9f4c66Sjsg 	if (poll) {
2070b9f4c66Sjsg 		count = 0;
20838923a19Sbluhm 		while (count++ < 400) {
2090b9f4c66Sjsg 			cmdword = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
21038923a19Sbluhm 			    sc->sc_reg_cmdresp);
2110b9f4c66Sjsg 			if (cmdword & PSP_CMDRESP_RESPONSE)
2120b9f4c66Sjsg 				goto done;
2130b9f4c66Sjsg 			delay(5000);
2140b9f4c66Sjsg 		}
2150b9f4c66Sjsg 
2160b9f4c66Sjsg 		/* timeout */
217*e283d8fbSbluhm 		return (EWOULDBLOCK);
2180b9f4c66Sjsg 	}
2190b9f4c66Sjsg 
220*e283d8fbSbluhm 	error = msleep_nsec(sc, &sc->psp_lock, PWAIT, "psp", SEC_TO_NSEC(2));
221*e283d8fbSbluhm 	if (error)
222*e283d8fbSbluhm 		return (error);
2230b9f4c66Sjsg 
22438923a19Sbluhm 	cmdword = bus_space_read_4(sc->sc_iot, sc->sc_ioh, sc->sc_reg_cmdresp);
2250b9f4c66Sjsg done:
22638923a19Sbluhm 	if (status != NULL)
22738923a19Sbluhm 		*status = cmdword;
2280b9f4c66Sjsg 	return (0);
2290b9f4c66Sjsg }
2300b9f4c66Sjsg 
2310b9f4c66Sjsg static int
2328eadc5ecSjsg ccp_docmd(struct psp_softc *sc, int cmd, uint64_t paddr)
2330b9f4c66Sjsg {
2340b9f4c66Sjsg 	uint32_t	plo, phi, cmdword, status;
235*e283d8fbSbluhm 	int		error;
2360b9f4c66Sjsg 
2370b9f4c66Sjsg 	plo = ((paddr >> 0) & 0xffffffff);
2380b9f4c66Sjsg 	phi = ((paddr >> 32) & 0xffffffff);
2390b9f4c66Sjsg 	cmdword = (cmd & 0x3ff) << 16;
2400b9f4c66Sjsg 	if (!cold)
2410b9f4c66Sjsg 		cmdword |= PSP_CMDRESP_IOC;
2420b9f4c66Sjsg 
2438f8d81e9Sbluhm 	mtx_enter(&sc->psp_lock);
24438923a19Sbluhm 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, sc->sc_reg_addrlo, plo);
24538923a19Sbluhm 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, sc->sc_reg_addrhi, phi);
24638923a19Sbluhm 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, sc->sc_reg_cmdresp, cmdword);
2470b9f4c66Sjsg 
248*e283d8fbSbluhm 	error = ccp_wait(sc, &status, cold);
2498f8d81e9Sbluhm 	mtx_leave(&sc->psp_lock);
250*e283d8fbSbluhm 	if (error)
251*e283d8fbSbluhm 		return (error);
2520b9f4c66Sjsg 
2530b9f4c66Sjsg 	/* Did PSP sent a response code? */
2540b9f4c66Sjsg 	if (status & PSP_CMDRESP_RESPONSE) {
2550b9f4c66Sjsg 		if ((status & PSP_STATUS_MASK) != PSP_STATUS_SUCCESS)
256*e283d8fbSbluhm 			return (EIO);
2570b9f4c66Sjsg 	}
2580b9f4c66Sjsg 
2590b9f4c66Sjsg 	return (0);
2600b9f4c66Sjsg }
2610b9f4c66Sjsg 
2620b9f4c66Sjsg int
2638eadc5ecSjsg psp_init(struct psp_softc *sc, struct psp_init *uinit)
2640b9f4c66Sjsg {
2650b9f4c66Sjsg 	struct psp_init		*init;
266*e283d8fbSbluhm 	int			 error;
2670b9f4c66Sjsg 
2680b9f4c66Sjsg 	init = (struct psp_init *)sc->sc_cmd_kva;
2690b9f4c66Sjsg 	bzero(init, sizeof(*init));
2700b9f4c66Sjsg 
2710b9f4c66Sjsg 	init->enable_es = uinit->enable_es;
2720b9f4c66Sjsg 	init->tmr_paddr = uinit->tmr_paddr;
2730b9f4c66Sjsg 	init->tmr_length = uinit->tmr_length;
2740b9f4c66Sjsg 
275*e283d8fbSbluhm 	error = ccp_docmd(sc, PSP_CMD_INIT, sc->sc_cmd_map->dm_segs[0].ds_addr);
276*e283d8fbSbluhm 	if (error)
277*e283d8fbSbluhm 		return (error);
2780b9f4c66Sjsg 
279305d28e7Sbluhm 	wbinvd_on_all_cpus_acked();
2800b9f4c66Sjsg 
281ff28563eSbluhm 	sc->sc_flags |= PSPF_INITIALIZED;
282ff28563eSbluhm 
2830b9f4c66Sjsg 	return (0);
2840b9f4c66Sjsg }
2850b9f4c66Sjsg 
2860b9f4c66Sjsg int
287ff28563eSbluhm psp_reinit(struct psp_softc *sc)
288ff28563eSbluhm {
289ff28563eSbluhm 	struct psp_init	init;
290ff28563eSbluhm 	size_t		size;
291*e283d8fbSbluhm 	int		nsegs, error;
292ff28563eSbluhm 
293ff28563eSbluhm 	if (sc->sc_flags & PSPF_INITIALIZED) {
294ff28563eSbluhm 		printf("%s: invalid flags 0x%x\n", __func__, sc->sc_flags);
295*e283d8fbSbluhm 		return (EBUSY);
296ff28563eSbluhm 	}
297ff28563eSbluhm 
298ff28563eSbluhm 	if (sc->sc_tmr_map != NULL)
299*e283d8fbSbluhm 		return (EBUSY);
300ff28563eSbluhm 
301ff28563eSbluhm 	/*
302ff28563eSbluhm 	 * create and map Trusted Memory Region (TMR); size 1 Mbyte,
303ff28563eSbluhm 	 * needs to be aligend to 1 Mbyte.
304ff28563eSbluhm 	 */
305ff28563eSbluhm 	sc->sc_tmr_size = size = PSP_TMR_SIZE;
306*e283d8fbSbluhm 	error = bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
307*e283d8fbSbluhm 	    BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW | BUS_DMA_64BIT, &sc->sc_tmr_map);
308*e283d8fbSbluhm 	if (error)
309ff28563eSbluhm 		goto fail_0;
310ff28563eSbluhm 
311*e283d8fbSbluhm 	error = bus_dmamem_alloc(sc->sc_dmat, size, size, 0, &sc->sc_tmr_seg, 1,
312*e283d8fbSbluhm 	    &nsegs, BUS_DMA_WAITOK | BUS_DMA_ZERO);
313*e283d8fbSbluhm 	if (error)
314ff28563eSbluhm 		goto fail_1;
315ff28563eSbluhm 
316*e283d8fbSbluhm 	error = bus_dmamem_map(sc->sc_dmat, &sc->sc_tmr_seg, nsegs, size,
317*e283d8fbSbluhm 	    &sc->sc_tmr_kva, BUS_DMA_WAITOK);
318*e283d8fbSbluhm 	if (error)
319ff28563eSbluhm 		goto fail_2;
320ff28563eSbluhm 
321*e283d8fbSbluhm 	error = bus_dmamap_load(sc->sc_dmat, sc->sc_tmr_map, sc->sc_tmr_kva,
322*e283d8fbSbluhm 	    size, NULL, BUS_DMA_WAITOK);
323*e283d8fbSbluhm 	if (error)
324*e283d8fbSbluhm 		goto fail_3;
325*e283d8fbSbluhm 
326ff28563eSbluhm 	memset(&init, 0, sizeof(init));
327ff28563eSbluhm 	init.enable_es = 1;
328ff28563eSbluhm 	init.tmr_length = PSP_TMR_SIZE;
329ff28563eSbluhm 	init.tmr_paddr = sc->sc_tmr_map->dm_segs[0].ds_addr;
330*e283d8fbSbluhm 	if ((error = psp_init(sc, &init)) != 0)
331*e283d8fbSbluhm 		goto fail_4;
332ff28563eSbluhm 
333ff28563eSbluhm 	return (0);
334ff28563eSbluhm 
335*e283d8fbSbluhm fail_4:
336ff28563eSbluhm 	bus_dmamap_unload(sc->sc_dmat, sc->sc_tmr_map);
337*e283d8fbSbluhm fail_3:
338ff28563eSbluhm 	bus_dmamem_unmap(sc->sc_dmat, sc->sc_tmr_kva, size);
339*e283d8fbSbluhm fail_2:
340*e283d8fbSbluhm 	bus_dmamem_free(sc->sc_dmat, &sc->sc_tmr_seg, nsegs);
341ff28563eSbluhm fail_1:
342ff28563eSbluhm 	bus_dmamap_destroy(sc->sc_dmat, sc->sc_tmr_map);
343*e283d8fbSbluhm fail_0:
344*e283d8fbSbluhm 	return (error);
345ff28563eSbluhm }
346ff28563eSbluhm 
347ff28563eSbluhm int
348b25bc4b2Sbluhm psp_shutdown(struct psp_softc *sc)
349b25bc4b2Sbluhm {
350*e283d8fbSbluhm 	int error;
351b25bc4b2Sbluhm 
352b25bc4b2Sbluhm 	if (sc->sc_tmr_map == NULL)
353b25bc4b2Sbluhm 		return (EINVAL);
354b25bc4b2Sbluhm 
355*e283d8fbSbluhm 	error = ccp_docmd(sc, PSP_CMD_SHUTDOWN, 0x0);
356*e283d8fbSbluhm 	if (error)
357*e283d8fbSbluhm 		return (error);
358b25bc4b2Sbluhm 
359b25bc4b2Sbluhm 	/* wbinvd right after SHUTDOWN */
360305d28e7Sbluhm 	wbinvd_on_all_cpus_acked();
361b25bc4b2Sbluhm 
362b25bc4b2Sbluhm 	/* release TMR */
363b25bc4b2Sbluhm 	bus_dmamap_unload(sc->sc_dmat, sc->sc_tmr_map);
364b25bc4b2Sbluhm 	bus_dmamem_unmap(sc->sc_dmat, sc->sc_tmr_kva, sc->sc_tmr_size);
365b25bc4b2Sbluhm 	bus_dmamem_free(sc->sc_dmat, &sc->sc_tmr_seg, 1);
366b25bc4b2Sbluhm 	bus_dmamap_destroy(sc->sc_dmat, sc->sc_tmr_map);
367b25bc4b2Sbluhm 	sc->sc_tmr_map = NULL;
368b25bc4b2Sbluhm 
369b25bc4b2Sbluhm 	/* reset flags */
370b25bc4b2Sbluhm 	sc->sc_flags = 0;
371b25bc4b2Sbluhm 
372b25bc4b2Sbluhm 	return (0);
373b25bc4b2Sbluhm }
374b25bc4b2Sbluhm 
375b25bc4b2Sbluhm int
3768eadc5ecSjsg psp_get_pstatus(struct psp_softc *sc, struct psp_platform_status *ustatus)
3770b9f4c66Sjsg {
3780b9f4c66Sjsg 	struct psp_platform_status	*status;
379*e283d8fbSbluhm 	int				 error;
3800b9f4c66Sjsg 
3810b9f4c66Sjsg 	status = (struct psp_platform_status *)sc->sc_cmd_kva;
3820b9f4c66Sjsg 	bzero(status, sizeof(*status));
3830b9f4c66Sjsg 
384*e283d8fbSbluhm 	error = ccp_docmd(sc, PSP_CMD_PLATFORMSTATUS,
3850b9f4c66Sjsg 	    sc->sc_cmd_map->dm_segs[0].ds_addr);
386*e283d8fbSbluhm 	if (error)
387*e283d8fbSbluhm 		return (error);
3880b9f4c66Sjsg 
3890b9f4c66Sjsg 	bcopy(status, ustatus, sizeof(*ustatus));
3900b9f4c66Sjsg 
3910b9f4c66Sjsg 	return (0);
3920b9f4c66Sjsg }
3930b9f4c66Sjsg 
3940b9f4c66Sjsg int
3958eadc5ecSjsg psp_df_flush(struct psp_softc *sc)
3960b9f4c66Sjsg {
397*e283d8fbSbluhm 	int error;
3980b9f4c66Sjsg 
399305d28e7Sbluhm 	wbinvd_on_all_cpus_acked();
4000b9f4c66Sjsg 
401*e283d8fbSbluhm 	error = ccp_docmd(sc, PSP_CMD_DF_FLUSH, 0x0);
4020b9f4c66Sjsg 
403*e283d8fbSbluhm 	return (error);
4040b9f4c66Sjsg }
4050b9f4c66Sjsg 
4060b9f4c66Sjsg int
4078eadc5ecSjsg psp_decommission(struct psp_softc *sc, struct psp_decommission *udecom)
4080b9f4c66Sjsg {
4090b9f4c66Sjsg 	struct psp_decommission	*decom;
410*e283d8fbSbluhm 	int			 error;
4110b9f4c66Sjsg 
4120b9f4c66Sjsg 	decom = (struct psp_decommission *)sc->sc_cmd_kva;
4130b9f4c66Sjsg 	bzero(decom, sizeof(*decom));
4140b9f4c66Sjsg 
4150b9f4c66Sjsg 	decom->handle = udecom->handle;
4160b9f4c66Sjsg 
417*e283d8fbSbluhm 	error = ccp_docmd(sc, PSP_CMD_DECOMMISSION,
4180b9f4c66Sjsg 	    sc->sc_cmd_map->dm_segs[0].ds_addr);
4190b9f4c66Sjsg 
420*e283d8fbSbluhm 	return (error);
4210b9f4c66Sjsg }
4220b9f4c66Sjsg 
4230b9f4c66Sjsg int
4248eadc5ecSjsg psp_get_gstatus(struct psp_softc *sc, struct psp_guest_status *ustatus)
4250b9f4c66Sjsg {
4260b9f4c66Sjsg 	struct psp_guest_status	*status;
427*e283d8fbSbluhm 	int			 error;
4280b9f4c66Sjsg 
4290b9f4c66Sjsg 	status = (struct psp_guest_status *)sc->sc_cmd_kva;
4300b9f4c66Sjsg 	bzero(status, sizeof(*status));
4310b9f4c66Sjsg 
4320b9f4c66Sjsg 	status->handle = ustatus->handle;
4330b9f4c66Sjsg 
434*e283d8fbSbluhm 	error = ccp_docmd(sc, PSP_CMD_GUESTSTATUS,
4350b9f4c66Sjsg 	    sc->sc_cmd_map->dm_segs[0].ds_addr);
436*e283d8fbSbluhm 	if (error)
437*e283d8fbSbluhm 		return (error);
4380b9f4c66Sjsg 
4390b9f4c66Sjsg 	ustatus->policy = status->policy;
4400b9f4c66Sjsg 	ustatus->asid = status->asid;
4410b9f4c66Sjsg 	ustatus->state = status->state;
4420b9f4c66Sjsg 
4430b9f4c66Sjsg 	return (0);
4440b9f4c66Sjsg }
4450b9f4c66Sjsg 
4460b9f4c66Sjsg int
4478eadc5ecSjsg psp_launch_start(struct psp_softc *sc, struct psp_launch_start *ustart)
4480b9f4c66Sjsg {
4490b9f4c66Sjsg 	struct psp_launch_start	*start;
450*e283d8fbSbluhm 	int			 error;
4510b9f4c66Sjsg 
4520b9f4c66Sjsg 	start = (struct psp_launch_start *)sc->sc_cmd_kva;
4530b9f4c66Sjsg 	bzero(start, sizeof(*start));
4540b9f4c66Sjsg 
4550b9f4c66Sjsg 	start->handle = ustart->handle;
4560b9f4c66Sjsg 	start->policy = ustart->policy;
4570b9f4c66Sjsg 
458*e283d8fbSbluhm 	error = ccp_docmd(sc, PSP_CMD_LAUNCH_START,
4590b9f4c66Sjsg 	    sc->sc_cmd_map->dm_segs[0].ds_addr);
460*e283d8fbSbluhm 	if (error)
461*e283d8fbSbluhm 		return (error);
4620b9f4c66Sjsg 
4630b9f4c66Sjsg 	/* If requested, return new handle. */
4640b9f4c66Sjsg 	if (ustart->handle == 0)
4650b9f4c66Sjsg 		ustart->handle = start->handle;
4660b9f4c66Sjsg 
4670b9f4c66Sjsg 	return (0);
4680b9f4c66Sjsg }
4690b9f4c66Sjsg 
4700b9f4c66Sjsg int
4717989dc90Sjsg psp_launch_update_data(struct psp_softc *sc,
4727989dc90Sjsg     struct psp_launch_update_data *ulud, struct proc *p)
4730b9f4c66Sjsg {
4740b9f4c66Sjsg 	struct psp_launch_update_data	*ludata;
4750b9f4c66Sjsg 	pmap_t				 pmap;
476a061ddb5Sbluhm 	vaddr_t				 v, next, start, end;
4770b9f4c66Sjsg 	size_t				 size, len, off;
478*e283d8fbSbluhm 	int				 error;
4790b9f4c66Sjsg 
4800b9f4c66Sjsg 	/* Ensure AES_XTS_BLOCKSIZE alignment and multiplicity. */
4810b9f4c66Sjsg 	if ((ulud->paddr & (AES_XTS_BLOCKSIZE - 1)) != 0 ||
4820b9f4c66Sjsg 	    (ulud->length % AES_XTS_BLOCKSIZE) != 0)
4830b9f4c66Sjsg 		return (EINVAL);
4840b9f4c66Sjsg 
4850b9f4c66Sjsg 	ludata = (struct psp_launch_update_data *)sc->sc_cmd_kva;
4860b9f4c66Sjsg 	bzero(ludata, sizeof(*ludata));
4870b9f4c66Sjsg 
4880b9f4c66Sjsg 	ludata->handle = ulud->handle;
4890b9f4c66Sjsg 
4900b9f4c66Sjsg 	/* Drain caches before we encrypt memory. */
491305d28e7Sbluhm 	wbinvd_on_all_cpus_acked();
4920b9f4c66Sjsg 
4930b9f4c66Sjsg 	/*
4940b9f4c66Sjsg 	 * Launch update one physical page at a time.  We could
4950b9f4c66Sjsg 	 * optimise this for contiguous pages of physical memory.
4960b9f4c66Sjsg 	 *
4970b9f4c66Sjsg 	 * vmd(8) provides the guest physical address, thus convert
4980b9f4c66Sjsg 	 * to system physical address.
4990b9f4c66Sjsg 	 */
5000b9f4c66Sjsg 	pmap = vm_map_pmap(&p->p_vmspace->vm_map);
501a061ddb5Sbluhm 	start = ulud->paddr;
5020b9f4c66Sjsg 	size = ulud->length;
503a061ddb5Sbluhm 	end = start + size;
504a061ddb5Sbluhm 
505a061ddb5Sbluhm 	/* Wire mapping. */
506*e283d8fbSbluhm 	error = uvm_map_pageable(&p->p_vmspace->vm_map, start, end, FALSE, 0);
507*e283d8fbSbluhm 	if (error)
508a061ddb5Sbluhm 		goto out;
509a061ddb5Sbluhm 
5100b9f4c66Sjsg 	for (v = ulud->paddr; v < end; v = next) {
5110b9f4c66Sjsg 		off = v & PAGE_MASK;
5120b9f4c66Sjsg 
5130b9f4c66Sjsg 		len = MIN(PAGE_SIZE - off, size);
5140b9f4c66Sjsg 
515*e283d8fbSbluhm 		if (!pmap_extract(pmap, v, (paddr_t *)&ludata->paddr)) {
516*e283d8fbSbluhm 			error = EINVAL;
517a061ddb5Sbluhm 			goto out;
518a061ddb5Sbluhm 		}
519*e283d8fbSbluhm 		ludata->length = len;
520*e283d8fbSbluhm 
521*e283d8fbSbluhm 		error = ccp_docmd(sc, PSP_CMD_LAUNCH_UPDATE_DATA,
522*e283d8fbSbluhm 		    sc->sc_cmd_map->dm_segs[0].ds_addr);
523*e283d8fbSbluhm 		if (error)
524*e283d8fbSbluhm 			goto out;
5250b9f4c66Sjsg 
5260b9f4c66Sjsg 		size -= len;
5270b9f4c66Sjsg 		next = v + len;
5280b9f4c66Sjsg 	}
5290b9f4c66Sjsg 
530a061ddb5Sbluhm out:
531*e283d8fbSbluhm 	/*
532*e283d8fbSbluhm 	 * Unwire again.  Ignore new error.  Error has either been set,
533*e283d8fbSbluhm 	 * or PSP command has already succeeded.
534*e283d8fbSbluhm 	 */
535*e283d8fbSbluhm 	(void) uvm_map_pageable(&p->p_vmspace->vm_map, start, end, TRUE, 0);
536a061ddb5Sbluhm 
537*e283d8fbSbluhm 	return (error);
5380b9f4c66Sjsg }
5390b9f4c66Sjsg 
5400b9f4c66Sjsg int
5418eadc5ecSjsg psp_launch_measure(struct psp_softc *sc, struct psp_launch_measure *ulm)
5420b9f4c66Sjsg {
5430b9f4c66Sjsg 	struct psp_launch_measure	*lm;
5440b9f4c66Sjsg 	uint64_t			 paddr;
545*e283d8fbSbluhm 	int				 error;
5460b9f4c66Sjsg 
5470b9f4c66Sjsg 	if (ulm->measure_len != sizeof(ulm->psp_measure))
5480b9f4c66Sjsg 		return (EINVAL);
5490b9f4c66Sjsg 
5500b9f4c66Sjsg 	lm = (struct psp_launch_measure *)sc->sc_cmd_kva;
5510b9f4c66Sjsg 	bzero(lm, sizeof(*lm));
5520b9f4c66Sjsg 
5530b9f4c66Sjsg 	lm->handle = ulm->handle;
5540b9f4c66Sjsg 	paddr = sc->sc_cmd_map->dm_segs[0].ds_addr;
5550b9f4c66Sjsg 	lm->measure_paddr =
5560b9f4c66Sjsg 	    paddr + offsetof(struct psp_launch_measure, psp_measure);
5570b9f4c66Sjsg 	lm->measure_len = sizeof(lm->psp_measure);
5580b9f4c66Sjsg 
559*e283d8fbSbluhm 	error = ccp_docmd(sc, PSP_CMD_LAUNCH_MEASURE, paddr);
560*e283d8fbSbluhm 	if (error)
561*e283d8fbSbluhm 		return (error);
562*e283d8fbSbluhm 	if (lm->measure_len != ulm->measure_len)
563*e283d8fbSbluhm 		return (ERANGE);
5640b9f4c66Sjsg 
5650b9f4c66Sjsg 	bcopy(&lm->psp_measure, &ulm->psp_measure, ulm->measure_len);
5660b9f4c66Sjsg 
5670b9f4c66Sjsg 	return (0);
5680b9f4c66Sjsg }
5690b9f4c66Sjsg 
5700b9f4c66Sjsg int
5718eadc5ecSjsg psp_launch_finish(struct psp_softc *sc, struct psp_launch_finish *ulf)
5720b9f4c66Sjsg {
5730b9f4c66Sjsg 	struct psp_launch_finish	*lf;
574*e283d8fbSbluhm 	int				 error;
5750b9f4c66Sjsg 
5760b9f4c66Sjsg 	lf = (struct psp_launch_finish *)sc->sc_cmd_kva;
5770b9f4c66Sjsg 	bzero(lf, sizeof(*lf));
5780b9f4c66Sjsg 
5790b9f4c66Sjsg 	lf->handle = ulf->handle;
5800b9f4c66Sjsg 
581*e283d8fbSbluhm 	error = ccp_docmd(sc, PSP_CMD_LAUNCH_FINISH,
5820b9f4c66Sjsg 	    sc->sc_cmd_map->dm_segs[0].ds_addr);
5830b9f4c66Sjsg 
584*e283d8fbSbluhm 	return (error);
5850b9f4c66Sjsg }
5860b9f4c66Sjsg 
5870b9f4c66Sjsg int
5888eadc5ecSjsg psp_attestation(struct psp_softc *sc, struct psp_attestation *uat)
5890b9f4c66Sjsg {
5900b9f4c66Sjsg 	struct psp_attestation	*at;
5910b9f4c66Sjsg 	uint64_t		 paddr;
592*e283d8fbSbluhm 	int			 error;
5930b9f4c66Sjsg 
5940b9f4c66Sjsg 	if (uat->attest_len != sizeof(uat->psp_report))
5950b9f4c66Sjsg 		return (EINVAL);
5960b9f4c66Sjsg 
5970b9f4c66Sjsg 	at = (struct psp_attestation *)sc->sc_cmd_kva;
5980b9f4c66Sjsg 	bzero(at, sizeof(*at));
5990b9f4c66Sjsg 
6000b9f4c66Sjsg 	at->handle = uat->handle;
6010b9f4c66Sjsg 	paddr = sc->sc_cmd_map->dm_segs[0].ds_addr;
6020b9f4c66Sjsg 	at->attest_paddr =
6030b9f4c66Sjsg 	    paddr + offsetof(struct psp_attestation, psp_report);
6040b9f4c66Sjsg 	bcopy(uat->attest_nonce, at->attest_nonce, sizeof(at->attest_nonce));
6050b9f4c66Sjsg 	at->attest_len = sizeof(at->psp_report);
6060b9f4c66Sjsg 
607*e283d8fbSbluhm 	error = ccp_docmd(sc, PSP_CMD_ATTESTATION, paddr);
608*e283d8fbSbluhm 	if (error)
609*e283d8fbSbluhm 		return (error);
610*e283d8fbSbluhm 	if (at->attest_len != uat->attest_len)
611*e283d8fbSbluhm 		return (ERANGE);
6120b9f4c66Sjsg 
6130b9f4c66Sjsg 	bcopy(&at->psp_report, &uat->psp_report, uat->attest_len);
6140b9f4c66Sjsg 
6150b9f4c66Sjsg 	return (0);
6160b9f4c66Sjsg }
6170b9f4c66Sjsg 
6180b9f4c66Sjsg int
6198eadc5ecSjsg psp_activate(struct psp_softc *sc, struct psp_activate *uact)
6200b9f4c66Sjsg {
6210b9f4c66Sjsg 	struct psp_activate	*act;
622*e283d8fbSbluhm 	int			 error;
6230b9f4c66Sjsg 
6240b9f4c66Sjsg 	act = (struct psp_activate *)sc->sc_cmd_kva;
6250b9f4c66Sjsg 	bzero(act, sizeof(*act));
6260b9f4c66Sjsg 
6270b9f4c66Sjsg 	act->handle = uact->handle;
6280b9f4c66Sjsg 	act->asid = uact->asid;
6290b9f4c66Sjsg 
630*e283d8fbSbluhm 	error = ccp_docmd(sc, PSP_CMD_ACTIVATE,
6310b9f4c66Sjsg 	    sc->sc_cmd_map->dm_segs[0].ds_addr);
6320b9f4c66Sjsg 
633*e283d8fbSbluhm 	return (error);
6340b9f4c66Sjsg }
6350b9f4c66Sjsg 
6360b9f4c66Sjsg int
6378eadc5ecSjsg psp_deactivate(struct psp_softc *sc, struct psp_deactivate *udeact)
6380b9f4c66Sjsg {
6390b9f4c66Sjsg 	struct psp_deactivate	*deact;
640*e283d8fbSbluhm 	int			 error;
6410b9f4c66Sjsg 
6420b9f4c66Sjsg 	deact = (struct psp_deactivate *)sc->sc_cmd_kva;
6430b9f4c66Sjsg 	bzero(deact, sizeof(*deact));
6440b9f4c66Sjsg 
6450b9f4c66Sjsg 	deact->handle = udeact->handle;
6460b9f4c66Sjsg 
647*e283d8fbSbluhm 	error = ccp_docmd(sc, PSP_CMD_DEACTIVATE,
6480b9f4c66Sjsg 	    sc->sc_cmd_map->dm_segs[0].ds_addr);
6490b9f4c66Sjsg 
650*e283d8fbSbluhm 	return (error);
6510b9f4c66Sjsg }
6520b9f4c66Sjsg 
6530b9f4c66Sjsg int
65452c926a1Sbluhm psp_downloadfirmware(struct psp_softc *sc, struct psp_downloadfirmware *udlfw)
65552c926a1Sbluhm {
65652c926a1Sbluhm 	struct psp_downloadfirmware	*dlfw;
65752c926a1Sbluhm 	bus_dmamap_t			 map;
65852c926a1Sbluhm 	bus_dma_segment_t		 seg;
65952c926a1Sbluhm 	caddr_t				 kva;
660*e283d8fbSbluhm 	int				 nsegs, error;
66152c926a1Sbluhm 
66252c926a1Sbluhm 	dlfw = (struct psp_downloadfirmware *)sc->sc_cmd_kva;
66352c926a1Sbluhm 	bzero(dlfw, sizeof(*dlfw));
66452c926a1Sbluhm 
665*e283d8fbSbluhm 	error = bus_dmamap_create(sc->sc_dmat, udlfw->fw_len, 1, udlfw->fw_len,
666*e283d8fbSbluhm 	    0, BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW | BUS_DMA_64BIT, &map);
667*e283d8fbSbluhm 	if (error)
66852c926a1Sbluhm 		goto fail_0;
669*e283d8fbSbluhm 
670*e283d8fbSbluhm 	error = bus_dmamem_alloc(sc->sc_dmat, udlfw->fw_len, 0, 0, &seg, 1,
671*e283d8fbSbluhm 	    &nsegs, BUS_DMA_WAITOK | BUS_DMA_ZERO);
672*e283d8fbSbluhm 	if (error)
67352c926a1Sbluhm 		goto fail_1;
674*e283d8fbSbluhm 
675*e283d8fbSbluhm 	error = bus_dmamem_map(sc->sc_dmat, &seg, nsegs, udlfw->fw_len, &kva,
676*e283d8fbSbluhm 	    BUS_DMA_WAITOK);
677*e283d8fbSbluhm 	if (error)
67852c926a1Sbluhm 		goto fail_2;
67952c926a1Sbluhm 
680*e283d8fbSbluhm 	error = bus_dmamap_load(sc->sc_dmat, map, kva, udlfw->fw_len, NULL,
681*e283d8fbSbluhm 	    BUS_DMA_WAITOK);
682*e283d8fbSbluhm 	if (error)
683*e283d8fbSbluhm 		goto fail_3;
684*e283d8fbSbluhm 
68552c926a1Sbluhm 	bcopy((void *)udlfw->fw_paddr, kva, udlfw->fw_len);
68652c926a1Sbluhm 
68752c926a1Sbluhm 	dlfw->fw_paddr = map->dm_segs[0].ds_addr;
68852c926a1Sbluhm 	dlfw->fw_len = map->dm_segs[0].ds_len;
68952c926a1Sbluhm 
690*e283d8fbSbluhm 	error = ccp_docmd(sc, PSP_CMD_DOWNLOADFIRMWARE,
69152c926a1Sbluhm 	    sc->sc_cmd_map->dm_segs[0].ds_addr);
69252c926a1Sbluhm 
69352c926a1Sbluhm 	bus_dmamap_unload(sc->sc_dmat, map);
694*e283d8fbSbluhm fail_3:
69552c926a1Sbluhm 	bus_dmamem_unmap(sc->sc_dmat, kva, udlfw->fw_len);
696*e283d8fbSbluhm fail_2:
697*e283d8fbSbluhm 	bus_dmamem_free(sc->sc_dmat, &seg, nsegs);
69852c926a1Sbluhm fail_1:
69952c926a1Sbluhm 	bus_dmamap_destroy(sc->sc_dmat, map);
700*e283d8fbSbluhm fail_0:
701*e283d8fbSbluhm 	return (error);
70252c926a1Sbluhm }
70352c926a1Sbluhm 
70452c926a1Sbluhm int
7058eadc5ecSjsg psp_guest_shutdown(struct psp_softc *sc, struct psp_guest_shutdown *ugshutdown)
7060b9f4c66Sjsg {
7070b9f4c66Sjsg 	struct psp_deactivate	deact;
7080b9f4c66Sjsg 	struct psp_decommission	decom;
709*e283d8fbSbluhm 	int			error;
7100b9f4c66Sjsg 
7110b9f4c66Sjsg 	bzero(&deact, sizeof(deact));
7120b9f4c66Sjsg 	deact.handle = ugshutdown->handle;
713*e283d8fbSbluhm 	if ((error = psp_deactivate(sc, &deact)) != 0)
714*e283d8fbSbluhm 		return (error);
7150b9f4c66Sjsg 
716*e283d8fbSbluhm 	if ((error = psp_df_flush(sc)) != 0)
717*e283d8fbSbluhm 		return (error);
7180b9f4c66Sjsg 
7190b9f4c66Sjsg 	bzero(&decom, sizeof(decom));
7200b9f4c66Sjsg 	decom.handle = ugshutdown->handle;
721*e283d8fbSbluhm 	if ((error = psp_decommission(sc, &decom)) != 0)
722*e283d8fbSbluhm 		return (error);
7230b9f4c66Sjsg 
7240b9f4c66Sjsg 	return (0);
7250b9f4c66Sjsg }
7260b9f4c66Sjsg 
7270b9f4c66Sjsg int
7287989dc90Sjsg psp_snp_get_pstatus(struct psp_softc *sc,
7297989dc90Sjsg     struct psp_snp_platform_status *ustatus)
7300b9f4c66Sjsg {
7310b9f4c66Sjsg 	struct psp_snp_platform_status	*status;
732*e283d8fbSbluhm 	int				 error;
7330b9f4c66Sjsg 
7340b9f4c66Sjsg 	status = (struct psp_snp_platform_status *)sc->sc_cmd_kva;
7350b9f4c66Sjsg 	bzero(status, sizeof(*status));
7360b9f4c66Sjsg 
737*e283d8fbSbluhm 	error = ccp_docmd(sc, PSP_CMD_SNP_PLATFORMSTATUS,
7380b9f4c66Sjsg 	    sc->sc_cmd_map->dm_segs[0].ds_addr);
739*e283d8fbSbluhm 	if (error)
740*e283d8fbSbluhm 		return (error);
7410b9f4c66Sjsg 
7420b9f4c66Sjsg 	bcopy(status, ustatus, sizeof(*ustatus));
7430b9f4c66Sjsg 
7440b9f4c66Sjsg 	return (0);
7450b9f4c66Sjsg }
7460b9f4c66Sjsg 
7470b9f4c66Sjsg int
7480b9f4c66Sjsg pspopen(dev_t dev, int flag, int mode, struct proc *p)
7490b9f4c66Sjsg {
7508eadc5ecSjsg 	struct psp_softc *sc;
7518eadc5ecSjsg 
7528eadc5ecSjsg 	sc = (struct psp_softc *)device_lookup(&psp_cd, minor(dev));
7538eadc5ecSjsg 	if (sc == NULL)
7548eadc5ecSjsg 		return (ENXIO);
7550b9f4c66Sjsg 
756*e283d8fbSbluhm 	/* Ignore error, proceed without new firmware. */
757*e283d8fbSbluhm 	(void) psp_load_ucode(sc);
7583c6d599cSbluhm 
759ff28563eSbluhm 	if (!(sc->sc_flags & PSPF_INITIALIZED))
760ff28563eSbluhm 		return (psp_reinit(sc));
761ff28563eSbluhm 
7620b9f4c66Sjsg 	return (0);
7630b9f4c66Sjsg }
7640b9f4c66Sjsg 
7650b9f4c66Sjsg int
7660b9f4c66Sjsg pspclose(dev_t dev, int flag, int mode, struct proc *p)
7670b9f4c66Sjsg {
7688eadc5ecSjsg 	struct psp_softc *sc;
7698eadc5ecSjsg 
7708eadc5ecSjsg 	sc = (struct psp_softc *)device_lookup(&psp_cd, minor(dev));
7718eadc5ecSjsg 	if (sc == NULL)
7728eadc5ecSjsg 		return (ENXIO);
7738eadc5ecSjsg 
7740b9f4c66Sjsg 	return (0);
7750b9f4c66Sjsg }
7760b9f4c66Sjsg 
7770b9f4c66Sjsg int
7780b9f4c66Sjsg pspioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
7790b9f4c66Sjsg {
7808eadc5ecSjsg 	struct psp_softc	*sc;
781*e283d8fbSbluhm 	int			 error;
7820b9f4c66Sjsg 
7838eadc5ecSjsg 	sc = (struct psp_softc *)device_lookup(&psp_cd, minor(dev));
7848eadc5ecSjsg 	if (sc == NULL)
7858eadc5ecSjsg 		return (ENXIO);
7868eadc5ecSjsg 
7878f8d81e9Sbluhm 	KERNEL_UNLOCK();
7888f8d81e9Sbluhm 
7898eadc5ecSjsg 	rw_enter_write(&sc->sc_lock);
7900b9f4c66Sjsg 
7910b9f4c66Sjsg 	switch (cmd) {
792ff28563eSbluhm 	case PSP_IOC_INIT:
793*e283d8fbSbluhm 		error = psp_reinit(sc);
794ff28563eSbluhm 		break;
795b25bc4b2Sbluhm 	case PSP_IOC_SHUTDOWN:
796*e283d8fbSbluhm 		error = psp_shutdown(sc);
797b25bc4b2Sbluhm 		break;
7980b9f4c66Sjsg 	case PSP_IOC_GET_PSTATUS:
799*e283d8fbSbluhm 		error = psp_get_pstatus(sc, (struct psp_platform_status *)data);
8000b9f4c66Sjsg 		break;
8010b9f4c66Sjsg 	case PSP_IOC_DF_FLUSH:
802*e283d8fbSbluhm 		error = psp_df_flush(sc);
8030b9f4c66Sjsg 		break;
8040b9f4c66Sjsg 	case PSP_IOC_DECOMMISSION:
805*e283d8fbSbluhm 		error = psp_decommission(sc, (struct psp_decommission *)data);
8060b9f4c66Sjsg 		break;
8070b9f4c66Sjsg 	case PSP_IOC_GET_GSTATUS:
808*e283d8fbSbluhm 		error = psp_get_gstatus(sc, (struct psp_guest_status *)data);
8090b9f4c66Sjsg 		break;
8100b9f4c66Sjsg 	case PSP_IOC_LAUNCH_START:
811*e283d8fbSbluhm 		error = psp_launch_start(sc, (struct psp_launch_start *)data);
8120b9f4c66Sjsg 		break;
8130b9f4c66Sjsg 	case PSP_IOC_LAUNCH_UPDATE_DATA:
814*e283d8fbSbluhm 		error = psp_launch_update_data(sc,
8150b9f4c66Sjsg 		    (struct psp_launch_update_data *)data, p);
8160b9f4c66Sjsg 		break;
8170b9f4c66Sjsg 	case PSP_IOC_LAUNCH_MEASURE:
818*e283d8fbSbluhm 		error = psp_launch_measure(sc,
819*e283d8fbSbluhm 		    (struct psp_launch_measure *)data);
8200b9f4c66Sjsg 		break;
8210b9f4c66Sjsg 	case PSP_IOC_LAUNCH_FINISH:
822*e283d8fbSbluhm 		error = psp_launch_finish(sc, (struct psp_launch_finish *)data);
8230b9f4c66Sjsg 		break;
8240b9f4c66Sjsg 	case PSP_IOC_ATTESTATION:
825*e283d8fbSbluhm 		error = psp_attestation(sc, (struct psp_attestation *)data);
8260b9f4c66Sjsg 		break;
8270b9f4c66Sjsg 	case PSP_IOC_ACTIVATE:
828*e283d8fbSbluhm 		error = psp_activate(sc, (struct psp_activate *)data);
8290b9f4c66Sjsg 		break;
8300b9f4c66Sjsg 	case PSP_IOC_DEACTIVATE:
831*e283d8fbSbluhm 		error = psp_deactivate(sc, (struct psp_deactivate *)data);
8320b9f4c66Sjsg 		break;
8330b9f4c66Sjsg 	case PSP_IOC_GUEST_SHUTDOWN:
834*e283d8fbSbluhm 		error = psp_guest_shutdown(sc,
835*e283d8fbSbluhm 		    (struct psp_guest_shutdown *)data);
8360b9f4c66Sjsg 		break;
8370b9f4c66Sjsg 	case PSP_IOC_SNP_GET_PSTATUS:
838*e283d8fbSbluhm 		error = psp_snp_get_pstatus(sc,
8398eadc5ecSjsg 		    (struct psp_snp_platform_status *)data);
8400b9f4c66Sjsg 		break;
8410b9f4c66Sjsg 	default:
842*e283d8fbSbluhm 		error = ENOTTY;
8430b9f4c66Sjsg 		break;
8440b9f4c66Sjsg 	}
8450b9f4c66Sjsg 
8468eadc5ecSjsg 	rw_exit_write(&sc->sc_lock);
8470b9f4c66Sjsg 
8488f8d81e9Sbluhm 	KERNEL_LOCK();
8498f8d81e9Sbluhm 
850*e283d8fbSbluhm 	return (error);
8510b9f4c66Sjsg }
8520b9f4c66Sjsg 
8530b9f4c66Sjsg int
8540b9f4c66Sjsg pledge_ioctl_psp(struct proc *p, long com)
8550b9f4c66Sjsg {
8560b9f4c66Sjsg 	switch (com) {
8570b9f4c66Sjsg 	case PSP_IOC_GET_PSTATUS:
8580b9f4c66Sjsg 	case PSP_IOC_DF_FLUSH:
8590b9f4c66Sjsg 	case PSP_IOC_GET_GSTATUS:
8600b9f4c66Sjsg 	case PSP_IOC_LAUNCH_START:
8610b9f4c66Sjsg 	case PSP_IOC_LAUNCH_UPDATE_DATA:
8620b9f4c66Sjsg 	case PSP_IOC_LAUNCH_MEASURE:
8630b9f4c66Sjsg 	case PSP_IOC_LAUNCH_FINISH:
8640b9f4c66Sjsg 	case PSP_IOC_ACTIVATE:
8650b9f4c66Sjsg 	case PSP_IOC_GUEST_SHUTDOWN:
8660b9f4c66Sjsg 		return (0);
8670b9f4c66Sjsg 	default:
8680b9f4c66Sjsg 		return (pledge_fail(p, EPERM, PLEDGE_VMM));
8690b9f4c66Sjsg 	}
8700b9f4c66Sjsg }
8718eadc5ecSjsg 
8728eadc5ecSjsg int
8738eadc5ecSjsg pspprint(void *aux, const char *pnp)
8748eadc5ecSjsg {
8758eadc5ecSjsg 	return QUIET;
8768eadc5ecSjsg }
8778eadc5ecSjsg 
8788eadc5ecSjsg int
8798eadc5ecSjsg pspsubmatch(struct device *parent, void *match, void *aux)
8808eadc5ecSjsg {
8818eadc5ecSjsg 	struct psp_attach_args *arg = aux;
8828eadc5ecSjsg 	struct cfdata *cf = match;
8838eadc5ecSjsg 
8848eadc5ecSjsg 	if (!(arg->capabilities & PSP_CAP_SEV))
8858eadc5ecSjsg 		return (0);
8868eadc5ecSjsg 	return ((*cf->cf_attach->ca_match)(parent, cf, aux));
8878eadc5ecSjsg }
8883c6d599cSbluhm 
8893c6d599cSbluhm struct ucode {
8903c6d599cSbluhm 	uint8_t		 family;
8913c6d599cSbluhm 	uint8_t		 model;
8923c6d599cSbluhm 	const char	*uname;
8933c6d599cSbluhm } const psp_ucode_table[] = {
8943c6d599cSbluhm 	{ 0x17, 0x0, "amdsev/amd_sev_fam17h_model0xh.sbin" },
8953c6d599cSbluhm 	{ 0x17, 0x3, "amdsev/amd_sev_fam17h_model3xh.sbin" },
8963c6d599cSbluhm 	{ 0x19, 0x0, "amdsev/amd_sev_fam19h_model0xh.sbin" },
8973c6d599cSbluhm 	{ 0x19, 0x1, "amdsev/amd_sev_fam19h_model1xh.sbin" },
8983c6d599cSbluhm 	{ 0, 0, NULL }
8993c6d599cSbluhm };
9003c6d599cSbluhm 
901*e283d8fbSbluhm int
9023c6d599cSbluhm psp_load_ucode(struct psp_softc *sc)
9033c6d599cSbluhm {
9043c6d599cSbluhm 	struct psp_downloadfirmware dlfw;
9053c6d599cSbluhm 	struct cpu_info		*ci = &cpu_info_primary;
9063c6d599cSbluhm 	const struct ucode	*uc;
9073c6d599cSbluhm 	uint8_t			 family, model;
9083c6d599cSbluhm 	int			 error;
9093c6d599cSbluhm 
9103c6d599cSbluhm 	if ((sc->sc_flags & PSPF_UCODELOADED) ||
9113c6d599cSbluhm 	    (sc->sc_flags & PSPF_NOUCODE) ||
9123c6d599cSbluhm 	    (sc->sc_flags & PSPF_INITIALIZED))
913*e283d8fbSbluhm 		return (EBUSY);
9143c6d599cSbluhm 
9153c6d599cSbluhm 	family = ci->ci_family;
9163c6d599cSbluhm 	model = (ci->ci_model & 0xf0) >> 4;
9173c6d599cSbluhm 
9183c6d599cSbluhm 	for (uc = psp_ucode_table; uc->uname; uc++) {
9193c6d599cSbluhm 		if ((uc->family == family) && (uc->model == model))
9203c6d599cSbluhm 			break;
9213c6d599cSbluhm 	}
9223c6d599cSbluhm 
9233c6d599cSbluhm 	if (uc->uname == NULL) {
9243c6d599cSbluhm 		printf("%s: no firmware found, CPU family 0x%x model 0x%x\n",
9253c6d599cSbluhm 		    sc->sc_dev.dv_xname, family, model);
9263c6d599cSbluhm 		sc->sc_flags |= PSPF_NOUCODE;
927*e283d8fbSbluhm 		return (EOPNOTSUPP);
9283c6d599cSbluhm 	}
9293c6d599cSbluhm 
9303c6d599cSbluhm 	error = loadfirmware(uc->uname, &sc->sc_ucodebuf, &sc->sc_ucodelen);
9313c6d599cSbluhm 	if (error) {
9323c6d599cSbluhm 		if (error != ENOENT) {
9333c6d599cSbluhm 			printf("%s: error %d, could not read firmware %s\n",
9343c6d599cSbluhm 			    sc->sc_dev.dv_xname, error, uc->uname);
9353c6d599cSbluhm 		}
9363c6d599cSbluhm 		sc->sc_flags |= PSPF_NOUCODE;
937*e283d8fbSbluhm 		return (error);
9383c6d599cSbluhm 	}
9393c6d599cSbluhm 
9403c6d599cSbluhm 	bzero(&dlfw, sizeof(dlfw));
9413c6d599cSbluhm 	dlfw.fw_len = sc->sc_ucodelen;
9423c6d599cSbluhm 	dlfw.fw_paddr = (uint64_t)sc->sc_ucodebuf;
9433c6d599cSbluhm 
944*e283d8fbSbluhm 	if ((error = psp_downloadfirmware(sc, &dlfw)) != 0)
9453c6d599cSbluhm 		goto out;
9463c6d599cSbluhm 
9473c6d599cSbluhm 	sc->sc_flags |= PSPF_UCODELOADED;
9483c6d599cSbluhm out:
9493c6d599cSbluhm 	if (sc->sc_ucodebuf) {
9503c6d599cSbluhm 		free(sc->sc_ucodebuf, M_DEVBUF, sc->sc_ucodelen);
9513c6d599cSbluhm 		sc->sc_ucodebuf = NULL;
9523c6d599cSbluhm 		sc->sc_ucodelen = 0;
9533c6d599cSbluhm 	}
954*e283d8fbSbluhm 
955*e283d8fbSbluhm 	return (error);
9563c6d599cSbluhm }
957