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 <willdeacon@google.com>
Signed-off-by: Keir Fraser <keirf@google.com>
This commit is contained in:
Will Deacon 2023-10-25 13:52:57 +01:00 committed by Keir Fraser
parent cc653d701f
commit 01dd8c280b

View file

@ -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