Add support for the AMD Platform Security Processor (PSP) to ccp(4).
authorbluhm <bluhm@openbsd.org>
Wed, 12 Jun 2024 12:54:54 +0000 (12:54 +0000)
committerbluhm <bluhm@openbsd.org>
Wed, 12 Jun 2024 12:54:54 +0000 (12:54 +0000)
Several commands for basic platform initialization and launch of
SEV/SEV-ES enabled guests are implemented.  These can be used by
e.g. vmd(8) later.

from hshoexer@; OK mlarkin@

sys/arch/amd64/amd64/conf.c
sys/conf/files
sys/dev/ic/ccp.c
sys/dev/ic/ccpvar.h
sys/dev/pci/ccp_pci.c

index 8acf196..ddcb29a 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: conf.c,v 1.80 2024/06/11 09:21:32 jsg Exp $   */
+/*     $OpenBSD: conf.c,v 1.81 2024/06/12 12:54:54 bluhm Exp $ */
 
 /*
  * Copyright (c) 1994, 1995 Charles M. Hannum.  All rights reserved.
@@ -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);
@@ -143,6 +152,8 @@ cdev_decl(nvram);
 #include "drm.h"
 #include "viocon.h"
 cdev_decl(viocon);
+#include "ccp.h"
+cdev_decl(psp);
 
 #include "wsdisplay.h"
 #include "wskbd.h"
@@ -281,6 +292,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);
 
index dc2ecc2..1be0a06 100644 (file)
@@ -1,4 +1,4 @@
-#      $OpenBSD: files,v 1.732 2024/05/29 13:56:49 mglocker Exp $
+#      $OpenBSD: files,v 1.733 2024/06/12 12:54:54 bluhm Exp $
 #      $NetBSD: files,v 1.87 1996/05/19 17:17:50 jonathan Exp $
 
 #      @(#)files.newconf       7.5 (Berkeley) 5/10/93
@@ -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
index 5a04b73..5e8a939 100644 (file)
@@ -1,7 +1,8 @@
-/*     $OpenBSD: ccp.c,v 1.3 2020/05/29 04:42:25 deraadt Exp $ */
+/*     $OpenBSD: ccp.c,v 1.4 2024/06/12 12:54:54 bluhm Exp $ */
 
 /*
  * 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
 
 #include <machine/bus.h>
 
+#ifdef __amd64__
+#include <sys/proc.h>
+#include <uvm/uvm.h>
+#include <crypto/xform.h>
+#endif
+
 #include <dev/ic/ccpvar.h>
 
 #define CCP_REG_TRNG           0xc
@@ -38,13 +45,23 @@ struct cfdriver ccp_cd = {
        DV_DULL
 };
 
+#ifdef __amd64__
+struct ccp_softc *ccp_softc;
+
+int    psp_get_pstatus(struct psp_platform_status *);
+int    psp_init(struct psp_init *);
+#endif
+
 void
 ccp_attach(struct ccp_softc *sc)
 {
        timeout_set(&sc->sc_tick, ccp_rng, sc);
        ccp_rng(sc);
 
-       printf("\n");
+       if (sc->sc_psp_attached)
+               printf(", RNG\n");
+       else
+               printf(": RNG\n");
 }
 
 static void
@@ -59,3 +76,585 @@ ccp_rng(void *arg)
 
        timeout_add_msec(&sc->sc_tick, 100);
 }
+
+#ifdef __amd64__
+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");
+
+       sc->sc_psp_attached = 1;
+
+       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);
+
+       wbinvd_on_all_cpus();
+
+       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;
+
+       wbinvd_on_all_cpus();
+
+       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;
+
+       /* Drain caches before we encrypt memory. */
+       wbinvd_on_all_cpus();
+
+       /*
+        * 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);
+}
+#endif /* __amd64__ */
index 237a5d4..6b4675f 100644 (file)
@@ -1,7 +1,8 @@
-/*     $OpenBSD: ccpvar.h,v 1.1 2018/04/20 04:37:21 dlg Exp $ */
+/*     $OpenBSD: ccpvar.h,v 1.2 2024/06/12 12:54:54 bluhm Exp $ */
 
 /*
  * 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
@@ -24,6 +25,266 @@ struct ccp_softc {
        bus_space_handle_t      sc_ioh;
 
        struct timeout          sc_tick;
+
+       bus_size_t              sc_size;
+       int                     sc_psp_attached;
+
+#ifdef __amd64__
+       bus_dma_tag_t           sc_dmat;
+       uint32_t                sc_capabilities;
+       int                     (*sc_sev_intr)(struct ccp_softc *, uint32_t);
+       void *                  sc_ih;
+
+       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 rwlock           sc_lock;
+#endif
 };
 
+#ifdef __amd64__
+
+#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
+
+#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)
+#endif /* __amd64__ */
+
+#ifdef _KERNEL
+
 void   ccp_attach(struct ccp_softc *);
+
+#ifdef __amd64__
+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
+
+#endif /* _KERNEL */
index 9ad536e..3f6df53 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ccp_pci.c,v 1.9 2024/05/24 06:02:53 jsg Exp $ */
+/*     $OpenBSD: ccp_pci.c,v 1.10 2024/06/12 12:54:54 bluhm Exp $ */
 
 /*
  * Copyright (c) 2018 David Gwynne <dlg@openbsd.org>
 int    ccp_pci_match(struct device *, void *, void *);
 void   ccp_pci_attach(struct device *, struct device *, void *);
 
+#ifdef __amd64__
+void   psp_pci_attach(struct device *, struct device *, void *);
+int    psp_pci_intr(void *);
+#endif
+
 const struct cfattach ccp_pci_ca = {
        sizeof(struct ccp_softc),
        ccp_pci_match,
@@ -69,10 +74,67 @@ 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;
        }
 
+#ifdef __amd64__
+       psp_pci_attach(parent, self, aux);
+#endif
+
        ccp_attach(sc);
 }
+
+#ifdef __amd64__
+void
+psp_pci_attach(struct device *parent, struct device *self, void *aux)
+{
+       struct ccp_softc *sc = (struct ccp_softc *)self;
+       struct pci_attach_args *pa = aux;
+       pci_intr_handle_t ih;
+       const char *intrstr = NULL;
+
+       sc->sc_dmat = pa->pa_dmat;
+
+       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");
+               bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_size);
+               return;
+       }
+
+       intrstr = pci_intr_string(pa->pa_pc, ih);
+       sc->sc_ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO, psp_pci_intr,
+           sc, sc->sc_dev.dv_xname);
+       if (sc->sc_ih != NULL)
+               printf(": %s", intrstr);
+
+       if (psp_attach(sc)) {
+               /* enable interrupts */
+               bus_space_write_4(sc->sc_iot, sc->sc_ioh, PSP_REG_INTEN, -1);
+       }
+}
+
+int
+psp_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);
+}
+#endif /* __amd64__ */