Linux-PCI Archive mirror
 help / color / mirror / Atom feed
From: Alexey Kardashevskiy <aik@amd.com>
To: Dan Williams <dan.j.williams@intel.com>, linux-coco@lists.linux.dev
Cc: Wu Hao <hao.wu@intel.com>, Yilun Xu <yilun.xu@intel.com>,
	Lukas Wunner <lukas@wunner.de>, Samuel Ortiz <sameo@rivosinc.com>,
	Bjorn Helgaas <bhelgaas@google.com>,
	Xu Yilun <yilun.xu@linux.intel.com>,
	kevin.tian@intel.com, gregkh@linuxfoundation.org,
	linux-pci@vger.kernel.org
Subject: Re: [RFC PATCH v2 5/6] PCI/TSM: Authenticate devices via platform TSM
Date: Mon, 22 Apr 2024 12:21:08 +1000	[thread overview]
Message-ID: <fc201452-080e-4942-b5a0-0c64d023ac6b@amd.com> (raw)
In-Reply-To: <171291193308.3532867.129739584130889725.stgit@dwillia2-xfh.jf.intel.com>

On 12/4/24 18:52, Dan Williams wrote:
> The PCIe 6.1 specification, section 11, introduces the Trusted Execution
> Environment (TEE) Device Interface Security Protocol (TDISP).  This
> interface definition builds upon Component Measurement and
> Authentication (CMA), and link Integrity and Data Encryption (IDE). It
> adds support for assigning devices (PCI physical or virtual function) to
> a confidential VM such that the assigned device is enabled to access
> guest private memory protected by technologies like Intel TDX, AMD
> SEV-SNP, RISCV COVE, or ARM CCA.
> 
> The "TSM" (TEE Security Manager) is a concept in the TDISP specification
> of an agent that mediates between a "DSM" (Device Security Manager) and
> system software in both a VMM and a confidential VM. A VMM uses TSM ABIs
> to setup link security and assign devices. A confidential VM uses TSM
> ABIs to transition an assigned device into the TDISP "RUN" state and
> validate its configuration. From a Linux perspective the TSM abstracts
> many of the details of TDISP, IDE, and CMA. Some of those details leak
> through at times, but for the most part TDISP is an internal
> implementation detail of the TSM.
> 
> Similar to the PCI core extensions to support CONFIG_PCI_CMA,
> CONFIG_PCI_TSM builds upon that to reuse the "authenticated" sysfs
> attribute, and add more properties + controls in a tsm/ subdirectory of
> the PCI device sysfs interface. Unlike CMA that can depend on a local to
> the PCI core implementation, PCI_TSM needs to be prepared for late
> loading of the platform TSM driver. Consider that the TSM driver may
> itself be a PCI driver. Userspace can depend on the common TSM device
> uevent to know when the PCI core has TSM services enabled. The PCI
> device tsm/ subdirectory is supplemented by the TSM device pci/
> directory for platform global TSM properties + controls.
> 
> The common verbs that the low-level TSM drivers implement are defined by
> 'enum pci_tsm_cmd'. For now only connect and disconnect are defined for
> establishing a trust relationship between the host and the device,
> securing the interconnect (optionally establishing IDE), and tearing
> that down.
> 
> The locking allows for multiple devices to be executing commands
> simultaneously, one outstanding command per-device and an rwsem flushes
> all inflight commands when a TSM low-level driver/device is removed.
> 
> In addition to commands submitted through an 'exec' operation the
> low-level TSM driver is notified of device arrival and departure events
> via 'add' and 'del' operations. With those it can setup per-device
> context, or filter devices that the TSM is not prepared to support.
> 
> Cc: Wu Hao <hao.wu@intel.com>
> Cc: Yilun Xu <yilun.xu@intel.com>
> Cc: Lukas Wunner <lukas@wunner.de>
> Cc: Samuel Ortiz <sameo@rivosinc.com>
> Cc: Alexey Kardashevskiy <aik@amd.com>
> Cc: Bjorn Helgaas <bhelgaas@google.com>
> Co-developed-by: Xu Yilun <yilun.xu@linux.intel.com>
> Signed-off-by: Xu Yilun <yilun.xu@linux.intel.com>
> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
> ---
>   Documentation/ABI/testing/sysfs-bus-pci |   46 +++++
>   MAINTAINERS                             |    2
>   drivers/pci/Kconfig                     |   13 +
>   drivers/pci/Makefile                    |    2
>   drivers/pci/pci-sysfs.c                 |    4
>   drivers/pci/pci.h                       |   10 +
>   drivers/pci/probe.c                     |    1
>   drivers/pci/remove.c                    |    1
>   drivers/pci/tsm.c                       |  270 +++++++++++++++++++++++++++++++
>   drivers/virt/coco/host/tsm-core.c       |   22 ++-
>   include/linux/pci-tsm.h                 |   80 +++++++++
>   include/linux/pci.h                     |   11 +
>   include/linux/tsm.h                     |    4
>   include/uapi/linux/pci_regs.h           |    4
>   14 files changed, 466 insertions(+), 4 deletions(-)
>   create mode 100644 drivers/pci/tsm.c
>   create mode 100644 include/linux/pci-tsm.h
> 
> diff --git a/Documentation/ABI/testing/sysfs-bus-pci b/Documentation/ABI/testing/sysfs-bus-pci
> index ecf47559f495..4ae50621e65b 100644
> --- a/Documentation/ABI/testing/sysfs-bus-pci
> +++ b/Documentation/ABI/testing/sysfs-bus-pci
> @@ -500,3 +500,49 @@ Description:
>   		console drivers from the device.  Raw users of pci-sysfs
>   		resourceN attributes must be terminated prior to resizing.
>   		Success of the resizing operation is not guaranteed.
> +
> +What:		/sys/bus/pci/devices/.../authenticated
> +Date:		March 2024
> +Contact:	linux-pci@vger.kernel.org
> +Description:
> +		This file contains 1 if the device authenticated successfully.
> +		It contains 0 if the device failed authentication (and may thus
> +		be malicious). There are 2 potential authentication methods:
> +		native PCI CMA (Component Measurement and Authentication) and
> +		PCI TSM (TEE Security Manager). In the PCI TSM case the device's
> +		PCI CMA interface is subsumed by the TSM driver. A TSM
> +		implementation uses its own private certificate store + keys to
> +		authenticate the device. Without a TSM the kernel can
> +		authenticate using its own certificate chain.
> +
> +		In the TSM case, "authenticated" is read-only (0444) and the
> +		"tsm/connect" attribute reflects whether the device is TSM
> +		"connected" which includes not only CMA authentication, but
> +		optionally IDE (link Integrity and Data encryption) if the TSM
> +		deems that is necessary. When the device is disconnected from
> +		the TSM the kernel may attempt authentication with its own
> +		certificate chain. See
> +		Documentation/ABI/testing/sysfs-devices-spdm.
> +
> +		The file is not visible if authentication is unsupported by the
> +		device, or if PCI CMA support is disabled and the TSM
> +		driver has no available authentication methods for the device.
> +
> +What:		/sys/bus/pci/devices/.../tsm/
> +Date:		March 2024
> +Contact:	linux-coco@lists.linux.dev
> +Description:
> +		This directory only appears if a device supports CMA and IDE,
> +		and only after a TSM driver has loaded and evaluated this
> +		PCI device. All present devices shall be dispositioned
> +		after the 'add' event for /sys/class/tsm/tsm0 triggers.
> +
> +What:		/sys/bus/pci/devices/.../tsm/connect
> +Date:		March 2024
> +Contact:	linux-coco@lists.linux.dev
> +Description:
> +		(RW) Writing "1" to this file triggers the TSM to establish a
> +		connection with the device. This typically includes an SPDM
> +		(DMTF Security Protocols and Data Models) session over PCIe DOE
> +		(Data Object Exchange) and may also include PCIe IDE (Integrity
> +		and Data Encryption) establishment.
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 8d5bcd9d43ac..0e1d995e7a16 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -22466,8 +22466,10 @@ M:	Dan Williams <dan.j.williams@intel.com>
>   L:	linux-coco@lists.linux.dev
>   S:	Maintained
>   F:	Documentation/ABI/testing/configfs-tsm
> +F:	drivers/pci/tsm.c
>   F:	drivers/virt/coco/guest/tsm_report.c
>   F:	drivers/virt/coco/host/
> +F:	include/linux/pci-tsm.h
>   F:	include/linux/tsm.h
>   
>   TTY LAYER AND SERIAL DRIVERS
> diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
> index d35001589d88..cd863c5e49ca 100644
> --- a/drivers/pci/Kconfig
> +++ b/drivers/pci/Kconfig
> @@ -121,6 +121,19 @@ config XEN_PCIDEV_FRONTEND
>   config PCI_ATS
>   	bool
>   
> +config PCI_TSM
> +	bool "TEE Security Manager for PCI Device Security"
> +	help
> +	  The TEE (Trusted Execution Environment) Device Interface
> +	  Security Protocol (TDISP) defines a "TSM" as a platform agent
> +	  that manages device authentication, link encryption, link
> +	  integrity protection, and assignment of PCI device functions
> +	  (virtual or physical) to confidential computing VMs that can
> +	  access (DMA) guest private memory.
> +
> +	  Enable a platform TSM driver to use this capability.
> +
> +
>   config PCI_DOE
>   	bool
>   
> diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
> index 175302036890..b9884a669c5f 100644
> --- a/drivers/pci/Makefile
> +++ b/drivers/pci/Makefile
> @@ -35,6 +35,8 @@ obj-$(CONFIG_VGA_ARB)		+= vgaarb.o
>   obj-$(CONFIG_PCI_DOE)		+= doe.o
>   obj-$(CONFIG_PCI_DYNAMIC_OF_NODES) += of_property.o
>   
> +obj-$(CONFIG_PCI_TSM)		+= tsm.o
> +
>   # Endpoint library must be initialized before its users
>   obj-$(CONFIG_PCI_ENDPOINT)	+= endpoint/
>   
> diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
> index 40cfa716392f..c6ea624dd76c 100644
> --- a/drivers/pci/pci-sysfs.c
> +++ b/drivers/pci/pci-sysfs.c
> @@ -1661,6 +1661,10 @@ const struct attribute_group *pci_dev_attr_groups[] = {
>   #endif
>   #ifdef CONFIG_PCIEASPM
>   	&aspm_ctrl_attr_group,
> +#endif
> +#ifdef CONFIG_PCI_TSM
> +	&pci_tsm_auth_attr_group,
> +	&pci_tsm_attr_group,
>   #endif
>   	NULL,
>   };
> diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
> index 17fed1846847..9b864cbf8682 100644
> --- a/drivers/pci/pci.h
> +++ b/drivers/pci/pci.h
> @@ -335,6 +335,16 @@ static inline void pci_doe_destroy(struct pci_dev *pdev) { }
>   static inline void pci_doe_disconnected(struct pci_dev *pdev) { }
>   #endif
>   
> +#ifdef CONFIG_PCI_TSM
> +void pci_tsm_init(struct pci_dev *pdev);
> +void pci_tsm_destroy(struct pci_dev *pdev);
> +extern const struct attribute_group pci_tsm_attr_group;
> +extern const struct attribute_group pci_tsm_auth_attr_group;
> +#else
> +static inline void pci_tsm_init(struct pci_dev *pdev) { }
> +static inline void pci_tsm_destroy(struct pci_dev *pdev) { }
> +#endif
> +
>   /**
>    * pci_dev_set_io_state - Set the new error state if possible.
>    *
> diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
> index 1325fbae2f28..d89b67541d02 100644
> --- a/drivers/pci/probe.c
> +++ b/drivers/pci/probe.c
> @@ -2481,6 +2481,7 @@ static void pci_init_capabilities(struct pci_dev *dev)
>   	pci_dpc_init(dev);		/* Downstream Port Containment */
>   	pci_rcec_init(dev);		/* Root Complex Event Collector */
>   	pci_doe_init(dev);		/* Data Object Exchange */
> +	pci_tsm_init(dev);		/* TEE Security Manager connection */
>   
>   	pcie_report_downtraining(dev);
>   	pci_init_reset_methods(dev);
> diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c
> index d749ea8250d6..d94b2458934a 100644
> --- a/drivers/pci/remove.c
> +++ b/drivers/pci/remove.c
> @@ -39,6 +39,7 @@ static void pci_destroy_dev(struct pci_dev *dev)
>   	list_del(&dev->bus_list);
>   	up_write(&pci_bus_sem);
>   
> +	pci_tsm_destroy(dev);
>   	pci_doe_destroy(dev);
>   	pcie_aspm_exit_link_state(dev);
>   	pci_bridge_d3_update(dev);
> diff --git a/drivers/pci/tsm.c b/drivers/pci/tsm.c
> new file mode 100644
> index 000000000000..9c5fb2c46662
> --- /dev/null
> +++ b/drivers/pci/tsm.c
> @@ -0,0 +1,270 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * TEE Security Manager for the TEE Device Interface Security Protocol
> + * (TDISP, PCIe r6.1 sec 11)
> + *
> + * Copyright(c) 2024 Intel Corporation. All rights reserved.
> + */
> +
> +#define dev_fmt(fmt) "TSM: " fmt
> +
> +#include <linux/pci.h>
> +#include <linux/pci-doe.h>
> +#include <linux/sysfs.h>
> +#include <linux/xarray.h>
> +#include <linux/pci-tsm.h>
> +#include <linux/bitfield.h>
> +#include "pci.h"
> +
> +/* collect TSM capable devices to rendezvous with the tsm driver */
> +static DEFINE_XARRAY(pci_tsm_devs);

imho either this or pci_dev::tsm is enough but not necessarily both.

> +
> +/*
> + * Provide a read/write lock against the init / exit of pdev tsm
> + * capabilities and arrival/departure of a tsm instance
> + */
> +static DECLARE_RWSEM(pci_tsm_rwsem);
> +static const struct pci_tsm_ops *tsm_ops;
> +
> +static int pci_tsm_disconnect(struct pci_dev *pdev)
> +{
> +	struct pci_tsm *pci_tsm = pdev->tsm;
> +
> +	lockdep_assert_held_read(&pci_tsm_rwsem);
> +	scoped_cond_guard(mutex_intr, return -EINTR, &pci_tsm->exec_lock) {
> +		int rc;
> +
> +		if (pci_tsm->state < PCI_TSM_CONNECT)
> +			return 0;
> +		if (pci_tsm->state < PCI_TSM_INIT)
> +			return -ENXIO;
> +
> +		rc = tsm_ops->exec(pdev, TSM_EXEC_DISCONNECT);
> +		if (rc)
> +			return rc;
> +		pci_tsm->state = PCI_TSM_INIT;
> +	}
> +	return 0;
> +}
> +
> +static int pci_tsm_connect(struct pci_dev *pdev)
> +{
> +	struct pci_tsm *pci_tsm = pdev->tsm;
> +
> +	lockdep_assert_held_read(&pci_tsm_rwsem);
> +	scoped_cond_guard(mutex_intr, return -EINTR, &pci_tsm->exec_lock) {
> +		int rc;
> +
> +		if (pci_tsm->state >= PCI_TSM_CONNECT)
> +			return 0;
> +		if (pci_tsm->state < PCI_TSM_INIT)
> +			return -ENXIO;
> +
> +		rc = tsm_ops->exec(pdev, TSM_EXEC_CONNECT);
> +		if (rc)
> +			return rc;
> +		pci_tsm->state = PCI_TSM_CONNECT;
> +	}
> +	return 0;
> +}
> +
> +static ssize_t connect_store(struct device *dev, struct device_attribute *attr,
> +			     const char *buf, size_t len)
> +{
> +	int rc;
> +	bool connect;
> +	struct pci_dev *pdev = to_pci_dev(dev);
> +
> +	rc = kstrtobool(buf, &connect);
> +	if (rc)
> +		return rc;
> +
> +	if (connect)
> +		rc = pci_tsm_connect(pdev);
> +	else
> +		rc = pci_tsm_disconnect(pdev);
> +	if (rc)
> +		return rc;
> +	return len;
> +}
> +
> +static ssize_t connect_show(struct device *dev, struct device_attribute *attr,
> +			    char *buf)
> +{
> +	struct pci_dev *pdev = to_pci_dev(dev);
> +
> +	return sysfs_emit(buf, "%d\n", pdev->tsm->state >= PCI_TSM_CONNECT);
> +}
> +static DEVICE_ATTR_RW(connect);
> +
> +static bool pci_tsm_group_visible(struct kobject *kobj)
> +{
> +	struct device *dev = kobj_to_dev(kobj);
> +	struct pci_dev *pdev = to_pci_dev(dev);
> +
> +	if (pdev->tsm && pdev->tsm->state > PCI_TSM_IDLE)
> +		return true;
> +	return false;
> +}
> +DEFINE_SIMPLE_SYSFS_GROUP_VISIBLE(pci_tsm);
> +
> +static struct attribute *pci_tsm_attrs[] = {
> +	&dev_attr_connect.attr,
> +	NULL,
> +};
> +
> +const struct attribute_group pci_tsm_attr_group = {
> +	.name = "tsm",
> +	.attrs = pci_tsm_attrs,
> +	.is_visible = SYSFS_GROUP_VISIBLE(pci_tsm),
> +};
> +
> +static ssize_t authenticated_show(struct device *dev,
> +				  struct device_attribute *attr, char *buf)
> +{
> +	/*
> +	 * When device authentication is TSM owned, 'authenticated' is
> +	 * identical to the connect state.
> +	 */
> +	return connect_show(dev, attr, buf);
> +}
> +static DEVICE_ATTR_RO(authenticated);
> +
> +static struct attribute *pci_tsm_auth_attrs[] = {
> +	&dev_attr_authenticated.attr,
> +	NULL,
> +};
> +
> +const struct attribute_group pci_tsm_auth_attr_group = {
> +	.attrs = pci_tsm_auth_attrs,
> +	.is_visible = SYSFS_GROUP_VISIBLE(pci_tsm),
> +};
> +
> +static int pci_tsm_add(struct pci_dev *pdev)
> +{
> +	struct pci_tsm *pci_tsm = pdev->tsm;
> +
> +	lockdep_assert_held(&pci_tsm_rwsem);
> +	if (!tsm_ops)
> +		return 0;
> +	if (pci_tsm->state < PCI_TSM_INIT) {
> +		int rc = tsm_ops->add(pdev);
> +
> +		if (rc)
> +			return rc;
> +	}
> +	pci_tsm->state = PCI_TSM_INIT;
> +	return sysfs_update_group(&pdev->dev.kobj, &pci_tsm_attr_group);
> +}
> +
> +static void pci_tsm_del(struct pci_dev *pdev)
> +{
> +	struct pci_tsm *pci_tsm = pdev->tsm;
> +
> +	lockdep_assert_held(&pci_tsm_rwsem);
> +	/* shutdown sysfs operations before tsm delete */
> +	scoped_guard(mutex, &pdev->tsm->exec_lock)
> +		pci_tsm->state = PCI_TSM_IDLE;
> +	sysfs_update_group(&pdev->dev.kobj, &pci_tsm_attr_group);
> +	tsm_ops->del(pdev);
> +}
> +
> +int pci_tsm_register(const struct pci_tsm_ops *ops)
> +{
> +	struct pci_dev *pdev;
> +	unsigned long index;
> +
> +	if (!ops)
> +		return 0;
> +	guard(rwsem_write)(&pci_tsm_rwsem);
> +	if (tsm_ops)
> +		return -EBUSY;
> +	tsm_ops = ops;
> +	xa_for_each(&pci_tsm_devs, index, pdev)
> +		pci_tsm_add(pdev);
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(pci_tsm_register);
> +
> +void pci_tsm_unregister(const struct pci_tsm_ops *ops)
> +{
> +	struct pci_dev *pdev;
> +	unsigned long index;
> +
> +	if (!ops)
> +		return;
> +	guard(rwsem_write)(&pci_tsm_rwsem);
> +	if (ops != tsm_ops)
> +		return;
> +	xa_for_each(&pci_tsm_devs, index, pdev)
> +		pci_tsm_del(pdev);
> +	tsm_ops = NULL;
> +}
> +EXPORT_SYMBOL_GPL(pci_tsm_unregister);
> +
> +int pci_tsm_doe_transfer(struct pci_dev *pdev, enum pci_doe_proto type,
> +			 const void *req, size_t req_sz, void *resp,
> +			 size_t resp_sz)
> +{
> +	if (!pdev->tsm || !pdev->tsm->doe_mb)
> +		return -ENXIO;
> +
> +	return pci_doe(pdev->tsm->doe_mb, PCI_VENDOR_ID_PCI_SIG, type, req,
> +		       req_sz, resp, resp_sz);
> +}
> +EXPORT_SYMBOL_GPL(pci_tsm_doe_transfer);
> +
> +static unsigned long pci_tsm_devid(struct pci_dev *pdev)
> +{
> +	return FIELD_PREP(GENMASK(15, 0),
> +			  PCI_DEVID(pdev->bus->number, pdev->devfn)) |
> +	       FIELD_PREP(GENMASK(31, 16), pci_domain_nr(pdev->bus));
> +}
> +
> +void pci_tsm_init(struct pci_dev *pdev)
> +{
> +	bool tee_cap;
> +	u16 ide_cap;
> +	int rc;
> +
> +	ide_cap = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_IDE);
> +	tee_cap = pdev->devcap & PCI_EXP_DEVCAP_TEE;
> +	if (ide_cap || tee_cap)

I'd swap if with else.

> +		pci_dbg(pdev,
> +			"Device security capabailities detected (%s%s ), init TSM\n",

capabailities

> +			ide_cap ? " ide" : "", tee_cap ? " tee" : "");
> +	else
> +		return;


If (!ide_cap && tee_cap), we get here but doing the below does not make 
sense for TEE (which are likely to be VFs).


> +	struct pci_tsm *pci_tsm __free(kfree) = kzalloc(sizeof(*pci_tsm), GFP_KERNEL);
> +	if (!pci_tsm)
> +		return;
> +
> +	pci_tsm->ide_cap = ide_cap;
> +	mutex_init(&pci_tsm->exec_lock);
> +
> +	pci_tsm->doe_mb = pci_find_doe_mailbox(pdev, PCI_VENDOR_ID_PCI_SIG,
> +					       PCI_DOE_PROTO_CMA);
> +	if (!pci_tsm->doe_mb)
> +		return;
> +
> +	rc = xa_insert(&pci_tsm_devs, pci_tsm_devid(pdev), pdev, GFP_KERNEL);
> +	if (rc) {
> +		pci_dbg(pdev, "failed to register TSM capable device\n");
> +		return;
> +	}
> +
> +	guard(rwsem_write)(&pci_tsm_rwsem);
> +	pdev->tsm = no_free_ptr(pci_tsm);
> +	pci_tsm_add(pdev);
> +}
> +
> +void pci_tsm_destroy(struct pci_dev *pdev)
> +{
> +	guard(rwsem_write)(&pci_tsm_rwsem);
> +	pci_tsm_del(pdev);
> +	xa_erase(&pci_tsm_devs, pci_tsm_devid(pdev));
> +	kfree(pdev->tsm);
> +	pdev->tsm = NULL;
> +}
> diff --git a/drivers/virt/coco/host/tsm-core.c b/drivers/virt/coco/host/tsm-core.c
> index 0ee738fc40ed..994a7f77c5c9 100644
> --- a/drivers/virt/coco/host/tsm-core.c
> +++ b/drivers/virt/coco/host/tsm-core.c
> @@ -8,11 +8,13 @@
>   #include <linux/device.h>
>   #include <linux/module.h>
>   #include <linux/cleanup.h>
> +#include <linux/pci-tsm.h>
>   
>   static DECLARE_RWSEM(tsm_core_rwsem);
>   static struct class *tsm_class;
>   static struct tsm_subsys {
>   	struct device dev;
> +	const struct pci_tsm_ops *pci_ops;
>   } *tsm_subsys;
>   
>   static struct tsm_subsys *
> @@ -40,7 +42,8 @@ static void put_tsm_subsys(struct tsm_subsys *subsys)
>   DEFINE_FREE(put_tsm_subsys, struct tsm_subsys *,
>   	    if (!IS_ERR_OR_NULL(_T)) put_tsm_subsys(_T))
>   struct tsm_subsys *tsm_register(struct device *parent,
> -				const struct attribute_group **groups)
> +				const struct attribute_group **groups,
> +				const struct pci_tsm_ops *pci_ops)
>   {
>   	struct device *dev;
>   	int rc;
> @@ -62,10 +65,20 @@ struct tsm_subsys *tsm_register(struct device *parent,
>   	if (rc)
>   		return ERR_PTR(rc);
>   
> +	rc = pci_tsm_register(pci_ops);
> +	if (rc) {
> +		dev_err(parent, "PCI initialization failure: %pe\n",
> +			ERR_PTR(rc));
> +		return ERR_PTR(rc);
> +	}
> +
>   	rc = device_add(dev);
> -	if (rc)
> +	if (rc) {
> +		pci_tsm_unregister(pci_ops);
>   		return ERR_PTR(rc);
> +	}
>   
> +	subsys->pci_ops = pci_ops;
>   	tsm_subsys = no_free_ptr(subsys);
>   
>   	return tsm_subsys;
> @@ -74,13 +87,18 @@ EXPORT_SYMBOL_GPL(tsm_register);
>   
>   void tsm_unregister(struct tsm_subsys *subsys)
>   {
> +	const struct pci_tsm_ops *pci_ops;
> +
>   	guard(rwsem_write)(&tsm_core_rwsem);
>   	if (!tsm_subsys || subsys != tsm_subsys) {
>   		pr_warn("failed to unregister, not currently registered\n");
>   		return;
>   	}
>   
> +	pci_ops = subsys->pci_ops;
>   	device_unregister(&subsys->dev);
> +
> +	pci_tsm_unregister(pci_ops);
>   	tsm_subsys = NULL;
>   }
>   EXPORT_SYMBOL_GPL(tsm_unregister);
> diff --git a/include/linux/pci-tsm.h b/include/linux/pci-tsm.h
> new file mode 100644
> index 000000000000..d17f5e0574c4
> --- /dev/null
> +++ b/include/linux/pci-tsm.h
> @@ -0,0 +1,80 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +#ifndef __PCI_TSM_H
> +#define __PCI_TSM_H
> +#include <linux/mutex.h>
> +
> +enum pci_tsm_cmd {
> +	TSM_EXEC_CONNECT,
> +	TSM_EXEC_DISCONNECT,
> +};
> +
> +struct pci_dev;
> +/**
> + * struct pci_tsm_ops - Low-level TSM-exported interface to the PCI core
> + * @add: accept device for tsm operation


What does "accept" means here? "Accept" sounds like some action needed 
from something but this is what exec() for. So far I have not noticed 
that allocating platform-specific structures prior calling a verb is any 
useful, i.e. having a separate state - PCI_TSM_INIT - is just an extra 
noise in the "painfully simple first TSM implementation".


> + * @del: teardown tsm context for @pdev
> + * @exec: synchronously execute @cmd
> + *
> + * Note that @add, and @del run in down_write(&pci_tsm_rswem) context to
> + * synchronize with TSM driver bind/unbind events and
> + * pci_device_add()/pci_destroy_dev(). @exec runs in
> + * @pdev->tsm->exec_lock context to synchronize @exec results with
> + * @pdev->tsm->state
> + */
> +struct pci_tsm_ops {
> +	int (*add)(struct pci_dev *pdev);
> +	void (*del)(struct pci_dev *pdev);
> +	int (*exec)(struct pci_dev *pdev, enum pci_tsm_cmd cmd);


A nit: the verbs seem working (especially reducing the amount of 
cut-n-paste of all this spdm forwarding) until I get to things like 
"get_status" which returns a structure to dump in the sysfs. Doing it 
like this means adding a structure in pci_tsm and manage its state 
(valid/partial/empty/...). Or we might want to generalize some input 
parameters for the verbs, adding u64 params is meh.


> +};
> +
> +enum pci_tsm_state {
> +	PCI_TSM_IDLE,
> +	PCI_TSM_INIT,
> +	PCI_TSM_CONNECT,
> +};
> +
> +/**
> + * struct pci_tsm - per device TSM context
> + * @state: reflect device initialized, connected, or bound
> + * @ide_cap: PCIe IDE Extended Capability offset
> + * @exec_lock: protect @state vs pci_tsm_ops.exec() results
> + * @doe_mb: PCIe Data Object Exchange mailbox
> + * @tsm_data: TSM driver private context
> + */
> +struct pci_tsm {
> +	enum pci_tsm_state state;
> +	u16 ide_cap;
> +	struct mutex exec_lock;
> +	struct pci_doe_mb *doe_mb;
> +	void *tsm_data;
> +};
> +
> +enum pci_doe_proto {
> +	PCI_DOE_PROTO_CMA = 1,
> +	PCI_DOE_PROTO_SSESSION = 2,
> +};
> +
> +#ifdef CONFIG_PCI_TSM
> +int pci_tsm_register(const struct pci_tsm_ops *ops);
> +void pci_tsm_unregister(const struct pci_tsm_ops *ops);
> +int pci_tsm_doe_transfer(struct pci_dev *pdev, enum pci_doe_proto type,
> +			 const void *req, size_t req_sz, void *resp,
> +			 size_t resp_sz);
> +#else
> +static inline int pci_tsm_register(const struct pci_tsm_ops *ops)
> +{
> +	return 0;
> +}
> +static inline void pci_tsm_unregister(const struct pci_tsm_ops *ops)
> +{
> +}
> +static inline int pci_tsm_doe_transfer(struct pci_dev *pdev,
> +				       enum pci_doe_proto type, const void *req,
> +				       size_t req_sz, void *resp,
> +				       size_t resp_sz)
> +{
> +	return -ENOENT;
> +}
> +
> +#endif
> +#endif /*__PCI_TSM_H */
> diff --git a/include/linux/pci.h b/include/linux/pci.h
> index 16493426a04f..dd4dc8719c5c 100644
> --- a/include/linux/pci.h
> +++ b/include/linux/pci.h
> @@ -515,6 +515,9 @@ struct pci_dev {
>   #endif
>   #ifdef CONFIG_PCI_DOE
>   	struct xarray	doe_mbs;	/* Data Object Exchange mailboxes */
> +#endif
> +#ifdef CONFIG_PCI_TSM
> +	struct pci_tsm *tsm;		/* TSM operation state */


I am wondering if pdev->dev.platform_data can be used for this.


>   #endif
>   	u16		acs_cap;	/* ACS Capability offset */
>   	phys_addr_t	rom;		/* Physical address if not from BAR */
> @@ -550,6 +553,12 @@ static inline int pci_channel_offline(struct pci_dev *pdev)
>   	return (pdev->error_state != pci_channel_io_normal);
>   }
>   
> +/* id resources that may be shared across host-bridges */
> +struct pci_hb_id_pool {
> +	int nr_stream_ids;
> +	int nr_cxl_cache_ids;
> +};
> +
>   /*
>    * Currently in ACPI spec, for each PCI host bridge, PCI Segment
>    * Group number is limited to a 16-bit value, therefore (int)-1 is
> @@ -568,6 +577,8 @@ struct pci_host_bridge {
>   	void		*sysdata;
>   	int		busnr;
>   	int		domain_nr;
> +	struct pci_hb_id_pool __pool;
> +	struct pci_hb_id_pool *pool;	/* &self->__pool, unless shared */


What are these for? Something for IDE (which I also have in the works, 
very basic set of wrappers)? Thanks,

>   	struct list_head windows;	/* resource_entry */
>   	struct list_head dma_ranges;	/* dma ranges resource list */
>   	u8 (*swizzle_irq)(struct pci_dev *, u8 *); /* Platform IRQ swizzler */
> diff --git a/include/linux/tsm.h b/include/linux/tsm.h
> index 2867c2ecbd11..6481cc99ea6d 100644
> --- a/include/linux/tsm.h
> +++ b/include/linux/tsm.h
> @@ -68,7 +68,9 @@ int tsm_report_register(const struct tsm_report_ops *ops, void *priv,
>   			const struct config_item_type *type);
>   int tsm_report_unregister(const struct tsm_report_ops *ops);
>   struct tsm_subsys;
> +struct pci_tsm_ops;
>   struct tsm_subsys *tsm_register(struct device *parent,
> -				const struct attribute_group **groups);
> +				const struct attribute_group **groups,
> +				const struct pci_tsm_ops *ops);
>   void tsm_unregister(struct tsm_subsys *subsys);
>   #endif /* __TSM_H */
> diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h
> index a39193213ff2..9aaffa379cae 100644
> --- a/include/uapi/linux/pci_regs.h
> +++ b/include/uapi/linux/pci_regs.h
> @@ -498,6 +498,7 @@
>   #define  PCI_EXP_DEVCAP_PWR_VAL	0x03fc0000 /* Slot Power Limit Value */
>   #define  PCI_EXP_DEVCAP_PWR_SCL	0x0c000000 /* Slot Power Limit Scale */
>   #define  PCI_EXP_DEVCAP_FLR     0x10000000 /* Function Level Reset */
> +#define  PCI_EXP_DEVCAP_TEE     0x40000000 /* TEE I/O (TDISP) Support */
>   #define PCI_EXP_DEVCTL		0x08	/* Device Control */
>   #define  PCI_EXP_DEVCTL_CERE	0x0001	/* Correctable Error Reporting En. */
>   #define  PCI_EXP_DEVCTL_NFERE	0x0002	/* Non-Fatal Error Reporting Enable */
> @@ -742,7 +743,8 @@
>   #define PCI_EXT_CAP_ID_PL_16GT	0x26	/* Physical Layer 16.0 GT/s */
>   #define PCI_EXT_CAP_ID_PL_32GT  0x2A    /* Physical Layer 32.0 GT/s */
>   #define PCI_EXT_CAP_ID_DOE	0x2E	/* Data Object Exchange */
> -#define PCI_EXT_CAP_ID_MAX	PCI_EXT_CAP_ID_DOE
> +#define PCI_EXT_CAP_ID_IDE	0x30	/* Integrity and Data Encryption */
> +#define PCI_EXT_CAP_ID_MAX	PCI_EXT_CAP_ID_IDE
>   
>   #define PCI_EXT_CAP_DSN_SIZEOF	12
>   #define PCI_EXT_CAP_MCAST_ENDPOINT_SIZEOF 40
> 

-- 
Alexey


  parent reply	other threads:[~2024-04-22  2:21 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-04-12  8:51 [RFC PATCH v2 0/6] Towards a shared TSM sysfs-ABI for Confidential Computing Dan Williams
2024-04-12  8:51 ` [RFC PATCH v2 1/6] configfs-tsm: Namespace TSM report symbols Dan Williams
2024-04-12  8:51 ` [RFC PATCH v2 2/6] coco/guest: Move shared guest CC infrastructure to drivers/virt/coco/guest/ Dan Williams
2024-04-12  8:52 ` [RFC PATCH v2 3/6] x86/tdx: Introduce a "tdx" subsystem and "tsm" device Dan Williams
2024-04-12  8:52 ` [RFC PATCH v2 4/6] coco/tsm: Introduce a class device for TEE Security Managers Dan Williams
2024-04-12  8:52 ` [RFC PATCH v2 5/6] PCI/TSM: Authenticate devices via platform TSM Dan Williams
2024-04-19 22:07   ` Bjorn Helgaas
2024-04-27  1:27     ` Dan Williams
2024-04-22  2:21   ` Alexey Kardashevskiy [this message]
2024-04-27  2:58     ` Dan Williams
2024-05-06 15:14       ` Xu Yilun
2024-05-07 18:21         ` Dan Williams
2024-05-08  2:21           ` Xu Yilun
2024-05-07  8:46       ` Xu Yilun
2024-05-07 18:28         ` Dan Williams
2024-05-14 17:13         ` Zhi Wang
2024-04-12  8:52 ` [RFC PATCH v2 6/6] tdx_tsm: TEE Security Manager driver for TDX Dan Williams

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=fc201452-080e-4942-b5a0-0c64d023ac6b@amd.com \
    --to=aik@amd.com \
    --cc=bhelgaas@google.com \
    --cc=dan.j.williams@intel.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=hao.wu@intel.com \
    --cc=kevin.tian@intel.com \
    --cc=linux-coco@lists.linux.dev \
    --cc=linux-pci@vger.kernel.org \
    --cc=lukas@wunner.de \
    --cc=sameo@rivosinc.com \
    --cc=yilun.xu@intel.com \
    --cc=yilun.xu@linux.intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).