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