From c87a42ddbf893d14b83a70213c1f1e17eedfcfc0 Mon Sep 17 00:00:00 2001 From: David Brazdil Date: Wed, 6 Apr 2022 16:19:58 +0100 Subject: [PATCH] ANDROID: KVM: arm64: iommu: Optimize snapshot_host_stage2 Currently the generic IOMMU code lets the driver initialize its PT and then invokes callbacks to set the permissions across the entire PA range. Optimize this by making it a requirement on the driver to initialize its PTs to all memory owned by the host. snapshot_host_stage2 then only calls the driver's callback for memory regions not owned by the host. Bug: 190463801 Bug: 218012133 Change-Id: I99a826d921d494269078c3a84d90323455a0b769 Signed-off-by: David Brazdil (cherry picked from commit 4e56697b422df13df9f25074f6d7710acd784394) Signed-off-by: Mostafa Saleh Signed-off-by: Quentin Perret --- arch/arm64/kvm/hyp/include/nvhe/iommu.h | 2 ++ arch/arm64/kvm/hyp/nvhe/iommu.c | 8 ++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/arch/arm64/kvm/hyp/include/nvhe/iommu.h b/arch/arm64/kvm/hyp/include/nvhe/iommu.h index d794f705fb1a..69bce1f01717 100644 --- a/arch/arm64/kvm/hyp/include/nvhe/iommu.h +++ b/arch/arm64/kvm/hyp/include/nvhe/iommu.h @@ -15,6 +15,8 @@ struct pkvm_iommu_ops { * Driver-specific arguments are passed in a buffer shared by the host. * The buffer memory has been pinned in EL2 but host retains R/W access. * Extra care must be taken when reading from it to avoid TOCTOU bugs. + * If the driver maintains its own page tables, it is expected to + * initialize them to all memory owned by the host. * Driver initialization lock held during callback. */ int (*init)(void *data, size_t size); diff --git a/arch/arm64/kvm/hyp/nvhe/iommu.c b/arch/arm64/kvm/hyp/nvhe/iommu.c index 3a56ea453745..d72ea5602eaf 100644 --- a/arch/arm64/kvm/hyp/nvhe/iommu.c +++ b/arch/arm64/kvm/hyp/nvhe/iommu.c @@ -181,16 +181,16 @@ static int __snapshot_host_stage2(u64 start, u64 pa_max, u32 level, { struct pkvm_iommu_driver * const drv = arg; u64 end = start + kvm_granule_size(level); - enum kvm_pgtable_prot prot; kvm_pte_t pte = *ptep; /* * Valid stage-2 entries are created lazily, invalid ones eagerly. * Note: In the future we may need to check if [start,end) is MMIO. + * Note: Drivers initialize their PTs to all memory owned by the host, + * so we only call the driver on regions where that is not the case. */ - prot = (!pte || kvm_pte_valid(pte)) ? PKVM_HOST_MEM_PROT : 0; - - drv->ops->host_stage2_idmap_prepare(start, end, prot); + if (pte && !kvm_pte_valid(pte)) + drv->ops->host_stage2_idmap_prepare(start, end, /*prot*/ 0); return 0; }