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