blob: 275338b95640e18dd5622b0782540013b995da2c [file] [log] [blame]
// 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);
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);