[PATCH v16 32/45] KVM: arm64: CCA: Handle Realm PSCI requests

Steven Price <[email protected]> Mon, 3 Aug 2026 14:43:48 +0100
Newsgroups dev.linux.lists.linux-coco,dev.linux.lists.kvmarm,org.infradead.lists.linux-arm-kernel,org.kernel.vger.kvm,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
Some PSCI commands cause a REC exit and the host has to call
RMI_PSCI_COMPLETE to provide the status value to return to the guest.

Co-developed-by: Suzuki K Poulose <[email protected]>
Signed-off-by: Suzuki K Poulose <[email protected]>
Signed-off-by: Steven Price <[email protected]>
---
Changes since v15:
 * Adapt to new exit handling.
Changes since v14:
 * Dropped the support for providing the target REC for a PSCI call (as
   per v2.0-bet2 spec).
Changes since v13:
 * The ioctl KVM_ARM_VCPU_RMI_PSCI_COMPLETE has gone. The RMI call is
   made automatically just before entering the REC again.
Changes since v12:
 * Change return code for non-realms to -ENXIO to better represent that
   the ioctl is invalid for non-realms (checkpatch is insistent that
   "ENOSYS means 'invalid syscall nr' and nothing else").
Changes since v11:
 * RMM->RMI renaming.
Changes since v6:
 * Use vcpu_is_rec() rather than kvm_is_realm(vcpu->kvm).
 * Minor renaming/formatting fixes.
---
 arch/arm64/include/asm/kvm_rmi.h |  2 ++
 arch/arm64/kvm/rmi.c             | 38 ++++++++++++++++++++++++++++++++
 2 files changed, 40 insertions(+)

diff --git a/arch/arm64/include/asm/kvm_rmi.h b/arch/arm64/include/asm/kvm_rmi.h
index 967c0a6e8e9c..0fb685004d5c 100644
--- a/arch/arm64/include/asm/kvm_rmi.h
+++ b/arch/arm64/include/asm/kvm_rmi.h
@@ -123,6 +123,8 @@ int realm_map_ipa(struct kvm *kvm, phys_addr_t ipa,
 		  enum kvm_pgtable_prot prot,
 		  struct kvm_mmu_memory_cache *memcache);
 
+int realm_psci_complete(struct kvm_vcpu *source, unsigned long status);
+
 static inline bool kvm_realm_is_private_address(struct realm *realm,
 						unsigned long addr)
 {
diff --git a/arch/arm64/kvm/rmi.c b/arch/arm64/kvm/rmi.c
index 3ef185bc8210..3f31ad25680f 100644
--- a/arch/arm64/kvm/rmi.c
+++ b/arch/arm64/kvm/rmi.c
@@ -3,6 +3,7 @@
  * Copyright (C) 2023-2026 ARM Ltd.
  */
 
+#include <uapi/linux/psci.h>
 #include <linux/kvm_host.h>
 
 #include <asm/kvm_emulate.h>
@@ -120,6 +121,17 @@ static void free_rtt(phys_addr_t phys)
 	kvm_account_pgtable_pages(phys_to_virt(phys), -1);
 }
 
+int realm_psci_complete(struct kvm_vcpu *source, unsigned long status)
+{
+	long ret;
+
+	ret = rmi_psci_complete(source->arch.rec.rec_phys, status);
+	if (ret)
+		return -ENXIO;
+
+	return 0;
+}
+
 static long realm_rtt_create(struct realm *realm,
 			     unsigned long addr,
 			     int level,
@@ -1145,6 +1157,30 @@ static int kvm_complete_ripas_change(struct kvm_vcpu *vcpu)
 	return 1;
 }
 
+static int kvm_rec_complete_psci(struct kvm_vcpu *vcpu)
+{
+	struct rec_run *run = vcpu->arch.rec.run;
+	unsigned long status = PSCI_RET_DENIED;
+	unsigned long ret = vcpu_get_reg(vcpu, 0);
+	int r;
+
+	switch (run->exit.gprs[0]) {
+	case PSCI_0_2_FN64_CPU_ON: {
+		if (ret != PSCI_RET_SUCCESS &&
+		    ret != PSCI_RET_ALREADY_ON)
+			status = PSCI_RET_DENIED;
+		else
+			status = PSCI_RET_SUCCESS;
+		break;
+	}
+	default:
+		return 1;
+	}
+
+	r = realm_psci_complete(vcpu, status);
+	return r ?: 1;
+}
+
 int kvm_rec_handle_request(struct kvm_vcpu *vcpu)
 {
 	struct realm_rec *rec = &vcpu->arch.rec;
@@ -1163,6 +1199,8 @@ int kvm_rec_handle_request(struct kvm_vcpu *vcpu)
 					vcpu_get_reg(vcpu, rt);
 		}
 		break;
+	case RMI_EXIT_PSCI:
+		return kvm_rec_complete_psci(vcpu);
 	case RMI_EXIT_RIPAS_CHANGE:
 		return kvm_complete_ripas_change(vcpu);
 	default:
-- 
2.43.0