From 09a2d1b37e4f8d641364dbdfdbc8dc71bc576092 Mon Sep 17 00:00:00 2001 From: Quentin Perret Date: Tue, 7 Jun 2022 12:00:07 +0000 Subject: [PATCH] ANDROID: KVM: arm64: Don't update IOMMUs unnecessarily When handling host stage-2 faults the hypervisor currently updates the CPU _and_ IOMMUs page-tables. However, since we currently proactively map accessible PA ranges into IOMMUs, updating them during stage-2 faults is unnecessary -- it only needs to be done during ownership transitions. Optimize this by skipping the IOMMU updates from the host memory abort path, which also reduces contention on the host stage-2 lock during boot and saves up to 1.1 sec of boot time on Pixel 6. Bug: 357781595 Bug: 384432312 Change-Id: Icb6f1b2d10de8cc2f976bbc94b9b79ad7aaa6135 Signed-off-by: Quentin Perret (cherry picked from commit 20c6e1ba55403fad0e7f039cc5d7e6f8c0fffa50) Signed-off-by: Mostafa Saleh --- arch/arm64/kvm/hyp/include/nvhe/mem_protect.h | 4 +++- arch/arm64/kvm/hyp/nvhe/mem_protect.c | 22 +++++++++++-------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/arch/arm64/kvm/hyp/include/nvhe/mem_protect.h b/arch/arm64/kvm/hyp/include/nvhe/mem_protect.h index 9fab66e8c70c..3838ce532f56 100644 --- a/arch/arm64/kvm/hyp/include/nvhe/mem_protect.h +++ b/arch/arm64/kvm/hyp/include/nvhe/mem_protect.h @@ -64,7 +64,9 @@ int __pkvm_host_use_dma(u64 phys_addr, size_t size); int __pkvm_host_unuse_dma(u64 phys_addr, size_t size); bool addr_is_memory(phys_addr_t phys); -int host_stage2_idmap_locked(phys_addr_t addr, u64 size, enum kvm_pgtable_prot prot); +int host_stage2_idmap_locked(phys_addr_t addr, u64 size, + enum kvm_pgtable_prot prot, + bool update_iommu); int host_stage2_set_owner_locked(phys_addr_t addr, u64 size, u8 owner_id); int host_stage2_unmap_reg_locked(phys_addr_t start, u64 size); int kvm_host_prepare_stage2(void *pgt_pool_base); diff --git a/arch/arm64/kvm/hyp/nvhe/mem_protect.c b/arch/arm64/kvm/hyp/nvhe/mem_protect.c index 0e6094c5ab79..0f7c305c8527 100644 --- a/arch/arm64/kvm/hyp/nvhe/mem_protect.c +++ b/arch/arm64/kvm/hyp/nvhe/mem_protect.c @@ -159,7 +159,7 @@ static int prepopulate_host_stage2(void) for (i = 0; i < hyp_memblock_nr; i++) { reg = &hyp_memory[i]; - ret = host_stage2_idmap_locked(reg->base, reg->size, PKVM_HOST_MEM_PROT); + ret = host_stage2_idmap_locked(reg->base, reg->size, PKVM_HOST_MEM_PROT, false); if (ret) return ret; } @@ -549,7 +549,8 @@ static bool range_is_memory(u64 start, u64 end) } static inline int __host_stage2_idmap(u64 start, u64 end, - enum kvm_pgtable_prot prot) + enum kvm_pgtable_prot prot, + bool update_iommu) { int ret; @@ -558,7 +559,8 @@ static inline int __host_stage2_idmap(u64 start, u64 end, if (ret) return ret; - kvm_iommu_host_stage2_idmap(start, end, prot); + if (update_iommu) + kvm_iommu_host_stage2_idmap(start, end, prot); return 0; } @@ -623,9 +625,10 @@ static int host_stage2_adjust_range(u64 addr, struct kvm_mem_range *range) } int host_stage2_idmap_locked(phys_addr_t addr, u64 size, - enum kvm_pgtable_prot prot) + enum kvm_pgtable_prot prot, + bool update_iommu) { - return host_stage2_try(__host_stage2_idmap, addr, addr + size, prot); + return host_stage2_try(__host_stage2_idmap, addr, addr + size, prot, update_iommu); } #define KVM_MAX_OWNER_ID FIELD_MAX(KVM_INVALID_PTE_OWNER_MASK) @@ -655,7 +658,7 @@ static int __host_stage2_set_owner_locked(phys_addr_t addr, u64 size, u8 owner_i if (owner_id == PKVM_ID_HOST) { prot = default_host_prot(addr_is_memory(addr)); - ret = host_stage2_idmap_locked(addr, size, prot); + ret = host_stage2_idmap_locked(addr, size, prot, false); } else { annotation = kvm_init_invalid_leaf_owner(owner_id); ret = host_stage2_try(kvm_pgtable_stage2_annotate, @@ -725,13 +728,14 @@ static int host_stage2_idmap(u64 addr) bool is_memory = !!find_mem_range(addr, &range); enum kvm_pgtable_prot prot = default_host_prot(is_memory); int ret; + bool update_iommu = !is_memory; host_lock_component(); ret = host_stage2_adjust_range(addr, &range); if (ret) goto unlock; - ret = host_stage2_idmap_locked(range.start, range.end - range.start, prot); + ret = host_stage2_idmap_locked(range.start, range.end - range.start, prot, update_iommu); unlock: host_unlock_component(); @@ -1016,7 +1020,7 @@ static int __host_set_page_state_range(u64 addr, u64 size, enum pkvm_page_state state) { if (hyp_phys_to_page(addr)->host_state & PKVM_NOPAGE) { - int ret = host_stage2_idmap_locked(addr, size, PKVM_HOST_MEM_PROT); + int ret = host_stage2_idmap_locked(addr, size, PKVM_HOST_MEM_PROT, true); if (ret) return ret; @@ -2054,7 +2058,7 @@ update: PKVM_MODULE_OWNED_PAGE); } else { ret = host_stage2_idmap_locked( - addr, nr_pages << PAGE_SHIFT, prot); + addr, nr_pages << PAGE_SHIFT, prot, false); } if (WARN_ON(ret) || !page || !prot)