Skip to contentSkip to conversation

coco/TSM: Host-side Arm CCA IDE setup via connect/disconnect callbacks

RFC PATCH Superseded Aneesh Kumar K.V (Arm) 4 participants 21 messages Apr 27 – Jun 2

Subsystems (10)
PCI Crypto API arm64 KVM arm64 +6 more subsystems

v4 of 5 Superseded Latest is v5 →

lore
Share & tools
lore
#0 lore raw

v4 cover coco/TSM: Host-side Arm CCA IDE setup via connect/disconnect callbacks

This patch series implements the TSM ->connect() and ->disconnect() callbacks required for the Arm CCA IDE setup as per the RMM 2.0bet1 specification [1].

This patchset includes the host-side flow needed by connect/disconnect, including:
- DA feature detection helpers
- host TSM callback wiring and IDE stream allocation support
- creation/registration of RMM pdev descriptors
- RMM pdev communication helpers
- pdev stop and teardown helpers for disconnect
- pdev instantiation from the connect path
- public key registration with RMM

To support public-key handling from the device certificate chain, the series also includes the required X.509 parser updates.

The series builds upon the TSM framework patches posted at [2] and depends on the KVM CCA patchset [3]. A git repository containing all the related changes is available at [4].

Testing / Usage

To initiate the IDE setup:
echo tsm0 > /sys/bus/pci/devices/$DEVICE/tsm/connect

To disconnect:
echo tsm0 > /sys/bus/pci/devices/$DEVICE/tsm/disconnect

Changes from v3:
https://lore.kernel.org/all/[email protected]
* updated the patches to follow the RMM 2.0bet1 specification
* reworked the host-side pdev lifecycle to better match the RMM 2.0bet1 flow, including common pdev state, root-port pdev support, and non-coherent stream setup and teardown
* split PF0 setup into identity collection and conditional public-key installation, and gate DA enablement on RMI_FEATURE_REGISTER_2_DA
* added coordinated handling for RMI_DEV_COMM_EXIT_STREAM_WAIT, along with stream connect/disconnect and stream key refresh/purge support during vdev teardown

Changes from v2:
rfc-v2 https://lore.kernel.org/all/[email protected]
* rebase to latest kernel and core TSM changes
* Address review feedback.

v1:
rfc-v1 https://lore.kernel.org/all/[email protected]

[1] https://developer.arm.com/documentation/den0137/2-0bet1/
[2] https://lore.kernel.org/all/[email protected]
[3] https://lore.kernel.org/all/[email protected]
[4] https://gitlab.arm.com/linux-arm/linux-cca.git cca/topics/cca-tdisp-upstream-rfc-v4

Cc Alexey Kardashevskiy <[email protected]>
Cc Catalin Marinas <[email protected]>
Cc Dan Williams <[email protected]>
Cc Jason Gunthorpe <[email protected]>
Cc Jonathan Cameron <[email protected]>
Cc Marc Zyngier <[email protected]>
Cc Samuel Ortiz <[email protected]>
Cc Steven Price <[email protected]>
Cc Suzuki K Poulose <[email protected]>
Cc Will Deacon <[email protected]>
Cc Xu Yilun <[email protected]>

Aneesh Kumar K.V (Arm) (11):
coco: host: arm64: Add host TSM callback and IDE stream allocation
support
coco: host: arm64: Create RMM pdev objects for PCI endpoints
coco: host: arm64: Add RMM device communication helpers
coco: host: arm64: Add helper to stop and tear down an RMM pdev
coco: host: arm64: Register device public key with RMM
coco: host: arm64: Initialize RMM pdev state for TDISP IDE connect
coco: host: arm64: Coordinate peer stream waits during pdev
communication
coco: host: arm64: Connect RMM pdev streams for IDE devices
coco: host: arm64: Refcount root-port pdevs used by IDE streams PCI/TSM: Move CMA DOE mailbox discovery out of
pci_tsm_pf0_constructor()
coco: host: arm64: Add NCOH_SYS stream support for RC endpoints

Lukas Wunner (3):
X.509: Make certificate parser public
X.509: Parse Subject Alternative Name in certificates X.509: Move certificate length retrieval into new helper

 arch/arm64/include/asm/rmi_cmds.h         |  85 +++
 arch/arm64/include/asm/rmi_smc.h          | 168 +++++
 crypto/asymmetric_keys/x509_cert_parser.c |   9 +
 crypto/asymmetric_keys/x509_loader.c      |  38 +-
 crypto/asymmetric_keys/x509_parser.h      |  42 +-
 drivers/crypto/ccp/sev-dev-tsm.c          |  13 +
 drivers/firmware/smccc/rmm.c              |  12 +
 drivers/firmware/smccc/rmm.h              |   8 +
 drivers/firmware/smccc/smccc.c            |   1 +
 drivers/pci/tsm/core.c                    |  14 +-
 drivers/virt/coco/Kconfig                 |   2 +
 drivers/virt/coco/Makefile                |   1 +
 drivers/virt/coco/arm-cca-host/Kconfig    |  23 +
 drivers/virt/coco/arm-cca-host/Makefile   |   5 +
 drivers/virt/coco/arm-cca-host/arm-cca.c  | 494 ++++++++++++
 drivers/virt/coco/arm-cca-host/rmi-da.c   | 867 ++++++++++++++++++++++
 drivers/virt/coco/arm-cca-host/rmi-da.h   | 217 ++++++
 drivers/virt/coco/tdx-host/tdx-host.c     |  13 +
 include/keys/asymmetric-type.h            |   2 +
 include/keys/x509-parser.h                |  57 ++
 20 files changed, 2012 insertions(+), 59 deletions(-)
 create mode 100644 drivers/virt/coco/arm-cca-host/Kconfig
 create mode 100644 drivers/virt/coco/arm-cca-host/Makefile
 create mode 100644 drivers/virt/coco/arm-cca-host/arm-cca.c
 create mode 100644 drivers/virt/coco/arm-cca-host/rmi-da.c
 create mode 100644 drivers/virt/coco/arm-cca-host/rmi-da.h
 create mode 100644 include/keys/x509-parser.h
Signature · 1 line
2.43.0
#1 lore raw

RFC PATCH v4 1/14 coco: host: arm64: Add host TSM callback and IDE stream allocation support

Register the TSM callback when the DA feature is supported by KVM.

This driver handles IDE stream setup for both the root port and PCIe endpoints. Root port IDE stream enablement itself is managed by RMM.

In addition, the driver registers pci_tsm_ops with the TSM subsystem.

---
 arch/arm64/include/asm/rmi_smc.h         |   2 +
 drivers/firmware/smccc/rmm.c             |  12 ++
 drivers/firmware/smccc/rmm.h             |   8 +
 drivers/firmware/smccc/smccc.c           |   1 +
 drivers/virt/coco/Kconfig                |   2 +
 drivers/virt/coco/Makefile               |   1 +
 drivers/virt/coco/arm-cca-host/Kconfig   |  19 ++
 drivers/virt/coco/arm-cca-host/Makefile  |   5 +
 drivers/virt/coco/arm-cca-host/arm-cca.c | 225 +++++++++++++++++++++++
 drivers/virt/coco/arm-cca-host/rmi-da.h  |  46 +++++
 10 files changed, 321 insertions(+)
 create mode 100644 drivers/virt/coco/arm-cca-host/Kconfig
 create mode 100644 drivers/virt/coco/arm-cca-host/Makefile
 create mode 100644 drivers/virt/coco/arm-cca-host/arm-cca.c
 create mode 100644 drivers/virt/coco/arm-cca-host/rmi-da.h
arch/arm64/include/asm/rmi_smc.h +2 -0
index fa23818e1b4c..109d6cc6ef37 100644
@@ -12,6 +12,8 @@
 
 #include <linux/arm-smccc.h>
 
+#define RMI_DEV_NAME "arm-rmi-dev"
+
 #define SMC_RMI_CALL(func)				\
 	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,		\
 			   ARM_SMCCC_SMC_64,		\
drivers/firmware/smccc/rmm.c +12 -0
index 2a6187df3285..7444cc3a588c 100644
@@ -21,3 +21,15 @@ void __init register_rsi_device(struct platform_device *pdev)
 	__devm_auxiliary_device_create(&pdev->dev,
 				       "arm_cca_guest", RSI_DEV_NAME, NULL, 0);
 }
+
+void __init register_rmi_device(struct platform_device *pdev)
+{
+	struct arm_smccc_res res;
+	unsigned long host_version = RMI_ABI_VERSION(RMI_ABI_MAJOR_VERSION,
+						     RMI_ABI_MINOR_VERSION);
+
+	arm_smccc_1_1_invoke(SMC_RMI_VERSION, host_version, &res);
+	if (res.a0 == RMI_SUCCESS)
+		__devm_auxiliary_device_create(&pdev->dev,
+					"arm_cca_host", RMI_DEV_NAME, NULL, 0);
+}
drivers/firmware/smccc/rmm.h +8 -0
index a47a650d4f51..37d0d95a099e 100644
@@ -6,12 +6,20 @@
 
 #ifdef CONFIG_ARM64
 #include <asm/rsi_cmds.h>
+#include <asm/rmi_smc.h>
+
 void __init register_rsi_device(struct platform_device *pdev);
+void __init register_rmi_device(struct platform_device *pdev);
 #else
 
 static void __init register_rsi_device(struct platform_device *pdev)
 {
 
+}
+
+static void __init register_rmi_device(struct platform_device *pdev)
+{
+
 }
 #endif
 #endif
drivers/firmware/smccc/smccc.c +1 -0
index fc9b44b7c687..2bf2d59e686d 100644
@@ -97,6 +97,7 @@ static int __init smccc_devices_init(void)
 		 * the required SMCCC function IDs at a supported revision.
 		 */
 		register_rsi_device(pdev);
+		register_rmi_device(pdev);
 	}
 
 	if (smccc_trng_available) {
drivers/virt/coco/Kconfig +2 -0
index f7691f64fbe3..1cbc2134f9ea 100644
@@ -19,5 +19,7 @@ endif
 
 source "drivers/virt/coco/tdx-host/Kconfig"
 
+source "drivers/virt/coco/arm-cca-host/Kconfig"
+
 config TSM
 	bool
drivers/virt/coco/Makefile +1 -0
index b323b0ae4f82..f2310c34daf9 100644
@@ -10,3 +10,4 @@ obj-$(CONFIG_INTEL_TDX_HOST)	+= tdx-host/
 obj-$(CONFIG_ARM_CCA_GUEST)	+= arm-cca-guest/
 obj-$(CONFIG_TSM) 		+= tsm-core.o
 obj-$(CONFIG_TSM_GUEST)		+= guest/
+obj-$(CONFIG_ARM_CCA_HOST)	+= arm-cca-host/
drivers/virt/coco/arm-cca-host/Kconfig new file +19 -0
new file mode 100644
index 000000000000..efe40d61d5d8
@@ -0,0 +1,19 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# TSM (TEE Security Manager) host drivers
+#
+config ARM_CCA_HOST
+	tristate "Arm CCA Host driver"
+	depends on ARM64
+	depends on PCI
+	depends on KVM
+	select PCI_TSM
+	select AUXILIARY_BUS
+
+	help
+	  ARM CCA RMM firmware is the trusted runtime that enforces memory
+	  isolation and security for confidential computing on ARM. This driver
+	  provides the interface for communicating with RMM to support secure
+	  device assignment.
+
+	  If you choose 'M' here, this module will be called arm-cca-host.
drivers/virt/coco/arm-cca-host/Makefile new file +5 -0
new file mode 100644
index 000000000000..c236827f002c
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+obj-$(CONFIG_ARM_CCA_HOST) += arm-cca-host.o
+
+arm-cca-host-y	+=  arm-cca.o
drivers/virt/coco/arm-cca-host/arm-cca.c new file +225 -0

225 lines not on this page · raw message

drivers/virt/coco/arm-cca-host/rmi-da.h new file +46 -0

46 lines not on this page · raw message

Signature · 1 line
2.43.0
#2 lore raw

Re: [RFC PATCH v4 01/14] coco: host: arm64: Add host TSM callback and IDE stream allocation support

Quoted 6 lines · Aneesh Kumar K.V (Arm)

Register the TSM callback when the DA feature is supported by KVM.

This driver handles IDE stream setup for both the root port and PCIe endpoints. Root port IDE stream enablement itself is managed by RMM.

In addition, the driver registers pci_tsm_ops with the TSM subsystem.

Do you want to call out that this is an infrastructure / scaffolding patch that only handles the PCI-TSM skeleton. The CCA meat comes later, in particular IDE key management. Tell a bit more of the story

Otherwise, mostly looks good.

Minor comments below...

Quoted 22 lines
---
 arch/arm64/include/asm/rmi_smc.h         |   2 +
 drivers/firmware/smccc/rmm.c             |  12 ++
 drivers/firmware/smccc/rmm.h             |   8 +
 drivers/firmware/smccc/smccc.c           |   1 +
 drivers/virt/coco/Kconfig                |   2 +
 drivers/virt/coco/Makefile               |   1 +
 drivers/virt/coco/arm-cca-host/Kconfig   |  19 ++
 drivers/virt/coco/arm-cca-host/Makefile  |   5 +
 drivers/virt/coco/arm-cca-host/arm-cca.c | 225 +++++++++++++++++++++++
 drivers/virt/coco/arm-cca-host/rmi-da.h  |  46 +++++
 10 files changed, 321 insertions(+)
 create mode 100644 drivers/virt/coco/arm-cca-host/Kconfig
 create mode 100644 drivers/virt/coco/arm-cca-host/Makefile
 create mode 100644 drivers/virt/coco/arm-cca-host/arm-cca.c
 create mode 100644 drivers/virt/coco/arm-cca-host/rmi-da.h
arch/arm64/include/asm/rmi_smc.h +0 -0
index fa23818e1b4c..109d6cc6ef37 100644

[..]

Quoted 4 lines
drivers/firmware/smccc/rmm.c +0 -0
index 2a6187df3285..7444cc3a588c 100644

[..]

Quoted 4 lines
drivers/firmware/smccc/rmm.h +0 -0
index a47a650d4f51..37d0d95a099e 100644

[..]

drivers/firmware/smccc/smccc.c static int __init smccc_devices_init(void) · line 101

Quoted 10 lines
drivers/firmware/smccc/smccc.c +1 -0
index fc9b44b7c687..2bf2d59e686d 100644
@@ -97,6 +97,7 @@ static int __init smccc_devices_init(void)
 		 * the required SMCCC function IDs at a supported revision.
 		 */
 		register_rsi_device(pdev);
+		register_rmi_device(pdev);
 	}

Would splitting the above three hunks make this series stand on its own relative to the base CCA series? I assume likely not as soon as we get to patch2.

Otherwise, just curious what your intended merge strategy is for this, tsm.git or arm.git, and what help this needs?

[..]
snip code that looks good.

Quoted 33 lines
drivers/virt/coco/arm-cca-host/Makefile new file +5 -0
new file mode 100644
index 000000000000..c236827f002c
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+obj-$(CONFIG_ARM_CCA_HOST) += arm-cca-host.o
+
+arm-cca-host-y	+=  arm-cca.o
drivers/virt/coco/arm-cca-host/arm-cca.c new file +16 -0
new file mode 100644
index 000000000000..67f7e80106e8
@@ -0,0 +1,225 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2026 ARM Ltd.
+ */
+
+#include <linux/auxiliary_bus.h>
+#include <linux/pci-tsm.h>
+#include <linux/pci-ide.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/tsm.h>
+#include <linux/vmalloc.h>
+#include <linux/cleanup.h>
+
+#include "rmi-da.h"
+

drivers/virt/coco/arm-cca-host/arm-cca.c line 26

Quoted 10 lines
drivers/virt/coco/arm-cca-host/arm-cca.c new file +10 -0
+/* Total number of stream id supported at root port level */
+#define MAX_STREAM_ID	256
+
+static struct pci_tsm *cca_tsm_pci_probe(struct tsm_dev *tsm_dev, struct pci_dev *pdev)
+{
+	int ret;
+
+	if (!is_pci_tsm_pf0(pdev)) {
+		struct cca_host_fn_dsc *fn_dsc __free(kfree) =
+			kzalloc(sizeof(*fn_dsc), GFP_KERNEL);

kzalloc_obj(*fn_dsc)

drivers/virt/coco/arm-cca-host/arm-cca.c line 39

Quoted 13 lines
drivers/virt/coco/arm-cca-host/arm-cca.c new file +13 -0
+
+		if (!fn_dsc)
+			return NULL;
+
+		ret = pci_tsm_link_constructor(pdev, &fn_dsc->pci, tsm_dev);
+		if (ret)
+			return NULL;
+
+		return &no_free_ptr(fn_dsc)->pci;
+	}
+
+	if (!pdev->ide_cap)
+		return NULL;

Bailing early?

Maybe the RMM knows something about this device not needing IDE? I have a similar question in patch2 around trusted sources for whether a device is internal or not.

Quoted 35 lines
drivers/virt/coco/arm-cca-host/arm-cca.c new file +35 -0
+
+	struct cca_host_pf0_ep_dsc *pf0_ep_dsc __free(kfree) =
+		kzalloc(sizeof(*pf0_ep_dsc), GFP_KERNEL);
+	if (!pf0_ep_dsc)
+		return NULL;
+
+	ret = pci_tsm_pf0_constructor(pdev, &pf0_ep_dsc->pci, tsm_dev);
+	if (ret)
+		return NULL;
+
+	pci_dbg(pdev, "tsm enabled\n");
+	return &no_free_ptr(pf0_ep_dsc)->pci.base_tsm;
+}
+
+static void cca_tsm_pci_remove(struct pci_tsm *tsm)
+{
+	struct pci_dev *pdev = tsm->pdev;
+
+	if (is_pci_tsm_pf0(pdev)) {
+		struct cca_host_pf0_ep_dsc *pf0_ep_dsc = to_cca_pf0_ep_dsc(pdev);
+
+		pci_tsm_pf0_destructor(&pf0_ep_dsc->pci);
+		kfree(pf0_ep_dsc);
+	} else {
+		kfree(to_cca_fn_dsc(pdev));
+	}
+}
+
+/* For now global for simplicity. Protected by pci_tsm_rwsem */
+static DECLARE_BITMAP(cca_stream_ids, MAX_STREAM_ID);
+static int alloc_stream_id(struct pci_host_bridge *hb)
+{
+	int stream_id;
+
+redo_alloc:

drivers/virt/coco/arm-cca-host/arm-cca.c line 84

Quoted 10 lines
drivers/virt/coco/arm-cca-host/arm-cca.c new file +10 -0
+	stream_id = find_first_zero_bit(cca_stream_ids, MAX_STREAM_ID);
+	if (stream_id == MAX_STREAM_ID)
+		return stream_id;
+
+	if (ida_exists(&hb->ide_stream_ids_ida, stream_id)) {
+		/* mark the stream allocated in the global bitmap. */
+		set_bit(stream_id, cca_stream_ids);
+		goto redo_alloc;
+	}
+	return stream_id;

Is 256 total an RMM limit, and/or does it require globally unique stream-ids? If not you could do what SEV-TIO does and just set stream-id == stream-index.

Quoted 48 lines
drivers/virt/coco/arm-cca-host/arm-cca.c new file +48 -0
+}
+
+static inline bool cca_pdev_need_sel_ide_streams(struct pci_dev *pdev)
+{
+	return pci_pcie_type(pdev) == PCI_EXP_TYPE_ENDPOINT;
+}
+
+static int cca_tsm_connect(struct pci_dev *pdev)
+{
+	struct pci_dev *rp = pcie_find_root_port(pdev);
+	struct cca_host_pf0_ep_dsc *pf0_ep_dsc;
+	struct pci_ide *ide;
+	int ret, stream_id = 0;
+
+	/* Only function 0 supports connect in host */
+	if (WARN_ON(!is_pci_tsm_pf0(pdev)))
+		return -EIO;
+
+	pf0_ep_dsc = to_cca_pf0_ep_dsc(pdev);
+	if (cca_pdev_need_sel_ide_streams(pdev)) {
+		/* Allocate stream id */
+		stream_id = alloc_stream_id(pci_find_host_bridge(pdev->bus));
+		if (stream_id == MAX_STREAM_ID)
+			return -EBUSY;
+		set_bit(stream_id, cca_stream_ids);
+
+		ide = pci_ide_stream_alloc(pdev);
+		if (!ide) {
+			ret = -ENOMEM;
+			goto err_stream_alloc;
+		}
+
+		pf0_ep_dsc->sel_stream = ide;
+		ide->stream_id = stream_id;
+		ret = pci_ide_stream_register(ide);
+		if (ret)
+			goto err_stream;
+		/*
+		 * Configure IDE capability for target device
+		 *
+		 * Some test devices work only with DEFAULT_STREAM enabled.
+		 * For simplicity, enable DEFAULT_STREAM for all devices. A
+		 * future decent solution may be to have a quirk table to
+		 * specify which devices need DEFAULT_STREAM.
+		 */
+		ide->partner[PCI_IDE_EP].default_stream = 1;
+		pci_ide_stream_setup(pdev, ide);
+		pci_ide_stream_setup(rp, ide);

drivers/virt/coco/arm-cca-host/arm-cca.c line 142

Quoted 10 lines
drivers/virt/coco/arm-cca-host/arm-cca.c new file +10 -0
+
+		ret = tsm_ide_stream_register(ide);
+		if (ret)
+			goto err_tsm;
+
+		/*
+		 * Once ide is setup, enable the stream at the endpoint
+		 * Root port will be done by RMM
+		 */
+		pci_ide_stream_enable(pdev, ide);

The end point of these patches follows the spec recommendation of delaying enable until after key programming.

drivers/virt/coco/arm-cca-host/arm-cca.c line 144

Quoted 2 lines
drivers/virt/coco/arm-cca-host/arm-cca.c new file +2 -0
+	}
+	return 0;

Should this be making security claims to userspace without taking any action for non-endpoint devices that happen to be passed in?

Thinking about a bisection case this should either fail here, print a message that is removed in the final enabling patch, or do the __maybe_unused arrangement to land all the CCA bits first and then do this hookup. Up to you.

#3 lore raw

Re: [RFC PATCH v4 01/14] coco: host: arm64: Add host TSM callback and IDE stream allocation support

Quoted 6 lines · Dan Williams (nvidia)
Quoted 5 lines · Aneesh Kumar K.V (Arm)

Register the TSM callback when the DA feature is supported by KVM.

This driver handles IDE stream setup for both the root port and PCIe endpoints. Root port IDE stream enablement itself is managed by RMM.

Quoted 8 lines
Quoted 1 line

In addition, the driver registers pci_tsm_ops with the TSM subsystem.

Do you want to call out that this is an infrastructure / scaffolding patch that only handles the PCI-TSM skeleton. The CCA meat comes later, in particular IDE key management. Tell a bit more of the story

Otherwise, mostly looks good.

Sure, I’ll update the commit message.

Quoted 51 lines

Minor comments below...

Quoted 22 lines
---
 arch/arm64/include/asm/rmi_smc.h         |   2 +
 drivers/firmware/smccc/rmm.c             |  12 ++
 drivers/firmware/smccc/rmm.h             |   8 +
 drivers/firmware/smccc/smccc.c           |   1 +
 drivers/virt/coco/Kconfig                |   2 +
 drivers/virt/coco/Makefile               |   1 +
 drivers/virt/coco/arm-cca-host/Kconfig   |  19 ++
 drivers/virt/coco/arm-cca-host/Makefile  |   5 +
 drivers/virt/coco/arm-cca-host/arm-cca.c | 225 +++++++++++++++++++++++
 drivers/virt/coco/arm-cca-host/rmi-da.h  |  46 +++++
 10 files changed, 321 insertions(+)
 create mode 100644 drivers/virt/coco/arm-cca-host/Kconfig
 create mode 100644 drivers/virt/coco/arm-cca-host/Makefile
 create mode 100644 drivers/virt/coco/arm-cca-host/arm-cca.c
 create mode 100644 drivers/virt/coco/arm-cca-host/rmi-da.h
arch/arm64/include/asm/rmi_smc.h +0 -0
index fa23818e1b4c..109d6cc6ef37 100644

[..]

Quoted 4 lines
drivers/firmware/smccc/rmm.c +0 -0
index 2a6187df3285..7444cc3a588c 100644

[..]

Quoted 4 lines
drivers/firmware/smccc/rmm.h +0 -0
index a47a650d4f51..37d0d95a099e 100644

[..]

drivers/firmware/smccc/smccc.c static int __init smccc_devices_init(void) · line 101

Quoted 10 lines
drivers/firmware/smccc/smccc.c +1 -0
index fc9b44b7c687..2bf2d59e686d 100644
@@ -97,6 +97,7 @@ static int __init smccc_devices_init(void)
 		 * the required SMCCC function IDs at a supported revision.
 		 */
 		register_rsi_device(pdev);
+		register_rmi_device(pdev);
 	}

Would splitting the above three hunks make this series stand on its own relative to the base CCA series? I assume likely not as soon as we get to patch2.

Quoted 6 lines

Otherwise, just curious what your intended merge strategy is for this, tsm.git or arm.git, and what help this needs?

[..]
snip code that looks good.

Yes, I’ll split this into a separate patch.

Quoted 63 lines
Quoted 34 lines
drivers/virt/coco/arm-cca-host/Makefile new file +5 -0
new file mode 100644
index 000000000000..c236827f002c
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+obj-$(CONFIG_ARM_CCA_HOST) += arm-cca-host.o
+
+arm-cca-host-y	+=  arm-cca.o
drivers/virt/coco/arm-cca-host/arm-cca.c new file +16 -0
new file mode 100644
index 000000000000..67f7e80106e8
@@ -0,0 +1,225 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2026 ARM Ltd.
+ */
+
+#include <linux/auxiliary_bus.h>
+#include <linux/pci-tsm.h>
+#include <linux/pci-ide.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/tsm.h>
+#include <linux/vmalloc.h>
+#include <linux/cleanup.h>
+
+#include "rmi-da.h"
+

drivers/virt/coco/arm-cca-host/arm-cca.c line 26

Quoted 10 lines
drivers/virt/coco/arm-cca-host/arm-cca.c new file +10 -0
+/* Total number of stream id supported at root port level */
+#define MAX_STREAM_ID	256
+
+static struct pci_tsm *cca_tsm_pci_probe(struct tsm_dev *tsm_dev, struct pci_dev *pdev)
+{
+	int ret;
+
+	if (!is_pci_tsm_pf0(pdev)) {
+		struct cca_host_fn_dsc *fn_dsc __free(kfree) =
+			kzalloc(sizeof(*fn_dsc), GFP_KERNEL);

kzalloc_obj(*fn_dsc)

drivers/virt/coco/arm-cca-host/arm-cca.c line 39

Quoted 13 lines
drivers/virt/coco/arm-cca-host/arm-cca.c new file +13 -0
+
+		if (!fn_dsc)
+			return NULL;
+
+		ret = pci_tsm_link_constructor(pdev, &fn_dsc->pci, tsm_dev);
+		if (ret)
+			return NULL;
+
+		return &no_free_ptr(fn_dsc)->pci;
+	}
+
+	if (!pdev->ide_cap)
+		return NULL;

Bailing early?

Quoted 4 lines

Maybe the RMM knows something about this device not needing IDE? I have a similar question in patch2 around trusted sources for whether a device is internal or not.

Yes. This get updated later in
https://lore.kernel.org/all/[email protected]

Quoted 42 lines
Quoted 42 lines
drivers/virt/coco/arm-cca-host/arm-cca.c new file +41 -0
+
+	struct cca_host_pf0_ep_dsc *pf0_ep_dsc __free(kfree) =
+		kzalloc(sizeof(*pf0_ep_dsc), GFP_KERNEL);
+	if (!pf0_ep_dsc)
+		return NULL;
+
+	ret = pci_tsm_pf0_constructor(pdev, &pf0_ep_dsc->pci, tsm_dev);
+	if (ret)
+		return NULL;
+
+	pci_dbg(pdev, "tsm enabled\n");
+	return &no_free_ptr(pf0_ep_dsc)->pci.base_tsm;
+}
+
+static void cca_tsm_pci_remove(struct pci_tsm *tsm)
+{
+	struct pci_dev *pdev = tsm->pdev;
+
+	if (is_pci_tsm_pf0(pdev)) {
+		struct cca_host_pf0_ep_dsc *pf0_ep_dsc = to_cca_pf0_ep_dsc(pdev);
+
+		pci_tsm_pf0_destructor(&pf0_ep_dsc->pci);
+		kfree(pf0_ep_dsc);
+	} else {
+		kfree(to_cca_fn_dsc(pdev));
+	}
+}
+
+/* For now global for simplicity. Protected by pci_tsm_rwsem */
+static DECLARE_BITMAP(cca_stream_ids, MAX_STREAM_ID);
+static int alloc_stream_id(struct pci_host_bridge *hb)
+{
+	int stream_id;
+
+redo_alloc:
+	stream_id = find_first_zero_bit(cca_stream_ids, MAX_STREAM_ID);
+	if (stream_id == MAX_STREAM_ID)
+		return stream_id;
+
+	if (ida_exists(&hb->ide_stream_ids_ida, stream_id)) {
+		/* mark the stream allocated in the global bitmap. */
Quoted 9 lines

drivers/virt/coco/arm-cca-host/arm-cca.c line 84

Quoted 4 lines
drivers/virt/coco/arm-cca-host/arm-cca.c new file +4 -0
+		set_bit(stream_id, cca_stream_ids);
+		goto redo_alloc;
+	}
+	return stream_id;

Is 256 total an RMM limit, and/or does it require globally unique stream-ids? If not you could do what SEV-TIO does and just set stream-id == stream-index.

Yes, I’ll switch to that.

Quoted 69 lines
Quoted 49 lines
drivers/virt/coco/arm-cca-host/arm-cca.c new file +48 -0
+}
+
+static inline bool cca_pdev_need_sel_ide_streams(struct pci_dev *pdev)
+{
+	return pci_pcie_type(pdev) == PCI_EXP_TYPE_ENDPOINT;
+}
+
+static int cca_tsm_connect(struct pci_dev *pdev)
+{
+	struct pci_dev *rp = pcie_find_root_port(pdev);
+	struct cca_host_pf0_ep_dsc *pf0_ep_dsc;
+	struct pci_ide *ide;
+	int ret, stream_id = 0;
+
+	/* Only function 0 supports connect in host */
+	if (WARN_ON(!is_pci_tsm_pf0(pdev)))
+		return -EIO;
+
+	pf0_ep_dsc = to_cca_pf0_ep_dsc(pdev);
+	if (cca_pdev_need_sel_ide_streams(pdev)) {
+		/* Allocate stream id */
+		stream_id = alloc_stream_id(pci_find_host_bridge(pdev->bus));
+		if (stream_id == MAX_STREAM_ID)
+			return -EBUSY;
+		set_bit(stream_id, cca_stream_ids);
+
+		ide = pci_ide_stream_alloc(pdev);
+		if (!ide) {
+			ret = -ENOMEM;
+			goto err_stream_alloc;
+		}
+
+		pf0_ep_dsc->sel_stream = ide;
+		ide->stream_id = stream_id;
+		ret = pci_ide_stream_register(ide);
+		if (ret)
+			goto err_stream;
+		/*
+		 * Configure IDE capability for target device
+		 *
+		 * Some test devices work only with DEFAULT_STREAM enabled.
+		 * For simplicity, enable DEFAULT_STREAM for all devices. A
+		 * future decent solution may be to have a quirk table to
+		 * specify which devices need DEFAULT_STREAM.
+		 */
+		ide->partner[PCI_IDE_EP].default_stream = 1;
+		pci_ide_stream_setup(pdev, ide);
+		pci_ide_stream_setup(rp, ide);

drivers/virt/coco/arm-cca-host/arm-cca.c line 142

Quoted 10 lines
drivers/virt/coco/arm-cca-host/arm-cca.c new file +10 -0
+
+		ret = tsm_ide_stream_register(ide);
+		if (ret)
+			goto err_tsm;
+
+		/*
+		 * Once ide is setup, enable the stream at the endpoint
+		 * Root port will be done by RMM
+		 */
+		pci_ide_stream_enable(pdev, ide);

The end point of these patches follows the spec recommendation of delaying enable until after key programming.

drivers/virt/coco/arm-cca-host/arm-cca.c line 144

Quoted 2 lines
drivers/virt/coco/arm-cca-host/arm-cca.c new file +2 -0
+	}
+	return 0;

Should this be making security claims to userspace without taking any action for non-endpoint devices that happen to be passed in?

Quoted 4 lines

Thinking about a bisection case this should either fail here, print a message that is removed in the final enabling patch, or do the __maybe_unused arrangement to land all the CCA bits first and then do this hookup. Up to you.

Will do the latter. ie, I’ll call tsm_register() only in the final patch.

-aneesh

#4 lore raw

RFC PATCH v4 2/14 coco: host: arm64: Create RMM pdev objects for PCI endpoints

In reply to Aneesh Kumar K.V (Arm)

Add the RMI definitions needed for pdev management, including the pdev state enum, parameter layout, and helpers for RMI_PDEV_CREATE and RMI_PDEV_GET_STATE.

Introduce a host-side pdev descriptor and cca_pdev_create() to allocate and delegate the backing granule, populate the pdev parameters from the PCI endpoint, and issue RMI_PDEV_CREATE to the RMM.

The new helper stores the created RMM pdev handle in the PF0 endpoint descriptor preparing the device for later IDE/TDISP setup.

---
 arch/arm64/include/asm/rmi_cmds.h       |  10 ++
 arch/arm64/include/asm/rmi_smc.h        |  49 ++++++++
 drivers/virt/coco/arm-cca-host/Makefile |   2 +-
 drivers/virt/coco/arm-cca-host/rmi-da.c | 151 ++++++++++++++++++++++++
 drivers/virt/coco/arm-cca-host/rmi-da.h |  26 ++++
 5 files changed, 237 insertions(+), 1 deletion(-)
 create mode 100644 drivers/virt/coco/arm-cca-host/rmi-da.c
arch/arm64/include/asm/rmi_cmds.h +10 -0
index 2901fc84d245..d23a0590c7ee 100644
@@ -726,4 +726,14 @@ static inline int rmi_rtt_unmap_unprotected(unsigned long rd,
 	return res.a0;
 }
 
+static inline unsigned long rmi_pdev_get_state(unsigned long pdev_phys, enum rmi_pdev_state *state)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_PDEV_GET_STATE, pdev_phys, &res);
+
+	*state = res.a1;
+	return res.a0;
+}
+
 #endif /* __ASM_RMI_CMDS_H */
arch/arm64/include/asm/rmi_smc.h +49 -0

53 lines not on this page · raw message

drivers/virt/coco/arm-cca-host/Makefile +1 -1
index c236827f002c..d48e8940af46 100644
@@ -2,4 +2,4 @@
 #
 obj-$(CONFIG_ARM_CCA_HOST) += arm-cca-host.o
 
-arm-cca-host-y	+=  arm-cca.o
+arm-cca-host-y	+=  arm-cca.o rmi-da.o
drivers/virt/coco/arm-cca-host/rmi-da.c new file +151 -0

151 lines not on this page · raw message

drivers/virt/coco/arm-cca-host/rmi-da.h +26 -0
index 4abc7ad159e5..de67f10ce20e 100644
@@ -12,13 +12,26 @@
 #include <asm/rmi_cmds.h>
 #include <asm/rmi_smc.h>
 
+/**
+ * struct cca_host_pdev_dsc - Common RMM pdev context
+ * @rmm_pdev: Delegated page backing the RMM pdev object
+ * @object_lock: Serializes access to the RMM pdev object and PF0/TDI caches
+ */
+struct cca_host_pdev_dsc {
+	void *rmm_pdev;
+	/* lock kept here to simplify the generic lock/unlock paths. */
+	struct mutex object_lock;
+};
+
 /**
  * struct cca_host_pf0_ep_dsc - PF0 endpoint device security context.
  * @pci: Physical Function 0 TDISP link context
+ * @pdev: pdev communication context
  * @sel_stream: Selective IDE Stream descriptor
  */
 struct cca_host_pf0_ep_dsc {
 	struct pci_tsm_pf0 pci;
+	struct cca_host_pdev_dsc pdev;
 	struct pci_ide *sel_stream;
 };
 
@@ -43,4 +56,17 @@ static inline struct cca_host_fn_dsc *to_cca_fn_dsc(struct pci_dev *pdev)
 	return container_of(tsm, struct cca_host_fn_dsc, pci);
 }
 
+static inline struct cca_host_pdev_dsc *to_cca_pdev_dsc(struct pci_dev *pdev)
+{
+	struct cca_host_pf0_ep_dsc *pf0_ep_dsc;
+
+	pf0_ep_dsc = to_cca_pf0_ep_dsc(pdev);
+	if (pf0_ep_dsc)
+		return &pf0_ep_dsc->pdev;
+
+	return NULL;
+}
+
+int cca_pdev_create(struct pci_dev *pdev);
+
 #endif
Signature · 1 line
2.43.0
#5 lore raw

RFC PATCH v4 3/14 coco: host: arm64: Add RMM device communication helpers

In reply to Aneesh Kumar K.V (Arm)

- add SMCCC IDs/wrappers for RMI_PDEV_COMMUNICATE/RMI_PDEV_ABORT
- describe the RMM device-communication ABI (struct rmi_dev_comm_*, cache flags, protocol/object IDs, busy error code)
- track per-PF0 communication state (buffers, workqueue, cache metadata) and serialize access behind object_lock
- plumb a DOE/SPDM worker plus shared helpers that submit the SMCCC call, cache multi-part responses, and handle retries/abort

---
 arch/arm64/include/asm/rmi_cmds.h        |  20 ++
 arch/arm64/include/asm/rmi_smc.h         |  60 +++++
 drivers/virt/coco/arm-cca-host/arm-cca.c |  50 ++++
 drivers/virt/coco/arm-cca-host/rmi-da.c  | 276 +++++++++++++++++++++++
 drivers/virt/coco/arm-cca-host/rmi-da.h  |  65 ++++++
 5 files changed, 471 insertions(+)
arch/arm64/include/asm/rmi_cmds.h +20 -0
index d23a0590c7ee..6664c439173f 100644
@@ -736,4 +736,24 @@ static inline unsigned long rmi_pdev_get_state(unsigned long pdev_phys, enum rmi
 	return res.a0;
 }
 
+static inline unsigned long rmi_pdev_communicate(unsigned long pdev_phys,
+						 unsigned long pdev_comm_data_phys)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_PDEV_COMMUNICATE,
+			     pdev_phys, pdev_comm_data_phys, &res);
+
+	return res.a0;
+}
+
+static inline unsigned long rmi_pdev_abort(unsigned long pdev_phys)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_PDEV_ABORT, pdev_phys, &res);
+
+	return res.a0;
+}
+
 #endif /* __ASM_RMI_CMDS_H */
arch/arm64/include/asm/rmi_smc.h +60 -0

64 lines not on this page · raw message

drivers/virt/coco/arm-cca-host/arm-cca.c +50 -0

62 lines not on this page · raw message

drivers/virt/coco/arm-cca-host/rmi-da.c +276 -0

285 lines not on this page · raw message

drivers/virt/coco/arm-cca-host/rmi-da.h +65 -0

103 lines not on this page · raw message

Signature · 1 line
2.43.0
#6 lore raw

RFC PATCH v4 4/14 coco: host: arm64: Add helper to stop and tear down an RMM pdev

In reply to Aneesh Kumar K.V (Arm)

Add helper to stop and tear down an RMM pdev
- describe the RMI_PDEV_STOP/RMI_PDEV_DESTROY SMC IDs and provide wrappers in rmi_cmds.h
- implement pdev_stop_and_destroy() so the host driver stops the pdev, waits for it to reach RMI_PDEV_STOPPED and destroys it

---
 arch/arm64/include/asm/rmi_cmds.h       |  9 +++++
 drivers/virt/coco/arm-cca-host/rmi-da.c | 47 ++++++++++++++++++++++++-
 drivers/virt/coco/arm-cca-host/rmi-da.h |  1 +
 3 files changed, 56 insertions(+), 1 deletion(-)
arch/arm64/include/asm/rmi_cmds.h +9 -0
index 6664c439173f..8024e9d89e55 100644
@@ -756,4 +756,13 @@ static inline unsigned long rmi_pdev_abort(unsigned long pdev_phys)
 	return res.a0;
 }
 
+static inline unsigned long rmi_pdev_stop(unsigned long pdev_phys)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_PDEV_STOP, pdev_phys, &res);
+
+	return res.a0;
+}
+
 #endif /* __ASM_RMI_CMDS_H */
drivers/virt/coco/arm-cca-host/rmi-da.c +46 -1

56 lines not on this page · raw message

drivers/virt/coco/arm-cca-host/rmi-da.h +1 -0
index 9f72ff8f28bf..784eb1fff95d 100644
@@ -133,5 +133,6 @@ static inline struct cca_host_comm_data *to_cca_comm_data(struct pci_dev *pdev)
 }
 
 int cca_pdev_create(struct pci_dev *pdev);
+void cca_pdev_stop_and_destroy(struct pci_dev *pdev);
 
 #endif
Signature · 1 line
2.43.0
#7 lore raw

RFC PATCH v4 5/14 X.509: Make certificate parser public

In reply to Aneesh Kumar K.V (Arm)

From: Lukas Wunner <[email protected]>

The upcoming support for PCI device authentication with CMA-SPDM (PCIe r6.1 sec 6.31) requires validating the Subject Alternative Name in X.509 certificates.

High-level functions for X.509 parsing such as key_create_or_update() throw away the internal, low-level struct x509_certificate after extracting the struct public_key and public_key_signature from it. The Subject Alternative Name is thus inaccessible when using those functions.

Afford CMA-SPDM access to the Subject Alternative Name by making struct x509_certificate public, together with the functions for parsing an X.509 certificate into such a struct and freeing such a struct.

The private header file x509_parser.h previously included <linux/time.h> for the definition of time64_t. That definition was since moved to <linux/time64.h> by commit 361a3bf00582 ("time64: Add time64.h header and define struct timespec64"), so adjust the #include directive as part of the move to the new public header file <keys/x509-parser.h>.

No functional change intended.

---
 crypto/asymmetric_keys/x509_parser.h | 42 +--------------------
 include/keys/x509-parser.h           | 55 ++++++++++++++++++++++++++++
 2 files changed, 56 insertions(+), 41 deletions(-)
 create mode 100644 include/keys/x509-parser.h
crypto/asymmetric_keys/x509_parser.h +1 -41
index b7aeebdddb36..39f1521b773d 100644
@@ -5,51 +5,11 @@
  * Written by David Howells ([email protected])
  */
 
-#include <linux/cleanup.h>
-#include <linux/time.h>
-#include <crypto/public_key.h>
-#include <keys/asymmetric-type.h>
-#include <crypto/sha2.h>
-
-struct x509_certificate {
-	struct x509_certificate *next;
-	struct x509_certificate *signer;	/* Certificate that signed this one */
-	struct public_key *pub;			/* Public key details */
-	struct public_key_signature *sig;	/* Signature parameters */
-	u8		sha256[SHA256_DIGEST_SIZE]; /* Hash for blacklist purposes */
-	char		*issuer;		/* Name of certificate issuer */
-	char		*subject;		/* Name of certificate subject */
-	struct asymmetric_key_id *id;		/* Issuer + Serial number */
-	struct asymmetric_key_id *skid;		/* Subject + subjectKeyId (optional) */
-	time64_t	valid_from;
-	time64_t	valid_to;
-	const void	*tbs;			/* Signed data */
-	unsigned	tbs_size;		/* Size of signed data */
-	unsigned	raw_sig_size;		/* Size of signature */
-	const void	*raw_sig;		/* Signature data */
-	const void	*raw_serial;		/* Raw serial number in ASN.1 */
-	unsigned	raw_serial_size;
-	unsigned	raw_issuer_size;
-	const void	*raw_issuer;		/* Raw issuer name in ASN.1 */
-	const void	*raw_subject;		/* Raw subject name in ASN.1 */
-	unsigned	raw_subject_size;
-	unsigned	raw_skid_size;
-	const void	*raw_skid;		/* Raw subjectKeyId in ASN.1 */
-	unsigned	index;
-	bool		seen;			/* Infinite recursion prevention */
-	bool		verified;
-	bool		self_signed;		/* T if self-signed (check unsupported_sig too) */
-	bool		unsupported_sig;	/* T if signature uses unsupported crypto */
-	bool		blacklisted;
-};
+#include <keys/x509-parser.h>
 
 /*
  * x509_cert_parser.c
  */
-extern void x509_free_certificate(struct x509_certificate *cert);
-DEFINE_FREE(x509_free_certificate, struct x509_certificate *,
-	    if (!IS_ERR(_T)) x509_free_certificate(_T))
-extern struct x509_certificate *x509_cert_parse(const void *data, size_t datalen);
 extern int x509_decode_time(time64_t *_t,  size_t hdrlen,
 			    unsigned char tag,
 			    const unsigned char *value, size_t vlen);
include/keys/x509-parser.h new file +55 -0

55 lines not on this page · raw message

Signature · 1 line
2.43.0
#8 lore raw

RFC PATCH v4 6/14 X.509: Parse Subject Alternative Name in certificates

In reply to Aneesh Kumar K.V (Arm)

From: Lukas Wunner <[email protected]>

The upcoming support for PCI device authentication with CMA-SPDM (PCIe r6.1 sec 6.31) requires validating the Subject Alternative Name in X.509 certificates.

Store a pointer to the Subject Alternative Name upon parsing for consumption by CMA-SPDM.

---
 crypto/asymmetric_keys/x509_cert_parser.c | 9 +++++++++
 include/keys/x509-parser.h                | 2 ++
 2 files changed, 11 insertions(+)
crypto/asymmetric_keys/x509_cert_parser.c +9 -0
index 37e4fb9da106..d81b7de4236c 100644
@@ -596,6 +596,15 @@ int x509_process_extension(void *context, size_t hdrlen,
 		return 0;
 	}
 
+	if (ctx->last_oid == OID_subjectAltName) {
+		if (ctx->cert->raw_san)
+			return -EBADMSG;
+
+		ctx->cert->raw_san = v;
+		ctx->cert->raw_san_size = vlen;
+		return 0;
+	}
+
 	if (ctx->last_oid == OID_keyUsage) {
 		/*
 		 * Get hold of the keyUsage bit string
include/keys/x509-parser.h +2 -0
index 8b68e720693a..4e6a05a8c7a6 100644
@@ -38,6 +38,8 @@ struct x509_certificate {
 	unsigned	raw_subject_size;
 	unsigned	raw_skid_size;
 	const void	*raw_skid;		/* Raw subjectKeyId in ASN.1 */
+	const void	*raw_san;		/* Raw subjectAltName in ASN.1 */
+	unsigned	raw_san_size;
 	unsigned	index;
 	bool		seen;			/* Infinite recursion prevention */
 	bool		verified;
Signature · 1 line
2.43.0
#9 lore raw

RFC PATCH v4 7/14 X.509: Move certificate length retrieval into new helper

In reply to Aneesh Kumar K.V (Arm)

From: Lukas Wunner <[email protected]>

The upcoming in-kernel SPDM library (Security Protocol and Data Model,
https://www.dmtf.org/dsp/DSP0274) needs to retrieve the length from ASN.1 DER-encoded X.509 certificates.

Such code already exists in x509_load_certificate_list(), so move it into a new helper for reuse by SPDM.

Export the helper so that SPDM can be tristate. (Some upcoming users of the SPDM libray may be modular, such as SCSI and ATA.)

No functional change intended.

---
 crypto/asymmetric_keys/x509_loader.c | 38 +++++++++++++++++++---------
 include/keys/asymmetric-type.h       |  2 ++
 2 files changed, 28 insertions(+), 12 deletions(-)
crypto/asymmetric_keys/x509_loader.c +26 -12
index a41741326998..25ff027fad1d 100644
@@ -4,28 +4,42 @@
 #include <linux/key.h>
 #include <keys/asymmetric-type.h>
 
+ssize_t x509_get_certificate_length(const u8 *p, unsigned long buflen)
+{
+	ssize_t plen;
+
+	/* Each cert begins with an ASN.1 SEQUENCE tag and must be more
+	 * than 256 bytes in size.
+	 */
+	if (buflen < 4)
+		return -EINVAL;
+
+	if (p[0] != 0x30 &&
+	    p[1] != 0x82)
+		return -EINVAL;
+
+	plen = (p[2] << 8) | p[3];
+	plen += 4;
+	if (plen > buflen)
+		return -EINVAL;
+
+	return plen;
+}
+EXPORT_SYMBOL_GPL(x509_get_certificate_length);
+
 int x509_load_certificate_list(const u8 cert_list[],
 			       const unsigned long list_size,
 			       const struct key *keyring)
 {
 	key_ref_t key;
 	const u8 *p, *end;
-	size_t plen;
+	ssize_t plen;
 
 	p = cert_list;
 	end = p + list_size;
 	while (p < end) {
-		/* Each cert begins with an ASN.1 SEQUENCE tag and must be more
-		 * than 256 bytes in size.
-		 */
-		if (end - p < 4)
-			goto dodgy_cert;
-		if (p[0] != 0x30 &&
-		    p[1] != 0x82)
-			goto dodgy_cert;
-		plen = (p[2] << 8) | p[3];
-		plen += 4;
-		if (plen > end - p)
+		plen = x509_get_certificate_length(p, end - p);
+		if (plen < 0)
 			goto dodgy_cert;
 
 		key = key_create_or_update(make_key_ref(keyring, 1),
include/keys/asymmetric-type.h +2 -0
index 1b91c8f98688..301efa952e26 100644
@@ -84,6 +84,8 @@ extern struct key *find_asymmetric_key(struct key *keyring,
 				       const struct asymmetric_key_id *id_2,
 				       bool partial);
 
+ssize_t x509_get_certificate_length(const u8 *p, unsigned long buflen);
+
 int x509_load_certificate_list(const u8 cert_list[], const unsigned long list_size,
 			       const struct key *keyring);
 
Signature · 1 line
2.43.0
#10 lore raw

RFC PATCH v4 8/14 coco: host: arm64: Register device public key with RMM

In reply to Aneesh Kumar K.V (Arm)

- Introduce the SMC_RMI_PDEV_SET_PUBKEY helper and the associated struct rmi_public_key_params so the host can hand the device’s public key to the RMM.

- Parse the certificate chain cached during SPDM session setup, extract the final certificate’s public key, and recognise RSA-3072, ECDSA-P256, and ECDSA-P384 keys before calling into the RMM.

---
 arch/arm64/include/asm/rmi_cmds.h       |   9 ++
 arch/arm64/include/asm/rmi_smc.h        |  17 +++
 drivers/virt/coco/arm-cca-host/Kconfig  |   4 +
 drivers/virt/coco/arm-cca-host/rmi-da.c | 155 ++++++++++++++++++++++++
 drivers/virt/coco/arm-cca-host/rmi-da.h |   2 +
 5 files changed, 187 insertions(+)
arch/arm64/include/asm/rmi_cmds.h +9 -0
index 8024e9d89e55..00e0a08e17a6 100644
@@ -765,4 +765,13 @@ static inline unsigned long rmi_pdev_stop(unsigned long pdev_phys)
 	return res.a0;
 }
 
+static inline unsigned long rmi_pdev_set_pubkey(unsigned long pdev_phys, unsigned long key_phys)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_PDEV_SET_PUBKEY, pdev_phys, key_phys, &res);
+
+	return res.a0;
+}
+
 #endif /* __ASM_RMI_CMDS_H */
arch/arm64/include/asm/rmi_smc.h +17 -0
index 9056a7639667..7a5d57a8be7a 100644
@@ -538,4 +538,21 @@ struct rmi_dev_comm_data {
 	};
 };
 
+#define RMI_SIG_RSASSA_3072	0
+#define RMI_SIG_ECDSA_P256	1
+#define RMI_SIG_ECDSA_P384	2
+
+struct rmi_public_key_params {
+	union {
+		struct {
+			u8 public_key[1024];
+			u8 metadata[1024];
+			u64 public_key_len;
+			u64 metadata_len;
+			u8 rmi_signature_algorithm;
+		};
+		u8 padding[0x1000];
+	};
+};
+
 #endif /* __ASM_RMI_SMC_H */
drivers/virt/coco/arm-cca-host/Kconfig +4 -0
index efe40d61d5d8..c5076e2b4eb5 100644
@@ -8,7 +8,11 @@ config ARM_CCA_HOST
 	depends on PCI
 	depends on KVM
 	select PCI_TSM
+	select KEYS
+	select X509_CERTIFICATE_PARSER
 	select AUXILIARY_BUS
+	select CRYPTO_ECDSA
+	select CRYPTO_RSA
 
 	help
 	  ARM CCA RMM firmware is the trusted runtime that enforces memory
drivers/virt/coco/arm-cca-host/rmi-da.c +155 -0

167 lines not on this page · raw message

drivers/virt/coco/arm-cca-host/rmi-da.h +2 -0
index 784eb1fff95d..7d38e548b659 100644
@@ -59,6 +59,7 @@ struct cca_host_pdev_dsc {
  * @pci: Physical Function 0 TDISP link context
  * @pdev: pdev communication context
  * @sel_stream: Selective IDE Stream descriptor
+ * @rmi_signature_algorithm: Signature algorithm used for public key
  * @cert_chain: cetrificate chain
  * @vca: SPDM's Version-Capabilities-Algorithms cache object
  */
@@ -67,6 +68,7 @@ struct cca_host_pf0_ep_dsc {
 	struct cca_host_pdev_dsc pdev;
 	struct pci_ide *sel_stream;
 
+	uint8_t rmi_signature_algorithm;
 	struct {
 		struct cache_object *cache;
 
Signature · 1 line
2.43.0
#11 lore raw

RFC PATCH v4 9/14 coco: host: arm64: Initialize RMM pdev state for TDISP IDE connect

In reply to Aneesh Kumar K.V (Arm)

Update connect() to:
- allocate device-communication buffers,
- create the RMM pdev object,
- perform initial device communication to collect identity, and
- set the device public key when the pdev enters NEEDS_KEY.

---
 drivers/virt/coco/arm-cca-host/arm-cca.c | 43 +++++++++--
 drivers/virt/coco/arm-cca-host/rmi-da.c  | 92 +++++++++++++++++++++++-
 drivers/virt/coco/arm-cca-host/rmi-da.h  |  3 +
 3 files changed, 128 insertions(+), 10 deletions(-)
drivers/virt/coco/arm-cca-host/arm-cca.c +36 -7
index 3c854aab95cc..f0aa4e46e96c 100644
@@ -66,7 +66,7 @@ static void cca_tsm_pci_remove(struct pci_tsm *tsm)
 	}
 }
 
-static __maybe_unused int init_dev_communication_buffers(struct pci_dev *pdev,
+static int init_dev_communication_buffers(struct pci_dev *pdev,
 		struct cca_host_comm_data *comm_data)
 {
 	int ret = -ENOMEM;
@@ -184,15 +184,40 @@ static int cca_tsm_connect(struct pci_dev *pdev)
 		ret = tsm_ide_stream_register(ide);
 		if (ret)
 			goto err_tsm;
+	}
 
-		/*
-		 * Once ide is setup, enable the stream at the endpoint
-		 * Root port will be done by RMM
-		 */
-		pci_ide_stream_enable(pdev, ide);
+	ret = init_dev_communication_buffers(pdev, &pf0_ep_dsc->pdev.comm_data);
+	if (ret)
+		goto err_comm_buff;
+	ret = cca_pdev_create(pdev);
+	if (ret)
+		goto err_pdev_create;
+
+	ret = cca_pdev_collect_identity(pdev);
+	if (ret)
+		goto pdev_destroy;
+
+	if (cca_pdev_needs_key(pdev)) {
+		ret = cca_pdev_set_public_key(pdev);
+		if (ret)
+			goto pdev_destroy;
 	}
+	/*
+	 * Once ide is setup, enable the stream at the endpoint
+	 * Root port will be done by RMM
+	 */
+	if (cca_pdev_need_sel_ide_streams(pdev))
+		pci_ide_stream_enable(pdev, ide);
+
 	return 0;
 
+pdev_destroy:
+	cca_pdev_stop_and_destroy(pdev);
+err_pdev_create:
+	free_dev_communication_buffers(&pf0_ep_dsc->pdev.comm_data);
+err_comm_buff:
+	if (cca_pdev_need_sel_ide_streams(pdev))
+		tsm_ide_stream_unregister(ide);
 err_tsm:
 	if (cca_pdev_need_sel_ide_streams(pdev)) {
 		pci_ide_stream_teardown(rp, ide);
@@ -222,12 +247,16 @@ static void cca_tsm_disconnect(struct pci_dev *pdev)
 	if (cca_pdev_need_sel_ide_streams(pdev)) {
 		ide = pf0_ep_dsc->sel_stream;
 		stream_id = ide->stream_id;
+	}
+
+	cca_pdev_stop_and_destroy(pdev);
+	free_dev_communication_buffers(&pf0_ep_dsc->pdev.comm_data);
 
+	if (cca_pdev_need_sel_ide_streams(pdev)) {
 		pci_ide_stream_release(ide);
 		pf0_ep_dsc->sel_stream = NULL;
 		clear_bit(stream_id, cca_stream_ids);
 	}
-
 }
 
 static struct pci_tsm_ops cca_link_pci_ops = {
drivers/virt/coco/arm-cca-host/rmi-da.c +89 -3

111 lines not on this page · raw message

drivers/virt/coco/arm-cca-host/rmi-da.h +3 -0
index 7d38e548b659..240b2993ae53 100644
@@ -135,6 +135,9 @@ static inline struct cca_host_comm_data *to_cca_comm_data(struct pci_dev *pdev)
 }
 
 int cca_pdev_create(struct pci_dev *pdev);
+int cca_pdev_collect_identity(struct pci_dev *pdev);
+bool cca_pdev_needs_key(struct pci_dev *pdev);
+int cca_pdev_set_public_key(struct pci_dev *pdev);
 void cca_pdev_stop_and_destroy(struct pci_dev *pdev);
 
 #endif
Signature · 1 line
2.43.0
#12 lore raw

RFC PATCH v4 10/14 coco: host: arm64: Coordinate peer stream waits during pdev communication

In reply to Aneesh Kumar K.V (Arm)

RMM stream operations can return RMI_DEV_COMM_EXIT_STREAM_WAIT while one side waits for the peer stream to reach the matching point in the protocol.

Teach arm-cca host device communication to detect STREAM_WAIT and add a helper that runs pdev communication for both sides in parallel until each side has made enough progress, then issue rmi_pdev_stream_complete().

This provides the synchronization needed for stream connect, disconnect, key refresh, and key purge operations.

---
 arch/arm64/include/asm/rmi_smc.h        |   1 +
 drivers/virt/coco/arm-cca-host/rmi-da.c | 116 +++++++++++++++++++++++-
 drivers/virt/coco/arm-cca-host/rmi-da.h |  13 +++
 3 files changed, 125 insertions(+), 5 deletions(-)
arch/arm64/include/asm/rmi_smc.h +1 -0
index 7a5d57a8be7a..e9437d56996a 100644
@@ -484,6 +484,7 @@ struct rmi_pdev_params {
 #define RMI_DEV_COMM_EXIT_WAIT		BIT(3)
 #define RMI_DEV_COMM_EXIT_RSP_RESET	BIT(4)
 #define RMI_DEV_COMM_EXIT_MULTI		BIT(5)
+#define RMI_DEV_COMM_EXIT_STREAM_WAIT	BIT(6)
 
 #define RMI_DEV_COMM_NONE	0
 #define RMI_DEV_COMM_RESPONSE	1
drivers/virt/coco/arm-cca-host/rmi-da.c +111 -5

154 lines not on this page · raw message

drivers/virt/coco/arm-cca-host/rmi-da.h +13 -0
index 240b2993ae53..5b0f43493485 100644
@@ -27,6 +27,19 @@ struct dev_comm_work {
 	struct work_struct work;
 };
 
+struct stream_sync {
+	wait_queue_head_t wq;
+	atomic_t val[2];
+};
+
+struct stream_connect_work {
+	struct pci_tsm *tsm;
+	struct work_struct work;
+	struct stream_sync *sync;
+	u8 my_index;
+	bool has_peer;
+};
+
 struct cca_host_comm_data {
 	void *rsp_buff;
 	void *req_buff;
Signature · 1 line
2.43.0
#13 lore raw

RFC PATCH v4 11/14 coco: host: arm64: Connect RMM pdev streams for IDE devices

In reply to Aneesh Kumar K.V (Arm)

Add the RMI definitions for pdev stream management, including the stream parameter layout and helpers for RMI_PDEV_STREAM_CONNECT, RMI_PDEV_STREAM_COMPLETE, and RMI_PDEV_STREAM_DISCONNECT.

Create an RMM pdev for the endpoint's root port when needed, build the non-coherent stream parameters from the endpoint/root-port pdevs, IDE stream ID, and bridge address windows, and issue the RMM stream connect before enabling IDE on the endpoint.

Store the returned stream handle in the PF0 descriptor

---
 arch/arm64/include/asm/rmi_cmds.h        |  37 +++++++
 arch/arm64/include/asm/rmi_smc.h         |  39 +++++++
 drivers/virt/coco/arm-cca-host/arm-cca.c | 127 +++++++++++++++++++++++
 drivers/virt/coco/arm-cca-host/rmi-da.c  |  40 ++++++-
 drivers/virt/coco/arm-cca-host/rmi-da.h  |  57 ++++++++++
 5 files changed, 299 insertions(+), 1 deletion(-)
arch/arm64/include/asm/rmi_cmds.h +37 -0
index 00e0a08e17a6..c82d4d9cbc06 100644
@@ -774,4 +774,41 @@ static inline unsigned long rmi_pdev_set_pubkey(unsigned long pdev_phys, unsigne
 	return res.a0;
 }
 
+
+static inline unsigned long rmi_pdev_stream_connect(unsigned long stream_params_phys,
+		unsigned long *stream_handle)
+{
+
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_PDEV_STREAM_CONNECT, stream_params_phys, &res);
+
+	*stream_handle = res.a1;
+	return res.a0;
+}
+
+static inline unsigned long rmi_pdev_stream_complete(unsigned long pdev1_phys,
+		unsigned long pdev2_phys, unsigned long stream_handle)
+{
+
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_PDEV_STREAM_COMPLETE, pdev1_phys,
+			     pdev2_phys, stream_handle, &res);
+
+	return res.a0;
+}
+
+static inline unsigned long rmi_pdev_stream_disconnect(unsigned long pdev1_phys,
+		unsigned long pdev2_phys, unsigned long stream_handle)
+{
+
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_PDEV_STREAM_DISCONNECT, pdev1_phys,
+			     pdev2_phys, stream_handle, &res);
+
+	return res.a0;
+}
+
 #endif /* __ASM_RMI_CMDS_H */
arch/arm64/include/asm/rmi_smc.h +39 -0
index e9437d56996a..7b16f1540a0e 100644
@@ -556,4 +556,43 @@ struct rmi_public_key_params {
 	};
 };
 
+#define MAX_STREAM_ADDR_RANGE	16
+
+enum rmi_pdev_stream_type {
+	RMI_PDEV_STREAM_NON_TEE,
+	RMI_PDEV_STREAM_NCOH,
+	RMI_PDEV_STREAM_COH,
+	RMI_PDEV_STREAM_NCOH_SYS,
+	RMI_PDEV_STREAM_COH_SYS,
+	RMI_PDEV_STREAM_NCOH_P2P,
+	RMI_PDEV_STREAM_COH_CMEM,
+};
+
+struct rmi_addr_range {
+	u64 base; /* inclusive */
+	u64 top;  /* exclusive */
+};
+
+struct rmi_pdev_stream_params {
+	union {
+		struct {
+			u64 flags;
+			union {
+				u8 type;
+				u8 padding1[8];
+			};
+			u64 pdev_1;
+			u64 pdev_2;
+			u64 ide_sid;
+			u64 num_addr_range;
+		};
+		u8 padding2[0x100];
+	};
+
+	union { /* 0x100 */
+		struct rmi_addr_range addr_range[MAX_STREAM_ADDR_RANGE];
+		u8 padding3[0xF00];
+	};
+};
+
 #endif /* __ASM_RMI_SMC_H */
drivers/virt/coco/arm-cca-host/arm-cca.c +127 -0

151 lines not on this page · raw message

drivers/virt/coco/arm-cca-host/rmi-da.c +39 -1
index 28f450e2db27..a10ac6ff03d1 100644
@@ -62,6 +62,10 @@ static int init_pdev_params(struct pci_dev *pdev, struct rmi_pdev_params *params
 		category = RMI_PDEV_FLAGS_CATEGORY_OFF_CHIP_EP;
 		break;
 	}
+	case PCI_EXP_TYPE_ROOT_PORT: {
+		category = RMI_PDEV_FLAGS_CATEGORY_ROOT_PORT;
+		break;
+	}
 	default:
 		return -EINVAL;
 	}
@@ -770,7 +774,7 @@ static void stream_connect_workfn(struct work_struct *work)
 	mutex_unlock(&pdev_dsc->object_lock);
 }
 
-static int __maybe_unused submit_stream_work(struct pci_dev *pdev1, struct pci_dev *pdev2,
+static int submit_stream_work(struct pci_dev *pdev1, struct pci_dev *pdev2,
 		unsigned long stream_handle)
 {
 	phys_addr_t rmm_pdev1_phys, rmm_pdev2_phys = 0;
@@ -814,6 +818,40 @@ static int __maybe_unused submit_stream_work(struct pci_dev *pdev1, struct pci_d
 	rmm_pdev1_phys = virt_to_phys(pdev_dsc1->rmm_pdev);
 	if (pdev2)
 		rmm_pdev2_phys = virt_to_phys(pdev_dsc2->rmm_pdev);
+	/*
+	 * If we had device communication error, this will error out.
+	 */
+	if (rmi_pdev_stream_complete(rmm_pdev1_phys, rmm_pdev2_phys, stream_handle))
+		return -EIO;
 
 	return 0;
 }
+
+int cca_pdev_stream_connect(struct pci_dev *pdev1, struct pci_dev *pdev2,
+		struct rmi_pdev_stream_params *stream_params,
+		unsigned long *stream_handle)
+{
+	phys_addr_t stream_params_phys = virt_to_phys(stream_params);
+
+	if (rmi_pdev_stream_connect(stream_params_phys, stream_handle))
+		return -EIO;
+
+	return submit_stream_work(pdev1, pdev2, *stream_handle);
+}
+
+int cca_pdev_disconnect_stream(struct pci_dev *pdev1,
+		struct pci_dev *pdev2, unsigned long stream_handle)
+{
+
+	phys_addr_t rmm_pdev2_phys = 0;
+	struct cca_host_pdev_dsc *pdev_dsc1 = to_cca_pdev_dsc(pdev1);
+
+	if (pdev2)
+		rmm_pdev2_phys = virt_to_phys(to_cca_pdev_dsc(pdev2)->rmm_pdev);
+
+	if (rmi_pdev_stream_disconnect(virt_to_phys(pdev_dsc1->rmm_pdev),
+				       rmm_pdev2_phys, stream_handle))
+		return -EIO;
+
+	return submit_stream_work(pdev1, pdev2, stream_handle);
+}
drivers/virt/coco/arm-cca-host/rmi-da.h +57 -0

100 lines not on this page · raw message

Signature · 1 line
2.43.0
#14 lore raw

RFC PATCH v4 12/14 coco: host: arm64: Refcount root-port pdevs used by IDE streams

In reply to Aneesh Kumar K.V (Arm)

Keep the root-port RMM pdev alive while endpoint IDE streams are attached to it.

Add a kref to the root-port descriptor, take a reference when reusing an existing root-port pdev for stream setup, and drop it when the endpoint disconnects. Release the root-port pdev once the final reference is dropped, tearing down the RMM object and its communication buffers at that point.

---
 drivers/virt/coco/arm-cca-host/arm-cca.c | 31 +++++++++++++++++++++---
 drivers/virt/coco/arm-cca-host/rmi-da.h  |  4 +++
 2 files changed, 32 insertions(+), 3 deletions(-)
drivers/virt/coco/arm-cca-host/arm-cca.c +28 -3
index de7a2e156549..0b1200f591ab 100644
@@ -134,6 +134,23 @@ static int alloc_stream_id(struct pci_host_bridge *hb)
 	return stream_id;
 }
 
+static void cca_root_port_pdev_release(struct kref *kref)
+{
+	struct cca_host_rp_dsc *rp_dsc = container_of(kref, struct cca_host_rp_dsc,
+						      tsm_ref);
+	struct pci_dev *rp = rp_dsc->pci.pdev;
+
+	cca_pdev_stop_and_destroy(rp);
+	free_dev_communication_buffers(&rp_dsc->pdev.comm_data);
+	rp->tsm = NULL;
+	kfree(rp_dsc);
+}
+
+static inline void cca_root_port_pdev_put(struct cca_host_rp_dsc *rp_dsc)
+{
+	kref_put(&rp_dsc->tsm_ref, cca_root_port_pdev_release);
+}
+
 static int cca_root_port_pdev_create(struct pci_dev *rp, struct tsm_dev *tsm_dev)
 {
 	int ret;
@@ -151,6 +168,7 @@ static int cca_root_port_pdev_create(struct pci_dev *rp, struct tsm_dev *tsm_dev
 	rp->tsm->dsm_dev = rp;
 	rp->tsm->pdev = rp;
 	rp->tsm->tsm_dev = tsm_dev;
+	kref_init(&rp_dsc->tsm_ref);
 	mutex_init(&rp_dsc->pdev.object_lock);
 
 	ret = init_dev_communication_buffers(rp, &rp_dsc->pdev.comm_data);
@@ -222,12 +240,15 @@ static int cca_pdev_create_ncoh_stream(struct pci_dev *pdev, unsigned long strea
 		/* Make sure they use the same TSM */
 		if (rp->tsm->tsm_dev != pf0_ep_dsc->pci.base_tsm.tsm_dev)
 			return -EINVAL;
-	}
 
+		kref_get(&rp_dsc->tsm_ref);
+	}
 
 	params = (struct rmi_pdev_stream_params *)get_zeroed_page(GFP_KERNEL);
-	if (!params)
+	if (!params) {
+		cca_root_port_pdev_put(rp_dsc);
 		return -ENOMEM;
+	}
 
 	params->flags = 0;
 	params->type = RMI_PDEV_STREAM_NCOH;
@@ -237,7 +258,9 @@ static int cca_pdev_create_ncoh_stream(struct pci_dev *pdev, unsigned long strea
 	params->num_addr_range = pci_dev_addr_range(pdev, params->addr_range);
 
 	ret = cca_pdev_stream_connect(pdev, rp, params, &stream_handle);
-	if (!ret)
+	if (ret)
+		cca_root_port_pdev_put(rp_dsc);
+	else
 		pf0_ep_dsc->stream_handle = stream_handle;
 
 	free_page((unsigned long)params);
@@ -375,6 +398,8 @@ static void cca_tsm_disconnect(struct pci_dev *pdev)
 	}
 
 	cca_pdev_disconnect_stream(pdev, rp, pf0_ep_dsc->stream_handle);
+	if (rp)
+		cca_root_port_pdev_put(to_cca_rp_dsc(rp));
 
 	cca_pdev_stop_and_destroy(pdev);
 	free_dev_communication_buffers(&pf0_ep_dsc->pdev.comm_data);
drivers/virt/coco/arm-cca-host/rmi-da.h +4 -0
index ea5f7df3541f..798a8ed7505f 100644
@@ -10,6 +10,9 @@
 #include <linux/pci-ide.h>
 #include <linux/pci-tsm.h>
 #include <linux/sizes.h>
+#include <linux/atomic.h>
+#include <linux/kref.h>
+#include <linux/wait.h>
 #include <asm/rmi_cmds.h>
 #include <asm/rmi_smc.h>
 
@@ -104,6 +107,7 @@ struct cca_host_pf0_ep_dsc {
 struct cca_host_rp_dsc {
 	struct pci_tsm pci;
 	struct cca_host_pdev_dsc pdev;
+	struct kref tsm_ref;
 };
 
 struct cca_host_fn_dsc {
Signature · 1 line
2.43.0
#15 lore raw

RFC PATCH v4 13/14 PCI/TSM: Move CMA DOE mailbox discovery out of pci_tsm_pf0_constructor()

In reply to Aneesh Kumar K.V (Arm)

pci_tsm_pf0_constructor() currently looks up a CMA DOE mailbox and fails PF0 initialization when one is not present. That is too strict for all link TSM drivers.

Move CMA DOE mailbox discovery into the low-level PF0 probe callbacks so each driver can decide whether a mailbox is mandatory.

Keep SEV-TIO and TDX requiring a CMA mailbox, while allowing the arm-cca host path to proceed on PF0 devices that do not support IDE and therefore have no DOE-based SPDM path.

---
 drivers/crypto/ccp/sev-dev-tsm.c         | 13 +++++++++++++
 drivers/pci/tsm/core.c                   | 14 ++++++++------
 drivers/virt/coco/arm-cca-host/arm-cca.c | 16 +++++++++++++---
 drivers/virt/coco/tdx-host/tdx-host.c    | 13 +++++++++++++
 4 files changed, 47 insertions(+), 9 deletions(-)
drivers/crypto/ccp/sev-dev-tsm.c +13 -0
index b07ae529b591..a7506cbbe392 100644
@@ -217,6 +217,19 @@ static struct pci_tsm *tio_pf0_probe(struct pci_dev *pdev, struct sev_device *se
 	if (rc)
 		return NULL;
 
+	/* if device have ide cap, setup doe mailbox */
+	if (pdev->ide_cap) {
+		struct pci_doe_mb *doe_mb;
+
+		doe_mb = pci_find_doe_mailbox(pdev, PCI_VENDOR_ID_PCI_SIG,
+					      PCI_DOE_FEATURE_CMA);
+		if (!doe_mb)
+			return NULL;
+		dsm->tsm.doe_mb = doe_mb;
+	} else {
+		return NULL;
+	}
+
 	pci_dbg(pdev, "TSM enabled\n");
 	dsm->sev = sev;
 	return &no_free_ptr(dsm)->tsm.base_tsm;
drivers/pci/tsm/core.c +8 -6
index bb440135b8f7..900306a43161 100644
@@ -1236,12 +1236,14 @@ int pci_tsm_pf0_constructor(struct pci_dev *pdev, struct pci_tsm_pf0 *tsm,
 			    struct tsm_dev *tsm_dev)
 {
 	mutex_init(&tsm->lock);
-	tsm->doe_mb = pci_find_doe_mailbox(pdev, PCI_VENDOR_ID_PCI_SIG,
-					   PCI_DOE_FEATURE_CMA);
-	if (!tsm->doe_mb) {
-		pci_warn(pdev, "TSM init failure, no CMA mailbox\n");
-		return -ENODEV;
-	}
+
+	/*
+	 * Note, low-level TSM driver responsible for determining if it wants to
+	 * proceed with a device that has no DOE mailbox. TSM may have an
+	 * alternate method for coordinating TDISP.
+	 */
+	if (!tsm->doe_mb)
+		pci_dbg(pdev, "no CMA mailbox\n");
 
 	return pci_tsm_link_constructor(pdev, &tsm->base_tsm, tsm_dev);
 }
drivers/virt/coco/arm-cca-host/arm-cca.c +13 -3
index 0b1200f591ab..265aa0cb612a 100644
@@ -11,6 +11,8 @@
 #include <linux/tsm.h>
 #include <linux/vmalloc.h>
 #include <linux/cleanup.h>
+#include <linux/pci-doe.h>
+
 
 #include "rmi-da.h"
 
@@ -35,14 +37,22 @@ static struct pci_tsm *cca_tsm_pci_probe(struct tsm_dev *tsm_dev, struct pci_dev
 		return &no_free_ptr(fn_dsc)->pci;
 	}
 
-	if (!pdev->ide_cap)
-		return NULL;
-
 	struct cca_host_pf0_ep_dsc *pf0_ep_dsc __free(kfree) =
 		kzalloc(sizeof(*pf0_ep_dsc), GFP_KERNEL);
 	if (!pf0_ep_dsc)
 		return NULL;
 
+	/* if device have ide cap, setup doe mailbox */
+	if (pdev->ide_cap) {
+		struct pci_doe_mb *doe_mb;
+
+		doe_mb = pci_find_doe_mailbox(pdev, PCI_VENDOR_ID_PCI_SIG,
+					      PCI_DOE_FEATURE_CMA);
+		if (!doe_mb)
+			return NULL;
+		pf0_ep_dsc->pci.doe_mb = doe_mb;
+	}
+
 	ret = pci_tsm_pf0_constructor(pdev, &pf0_ep_dsc->pci, tsm_dev);
 	if (ret)
 		return NULL;
drivers/virt/coco/tdx-host/tdx-host.c +13 -0
index ea7c2167660f..4947b9bc2359 100644
@@ -634,6 +634,19 @@ static struct pci_tsm *tdx_link_pf0_probe(struct tsm_dev *tsm_dev,
 	spdm_conf->vmm_spdm_cap = SPDM_CAP_KEY_UPD;
 	spdm_conf->certificate_slot_mask = 0xff;
 
+	/* if device have ide cap, setup doe mailbox */
+	if (pdev->ide_cap) {
+		struct pci_doe_mb *doe_mb;
+
+		doe_mb = pci_find_doe_mailbox(pdev, PCI_VENDOR_ID_PCI_SIG,
+					      PCI_DOE_FEATURE_CMA);
+		if (!doe_mb)
+			return NULL;
+		tlink->pci.doe_mb = doe_mb;
+	} else {
+		return NULL;
+	}
+
 	tlink->in_msg = no_free_ptr(in_msg);
 	tlink->out_msg = no_free_ptr(out_msg);
 	tlink->spdm_conf = no_free_ptr(spdm_conf);
Signature · 1 line
2.43.0
#16 lore raw

RFC PATCH v4 14/14 coco: host: arm64: Add NCOH_SYS stream support for RC endpoints

In reply to Aneesh Kumar K.V (Arm)

Teach the host CCA pdev setup to handle PCI_EXP_TYPE_RC_END devices.

Classify RC integrated endpoints as RMI_PDEV_FLAGS_CATEGORY_ON_CHIP_EP when building the RMM pdev parameters, and only advertise SPDM support when a DOE mailbox is present.

Also add the stream setup path for these devices by creating an RMI_PDEV_STREAM_NCOH_SYS stream using the endpoint pdev and its bridge address windows. This allows RC endpoints to participate in the TDISP flow without requiring a separate root-port pdev.

---
 drivers/virt/coco/arm-cca-host/arm-cca.c | 28 ++++++++++++++++++++++++
 drivers/virt/coco/arm-cca-host/rmi-da.c  | 10 +++++++++
 2 files changed, 38 insertions(+)
drivers/virt/coco/arm-cca-host/arm-cca.c +28 -0
index 265aa0cb612a..8b1182620872 100644
@@ -277,11 +277,39 @@ static int cca_pdev_create_ncoh_stream(struct pci_dev *pdev, unsigned long strea
 	return ret;
 }
 
+static int cca_pdev_create_ncoh_sys_stream(struct pci_dev *pdev)
+{
+	int ret;
+	long stream_handle;
+	struct rmi_pdev_stream_params *params;
+	struct cca_host_pf0_ep_dsc *pf0_ep_dsc = to_cca_pf0_ep_dsc(pdev);
+
+	params = (struct rmi_pdev_stream_params *)get_zeroed_page(GFP_KERNEL);
+	if (!params)
+		return -ENOMEM;
+
+	params->flags = 0;
+	params->type = RMI_PDEV_STREAM_NCOH_SYS;
+	params->pdev_1 = virt_to_phys(pf0_ep_dsc->pdev.rmm_pdev);
+	params->pdev_2 = 0; /* ignored */
+	params->ide_sid = 0; /* ignored */
+	params->num_addr_range = pci_dev_addr_range(pdev, params->addr_range);
+
+	ret = cca_pdev_stream_connect(pdev, NULL, params, &stream_handle);
+	if (!ret)
+		pf0_ep_dsc->stream_handle = stream_handle;
+
+	free_page((unsigned long)params);
+	return ret;
+}
+
 static int cca_pdev_create_streams(struct pci_dev *pdev, unsigned long stream_id)
 {
 	switch (pci_pcie_type(pdev)) {
 	case PCI_EXP_TYPE_ENDPOINT:
 		return cca_pdev_create_ncoh_stream(pdev, stream_id);
+	case PCI_EXP_TYPE_RC_END:
+		return cca_pdev_create_ncoh_sys_stream(pdev);
 	default:
 		return -EINVAL;
 	}
drivers/virt/coco/arm-cca-host/rmi-da.c +10 -0
index a10ac6ff03d1..33a2551fd09f 100644
@@ -66,6 +66,16 @@ static int init_pdev_params(struct pci_dev *pdev, struct rmi_pdev_params *params
 		category = RMI_PDEV_FLAGS_CATEGORY_ROOT_PORT;
 		break;
 	}
+	case PCI_EXP_TYPE_RC_END: {
+		struct cca_host_pf0_ep_dsc *pf0_ep_dsc = to_cca_pf0_ep_dsc(pdev);
+
+		/* Use SPDM if present */
+		if (pf0_ep_dsc->pci.doe_mb)
+			params->flags = RMI_PDEV_FLAGS_SPDM;
+
+		category = RMI_PDEV_FLAGS_CATEGORY_ON_CHIP_EP;
+		break;
+	}
 	default:
 		return -EINVAL;
 	}
Signature · 1 line
2.43.0
maintainer
#17 lore raw
In reply to Aneesh Kumar K.V (Arm)
Quoted 2 lines · Aneesh Kumar K.V (Arm)
 arch/arm64/include/asm/rmi_cmds.h         |  85 +++
 arch/arm64/include/asm/rmi_smc.h          | 168 +++++

Curious, but why does this stuff have to live in the arch code? Wouldn't it be better off somewhere like drivers/firmware/ or include/linux/arm-rmi.h?

Will

#18 lore raw
Quoted 8 lines · Will Deacon
Quoted 2 lines · Aneesh Kumar K.V (Arm)
 arch/arm64/include/asm/rmi_cmds.h         |  85 +++
 arch/arm64/include/asm/rmi_smc.h          | 168 +++++

Curious, but why does this stuff have to live in the arch code? Wouldn't it be better off somewhere like drivers/firmware/ or include/linux/arm-rmi.h?

Those headers are used to collect all RMI-related helpers and #defines. They were introduced by the Realm KVM/host support patch series, and I am continuing to use the same headers to add more helpers.

We can consider moving the RMI helpers used by virt/coco/arm-caa-guest/, virt/coco/arm-cca-host/, and drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-realm.c into a more generic header such as include/linux/arm-rmi.h. However, that would either require moving all the helpers currently used by KVM there as well, otherwise we would end up with two separate headers carrying RMI helpers.

Additionally, there are also arch/arm64/include/asm/rsi_cmds.h and arch/arm64/include/asm/rsi_smc.h to consider.

-aneesh

#19 lore raw
In reply to Will Deacon
Quoted 7 lines · Will Deacon
Quoted 2 lines · Aneesh Kumar K.V (Arm)
  arch/arm64/include/asm/rmi_cmds.h         |  85 +++
  arch/arm64/include/asm/rmi_smc.h          | 168 +++++

Curious, but why does this stuff have to live in the arch code? Wouldn't it be better off somewhere like drivers/firmware/ or include/linux/arm-rmi.h?

Good point. RMI interface is only available for arm64 (not in Arm32). That said, it is indeed a firmware ! ;-) interface. The APIs are closely integrated with the KVM Realm management. If the general consensus is
to move them under drivers/firmware (like PSCI), we could take that
approach.

Suzuki

Quoted 2 lines

Will

maintainer
#20 lore raw
Quoted 9 lines · Suzuki K Poulose
Quoted 7 lines · Will Deacon
Quoted 2 lines · Aneesh Kumar K.V (Arm)
  arch/arm64/include/asm/rmi_cmds.h         |  85 +++
  arch/arm64/include/asm/rmi_smc.h          | 168 +++++

Curious, but why does this stuff have to live in the arch code? Wouldn't it be better off somewhere like drivers/firmware/ or include/linux/arm-rmi.h?

Quoted 5 lines

Good point. RMI interface is only available for arm64 (not in Arm32). That said, it is indeed a firmware ! ;-) interface. The APIs are closely integrated with the KVM Realm management. If the general consensus is to move them under drivers/firmware (like PSCI), we could take that approach.

I'd certainly prefer that as it means it's co-located with other firmware interface code and also means that the arch maintainers don't need to worry about changes to driver code :p

Will