Download raw body.
AMD SEV: ccp(4) diff to support the PSP
> Date: Thu, 18 Apr 2024 14:21:50 +0200
> From: Hans-Jörg Höxer <Hans-Joerg_Hoexer@genua.de>
>
> 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 <dlg@openbsd.org>
> + * Copyright (c) 2023, 2024 Hans-Joerg Hoexer <hshoexer@genua.de>
> *
> * 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 <sys/malloc.h>
> #include <sys/kernel.h>
> #include <sys/timeout.h>
> +#include <sys/proc.h>
> +
> +#include <uvm/uvm.h>
>
> #include <machine/bus.h>
>
> +#include <crypto/xform.h>
> +
> #include <dev/ic/ccpvar.h>
>
> #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 <dlg@openbsd.org>
> + * Copyright (c) 2023, 2024 Hans-Joerg Hoexer <hshoexer@genua.de>
> *
> * 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 <sys/timeout.h>
> +#include <sys/ioctl.h>
> +#include <sys/rwlock.h>
> +
> +/* 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 <machine/conf.h>
> #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)]
>
AMD SEV: ccp(4) diff to support the PSP