mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-06 02:50:49 +09:00
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:
@@ -773,6 +773,22 @@ static int stage2_map_walk_table_pre(u64 addr, u64 end, u32 level,
|
|||||||
return 0;
|
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,
|
static int stage2_map_walk_leaf(u64 addr, u64 end, u32 level, kvm_pte_t *ptep,
|
||||||
struct stage2_map_data *data)
|
struct stage2_map_data *data)
|
||||||
{
|
{
|
||||||
@@ -803,6 +819,12 @@ static int stage2_map_walk_leaf(u64 addr, u64 end, u32 level, kvm_pte_t *ptep,
|
|||||||
if (!childp)
|
if (!childp)
|
||||||
return -ENOMEM;
|
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
|
* If we've run into an existing block mapping then replace it with
|
||||||
* a table. Accesses beyond 'end' that fall within the new table
|
* a table. Accesses beyond 'end' that fall within the new table
|
||||||
|
|||||||
Reference in New Issue
Block a user