[RFC PATCH v6 28/35] KVM: arm64: at: Use callback for reading descriptor

Alexandru Elisei
2025-11-14T16:08:45Z

Allow callers of __kvm_translate_va() to use a custom defined function for
reading the translation table descriptor from guest memory. This will be
useful for SPE virtualization, where the translation tables must also be
mapped at stage 2 for the entire duration of the guest profiling session.

Signed-off-by: Alexandru Elisei <alexandru.elisei@arm.com>
---
arch/arm64/include/asm/kvm_nested.h | 6 ++++++
arch/arm64/kvm/at.c | 17 +++++++++++++----
arch/arm64/kvm/nested.c | 7 ++++---
3 files changed, 23 insertions(+), 7 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_nested.h b/arch/arm64/include/asm/kvm_nested.h
index f7c06a840963..e9a73ea74f24 100644
--- a/arch/arm64/include/asm/kvm_nested.h
+++ b/arch/arm64/include/asm/kvm_nested.h
@@ -284,6 +284,11 @@ static inline unsigned int ps_to_output_size(unsigned int ps, bool pa52bit)
}
}

+typedef int (*read_desc_fn)(struct kvm_vcpu *, gpa_t, void *, unsigned long);
+
+int kvm_vcpu_read_desc(struct kvm_vcpu *vcpu, gpa_t gpa, void *desc,
+ unsigned long len);
+
enum trans_regime {
TR_EL10,
TR_EL20,
@@ -305,6 +310,7 @@ struct s1_walk_filter {

struct s1_walk_info {
struct s1_walk_filter *filter;
+ read_desc_fn read_desc;
u64 baddr;
enum trans_regime regime;
unsigned int max_oa_bits;
diff --git a/arch/arm64/kvm/at.c b/arch/arm64/kvm/at.c
index be26d5aa668c..e1df4278d5d5 100644
--- a/arch/arm64/kvm/at.c
+++ b/arch/arm64/kvm/at.c
@@ -110,6 +110,12 @@ static u64 effective_tcr2(struct kvm_vcpu *vcpu, enum trans_regime regime)
return vcpu_read_sys_reg(vcpu, TCR2_EL2);
}

+int kvm_vcpu_read_desc(struct kvm_vcpu *vcpu, gpa_t gpa, void *desc,
+ unsigned long len)
+{
+ return kvm_read_guest(vcpu->kvm, gpa, desc, len);
+}
+
static bool s1pie_enabled(struct kvm_vcpu *vcpu, enum trans_regime regime)
{
if (!kvm_has_s1pie(vcpu->kvm))
@@ -142,6 +148,9 @@ static int setup_s1_walk(struct kvm_vcpu *vcpu, struct s1_walk_info *wi,
unsigned int stride, x;
bool va55, tbi, lva;

+ if (!wi->read_desc)
+ return -EINVAL;
+
va55 = va & BIT(55);

if (vcpu_has_nv(vcpu)) {
@@ -414,7 +423,7 @@ static int walk_s1(struct kvm_vcpu *vcpu, struct s1_walk_info *wi,
return ret;
}

- ret = kvm_read_guest(vcpu->kvm, ipa, &desc, sizeof(desc));
+ ret = wi->read_desc(vcpu, ipa, &desc, sizeof(desc));
if (ret) {
fail_s1_walk(wr, ESR_ELx_FSC_SEA_TTW(level), false);
return ret;
@@ -1542,9 +1551,9 @@ void __kvm_at_s12(struct kvm_vcpu *vcpu, u32 op, u64 vaddr)
}

/*
- * Translate a VA for a given EL in a given translation regime, with
- * or without PAN. This requires wi->{regime, as_el0, pan} to be
- * set. The rest of the wi and wr should be 0-initialised.
+ * Translate a VA for a given EL in a given translation regime, with or without
+ * PAN. This requires wi->{read_desc, regime, as_el0, pan} to be set. The rest
+ * of the wi and wr should be 0-initialised.
*/
int __kvm_translate_va(struct kvm_vcpu *vcpu, struct s1_walk_info *wi,
struct s1_walk_result *wr, u64 va)
diff --git a/arch/arm64/kvm/nested.c b/arch/arm64/kvm/nested.c
index f04cda40545b..92e94bb96bcc 100644
--- a/arch/arm64/kvm/nested.c
+++ b/arch/arm64/kvm/nested.c
@@ -1196,9 +1196,10 @@ static int kvm_translate_vncr(struct kvm_vcpu *vcpu, bool *is_gmem)
invalidate_vncr(vt);

vt->wi = (struct s1_walk_info) {
- .regime = TR_EL20,
- .as_el0 = false,
- .pan = false,
+ .read_desc = kvm_vcpu_read_desc,
+ .regime = TR_EL20,
+ .as_el0 = false,
+ .pan = false,
};
vt->wr = (struct s1_walk_result){};
}
--
2.51.2