[PATCH v3 17/23] KVM: arm64: Add vcpu conduit for pkvm_hyp_req
Vincent Donnefort
vdonnefort at google.com
Mon Nov 2 12:46:22 PST 2026
The pKVM hypervisor depends on the host for a lot of operations like
memory allocation. It can raise a request by populating a pkvm_hyp_req
on the extra registers when returning a SMCCC call.
Add a new conduit, using a per-vCPU pkvm_hyp_req, populated on
ARM_EXCEPTION_PKVM_HYP_REQ. This allows processing the request later, in
a less restrictive context than the one from where the __kvm_vcpu_run
HVC is called, just like the other exceptions are handled.
Signed-off-by: Vincent Donnefort <vdonnefort at google.com>
---
arch/arm64/include/asm/kvm_asm.h | 10 ++++++----
arch/arm64/include/asm/kvm_host.h | 26 ++++++++++++++++++++++++++
arch/arm64/include/asm/kvm_pkvm.h | 24 +-----------------------
arch/arm64/kvm/handle_exit.c | 3 +++
arch/arm64/kvm/hyp/nvhe/hyp-main.c | 2 ++
arch/arm64/kvm/pkvm.c | 9 +++++++--
6 files changed, 45 insertions(+), 29 deletions(-)
diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h
index 3efc63e1a823..872185f9ac53 100644
--- a/arch/arm64/include/asm/kvm_asm.h
+++ b/arch/arm64/include/asm/kvm_asm.h
@@ -17,10 +17,11 @@
#define ARM_EXCEPTION_IS_TRAP(x) (ARM_EXCEPTION_CODE((x)) == ARM_EXCEPTION_TRAP)
#define ARM_SERROR_PENDING(x) !!((x) & (1U << ARM_EXIT_WITH_SERROR_BIT))
-#define ARM_EXCEPTION_IRQ 0
-#define ARM_EXCEPTION_EL1_SERROR 1
-#define ARM_EXCEPTION_TRAP 2
-#define ARM_EXCEPTION_IL 3
+#define ARM_EXCEPTION_IRQ 0
+#define ARM_EXCEPTION_EL1_SERROR 1
+#define ARM_EXCEPTION_TRAP 2
+#define ARM_EXCEPTION_IL 3
+#define ARM_EXCEPTION_PKVM_HYP_REQ 4
/* The hyp-stub will return this for any kvm_call_hyp() call */
#define ARM_EXCEPTION_HYP_GONE HVC_STUB_ERR
@@ -28,6 +29,7 @@
{ARM_EXCEPTION_IRQ, "IRQ" }, \
{ARM_EXCEPTION_EL1_SERROR, "SERROR" }, \
{ARM_EXCEPTION_TRAP, "TRAP" }, \
+ {ARM_EXCEPTION_PKVM_HYP_REQ, "PKVM_HYP_REQ" }, \
{ARM_EXCEPTION_HYP_GONE, "HYP_GONE" }
/*
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index 97332ffcb130..0161bcb8123b 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -138,6 +138,29 @@ u32 __attribute_const__ kvm_target_cpu(void);
void kvm_reset_vcpu(struct kvm_vcpu *vcpu);
void kvm_arm_vcpu_destroy(struct kvm_vcpu *vcpu);
+enum pkvm_hyp_req_type {
+ PKVM_HYP_NO_REQ = 0,
+ PKVM_HYP_REQ_HYP_ALLOC,
+ PKVM_HYP_REQ_HYP_ALLOC_SELFTEST,
+ __PKVM_HYP_REQ_TYPE_MAX,
+};
+
+#define PKVM_HYP_REQ_SMCCC_ARG_SIZE_MAX \
+ (sizeof(struct arm_smccc_res) - offsetof(struct arm_smccc_res, a2) - 1)
+
+struct pkvm_hyp_req {
+ u8 type;
+ union {
+ struct {
+ u32 nr_pages;
+ } mem;
+ struct {
+ /* Helper for SMCCC encoding/decoding */
+ u8 args[PKVM_HYP_REQ_SMCCC_ARG_SIZE_MAX];
+ } args;
+ };
+};
+
struct kvm_hyp_memcache {
phys_addr_t head;
unsigned long nr_pages;
@@ -1006,6 +1029,9 @@ struct kvm_vcpu_arch {
/* Pages to top-up the pKVM/EL2 guest stage-2 pool */
struct kvm_hyp_memcache stage2_mc;
+ /* To be read on ARM_EXCEPTION_PKVM_HYP_REQ */
+ struct pkvm_hyp_req pkvm_hyp_req;
+
/* Virtual SError ESR to restore when HCR_EL2.VSE is set */
u64 vsesr_el2;
diff --git a/arch/arm64/include/asm/kvm_pkvm.h b/arch/arm64/include/asm/kvm_pkvm.h
index b75dc3d03a98..3e51337f2d9e 100644
--- a/arch/arm64/include/asm/kvm_pkvm.h
+++ b/arch/arm64/include/asm/kvm_pkvm.h
@@ -22,6 +22,7 @@ int pkvm_create_hyp_vm(struct kvm *kvm);
bool pkvm_hyp_vm_is_created(struct kvm *kvm);
void pkvm_destroy_hyp_vm(struct kvm *kvm);
int pkvm_create_hyp_vcpu(struct kvm_vcpu *vcpu);
+int __pkvm_handle_vcpu_req(struct kvm_vcpu *vcpu);
/*
* Check whether the specific capability is allowed in pKVM.
@@ -231,29 +232,6 @@ struct pkvm_mapping {
u64 __subtree_last; /* Internal member for interval tree */
};
-enum pkvm_hyp_req_type {
- PKVM_HYP_NO_REQ = 0,
- PKVM_HYP_REQ_HYP_ALLOC,
- PKVM_HYP_REQ_HYP_ALLOC_SELFTEST,
- __PKVM_HYP_REQ_TYPE_MAX,
-};
-
-#define PKVM_HYP_REQ_SMCCC_ARG_SIZE_MAX \
- (sizeof(struct arm_smccc_res) - offsetof(struct arm_smccc_res, a2) - 1)
-
-struct pkvm_hyp_req {
- u8 type;
- union {
- struct {
- u32 nr_pages;
- } mem;
- struct {
- /* Helper for SMCCC encoding/decoding */
- u8 args[PKVM_HYP_REQ_SMCCC_ARG_SIZE_MAX];
- } args;
- };
-};
-
static inline size_t pkvm_hyp_req_arg_size(u8 type)
{
struct pkvm_hyp_req *req;
diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c
index 9931192735d4..2030675304ca 100644
--- a/arch/arm64/kvm/handle_exit.c
+++ b/arch/arm64/kvm/handle_exit.c
@@ -18,6 +18,7 @@
#include <asm/kvm_emulate.h>
#include <asm/kvm_mmu.h>
#include <asm/kvm_nested.h>
+#include <asm/kvm_pkvm.h>
#include <asm/debug-monitors.h>
#include <asm/stacktrace/nvhe.h>
#include <asm/traps.h>
@@ -464,6 +465,8 @@ int handle_exit(struct kvm_vcpu *vcpu, int exception_index)
return 1;
case ARM_EXCEPTION_TRAP:
return handle_trap_exceptions(vcpu);
+ case ARM_EXCEPTION_PKVM_HYP_REQ:
+ return __pkvm_handle_vcpu_req(vcpu);
case ARM_EXCEPTION_HYP_GONE:
/*
* EL2 has been reset to the hyp-stub. This happens when a guest
diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
index c322ef4432c9..41817f45115d 100644
--- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
+++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
@@ -734,6 +734,7 @@ static void flush_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu)
case ARM_EXCEPTION_IRQ:
case ARM_EXCEPTION_EL1_SERROR:
case ARM_EXCEPTION_IL:
+ case ARM_EXCEPTION_PKVM_HYP_REQ:
break;
case ARM_EXCEPTION_TRAP:
/* Nothing was marshalled for this trap, see sync_hyp_vcpu(). */
@@ -803,6 +804,7 @@ static void sync_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu, u32 exit_reason)
break;
case ARM_EXCEPTION_EL1_SERROR:
case ARM_EXCEPTION_IL:
+ case ARM_EXCEPTION_PKVM_HYP_REQ:
break;
default:
BUG();
diff --git a/arch/arm64/kvm/pkvm.c b/arch/arm64/kvm/pkvm.c
index ae53c701206a..c55b6d442d0e 100644
--- a/arch/arm64/kvm/pkvm.c
+++ b/arch/arm64/kvm/pkvm.c
@@ -765,7 +765,7 @@ bool pkvm_force_reclaim_guest_page(phys_addr_t phys)
return !ret || ret == -EAGAIN;
}
-static int pkvm_handle_hyp_req(struct pkvm_hyp_req *req)
+static int pkvm_handle_hyp_req(struct pkvm_hyp_req *req, struct kvm_vcpu *vcpu)
{
int ret = -EINVAL;
@@ -788,7 +788,12 @@ int __pkvm_handle_smccc_req(struct arm_smccc_res *res)
struct pkvm_hyp_req req;
if (smccc_to_pkvm_hyp_req(&req, res))
- return pkvm_handle_hyp_req(&req);
+ return pkvm_handle_hyp_req(&req, NULL);
return res->a1;
}
+
+int __pkvm_handle_vcpu_req(struct kvm_vcpu *vcpu)
+{
+ return pkvm_handle_hyp_req(&vcpu->arch.pkvm_hyp_req, vcpu) ?: 1;
+}
--
2.56.0.385.gac671c819a-goog
More information about the linux-arm-kernel
mailing list