From 01dd8c280b9cfa4b3bbd4a2ffbaa0e07567a5163 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Wed, 25 Oct 2023 13:52:57 +0100 Subject: [PATCH] ANDROID: KVM: arm64: Prefault entries when splitting a block mapping When splitting a block mapping, we install a table entry pointing to an empty page and recreate the new entries lazily as we fault them in. For page-tables with the KVM_PGTABLE_S2_IDMAP flag, this can result in unnecessary translation faults. When splitting a block for a page-table with KVM_PGTABLE_S2_IDMAP set, pre-populate the newly allocate page-table page with contiguous ptes based on the attributes of the block. Bug: 308373293 Change-Id: I0c53d048de913e193830caef93d75755270db709 Signed-off-by: Will Deacon Signed-off-by: Keir Fraser --- arch/arm64/kvm/hyp/pgtable.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/arch/arm64/kvm/hyp/pgtable.c b/arch/arm64/kvm/hyp/pgtable.c index b7e8faa894c9..2d11455aabe8 100644 --- a/arch/arm64/kvm/hyp/pgtable.c +++ b/arch/arm64/kvm/hyp/pgtable.c @@ -775,6 +775,22 @@ 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) +{ + u64 granule = kvm_granule_size(level); + int i; + + if (!kvm_pte_valid(attr)) + 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; + } +} + static int stage2_map_walk_leaf(u64 addr, u64 end, u32 level, kvm_pte_t *ptep, struct stage2_map_data *data) { @@ -805,6 +821,12 @@ static int stage2_map_walk_leaf(u64 addr, u64 end, u32 level, kvm_pte_t *ptep, if (!childp) 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); + } + /* * If we've run into an existing block mapping then replace it with * a table. Accesses beyond 'end' that fall within the new table