public inbox for linux-coco@lists.linux.dev
 help / color / mirror / Atom feed
From: "Aneesh Kumar K.V (Arm)" <aneesh.kumar@kernel.org>
To: linux-coco@lists.linux.dev, kvmarm@lists.linux.dev,
	linux-arm-kernel@lists.infradead.org
Cc: linux-kernel@vger.kernel.org,
	"Aneesh Kumar K.V (Arm)" <aneesh.kumar@kernel.org>,
	Marc Zyngier <maz@kernel.org>,
	Catalin Marinas <catalin.marinas@arm.com>,
	Will Deacon <will@kernel.org>,
	Jonathan Cameron <Jonathan.Cameron@huawei.com>,
	Jason Gunthorpe <jgg@ziepe.ca>,
	Dan Williams <dan.j.williams@intel.com>,
	Alexey Kardashevskiy <aik@amd.com>,
	Samuel Ortiz <sameo@rivosinc.com>,
	Xu Yilun <yilun.xu@linux.intel.com>,
	Suzuki K Poulose <Suzuki.Poulose@arm.com>,
	Steven Price <steven.price@arm.com>
Subject: [RFC PATCH v3 08/12] coco: host: KVM: arm64: Handle vdev request exits and completion
Date: Thu, 12 Mar 2026 13:37:39 +0530	[thread overview]
Message-ID: <20260312080743.3487326-9-aneesh.kumar@kernel.org> (raw)
In-Reply-To: <20260312080743.3487326-1-aneesh.kumar@kernel.org>

- add the RMI/RHI definitions for RMI_VDEV_COMPLETE, the new exit
  reason, and the extended REC exit payload
- update KVM to recognize RMI_EXIT_VDEV_REQUEST and surface it to
  userspace via KVM_EXIT_ARM64_TIO
- Add CCA TSM guest request handler for __REC_EXIT_DA_VDEV_REQUEST which
  takes a vCPU fd and verify it belongs to the same VM before calling
  rmi_vdev_complete()

This lets Realm firmware hand control back to the VMM when it needs host
assistance for vdev operations, and gives userspace a way to finish the
request.

Cc: Marc Zyngier <maz@kernel.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Cc: Jason Gunthorpe <jgg@ziepe.ca>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Alexey Kardashevskiy <aik@amd.com>
Cc: Samuel Ortiz <sameo@rivosinc.com>
Cc: Xu Yilun <yilun.xu@linux.intel.com>
Cc: Suzuki K Poulose <Suzuki.Poulose@arm.com>
Cc: Steven Price <steven.price@arm.com>
Signed-off-by: Aneesh Kumar K.V (Arm) <aneesh.kumar@kernel.org>
---
 Documentation/virt/kvm/api.rst           | 22 +++++++++++++++++
 arch/arm64/include/asm/rhi.h             |  1 +
 arch/arm64/include/asm/rmi_cmds.h        | 10 ++++++++
 arch/arm64/include/asm/rmi_smc.h         | 17 ++++++++++++--
 arch/arm64/include/uapi/asm/rmi-da.h     |  5 ++++
 arch/arm64/kvm/rmi-exit.c                | 17 ++++++++++++++
 drivers/virt/coco/arm-cca-host/arm-cca.c | 12 ++++++++++
 drivers/virt/coco/arm-cca-host/rmi-da.c  | 30 ++++++++++++++++++++++++
 drivers/virt/coco/arm-cca-host/rmi-da.h  |  2 ++
 include/linux/kvm_host.h                 |  1 +
 include/uapi/linux/kvm.h                 | 10 ++++++++
 virt/kvm/kvm_main.c                      |  6 +++++
 12 files changed, 131 insertions(+), 2 deletions(-)

diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
index bd2f0dd0aeda..041009307ee8 100644
--- a/Documentation/virt/kvm/api.rst
+++ b/Documentation/virt/kvm/api.rst
@@ -7429,6 +7429,28 @@ the ``KVM_EXIT_ARM_SEA_FLAG_GPA_VALID`` flag is set. Otherwise, the value of
 ``gpa`` is unknown.
 
 ::
+		/* KVM_EXIT_ARM64_TIO*/
+		struct {
+			__u64 flags;
+			__u64 nr;
+			__u64 vdev_id;
+			__u64 gpa_base;
+			__u64 gpa_top;
+			__u64 pa_base;
+		} cca_exit;
+
+Used on arm64 systems. When the VM capability ``KVM_CAP_ARM_RMI`` is enabled,
+KVM generates a VM exit whenever the guest needs host assistance to map a vdev
+ID to a vdev object, or to validate a device-memory GPA-to-PA mapping. The
+``nr`` field records the exit reason; currently the following values are
+defined:
+
+* ``RMI_EXIT_VDEV_REQUEST``: the RMM is requiring host to provide the vdev
+  object details matching a specific virtual device id.
+* ``RMI_EXIT_VDEV_MAP``: the guest wants the host to validate or install a
+  device-memory mapping.
+
+The ``flags`` field must be zero.
 
 		/* Fix the size of the union. */
 		char padding[256];
diff --git a/arch/arm64/include/asm/rhi.h b/arch/arm64/include/asm/rhi.h
index a18ad7bbc028..888b3a1c3953 100644
--- a/arch/arm64/include/asm/rhi.h
+++ b/arch/arm64/include/asm/rhi.h
@@ -84,5 +84,6 @@ enum rhi_tdi_state {
 #define __RHI_DA_OBJECT_READ		0x2
 #define __RHI_DA_VDEV_GET_INTERFACE_REPORT 0x3
 #define __RHI_DA_VDEV_GET_MEASUREMENTS	0x4
+#define __REC_EXIT_DA_VDEV_REQUEST	0x5
 
 #endif
diff --git a/arch/arm64/include/asm/rmi_cmds.h b/arch/arm64/include/asm/rmi_cmds.h
index aad245675c7d..f29c2de5d3b9 100644
--- a/arch/arm64/include/asm/rmi_cmds.h
+++ b/arch/arm64/include/asm/rmi_cmds.h
@@ -685,4 +685,14 @@ rmi_vdev_get_device_measurements(unsigned long rd, unsigned long pdev_phys,
 
 	return res.a0;
 }
+
+static inline unsigned long rmi_vdev_complete(unsigned long rec_phys, unsigned long vdev_phys)
+{
+	struct arm_smccc_res res;
+
+	arm_smccc_1_1_invoke(SMC_RMI_VDEV_COMPLETE, rec_phys, vdev_phys, &res);
+
+	return res.a0;
+}
+
 #endif /* __ASM_RMI_CMDS_H */
diff --git a/arch/arm64/include/asm/rmi_smc.h b/arch/arm64/include/asm/rmi_smc.h
index 36c3db8b821d..6b685585e750 100644
--- a/arch/arm64/include/asm/rmi_smc.h
+++ b/arch/arm64/include/asm/rmi_smc.h
@@ -60,6 +60,7 @@
 #define SMC_RMI_VDEV_DESTROY		SMC_RMI_CALL(0x0188)
 #define SMC_RMI_VDEV_GET_STATE		SMC_RMI_CALL(0x0189)
 #define SMC_RMI_VDEV_UNLOCK		SMC_RMI_CALL(0x018A)
+#define SMC_RMI_VDEV_COMPLETE		SMC_RMI_CALL(0x018e)
 #define SMC_RMI_VDEV_GET_INTERFACE_REPORT SMC_RMI_CALL(0x01D0)
 #define SMC_RMI_VDEV_GET_DEV_MEASUREMENTS	SMC_RMI_CALL(0x01D1)
 #define SMC_RMI_VDEV_LOCK		SMC_RMI_CALL(0x01D2)
@@ -225,6 +226,7 @@ struct rec_enter {
 #define RMI_EXIT_RIPAS_CHANGE		0x04
 #define RMI_EXIT_HOST_CALL		0x05
 #define RMI_EXIT_SERROR			0x06
+#define RMI_EXIT_VDEV_REQUEST		0x08
 
 struct rec_exit {
 	union { /* 0x000 */
@@ -266,12 +268,23 @@ struct rec_exit {
 			u64 ripas_base;
 			u64 ripas_top;
 			u8 ripas_value;
-			u8 padding8[7];
+			u8 padding8[15];
+			u64 s2ap_base;
+			u64 s2ap_top;
+			u64 vdev_id_1;
+			u64 vdev_id_2;
+			u64 dev_mem_base;
+			u64 dev_mem_top;
+			u64 dev_mem_pa;
 		};
 		u8 padding5[0x100];
 	};
 	union { /* 0x600 */
-		u16 imm;
+		struct {
+			u16 imm;
+			u8 padding[6];
+			u64 plane;
+		};
 		u8 padding6[0x100];
 	};
 	union { /* 0x700 */
diff --git a/arch/arm64/include/uapi/asm/rmi-da.h b/arch/arm64/include/uapi/asm/rmi-da.h
index 1c21a5e78eb5..ac6e2fd2807d 100644
--- a/arch/arm64/include/uapi/asm/rmi-da.h
+++ b/arch/arm64/include/uapi/asm/rmi-da.h
@@ -22,4 +22,9 @@ struct arm64_vdev_device_measurement_guest_req {
 	__aligned_u64 nonce;
 };
 
+struct arm64_vdev_device_idmap_guest_req {
+	__u32 req_type;
+	__s32 vcpu_fd;
+};
+
 #endif
diff --git a/arch/arm64/kvm/rmi-exit.c b/arch/arm64/kvm/rmi-exit.c
index 7eff6967530c..3bba5e6afe88 100644
--- a/arch/arm64/kvm/rmi-exit.c
+++ b/arch/arm64/kvm/rmi-exit.c
@@ -129,6 +129,21 @@ static int rec_exit_host_call(struct kvm_vcpu *vcpu)
 	return kvm_smccc_call_handler(vcpu);
 }
 
+static inline void kvm_prepare_vdev_request_exit(struct kvm_vcpu *vcpu, unsigned long vdev_id)
+{
+	vcpu->run->exit_reason = KVM_EXIT_ARM64_TIO;
+	vcpu->run->cca_exit.nr = RMI_EXIT_VDEV_REQUEST;
+	vcpu->run->cca_exit.vdev_id  = vdev_id;
+	vcpu->run->cca_exit.flags = 0;
+}
+
+static int rec_exit_vdev_request(struct kvm_vcpu *vcpu)
+{
+	struct realm_rec *rec = &vcpu->arch.rec;
+
+	kvm_prepare_vdev_request_exit(vcpu, rec->run->exit.vdev_id_1);
+	return 0;
+}
 static void update_arch_timer_irq_lines(struct kvm_vcpu *vcpu)
 {
 	struct realm_rec *rec = &vcpu->arch.rec;
@@ -198,6 +213,8 @@ int handle_rec_exit(struct kvm_vcpu *vcpu, int rec_run_ret)
 		return rec_exit_ripas_change(vcpu);
 	case RMI_EXIT_HOST_CALL:
 		return rec_exit_host_call(vcpu);
+	case RMI_EXIT_VDEV_REQUEST:
+		return rec_exit_vdev_request(vcpu);
 	}
 
 	kvm_pr_unimpl("Unsupported exit reason: %u\n",
diff --git a/drivers/virt/coco/arm-cca-host/arm-cca.c b/drivers/virt/coco/arm-cca-host/arm-cca.c
index ba2751eb06f7..8aa362f44090 100644
--- a/drivers/virt/coco/arm-cca-host/arm-cca.c
+++ b/drivers/virt/coco/arm-cca-host/arm-cca.c
@@ -362,6 +362,18 @@ static ssize_t cca_tsm_guest_req(struct pci_tdi *tdi, enum pci_tsm_req_scope sco
 							       (u8 *)req_obj.nonce);
 			return ret;
 		}
+		case __REC_EXIT_DA_VDEV_REQUEST:
+		{
+			struct arm64_vdev_device_idmap_guest_req req_obj;
+
+			if (req_len != sizeof(req_obj))
+				return -EINVAL;
+
+			if (copy_from_user((void *)&req_obj, req.user, req_len))
+				return -EFAULT;
+
+			return cca_vdev_device_request(pdev, req_obj.vcpu_fd);
+		}
 		default:
 			return -EINVAL;
 		}
diff --git a/drivers/virt/coco/arm-cca-host/rmi-da.c b/drivers/virt/coco/arm-cca-host/rmi-da.c
index 58a20877c6b6..3c19dfe89c0a 100644
--- a/drivers/virt/coco/arm-cca-host/rmi-da.c
+++ b/drivers/virt/coco/arm-cca-host/rmi-da.c
@@ -1078,3 +1078,33 @@ int cca_vdev_get_device_measurements(struct pci_dev *pdev, unsigned long flags,
 	/* get and update the interface report cache. */
 	return vdev_update_device_measurements_cache(pdev);
 }
+
+int cca_vdev_device_request(struct pci_dev *pdev, unsigned long vcpu_fd)
+{
+	struct kvm *kvm;
+	struct kvm_vcpu *vcpu;
+	unsigned long rec_phys;
+	struct cca_host_tdi *host_tdi = NULL;
+	struct file *vcpu_filp __free(fput) = fget(vcpu_fd);
+
+	if (!file_is_vcpu(vcpu_filp))
+		return -EINVAL;
+
+	vcpu = vcpu_filp->private_data;
+	if (!vcpu)
+		return -EINVAL;
+
+	rec_phys = virt_to_phys(vcpu->arch.rec.rec_page);
+	host_tdi = to_cca_host_tdi(pdev);
+	if (!host_tdi)
+		return -EINVAL;
+
+	kvm = host_tdi->tdi.kvm;
+	/* make sure this is the same vm */
+	if (vcpu->kvm != kvm)
+		return -EINVAL;
+
+	if (rmi_vdev_complete(rec_phys, virt_to_phys(host_tdi->rmm_vdev)))
+		return -ENXIO;
+	return 0;
+}
diff --git a/drivers/virt/coco/arm-cca-host/rmi-da.h b/drivers/virt/coco/arm-cca-host/rmi-da.h
index 6304cee85874..2547afa1256f 100644
--- a/drivers/virt/coco/arm-cca-host/rmi-da.h
+++ b/drivers/virt/coco/arm-cca-host/rmi-da.h
@@ -93,6 +93,7 @@ struct cca_host_tdi {
 	struct pci_tdi tdi;
 	struct realm *realm;
 	void *rmm_vdev;
+	unsigned long vdev_id;
 	/* protected by cca_host_pf0_dsc.object_lock */
 	struct cache_object *interface_report;
 	struct cache_object *measurements;
@@ -152,4 +153,5 @@ int cca_vdev_read_cached_object(struct pci_dev *pdev, int type, unsigned long of
 				unsigned long max_len, void __user *user_buf);
 int cca_vdev_get_interface_report(struct pci_dev *pdev);
 int cca_vdev_get_device_measurements(struct pci_dev *pdev, unsigned long flags, u8 *nonce);
+int cca_vdev_device_request(struct pci_dev *pdev, unsigned long rec_id);
 #endif
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 34759a262b28..26a9619c364c 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -1066,6 +1066,7 @@ void kvm_get_kvm(struct kvm *kvm);
 bool kvm_get_kvm_safe(struct kvm *kvm);
 void kvm_put_kvm(struct kvm *kvm);
 bool file_is_kvm(struct file *file);
+bool file_is_vcpu(struct file *file);
 void kvm_put_kvm_no_destroy(struct kvm *kvm);
 
 static inline struct kvm_memslots *__kvm_memslots(struct kvm *kvm, int as_id)
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 49d5ce0b7a26..c2e12a1bb23b 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -188,6 +188,7 @@ struct kvm_exit_snp_req_certs {
 #define KVM_EXIT_ARM_SEA          41
 #define KVM_EXIT_ARM_LDST64B      42
 #define KVM_EXIT_SNP_REQ_CERTS    43
+#define KVM_EXIT_ARM64_TIO	  44
 
 /* For KVM_EXIT_INTERNAL_ERROR */
 /* Emulate instruction failed. */
@@ -492,6 +493,15 @@ struct kvm_run {
 		} arm_sea;
 		/* KVM_EXIT_SNP_REQ_CERTS */
 		struct kvm_exit_snp_req_certs snp_req_certs;
+		/* KVM_EXIT_ARM64_TIO*/
+		struct {
+			__u64 flags;
+			__u64 nr;
+			__u64 vdev_id;
+			__u64 gpa_base;
+			__u64 gpa_top;
+			__u64 pa_base;
+		} cca_exit;
 		/* Fix the size of the union. */
 		char padding[256];
 	};
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index f076c5a7a290..229c2b14bc83 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -4110,6 +4110,12 @@ static struct file_operations kvm_vcpu_fops = {
 	KVM_COMPAT(kvm_vcpu_compat_ioctl),
 };
 
+bool file_is_vcpu(struct file *file)
+{
+	return file && file->f_op == &kvm_vcpu_fops;
+}
+EXPORT_SYMBOL_GPL(file_is_vcpu);
+
 /*
  * Allocates an inode for the vcpu.
  */
-- 
2.43.0


  parent reply	other threads:[~2026-03-12  8:08 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-03-12  8:07 [RFC PATCH v3 00/12] coco/TSM: Implement host-side support for Arm CCA TDISP setup Aneesh Kumar K.V (Arm)
2026-03-12  8:07 ` [RFC PATCH v3 01/12] coco: host: arm64: Add support for virtual device communication Aneesh Kumar K.V (Arm)
2026-03-12  8:07 ` [RFC PATCH v3 02/12] coco: host: arm64: Add support for RMM vdev objects Aneesh Kumar K.V (Arm)
2026-03-12  8:07 ` [RFC PATCH v3 03/12] coco: host: arm64: Add helpers to unlock and destroy RMM vdev Aneesh Kumar K.V (Arm)
2026-03-12  8:07 ` [RFC PATCH v3 04/12] coco: host: arm64: Add support for da object read RHI handling Aneesh Kumar K.V (Arm)
2026-03-12  8:07 ` [RFC PATCH v3 05/12] coco: host: arm64: Add helper for cached object fetches Aneesh Kumar K.V (Arm)
2026-03-12  8:07 ` [RFC PATCH v3 06/12] coco: host: arm64: Fetch interface report via RMI Aneesh Kumar K.V (Arm)
2026-03-12  8:07 ` [RFC PATCH v3 07/12] coco: host: arm64: Fetch device measurements " Aneesh Kumar K.V (Arm)
2026-03-12  8:07 ` Aneesh Kumar K.V (Arm) [this message]
2026-03-12  8:07 ` [RFC PATCH v3 09/12] coco: host: KVM: arm64: Handle vdev map/validation exits Aneesh Kumar K.V (Arm)
2026-03-12  8:07 ` [RFC PATCH v3 10/12] KVM: arm64: Unmap device mappings when a private granule is destroyed Aneesh Kumar K.V (Arm)
2026-03-12  8:07 ` [RFC PATCH v3 11/12] coco: host: arm64: Transition vdevs to TDISP RUN state Aneesh Kumar K.V (Arm)
2026-03-12  8:07 ` [RFC PATCH v3 12/12] KVM: arm64: CCA: enable DA in realm create parameters Aneesh Kumar K.V (Arm)

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=20260312080743.3487326-9-aneesh.kumar@kernel.org \
    --to=aneesh.kumar@kernel.org \
    --cc=Jonathan.Cameron@huawei.com \
    --cc=Suzuki.Poulose@arm.com \
    --cc=aik@amd.com \
    --cc=catalin.marinas@arm.com \
    --cc=dan.j.williams@intel.com \
    --cc=jgg@ziepe.ca \
    --cc=kvmarm@lists.linux.dev \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-coco@lists.linux.dev \
    --cc=linux-kernel@vger.kernel.org \
    --cc=maz@kernel.org \
    --cc=sameo@rivosinc.com \
    --cc=steven.price@arm.com \
    --cc=will@kernel.org \
    --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