From: Mark Kettenis Subject: Re: AMD SEV: ccp(4) diff to support the PSP To: Hans-Jörg Höxer Cc: tech@openbsd.org, mlarkin@nested.page, dlg@openbsd.org Date: Thu, 18 Apr 2024 16:53:45 +0200 > Date: Thu, 18 Apr 2024 14:21:50 +0200 > From: Hans-Jörg Höxer > > Hi, > > I've reworked the support of the AMD Platform Security Processor (PSP) > as part of the ccp(4) driver. It's based on the large diff I sent a > month or so ago. > > The driver provides a set of ioctls that will be needed for eg. vmd(8) > to associated SEV memory encryption with a certain guest and to encrypt > pages for that guest on startup (ie. bsd elf image and initial page > tables, GDT, stack, etc.). > > Things to consider: > > - at least the PSP is somewhat machine depend and specific to amd64 > AMD cpus; nonetheless the ccp(4) driver is also configure for arm64 > GENERIC; so I guess at least the CCP part is also found on arm64 cpus or > devices; so I'm not sure if putting the PSP stuff into ccp(4) make > sense; however both PSP and CCP share the same set of PCI registers Yes. The Opteron A1100 has ccp(4). A bunch of developers have machines with that SoC. Not sure what functionality besides the RNG is implemented on those SoCs. Maybe the PSP bits should be made amd64-specific. > - two ioctl (psp_init() and psp_df_flush()) require wbinvd on all cores > after issuing the command to the PSP (according to PSP API > specification); this is machine dependend; might it make sense to move > the wbinvd to MD part of vmm(4) and provide an ioctl there? so vmd(8) > could first call ioctl of ccp(4) and then the wbinvd via vmm(4) ioctl? > > - the ioctl psp_lauch_update_data() is doing the actual memory encryption > when launching a VM; I put a wbinvd there too; I'm not sure if this > is really needed > > - in psp_lauch_update_data I also wire the pages that will be encrypted > > What do you think? > > Take care, > Hans-Joerg > > ------------------------------------------------------------------------- > > diff --git a/sys/arch/amd64/amd64/conf.c b/sys/arch/amd64/amd64/conf.c > index f87df421880..e8b52718757 100644 > --- a/sys/arch/amd64/amd64/conf.c > +++ b/sys/arch/amd64/amd64/conf.c > @@ -98,6 +98,15 @@ int nblkdev = nitems(bdevsw); > (dev_type_stop((*))) enodev, 0, \ > (dev_type_mmap((*))) enodev, 0, 0, seltrue_kqfilter } > > +/* open, close, ioctl */ > +#define cdev_psp_init(c,n) { \ > + dev_init(c,n,open), dev_init(c,n,close), \ > + (dev_type_read((*))) enodev, \ > + (dev_type_write((*))) enodev, \ > + dev_init(c,n,ioctl), \ > + (dev_type_stop((*))) enodev, 0, \ > + (dev_type_mmap((*))) enodev, 0, 0, seltrue_kqfilter } > + > #define mmread mmrw > #define mmwrite mmrw > cdev_decl(mm); > @@ -152,6 +161,8 @@ cdev_decl(nvram); > cdev_decl(drm); > #include "viocon.h" > cdev_decl(viocon); > +#include "ccp.h" > +cdev_decl(psp); > > #include "wsdisplay.h" > #include "wskbd.h" > @@ -290,6 +301,7 @@ struct cdevsw cdevsw[] = > cdev_fido_init(NFIDO,fido), /* 98: FIDO/U2F security keys */ > cdev_pppx_init(NPPPX,pppac), /* 99: PPP Access Concentrator */ > cdev_ujoy_init(NUJOY,ujoy), /* 100: USB joystick/gamecontroller */ > + cdev_psp_init(NCCP,psp), /* 101: PSP */ > }; > int nchrdev = nitems(cdevsw); > > diff --git a/sys/conf/files b/sys/conf/files > index 93392b22336..b9c997e5f24 100644 > --- a/sys/conf/files > +++ b/sys/conf/files > @@ -467,7 +467,7 @@ file dev/usb/xhci.c xhci needs-flag > > # AMD Cryptographic Co-processor > device ccp > -file dev/ic/ccp.c ccp > +file dev/ic/ccp.c ccp needs-flag > > # SDHC SD/MMC controller > define sdhc > diff --git a/sys/dev/ic/ccp.c b/sys/dev/ic/ccp.c > index 5a04b73938f..0acec20133b 100644 > --- a/sys/dev/ic/ccp.c > +++ b/sys/dev/ic/ccp.c > @@ -2,6 +2,7 @@ > > /* > * Copyright (c) 2018 David Gwynne > + * Copyright (c) 2023, 2024 Hans-Joerg Hoexer > * > * Permission to use, copy, modify, and distribute this software for any > * purpose with or without fee is hereby granted, provided that the above > @@ -23,9 +24,14 @@ > #include > #include > #include > +#include > + > +#include > > #include > > +#include > + > #include > > #define CCP_REG_TRNG 0xc > @@ -38,13 +44,18 @@ struct cfdriver ccp_cd = { > DV_DULL > }; > > +struct ccp_softc *ccp_softc; > + > +int psp_get_pstatus(struct psp_platform_status *); > +int psp_init(struct psp_init *); > + > void > ccp_attach(struct ccp_softc *sc) > { > timeout_set(&sc->sc_tick, ccp_rng, sc); > ccp_rng(sc); > > - printf("\n"); > + printf(", RNG"); > } > > static void > @@ -59,3 +70,587 @@ ccp_rng(void *arg) > > timeout_add_msec(&sc->sc_tick, 100); > } > + > +int > +psp_sev_intr(struct ccp_softc *sc, uint32_t status) > +{ > + if (!(status & PSP_CMDRESP_COMPLETE)) > + return (0); > + > + wakeup(sc); > + > + return (1); > +} > + > +int > +psp_attach(struct ccp_softc *sc) > +{ > + struct psp_platform_status pst; > + struct psp_init init; > + size_t size; > + int nsegs; > + > + if (!(sc->sc_capabilities & PSP_CAP_SEV)) > + return (0); > + > + rw_init(&sc->sc_lock, "ccp_lock"); > + > + /* create and map SEV command buffer */ > + sc->sc_cmd_size = size = PAGE_SIZE; > + if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, > + BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW | BUS_DMA_64BIT, > + &sc->sc_cmd_map) != 0) > + return (0); > + > + if (bus_dmamem_alloc(sc->sc_dmat, size, 0, 0, &sc->sc_cmd_seg, 1, > + &nsegs, BUS_DMA_WAITOK | BUS_DMA_ZERO) != 0) > + goto fail_0; > + > + if (bus_dmamem_map(sc->sc_dmat, &sc->sc_cmd_seg, nsegs, size, > + &sc->sc_cmd_kva, BUS_DMA_WAITOK) != 0) > + goto fail_1; > + > + if (bus_dmamap_load(sc->sc_dmat, sc->sc_cmd_map, sc->sc_cmd_kva, > + size, NULL, BUS_DMA_WAITOK) != 0) > + goto fail_2; > + > + sc->sc_sev_intr = psp_sev_intr; > + ccp_softc = sc; > + > + if (psp_get_pstatus(&pst) || pst.state != 0) > + goto fail_3; > + > + printf(", SEV"); > + > + /* > + * create and map Trusted Memory Region (TMR); size 1 Mbyte, > + * needs to be aligend to 1 Mbyte. > + */ > + sc->sc_tmr_size = size = PSP_TMR_SIZE; > + if (bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, > + BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW | BUS_DMA_64BIT, > + &sc->sc_tmr_map) != 0) > + goto fail_3; > + > + if (bus_dmamem_alloc(sc->sc_dmat, size, size, 0, &sc->sc_tmr_seg, 1, > + &nsegs, BUS_DMA_WAITOK | BUS_DMA_ZERO) != 0) > + goto fail_4; > + > + if (bus_dmamem_map(sc->sc_dmat, &sc->sc_tmr_seg, nsegs, size, > + &sc->sc_tmr_kva, BUS_DMA_WAITOK) != 0) > + goto fail_5; > + > + if (bus_dmamap_load(sc->sc_dmat, sc->sc_tmr_map, sc->sc_tmr_kva, > + size, NULL, BUS_DMA_WAITOK) != 0) > + goto fail_6; > + > + memset(&init, 0, sizeof(init)); > + init.enable_es = 1; > + init.tmr_length = PSP_TMR_SIZE; > + init.tmr_paddr = sc->sc_tmr_map->dm_segs[0].ds_addr; > + if (psp_init(&init)) > + goto fail_7; > + > + psp_get_pstatus(&pst); > + if ((pst.state == 1) && (pst.cfges_build & 0x1)) > + printf(", SEV-ES"); > + > + return (1); > + > +fail_7: > + bus_dmamap_unload(sc->sc_dmat, sc->sc_tmr_map); > +fail_6: > + bus_dmamem_unmap(sc->sc_dmat, sc->sc_tmr_kva, size); > +fail_5: > + bus_dmamem_free(sc->sc_dmat, &sc->sc_tmr_seg, 1); > +fail_4: > + bus_dmamap_destroy(sc->sc_dmat, sc->sc_tmr_map); > +fail_3: > + bus_dmamap_unload(sc->sc_dmat, sc->sc_cmd_map); > +fail_2: > + bus_dmamem_unmap(sc->sc_dmat, sc->sc_cmd_kva, size); > +fail_1: > + bus_dmamem_free(sc->sc_dmat, &sc->sc_cmd_seg, 1); > +fail_0: > + bus_dmamap_destroy(sc->sc_dmat, sc->sc_cmd_map); > + > + ccp_softc = NULL; > + > + return (0); > +} > + > +static int > +ccp_wait(struct ccp_softc *sc, uint32_t *status, int poll) > +{ > + uint32_t cmdword; > + int count; > + > + if (poll) { > + count = 0; > + while (count++ < 10) { > + cmdword = bus_space_read_4(sc->sc_iot, sc->sc_ioh, > + PSP_REG_CMDRESP); > + if (cmdword & PSP_CMDRESP_RESPONSE) > + goto done; > + delay(5000); > + } > + > + /* timeout */ > + return (1); > + } > + > + if (tsleep_nsec(sc, PWAIT, "psp", SEC_TO_NSEC(1)) == EWOULDBLOCK) > + return (1); > + > +done: > + if (status) { > + *status = bus_space_read_4(sc->sc_iot, sc->sc_ioh, > + PSP_REG_CMDRESP); > + } > + > + return (0); > +} > + > +static int > +ccp_docmd(struct ccp_softc *sc, int cmd, uint64_t paddr) > +{ > + uint32_t plo, phi, cmdword, status; > + > + plo = ((paddr >> 0) & 0xffffffff); > + phi = ((paddr >> 32) & 0xffffffff); > + cmdword = (cmd & 0x3f) << 16; > + if (!cold) > + cmdword |= PSP_CMDRESP_IOC; > + > + bus_space_write_4(sc->sc_iot, sc->sc_ioh, PSP_REG_ADDRLO, plo); > + bus_space_write_4(sc->sc_iot, sc->sc_ioh, PSP_REG_ADDRHI, phi); > + bus_space_write_4(sc->sc_iot, sc->sc_ioh, PSP_REG_CMDRESP, cmdword); > + > + if (ccp_wait(sc, &status, cold)) > + return (1); > + > + /* Did PSP sent a response code? */ > + if (status & PSP_CMDRESP_RESPONSE) { > + if ((status & PSP_STATUS_MASK) != PSP_STATUS_SUCCESS) { > + printf("%s: command failed: 0x%x\n", __func__, > + (status & PSP_STATUS_MASK)); > + return (1); > + } > + } > + > + return (0); > +} > + > +int > +psp_init(struct psp_init *uinit) > +{ > + struct ccp_softc *sc = ccp_softc; > + struct psp_init *init; > + int ret; > + > + init = (struct psp_init *)sc->sc_cmd_kva; > + bzero(init, sizeof(*init)); > + > + init->enable_es = uinit->enable_es; > + init->tmr_paddr = uinit->tmr_paddr; > + init->tmr_length = uinit->tmr_length; > + > + ret = ccp_docmd(sc, PSP_CMD_INIT, sc->sc_cmd_map->dm_segs[0].ds_addr); > + > +#ifdef __amd64__ > + wbinvd_on_all_cpus(); > +#endif > + > + if (ret != 0) > + return (EIO); > + > + return (0); > +} > + > +int > +psp_get_pstatus(struct psp_platform_status *ustatus) > +{ > + struct ccp_softc *sc = ccp_softc; > + struct psp_platform_status *status; > + int ret; > + > + status = (struct psp_platform_status *)sc->sc_cmd_kva; > + bzero(status, sizeof(*status)); > + > + ret = ccp_docmd(sc, PSP_CMD_PLATFORMSTATUS, > + sc->sc_cmd_map->dm_segs[0].ds_addr); > + > + if (ret != 0) > + return (EIO); > + > + bcopy(status, ustatus, sizeof(*ustatus)); > + > + return (0); > +} > + > +int > +psp_df_flush(void) > +{ > + struct ccp_softc *sc = ccp_softc; > + int ret; > + > +#ifdef __amd64__ > + wbinvd_on_all_cpus(); > +#endif > + > + ret = ccp_docmd(sc, PSP_CMD_DF_FLUSH, 0x0); > + > + if (ret != 0) > + return (EIO); > + > + return (0); > +} > + > +int > +psp_decommission(struct psp_decommission *udecom) > +{ > + struct ccp_softc *sc = ccp_softc; > + struct psp_decommission *decom; > + int ret; > + > + decom = (struct psp_decommission *)sc->sc_cmd_kva; > + bzero(decom, sizeof(*decom)); > + > + decom->handle = udecom->handle; > + > + ret = ccp_docmd(sc, PSP_CMD_DECOMMISSION, > + sc->sc_cmd_map->dm_segs[0].ds_addr); > + > + if (ret != 0) > + return (EIO); > + > + return (0); > +} > + > +int > +psp_get_gstatus(struct psp_guest_status *ustatus) > +{ > + struct ccp_softc *sc = ccp_softc; > + struct psp_guest_status *status; > + int ret; > + > + status = (struct psp_guest_status *)sc->sc_cmd_kva; > + bzero(status, sizeof(*status)); > + > + status->handle = ustatus->handle; > + > + ret = ccp_docmd(sc, PSP_CMD_GUESTSTATUS, > + sc->sc_cmd_map->dm_segs[0].ds_addr); > + > + if (ret != 0) > + return (EIO); > + > + ustatus->policy = status->policy; > + ustatus->asid = status->asid; > + ustatus->state = status->state; > + > + return (0); > +} > + > +int > +psp_launch_start(struct psp_launch_start *ustart) > +{ > + struct ccp_softc *sc = ccp_softc; > + struct psp_launch_start *start; > + int ret; > + > + start = (struct psp_launch_start *)sc->sc_cmd_kva; > + bzero(start, sizeof(*start)); > + > + start->handle = ustart->handle; > + start->policy = ustart->policy; > + > + ret = ccp_docmd(sc, PSP_CMD_LAUNCH_START, > + sc->sc_cmd_map->dm_segs[0].ds_addr); > + > + if (ret != 0) > + return (EIO); > + > + /* If requested, return new handle. */ > + if (ustart->handle == 0) > + ustart->handle = start->handle; > + > + return (0); > +} > + > +int > +psp_launch_update_data(struct psp_launch_update_data *ulud, struct proc *p) > +{ > + struct ccp_softc *sc = ccp_softc; > + struct psp_launch_update_data *ludata; > + pmap_t pmap; > + vaddr_t v, next, end; > + size_t size, len, off; > + int ret; > + > + /* Ensure AES_XTS_BLOCKSIZE alignment and multiplicity. */ > + if ((ulud->paddr & (AES_XTS_BLOCKSIZE - 1)) != 0 || > + (ulud->length % AES_XTS_BLOCKSIZE) != 0) > + return (EINVAL); > + > + ludata = (struct psp_launch_update_data *)sc->sc_cmd_kva; > + bzero(ludata, sizeof(*ludata)); > + > + ludata->handle = ulud->handle; > + > +#ifdef __amd64__ > + /* Drain caches before we encrypt memory. */ > + wbinvd_on_all_cpus(); > +#endif > + > + /* > + * Launch update one physical page at a time. We could > + * optimise this for contiguous pages of physical memory. > + * > + * vmd(8) provides the guest physical address, thus convert > + * to system physical address. > + */ > + pmap = vm_map_pmap(&p->p_vmspace->vm_map); > + size = ulud->length; > + end = ulud->paddr + ulud->length; > + for (v = ulud->paddr; v < end; v = next) { > + off = v & PAGE_MASK; > + > + len = MIN(PAGE_SIZE - off, size); > + > + /* Wire mapping. */ > + if (uvm_map_pageable(&p->p_vmspace->vm_map, v, v+len, FALSE, 0)) > + return (EINVAL); > + if (!pmap_extract(pmap, v, (paddr_t *)&ludata->paddr)) > + return (EINVAL); > + ludata->length = len; > + > + ret = ccp_docmd(sc, PSP_CMD_LAUNCH_UPDATE_DATA, > + sc->sc_cmd_map->dm_segs[0].ds_addr); > + > + if (ret != 0) > + return (EIO); > + > + size -= len; > + next = v + len; > + } > + > + return (0); > +} > + > +int > +psp_launch_measure(struct psp_launch_measure *ulm) > +{ > + struct psp_launch_measure *lm; > + struct ccp_softc *sc = ccp_softc; > + int ret; > + uint64_t paddr; > + > + if (ulm->measure_len != sizeof(ulm->psp_measure)) > + return (EINVAL); > + > + lm = (struct psp_launch_measure *)sc->sc_cmd_kva; > + bzero(lm, sizeof(*lm)); > + > + lm->handle = ulm->handle; > + paddr = sc->sc_cmd_map->dm_segs[0].ds_addr; > + lm->measure_paddr = > + paddr + offsetof(struct psp_launch_measure, psp_measure); > + lm->measure_len = sizeof(lm->psp_measure); > + > + ret = ccp_docmd(sc, PSP_CMD_LAUNCH_MEASURE, paddr); > + > + if (ret != 0 || lm->measure_len != ulm->measure_len) > + return (EIO); > + > + bcopy(&lm->psp_measure, &ulm->psp_measure, ulm->measure_len); > + > + return (0); > +} > + > +int > +psp_launch_finish(struct psp_launch_finish *ulf) > +{ > + struct ccp_softc *sc = ccp_softc; > + struct psp_launch_finish *lf; > + int ret; > + > + lf = (struct psp_launch_finish *)sc->sc_cmd_kva; > + bzero(lf, sizeof(*lf)); > + > + lf->handle = ulf->handle; > + > + ret = ccp_docmd(sc, PSP_CMD_LAUNCH_FINISH, > + sc->sc_cmd_map->dm_segs[0].ds_addr); > + > + if (ret != 0) > + return (EIO); > + > + return (0); > +} > + > +int > +psp_attestation(struct psp_attestation *uat) > +{ > + struct ccp_softc *sc = ccp_softc; > + struct psp_attestation *at; > + int ret; > + uint64_t paddr; > + > + if (uat->attest_len != sizeof(uat->psp_report)) > + return (EINVAL); > + > + at = (struct psp_attestation *)sc->sc_cmd_kva; > + bzero(at, sizeof(*at)); > + > + at->handle = uat->handle; > + paddr = sc->sc_cmd_map->dm_segs[0].ds_addr; > + at->attest_paddr = > + paddr + offsetof(struct psp_attestation, psp_report); > + bcopy(uat->attest_nonce, at->attest_nonce, sizeof(at->attest_nonce)); > + at->attest_len = sizeof(at->psp_report); > + > + ret = ccp_docmd(sc, PSP_CMD_ATTESTATION, paddr); > + > + if (ret != 0 || at->attest_len != uat->attest_len) > + return (EIO); > + > + bcopy(&at->psp_report, &uat->psp_report, uat->attest_len); > + > + return (0); > +} > + > +int > +psp_activate(struct psp_activate *uact) > +{ > + struct ccp_softc *sc = ccp_softc; > + struct psp_activate *act; > + int ret; > + > + act = (struct psp_activate *)sc->sc_cmd_kva; > + bzero(act, sizeof(*act)); > + > + act->handle = uact->handle; > + act->asid = uact->asid; > + > + ret = ccp_docmd(sc, PSP_CMD_ACTIVATE, > + sc->sc_cmd_map->dm_segs[0].ds_addr); > + > + if (ret != 0) > + return (EIO); > + > + return (0); > +} > + > +int > +psp_deactivate(struct psp_deactivate *udeact) > +{ > + struct ccp_softc *sc = ccp_softc; > + struct psp_deactivate *deact; > + int ret; > + > + deact = (struct psp_deactivate *)sc->sc_cmd_kva; > + bzero(deact, sizeof(*deact)); > + > + deact->handle = udeact->handle; > + > + ret = ccp_docmd(sc, PSP_CMD_DEACTIVATE, > + sc->sc_cmd_map->dm_segs[0].ds_addr); > + > + if (ret != 0) > + return (EIO); > + > + return (0); > +} > + > +int > +psp_snp_get_pstatus(struct psp_snp_platform_status *ustatus) > +{ > + struct ccp_softc *sc = ccp_softc; > + struct psp_snp_platform_status *status; > + int ret; > + > + status = (struct psp_snp_platform_status *)sc->sc_cmd_kva; > + bzero(status, sizeof(*status)); > + > + ret = ccp_docmd(sc, PSP_CMD_SNP_PLATFORMSTATUS, > + sc->sc_cmd_map->dm_segs[0].ds_addr); > + > + if (ret != 0) > + return (EIO); > + > + bcopy(status, ustatus, sizeof(*ustatus)); > + > + return (0); > +} > + > +int > +pspopen(dev_t dev, int flag, int mode, struct proc *p) > +{ > + if (ccp_softc == NULL) > + return (ENODEV); > + > + return (0); > +} > + > +int > +pspclose(dev_t dev, int flag, int mode, struct proc *p) > +{ > + return (0); > +} > + > +int > +pspioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) > +{ > + int ret; > + > + rw_enter_write(&ccp_softc->sc_lock); > + > + switch (cmd) { > + case PSP_IOC_GET_PSTATUS: > + ret = psp_get_pstatus((struct psp_platform_status *)data); > + break; > + case PSP_IOC_DF_FLUSH: > + ret = psp_df_flush(); > + break; > + case PSP_IOC_DECOMMISSION: > + ret = psp_decommission((struct psp_decommission *)data); > + break; > + case PSP_IOC_GET_GSTATUS: > + ret = psp_get_gstatus((struct psp_guest_status *)data); > + break; > + case PSP_IOC_LAUNCH_START: > + ret = psp_launch_start((struct psp_launch_start *)data); > + break; > + case PSP_IOC_LAUNCH_UPDATE_DATA: > + ret = psp_launch_update_data( > + (struct psp_launch_update_data *)data, p); > + break; > + case PSP_IOC_LAUNCH_MEASURE: > + ret = psp_launch_measure((struct psp_launch_measure *)data); > + break; > + case PSP_IOC_LAUNCH_FINISH: > + ret = psp_launch_finish((struct psp_launch_finish *)data); > + break; > + case PSP_IOC_ATTESTATION: > + ret = psp_attestation((struct psp_attestation *)data); > + break; > + case PSP_IOC_ACTIVATE: > + ret = psp_activate((struct psp_activate *)data); > + break; > + case PSP_IOC_DEACTIVATE: > + ret = psp_deactivate((struct psp_deactivate *)data); > + break; > + case PSP_IOC_SNP_GET_PSTATUS: > + ret = > + psp_snp_get_pstatus((struct psp_snp_platform_status *)data); > + break; > + default: > + printf("%s: unkown ioctl code 0x%lx\n", __func__, cmd); > + ret = ENOTTY; > + } > + > + rw_exit_write(&ccp_softc->sc_lock); > + > + return (ret); > +} > diff --git a/sys/dev/ic/ccpvar.h b/sys/dev/ic/ccpvar.h > index 237a5d45f5e..6688f4ef2f8 100644 > --- a/sys/dev/ic/ccpvar.h > +++ b/sys/dev/ic/ccpvar.h > @@ -2,6 +2,7 @@ > > /* > * Copyright (c) 2018 David Gwynne > + * Copyright (c) 2023, 2024 Hans-Joerg Hoexer > * > * Permission to use, copy, modify, and distribute this software for any > * purpose with or without fee is hereby granted, provided that the above > @@ -17,13 +18,263 @@ > */ > > #include > +#include > +#include > + > +/* AMD 17h */ > +#define PSP_REG_INTEN 0x10690 > +#define PSP_REG_INTSTS 0x10694 > +#define PSP_REG_CMDRESP 0x10980 > +#define PSP_REG_ADDRLO 0x109e0 > +#define PSP_REG_ADDRHI 0x109e4 > +#define PSP_REG_CAPABILITIES 0x109fc > + > +#define PSP_PSTATE_UNINIT 0x0 > +#define PSP_PSTATE_INIT 0x1 > +#define PSP_PSTATE_WORKING 0x2 > + > +#define PSP_GSTATE_UNINIT 0x0 > +#define PSP_GSTATE_LUPDATE 0x1 > +#define PSP_GSTATE_LSECRET 0x2 > +#define PSP_GSTATE_RUNNING 0x3 > +#define PSP_GSTATE_SUPDATE 0x4 > +#define PSP_GSTATE_RUPDATE 0x5 > +#define PSP_GSTATE_SENT 0x6 > + > +#define PSP_CAP_SEV (1 << 0) > +#define PSP_CAP_TEE (1 << 1) > +#define PSP_CAP_DBC_THRU_EXT (1 << 2) > +#define PSP_CAP_SECURITY_REPORTING (1 << 7) > +#define PSP_CAP_SECURITY_FUSED_PART (1 << 8) > +#define PSP_CAP_SECURITY_DEBUG_LOCK_ON (1 << 10) > +#define PSP_CAP_SECURITY_TSME_STATUS (1 << 13) > +#define PSP_CAP_SECURITY_ANTI_ROLLBACK_STATUS (1 << 15) > +#define PSP_CAP_SECURITY_RPMC_PRODUCTION_ENABLED (1 << 16) > +#define PSP_CAP_SECURITY_RPMC_SPIROM_AVAILABLE (1 << 17) > +#define PSP_CAP_SECURITY_HSP_TPM_AVAILABLE (1 << 18) > +#define PSP_CAP_SECURITY_ROM_ARMOR_ENFORCED (1 << 19) > + > +#define PSP_CAP_BITS "\20\001SEV\002TEE\003DBC_THRU_EXT\010REPORTING\011FUSED_PART\013DEBUG_LOCK_ON\016TSME_STATUS\020ANTI_ROLLBACK_STATUS\021RPMC_PRODUCTION_ENABLED\022RPMC_SPIROM_AVAILABLE\023HSP_TPM_AVAILABLE\024ROM_ARMOR_ENFORCED" > + > +#define PSP_CMDRESP_IOC (1 << 0) > +#define PSP_CMDRESP_COMPLETE (1 << 1) > +#define PSP_CMDRESP_RESPONSE (1 << 31) > + > +#define PSP_STATUS_MASK 0xffff > +#define PSP_STATUS_SUCCESS 0x0000 > +#define PSP_STATUS_INVALID_PLATFORM_STATE 0x0001 > > struct ccp_softc { > struct device sc_dev; > bus_space_tag_t sc_iot; > bus_space_handle_t sc_ioh; > + bus_size_t sc_size; > + bus_dma_tag_t sc_dmat; > + void * sc_ih; > + > + uint32_t sc_capabilities; > + int (*sc_sev_intr)(struct ccp_softc *, uint32_t); > + > + bus_dmamap_t sc_cmd_map; > + bus_dma_segment_t sc_cmd_seg; > + size_t sc_cmd_size; > + caddr_t sc_cmd_kva; > + > + bus_dmamap_t sc_tmr_map; > + bus_dma_segment_t sc_tmr_seg; > + size_t sc_tmr_size; > + caddr_t sc_tmr_kva; > > struct timeout sc_tick; > + > + struct rwlock sc_lock; > }; > > +#define PSP_TMR_SIZE (1024*1024) /* 1 Mb */ > + > +#define PSP_SUCCESS 0x0000 > +#define PSP_INVALID_ADDRESS 0x0009 > + > +/* Selection of PSP commands of the SEV API Version 0.24 */ > + > +#define PSP_CMD_INIT 0x1 > +#define PSP_CMD_PLATFORMSTATUS 0x4 > +#define PSP_CMD_DF_FLUSH 0xa > +#define PSP_CMD_DECOMMISSION 0x20 > +#define PSP_CMD_ACTIVATE 0x21 > +#define PSP_CMD_DEACTIVATE 0x22 > +#define PSP_CMD_GUESTSTATUS 0x23 > +#define PSP_CMD_LAUNCH_START 0x30 > +#define PSP_CMD_LAUNCH_UPDATE_DATA 0x31 > +#define PSP_CMD_LAUNCH_MEASURE 0x33 > +#define PSP_CMD_LAUNCH_FINISH 0x35 > +#define PSP_CMD_ATTESTATION 0x36 > + > +struct psp_platform_status { > + /* Output parameters from PSP_CMD_PLATFORMSTATUS */ > + uint8_t api_major; > + uint8_t api_minor; > + uint8_t state; > + uint8_t owner; > + uint32_t cfges_build; > + uint32_t guest_count; > +} __packed; > + > +struct psp_guest_status { > + /* Input parameter for PSP_CMD_GUESTSTATUS */ > + uint32_t handle; > + > + /* Output parameters from PSP_CMD_GUESTSTATUS */ > + uint32_t policy; > + uint32_t asid; > + uint8_t state; > +} __packed; > + > +struct psp_launch_start { > + /* Input/Output parameter for PSP_CMD_LAUNCH_START */ > + uint32_t handle; > + > + /* Input parameters for PSP_CMD_LAUNCH_START */ > + uint32_t policy; > + > + /* The following input parameters are not used yet */ > + uint64_t dh_cert_paddr; > + uint32_t dh_cert_len; > + uint32_t reserved; > + uint64_t session_paddr; > + uint32_t session_len; > +} __packed; > + > +struct psp_launch_update_data { > + /* Input parameters for PSP_CMD_LAUNCH_UPDATE_DATA */ > + uint32_t handle; > + uint32_t reserved; > + uint64_t paddr; > + uint32_t length; > +} __packed; > + > +struct psp_measure { > + /* Output buffer for PSP_CMD_LAUNCH_MEASURE */ > + uint8_t measure[32]; > + uint8_t measure_nonce[16]; > +} __packed; > + > +struct psp_launch_measure { > + /* Input parameters for PSP_CMD_LAUNCH_MEASURE */ > + uint32_t handle; > + uint32_t reserved; > + uint64_t measure_paddr; > + > + /* Input/output parameter for PSP_CMD_LAUNCH_MEASURE */ > + uint32_t measure_len; > + uint32_t padding; > + > + /* Output buffer from PSP_CMD_LAUNCH_MEASURE */ > + struct psp_measure psp_measure; /* 64bit aligned */ > +#define measure psp_measure.measure > +#define measure_nonce psp_measure.measure_nonce > +} __packed; > + > +struct psp_launch_finish { > + /* Input parameter for PSP_CMD_LAUNCH_FINISH */ > + uint32_t handle; > +} __packed; > + > +struct psp_report { > + /* Output buffer for PSP_CMD_ATTESTATION */ > + uint8_t report_nonce[16]; > + uint8_t report_launch_digest[32]; > + uint32_t report_policy; > + uint32_t report_sig_usage; > + uint32_t report_sig_algo; > + uint32_t reserved2; > + uint8_t report_sig1[144]; > +} __packed; > + > +struct psp_attestation { > + /* Input parameters for PSP_CMD_ATTESTATION */ > + uint32_t handle; > + uint32_t reserved; > + uint64_t attest_paddr; > + uint8_t attest_nonce[16]; > + > + /* Input/output parameter from PSP_CMD_ATTESTATION */ > + uint32_t attest_len; > + uint32_t padding; > + > + /* Output parameter from PSP_CMD_ATTESTATION */ > + struct psp_report psp_report; /* 64bit aligned */ > +#define report_nonce psp_report.report_nonce > +#define report_launch_digest psp_report.report_launch_digest > +#define report_policy psp_report.report_policy > +#define report_sig_usage psp_report.report_sig_usage; > +#define report_report_sig_alg psp_report.report_sig_algo; > +#define report_report_sig1 psp_report.report_sig1; > +} __packed; > + > +struct psp_activate { > + /* Input parameters for PSP_CMD_ACTIVATE */ > + uint32_t handle; > + uint32_t asid; > +} __packed; > + > +struct psp_deactivate { > + /* Input parameter for PSP_CMD_DEACTIVATE */ > + uint32_t handle; > +} __packed; > + > +struct psp_decommission { > + /* Input parameter for PSP_CMD_DECOMMISSION */ > + uint32_t handle; > +} __packed; > + > +struct psp_init { > + /* Output parameters from PSP_CMD_INIT */ > + uint32_t enable_es; > + uint32_t reserved; > + uint64_t tmr_paddr; > + uint32_t tmr_length; > +} __packed; > + > + > +/* Selection of PSP commands of the SEV-SNP ABI Version 1.55 */ > + > +#define PSP_CMD_SNP_PLATFORMSTATUS 0x81 > + > +struct psp_snp_platform_status { > + uint8_t api_major; > + uint8_t api_minor; > + uint8_t state; > + uint8_t is_rmp_init; > + uint32_t build; > + uint32_t features; > + uint32_t guest_count; > + uint64_t current_tcb; > + uint64_t reported_tcb; > +} __packed; > + > +#define PSP_IOC_GET_PSTATUS _IOR('P', 0, struct psp_platform_status) > +#define PSP_IOC_DF_FLUSH _IO('P', 1) > +#define PSP_IOC_DECOMMISSION _IOW('P', 2, struct psp_decommission) > +#define PSP_IOC_GET_GSTATUS _IOWR('P', 3, struct psp_guest_status) > +#define PSP_IOC_LAUNCH_START _IOWR('P', 4, struct psp_launch_start) > +#define PSP_IOC_LAUNCH_UPDATE_DATA \ > + _IOW('P', 5, struct psp_launch_update_data) > +#define PSP_IOC_LAUNCH_MEASURE _IOWR('P', 6, struct psp_launch_measure) > +#define PSP_IOC_LAUNCH_FINISH _IOW('P', 7, struct psp_launch_finish) > +#define PSP_IOC_ATTESTATION _IOWR('P', 8, struct psp_attestation) > +#define PSP_IOC_ACTIVATE _IOW('P', 9, struct psp_activate) > +#define PSP_IOC_DEACTIVATE _IOW('P', 10, struct psp_deactivate) > +#define PSP_IOC_SNP_GET_PSTATUS _IOR('P', 11, struct psp_snp_platform_status) > + > +#ifdef _KERNEL > + > void ccp_attach(struct ccp_softc *); > + > +int psp_attach(struct ccp_softc *); > + > +int pspclose(dev_t, int, int, struct proc *); > +int pspopen(dev_t, int, int, struct proc *); > +int pspioctl(dev_t, u_long, caddr_t, int, struct proc *); > + > +#endif /* _KERNEL */ > diff --git a/sys/dev/pci/ccp_pci.c b/sys/dev/pci/ccp_pci.c > index 18407281d6c..07799281a92 100644 > --- a/sys/dev/pci/ccp_pci.c > +++ b/sys/dev/pci/ccp_pci.c > @@ -36,6 +36,8 @@ > int ccp_pci_match(struct device *, void *, void *); > void ccp_pci_attach(struct device *, struct device *, void *); > > +int ccp_pci_intr(void *); > + > const struct cfattach ccp_pci_ca = { > sizeof(struct ccp_softc), > ccp_pci_match, > @@ -64,6 +66,10 @@ ccp_pci_attach(struct device *parent, struct device *self, void *aux) > struct ccp_softc *sc = (struct ccp_softc *)self; > struct pci_attach_args *pa = aux; > pcireg_t memtype; > + pci_intr_handle_t ih; > + const char *intrstr = NULL; > + > + sc->sc_dmat = pa->pa_dmat; > > memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, CCP_PCI_BAR); > if (PCI_MAPREG_TYPE(memtype) != PCI_MAPREG_TYPE_MEM) { > @@ -72,10 +78,55 @@ ccp_pci_attach(struct device *parent, struct device *self, void *aux) > } > > if (pci_mapreg_map(pa, CCP_PCI_BAR, memtype, 0, > - &sc->sc_iot, &sc->sc_ioh, NULL, NULL, 0) != 0) { > + &sc->sc_iot, &sc->sc_ioh, NULL, &sc->sc_size, 0) != 0) { > printf(": cannot map registers\n"); > return; > } > > + sc->sc_capabilities = bus_space_read_4(sc->sc_iot, sc->sc_ioh, > + PSP_REG_CAPABILITIES); > + > + /* clear and disable interrupts */ > + bus_space_write_4(sc->sc_iot, sc->sc_ioh, PSP_REG_INTEN, 0); > + bus_space_write_4(sc->sc_iot, sc->sc_ioh, PSP_REG_INTSTS, -1); > + > + if (pci_intr_map_msix(pa, 0, &ih) != 0 && > + pci_intr_map_msi(pa, &ih) != 0 && pci_intr_map(pa, &ih) != 0) { > + printf(": couldn't map interrupt\n"); > + goto unmap_ret; > + } > + > + intrstr = pci_intr_string(pa->pa_pc, ih); > + sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO, ccp_pci_intr, > + sc, sc->sc_dev.dv_xname); > + if (sc->sc_ih != NULL) > + printf(": %s", intrstr); > + > ccp_attach(sc); > + if (psp_attach(sc)) { > + /* enable interrupts */ > + bus_space_write_4(sc->sc_iot, sc->sc_ioh, PSP_REG_INTEN, -1); > + } > + > + printf ("\n"); > + > + return; > + > +unmap_ret: > + bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_size); > +} > + > +int > +ccp_pci_intr(void *arg) > +{ > + struct ccp_softc *sc = arg; > + uint32_t status; > + > + status = bus_space_read_4(sc->sc_iot, sc->sc_ioh, PSP_REG_INTSTS); > + bus_space_write_4(sc->sc_iot, sc->sc_ioh, PSP_REG_INTSTS, status); > + > + if (sc->sc_sev_intr) > + return (sc->sc_sev_intr(sc, status)); > + > + return (1); > } > diff --git a/sys/kern/kern_pledge.c b/sys/kern/kern_pledge.c > index dce4d91ccf9..a2dd5ba6c15 100644 > --- a/sys/kern/kern_pledge.c > +++ b/sys/kern/kern_pledge.c > @@ -76,6 +76,7 @@ > #if NVMM > 0 > #include > #endif > +#include "ccp.h" > #endif > > #include "drm.h" > @@ -1348,6 +1349,20 @@ pledge_ioctl(struct proc *p, long com, struct file *fp) > } > #endif > > +#if NCCP > 0 > +#if NVMM > 0 > + if ((pledge & PLEDGE_VMM)) { > + extern int pspopen(dev_t, int, int, struct proc *); > + > + if ((fp->f_type == DTYPE_VNODE) && > + (vp->v_type == VCHR) && > + (cdevsw[major(vp->v_rdev)].d_open == pspopen)) { > + return (0); > + } > + } > +#endif > +#endif > + > return pledge_fail(p, error, PLEDGE_TTY); > } > > > [1/2:application/pgp-signature Show Save:signature.asc (833B)] > > > [2:application/pkcs7-signature Show Save:smime.p7s (5kB)] >