]> www.infradead.org Git - users/hch/misc.git/commitdiff
KVM: arm64: Add filtering hook to S1 page table walk
authorMarc Zyngier <maz@kernel.org>
Mon, 25 Aug 2025 10:28:19 +0000 (11:28 +0100)
committerMarc Zyngier <maz@kernel.org>
Sat, 20 Sep 2025 10:05:13 +0000 (11:05 +0100)
Add a filtering hook that can get called on each level of the
walk, and providing access to the full state.

Crucially, this is called *before* the access is made, so that
it is possible to track down the level of a faulting access.

Reviewed-by: Oliver Upton <oliver.upton@linux.dev>
Signed-off-by: Marc Zyngier <maz@kernel.org>
arch/arm64/include/asm/kvm_nested.h
arch/arm64/kvm/at.c

index f3135ded47b7d8dca2d7795e95af532ab890ce90..cce0e4cb54484952b9d63750f642329522934ced 100644 (file)
@@ -288,7 +288,21 @@ enum trans_regime {
        TR_EL2,
 };
 
+struct s1_walk_info;
+
+struct s1_walk_context {
+       struct s1_walk_info     *wi;
+       u64                     table_ipa;
+       int                     level;
+};
+
+struct s1_walk_filter {
+       int     (*fn)(struct s1_walk_context *, void *);
+       void    *priv;
+};
+
 struct s1_walk_info {
+       struct s1_walk_filter   *filter;
        u64                     baddr;
        enum trans_regime       regime;
        unsigned int            max_oa_bits;
index c06a8e831f331f57f4f5fe9b230038f720a477db..b70b777a3c2098c19dcc634e0430ecf81a5149e8 100644 (file)
@@ -404,6 +404,17 @@ static int walk_s1(struct kvm_vcpu *vcpu, struct s1_walk_info *wi,
                        ipa = kvm_s2_trans_output(&s2_trans);
                }
 
+               if (wi->filter) {
+                       ret = wi->filter->fn(&(struct s1_walk_context)
+                                            {
+                                                    .wi        = wi,
+                                                    .table_ipa = baddr,
+                                                    .level     = level,
+                                            }, wi->filter->priv);
+                       if (ret)
+                               return ret;
+               }
+
                ret = kvm_read_guest(vcpu->kvm, ipa, &desc, sizeof(desc));
                if (ret) {
                        fail_s1_walk(wr, ESR_ELx_FSC_SEA_TTW(level), false);