@@ -21385,6 +21385,7 @@ L: linux-cxl@vger.kernel.org
L: linux-pci@vger.kernel.org
S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/devsec/spdm.git
+F: drivers/pci/cma.c
F: include/linux/spdm.h
F: lib/rspdm/
@@ -121,6 +121,19 @@ config XEN_PCIDEV_FRONTEND
config PCI_ATS
bool
+config PCI_CMA
+ bool "Component Measurement and Authentication (CMA-SPDM)"
+ select CRYPTO_ECDSA
+ select CRYPTO_RSA
+ select CRYPTO_SHA256
+ select CRYPTO_SHA512
+ select PCI_DOE
+ select RSPDM
+ help
+ Authenticate devices on enumeration per PCIe r6.2 sec 6.31.
+ A PCI DOE mailbox is used as transport for DMTF SPDM based
+ authentication, measurement and secure channel establishment.
+
config PCI_DOE
bool
@@ -38,6 +38,8 @@ obj-$(CONFIG_PCI_DYNAMIC_OF_NODES) += of_property.o
obj-$(CONFIG_PCI_NPEM) += npem.o
obj-$(CONFIG_PCIE_TPH) += tph.o
+obj-$(CONFIG_PCI_CMA) += cma.o
+
# Endpoint library must be initialized before its users
obj-$(CONFIG_PCI_ENDPOINT) += endpoint/
new file mode 100644
@@ -0,0 +1,101 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Component Measurement and Authentication (CMA-SPDM, PCIe r6.2 sec 6.31)
+ *
+ * Copyright (C) 2021 Huawei
+ * Jonathan Cameron <Jonathan.Cameron@huawei.com>
+ *
+ * Copyright (C) 2022-24 Intel Corporation
+ */
+
+#define dev_fmt(fmt) "CMA: " fmt
+
+#include <linux/pci.h>
+#include <linux/pci-doe.h>
+#include <linux/pm_runtime.h>
+#include <linux/spdm.h>
+
+#include "pci.h"
+
+/* Keyring that userspace can poke certs into */
+static struct key *pci_cma_keyring;
+
+#define PCI_DOE_FEATURE_CMA 1
+
+static ssize_t pci_doe_transport(void *priv, struct device *dev,
+ const void *request, size_t request_sz,
+ void *response, size_t response_sz)
+{
+ struct pci_doe_mb *doe = priv;
+ ssize_t rc;
+
+ /*
+ * CMA-SPDM operation in non-D0 states is optional (PCIe r6.2
+ * sec 6.31.3). The spec does not define a way to determine
+ * if it's supported, so resume to D0 unconditionally.
+ */
+ rc = pm_runtime_resume_and_get(dev);
+ if (rc)
+ return rc;
+
+ rc = pci_doe(doe, PCI_VENDOR_ID_PCI_SIG, PCI_DOE_FEATURE_CMA,
+ request, request_sz, response, response_sz);
+
+ pm_runtime_put(dev);
+
+ return rc;
+}
+
+void pci_cma_init(struct pci_dev *pdev)
+{
+ struct pci_doe_mb *doe;
+
+ if (IS_ERR(pci_cma_keyring))
+ return;
+
+ if (!pci_is_pcie(pdev))
+ return;
+
+ doe = pci_find_doe_mailbox(pdev, PCI_VENDOR_ID_PCI_SIG,
+ PCI_DOE_FEATURE_CMA);
+ if (!doe)
+ return;
+
+ pdev->spdm_state = spdm_create(&pdev->dev, pci_doe_transport, doe,
+ PCI_DOE_MAX_PAYLOAD, pci_cma_keyring,
+ NULL);
+ if (!pdev->spdm_state)
+ return;
+
+ /*
+ * Keep spdm_state allocated even if initial authentication fails
+ * to allow for provisioning of certificates and reauthentication.
+ */
+ spdm_authenticate(pdev->spdm_state);
+}
+
+void pci_cma_destroy(struct pci_dev *pdev)
+{
+ if (!pdev->spdm_state)
+ return;
+
+ spdm_destroy(pdev->spdm_state);
+}
+
+__init static int pci_cma_keyring_init(void)
+{
+ pci_cma_keyring = keyring_alloc(".cma", KUIDT_INIT(0), KGIDT_INIT(0),
+ current_cred(),
+ (KEY_POS_ALL & ~KEY_POS_SETATTR) |
+ KEY_USR_VIEW | KEY_USR_READ |
+ KEY_USR_WRITE | KEY_USR_SEARCH,
+ KEY_ALLOC_NOT_IN_QUOTA |
+ KEY_ALLOC_SET_KEEP, NULL, NULL);
+ if (IS_ERR(pci_cma_keyring)) {
+ pr_err("PCI: Could not allocate .cma keyring\n");
+ return PTR_ERR(pci_cma_keyring);
+ }
+
+ return 0;
+}
+arch_initcall(pci_cma_keyring_init);
@@ -31,9 +31,6 @@
#define PCI_DOE_FLAG_CANCEL 0
#define PCI_DOE_FLAG_DEAD 1
-/* Max data object length is 2^18 dwords */
-#define PCI_DOE_MAX_LENGTH (1 << 18)
-
/**
* struct pci_doe_mb - State for a single DOE mailbox
*
@@ -448,6 +448,14 @@ static inline void pci_doe_destroy(struct pci_dev *pdev) { }
static inline void pci_doe_disconnected(struct pci_dev *pdev) { }
#endif
+#ifdef CONFIG_PCI_CMA
+void pci_cma_init(struct pci_dev *pdev);
+void pci_cma_destroy(struct pci_dev *pdev);
+#else
+static inline void pci_cma_init(struct pci_dev *pdev) { }
+static inline void pci_cma_destroy(struct pci_dev *pdev) { }
+#endif
+
#ifdef CONFIG_PCI_NPEM
void pci_npem_create(struct pci_dev *dev);
void pci_npem_remove(struct pci_dev *dev);
@@ -2565,6 +2565,7 @@ static void pci_init_capabilities(struct pci_dev *dev)
pci_rcec_init(dev); /* Root Complex Event Collector */
pci_doe_init(dev); /* Data Object Exchange */
pci_tph_init(dev); /* TLP Processing Hints */
+ pci_cma_init(dev); /* Component Measurement & Auth */
pcie_report_downtraining(dev);
pci_init_reset_methods(dev);
@@ -61,6 +61,7 @@ static void pci_destroy_dev(struct pci_dev *dev)
list_del(&dev->bus_list);
up_write(&pci_bus_sem);
+ pci_cma_destroy(dev);
pci_doe_destroy(dev);
pcie_aspm_exit_link_state(dev);
pci_bridge_d3_update(dev);
@@ -15,6 +15,10 @@
struct pci_doe_mb;
+/* Max data object length is 2^18 dwords (including 2 dwords for header) */
+#define PCI_DOE_MAX_LENGTH (1 << 18)
+#define PCI_DOE_MAX_PAYLOAD ((PCI_DOE_MAX_LENGTH - 2) * sizeof(u32))
+
struct pci_doe_mb *pci_find_doe_mailbox(struct pci_dev *pdev, u16 vendor,
u8 type);
@@ -39,6 +39,7 @@
#include <linux/io.h>
#include <linux/resource_ext.h>
#include <linux/msi_api.h>
+#include <linux/spdm.h>
#include <uapi/linux/pci.h>
#include <linux/pci_ids.h>
@@ -528,6 +529,9 @@ struct pci_dev {
#ifdef CONFIG_PCI_DOE
struct xarray doe_mbs; /* Data Object Exchange mailboxes */
#endif
+#ifdef CONFIG_PCI_CMA
+ struct spdm_state *spdm_state; /* Security Protocol and Data Model */
+#endif
#ifdef CONFIG_PCI_NPEM
struct npem *npem; /* Native PCIe Enclosure Management */
#endif