From: Jack Thomson <[email protected]>

Allow callers of kvm_pgtable_get_leaf() to specify the page-table walk
flags, in preparation for performing walks under the MMU read lock.

Reading a stage-2 leaf while only holding the read lock requires
KVM_PGTABLE_WALK_SHARED: parallel faults (which also only hold the read
lock) can unlink table pages and free them via RCU, so the walker must
be inside an RCU read-side critical section, which the shared walk flag
provides via kvm_pgtable_walk_begin().

All existing callers either hold the write lock, walk with interrupts
disabled, or run at hyp where shared walks are rejected; they keep the
current behaviour by passing no flags.

No functional change intended.

Signed-off-by: Jack Thomson <[email protected]>
---
 arch/arm64/include/asm/kvm_pgtable.h  |  5 ++++-
 arch/arm64/kvm/hyp/nvhe/mem_protect.c | 10 +++++-----
 arch/arm64/kvm/hyp/pgtable.c          |  5 +++--
 arch/arm64/kvm/mmu.c                  |  2 +-
 arch/arm64/kvm/nested.c               |  2 +-
 5 files changed, 14 insertions(+), 10 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_pgtable.h 
b/arch/arm64/include/asm/kvm_pgtable.h
index 41a8687938eb..d0167f7dfbee 100644
--- a/arch/arm64/include/asm/kvm_pgtable.h
+++ b/arch/arm64/include/asm/kvm_pgtable.h
@@ -859,6 +859,8 @@ int kvm_pgtable_walk(struct kvm_pgtable *pgt, u64 addr, u64 
size,
  * @addr:      Input address for the start of the walk.
  * @ptep:      Pointer to storage for the retrieved PTE.
  * @level:     Pointer to storage for the level of the retrieved PTE.
+ * @flags:     Flags to control the page-table walk
+ *             (see struct kvm_pgtable_visit_ctx).
  *
  * The offset of @addr within a page is ignored.
  *
@@ -869,7 +871,8 @@ int kvm_pgtable_walk(struct kvm_pgtable *pgt, u64 addr, u64 
size,
  * Return: 0 on success, negative error code on failure.
  */
 int kvm_pgtable_get_leaf(struct kvm_pgtable *pgt, u64 addr,
-                        kvm_pte_t *ptep, s8 *level);
+                        kvm_pte_t *ptep, s8 *level,
+                        enum kvm_pgtable_walk_flags flags);
 
 /**
  * kvm_pgtable_stage2_pte_prot() - Retrieve the protection attributes of a
diff --git a/arch/arm64/kvm/hyp/nvhe/mem_protect.c 
b/arch/arm64/kvm/hyp/nvhe/mem_protect.c
index 25f04629014e..3b765c9ff7e8 100644
--- a/arch/arm64/kvm/hyp/nvhe/mem_protect.c
+++ b/arch/arm64/kvm/hyp/nvhe/mem_protect.c
@@ -522,7 +522,7 @@ static int host_stage2_adjust_range(u64 addr, struct 
kvm_mem_range *range)
        int ret;
 
        hyp_assert_lock_held(&host_mmu.lock);
-       ret = kvm_pgtable_get_leaf(&host_mmu.pgt, addr, &pte, &level);
+       ret = kvm_pgtable_get_leaf(&host_mmu.pgt, addr, &pte, &level, 0);
        if (ret)
                return ret;
 
@@ -890,7 +890,7 @@ static int get_valid_guest_pte(struct pkvm_hyp_vm *vm, u64 
ipa, kvm_pte_t *ptep,
        s8 level;
        int ret;
 
-       ret = kvm_pgtable_get_leaf(&vm->pgt, ipa, &pte, &level);
+       ret = kvm_pgtable_get_leaf(&vm->pgt, ipa, &pte, &level, 0);
        if (ret)
                return ret;
        if (guest_pte_is_poisoned(pte))
@@ -939,7 +939,7 @@ int __pkvm_vcpu_in_poison_fault(struct pkvm_hyp_vcpu 
*hyp_vcpu)
        ipa |= FAR_TO_FIPA_OFFSET(kvm_vcpu_get_hfar(&hyp_vcpu->vcpu));
 
        guest_lock_component(vm);
-       ret = kvm_pgtable_get_leaf(&vm->pgt, ipa, &pte, &level);
+       ret = kvm_pgtable_get_leaf(&vm->pgt, ipa, &pte, &level, 0);
        if (ret)
                goto unlock;
 
@@ -1293,7 +1293,7 @@ static int host_stage2_get_guest_info(phys_addr_t phys, 
struct pkvm_hyp_vm **vm,
                return -EPERM;
        }
 
-       ret = kvm_pgtable_get_leaf(&host_mmu.pgt, phys, &pte, &level);
+       ret = kvm_pgtable_get_leaf(&host_mmu.pgt, phys, &pte, &level, 0);
        if (ret)
                return ret;
 
@@ -1522,7 +1522,7 @@ static int __check_host_shared_guest(struct pkvm_hyp_vm 
*vm, u64 *__phys, u64 ip
        s8 level;
        int ret;
 
-       ret = kvm_pgtable_get_leaf(&vm->pgt, ipa, &pte, &level);
+       ret = kvm_pgtable_get_leaf(&vm->pgt, ipa, &pte, &level, 0);
        if (ret)
                return ret;
        if (!kvm_pte_valid(pte))
diff --git a/arch/arm64/kvm/hyp/pgtable.c b/arch/arm64/kvm/hyp/pgtable.c
index 0c1defa5fb0f..6a839a32e246 100644
--- a/arch/arm64/kvm/hyp/pgtable.c
+++ b/arch/arm64/kvm/hyp/pgtable.c
@@ -298,12 +298,13 @@ static int leaf_walker(const struct kvm_pgtable_visit_ctx 
*ctx,
 }
 
 int kvm_pgtable_get_leaf(struct kvm_pgtable *pgt, u64 addr,
-                        kvm_pte_t *ptep, s8 *level)
+                        kvm_pte_t *ptep, s8 *level,
+                        enum kvm_pgtable_walk_flags flags)
 {
        struct leaf_walk_data data;
        struct kvm_pgtable_walker walker = {
                .cb     = leaf_walker,
-               .flags  = KVM_PGTABLE_WALK_LEAF,
+               .flags  = flags | KVM_PGTABLE_WALK_LEAF,
                .arg    = &data,
        };
        int ret;
diff --git a/arch/arm64/kvm/mmu.c b/arch/arm64/kvm/mmu.c
index 4da9281312eb..c720f07cb82e 100644
--- a/arch/arm64/kvm/mmu.c
+++ b/arch/arm64/kvm/mmu.c
@@ -839,7 +839,7 @@ static int get_user_mapping_size(struct kvm *kvm, u64 addr)
         * IPI-ing threads).
         */
        local_irq_save(flags);
-       ret = kvm_pgtable_get_leaf(&pgt, addr, &pte, &level);
+       ret = kvm_pgtable_get_leaf(&pgt, addr, &pte, &level, 0);
        local_irq_restore(flags);
 
        if (ret)
diff --git a/arch/arm64/kvm/nested.c b/arch/arm64/kvm/nested.c
index 38f672e94087..e45aed6d9e65 100644
--- a/arch/arm64/kvm/nested.c
+++ b/arch/arm64/kvm/nested.c
@@ -559,7 +559,7 @@ static u8 get_guest_mapping_ttl(struct kvm_s2_mmu *mmu, u64 
addr)
                return 0;
 
        tmp &= ~(sz - 1);
-       if (kvm_pgtable_get_leaf(mmu->pgt, tmp, &pte, NULL))
+       if (kvm_pgtable_get_leaf(mmu->pgt, tmp, &pte, NULL, 0))
                goto again;
        if (!(pte & PTE_VALID))
                goto again;
-- 
2.43.0


Reply via email to