[RFC PATCH v1 32/38] coco: guest: arm64: Add support for guest initiated TDI bind/unbind

Aneesh Kumar K.V (Arm)
2025-07-28T13:55:47Z

Add RHI for VDEV_SET_TDI_STATE

Note: This is not part of RHI spec. This is a POC implementation
and will be later switced to correct interface defined by RHI.

Signed-off-by: Aneesh Kumar K.V (Arm) <aneesh.kumar@kernel.org>
---
arch/arm64/include/asm/rhi.h | 7 +++++
arch/arm64/kernel/Makefile | 2 +-
arch/arm64/kernel/rhi.c | 35 +++++++++++++++++++++++
drivers/virt/coco/arm-cca-guest/arm-cca.c | 22 ++++++++++++--
drivers/virt/coco/arm-cca-host/arm-cca.c | 8 ++++--
5 files changed, 69 insertions(+), 5 deletions(-)
create mode 100644 arch/arm64/kernel/rhi.c

diff --git a/arch/arm64/include/asm/rhi.h b/arch/arm64/include/asm/rhi.h
index d3c22e582678..993b4b15b057 100644
--- a/arch/arm64/include/asm/rhi.h
+++ b/arch/arm64/include/asm/rhi.h
@@ -16,6 +16,7 @@
#define RHI_DA_FEATURES SMC_RHI_CALL(0x004d)
#define RHI_DA_OBJECT_SIZE SMC_RHI_CALL(0x004e)
#define RHI_DA_OBJECT_READ SMC_RHI_CALL(0x004f)
+#define RHI_DA_VDEV_SET_TDI_STATE SMC_RHI_CALL(0x0052)

#define RHI_DA_OBJECT_CERTIFICATE 0x1
#define RHI_DA_OBJECT_MEASUREMENT 0x2
@@ -29,4 +30,10 @@
#define RHI_ERROR_DATA_NOT_AVAILABLE 0x4
#define RHI_ERROR_INVALID_OFFSET 0x5
#define RHI_ERROR_INVALID_ADDR 0x6
+
+#define RHI_DA_TDI_CONFIG_UNLOCKED 0x0
+#define RHI_DA_TDI_CONFIG_LOCKED 0x1
+#define RHI_DA_TDI_CONFIG_RUN 0x2
+long rhi_da_vdev_set_tdi_state(unsigned long vdev_id, unsigned long target_state);
+
#endif
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index a2faf0049dab..dde8fa78852c 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -34,7 +34,7 @@ obj-y := debug-monitors.o entry.o irq.o fpsimd.o \
cpufeature.o alternative.o cacheinfo.o \
smp.o smp_spin_table.o topology.o smccc-call.o \
syscall.o proton-pack.o idle.o patching.o pi/ \
- rsi.o jump_label.o
+ rsi.o jump_label.o rhi.o

obj-$(CONFIG_COMPAT) += sys32.o signal32.o \
sys_compat.o
diff --git a/arch/arm64/kernel/rhi.c b/arch/arm64/kernel/rhi.c
new file mode 100644
index 000000000000..3685b50c2e94
--- /dev/null
+++ b/arch/arm64/kernel/rhi.c
@@ -0,0 +1,35 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2025 ARM Ltd.
+ */
+
+#include <asm/memory.h>
+#include <asm/string.h>
+#include <asm/rsi.h>
+#include <asm/rhi.h>
+
+#include <linux/slab.h>
+
+long rhi_da_vdev_set_tdi_state(unsigned long guest_rid, unsigned long target_state)
+{
+ long ret;
+ struct rsi_host_call *rhi_call;
+
+ rhi_call = kmalloc(sizeof(struct rsi_host_call), GFP_KERNEL);
+ if (!rhi_call)
+ return -ENOMEM;
+
+ rhi_call->imm = 0;
+ rhi_call->gprs[0] = RHI_DA_VDEV_SET_TDI_STATE;
+ rhi_call->gprs[1] = guest_rid;
+ rhi_call->gprs[2] = target_state;
+
+ ret = rsi_host_call(virt_to_phys(rhi_call));
+ if (ret != RSI_SUCCESS)
+ ret = -EIO;
+ else
+ ret = rhi_call->gprs[0];
+
+ kfree(rhi_call);
+ return ret;
+}
diff --git a/drivers/virt/coco/arm-cca-guest/arm-cca.c b/drivers/virt/coco/arm-cca-guest/arm-cca.c
index 2c0190bcb2a9..de70fba09e92 100644
--- a/drivers/virt/coco/arm-cca-guest/arm-cca.c
+++ b/drivers/virt/coco/arm-cca-guest/arm-cca.c
@@ -222,11 +222,20 @@ static void cca_tsm_pci_remove(struct pci_tsm *tsm)

static int cca_tsm_lock(struct pci_dev *pdev)
{
- unsigned long ret;
+ long ret;
+ int vdev_id = (pci_domain_nr(pdev->bus) << 16) |
+ PCI_DEVID(pdev->bus->number, pdev->devfn);

+ ret = rhi_da_vdev_set_tdi_state(vdev_id, RHI_DA_TDI_CONFIG_LOCKED);
+ if (ret) {
+ pci_err(pdev, "failed to TSM bind the device (%ld)\n", ret);
+ return -EIO;
+ }
+
+ /* This will be done by above rhi in later spec */
ret = rsi_device_lock(pdev);
if (ret) {
- pci_err(pdev, "failed to lock the device (%lu)\n", ret);
+ pci_err(pdev, "failed to lock the device (%ld)\n", ret);
return -EIO;
}
return 0;
@@ -234,6 +243,15 @@ static int cca_tsm_lock(struct pci_dev *pdev)

static void cca_tsm_unlock(struct pci_dev *pdev)
{
+ long ret;
+ int vdev_id = (pci_domain_nr(pdev->bus) << 16) |
+ PCI_DEVID(pdev->bus->number, pdev->devfn);
+
+ ret = rhi_da_vdev_set_tdi_state(vdev_id, RHI_DA_TDI_CONFIG_UNLOCKED);
+ if (ret) {
+ pci_err(pdev, "failed to TSM unbind the device (%ld)\n", ret);
+ return;
+ }
}

static const struct pci_tsm_ops cca_pci_ops = {
diff --git a/drivers/virt/coco/arm-cca-host/arm-cca.c b/drivers/virt/coco/arm-cca-host/arm-cca.c
index 0807fcf8d222..18d0a627baa4 100644
--- a/drivers/virt/coco/arm-cca-host/arm-cca.c
+++ b/drivers/virt/coco/arm-cca-host/arm-cca.c
@@ -254,9 +254,13 @@ static struct pci_tdi *cca_tsm_bind(struct pci_dev *pdev, struct pci_dev *pf0_de
static void cca_tsm_unbind(struct pci_tdi *tdi)
{
struct realm *realm = &tdi->kvm->arch.realm;
-
+ /*
+ * FIXME!!
+ * All the related DEV RIPAS regions should be unmapped by now.
+ * For now we handle them during stage2 teardown. There is no
+ * bound IPA address available here. Possibly dmabuf can help
+ */
rme_unbind_vdev(realm, tdi->pdev, tdi->pdev->tsm->dsm_dev);
-
module_put(THIS_MODULE);
}

--
2.43.0