From 4fa87d4d8fce9c45afcbcb03258b7be84052f7c0 Mon Sep 17 00:00:00 2001 From: Keir Fraser Date: Tue, 7 Nov 2023 15:40:41 +0000 Subject: [PATCH] ANDROID: KVM: arm64: Skip prefaulting ptes which will be modified later Block mappings can be split as part of a page table update. When prefaulting entries during the split, it is pointless to install valid ptes which will later be modified by the same walk. At the same time, push the check for pte_is_counted into the prefault handler, where it logically belongs. Bug: 308373293 Change-Id: If4599b2860aa62d82ce8db019a8410c2d883de71 Signed-off-by: Keir Fraser --- arch/arm64/kvm/hyp/pgtable.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/arch/arm64/kvm/hyp/pgtable.c b/arch/arm64/kvm/hyp/pgtable.c index b9140293da7d..64387388584c 100644 --- a/arch/arm64/kvm/hyp/pgtable.c +++ b/arch/arm64/kvm/hyp/pgtable.c @@ -783,19 +783,27 @@ static int stage2_map_walk_table_pre(u64 addr, u64 end, u32 level, return 0; } -static void stage2_map_prefault_idmap(u64 addr, u32 level, kvm_pte_t *ptep, - kvm_pte_t attr) +static void stage2_map_prefault_idmap(struct kvm_pgtable_pte_ops *pte_ops, + u64 addr, u64 end, u32 level, + kvm_pte_t *ptep, kvm_pte_t block_pte) { - u64 granule = kvm_granule_size(level); + u64 pa, granule; int i; - if (!kvm_pte_valid(attr)) + WARN_ON(pte_ops->pte_is_counted_cb(block_pte, level-1)); + + if (!kvm_pte_valid(block_pte)) return; - for (i = 0; i < PTRS_PER_PTE; ++i, ++ptep, addr += granule) { - kvm_pte_t pte = kvm_init_valid_leaf_pte(addr, attr, level); - /* We can write non-atomically: ptep isn't yet live. */ - *ptep = pte; + pa = ALIGN_DOWN(addr, kvm_granule_size(level-1)); + granule = kvm_granule_size(level); + for (i = 0; i < PTRS_PER_PTE; ++i, ++ptep, pa += granule) { + kvm_pte_t pte = kvm_init_valid_leaf_pte(pa, block_pte, level); + /* Skip ptes in the range being modified by the caller. */ + if ((pa < addr) || (pa >= end)) { + /* We can write non-atomically: ptep isn't yet live. */ + *ptep = pte; + } } } @@ -830,9 +838,8 @@ static int stage2_map_walk_leaf(u64 addr, u64 end, u32 level, kvm_pte_t *ptep, return -ENOMEM; if (pgt->flags & KVM_PGTABLE_S2_IDMAP) { - WARN_ON(pte_ops->pte_is_counted_cb(pte, level)); - addr = ALIGN_DOWN(addr, kvm_granule_size(level)); - stage2_map_prefault_idmap(addr, level + 1, childp, pte); + stage2_map_prefault_idmap(pte_ops, addr, end, level + 1, + childp, pte); } /*