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 <dbrazdil@google.com>
(cherry picked from commit 4e56697b422df13df9f25074f6d7710acd784394)
Signed-off-by: Mostafa Saleh <smostafa@google.com>
Signed-off-by: Quentin Perret <qperret@google.com>
This commit is contained in:
David Brazdil 2022-04-06 16:19:58 +01:00 committed by Quentin Perret
parent 8fda1979fd
commit c87a42ddbf
2 changed files with 6 additions and 4 deletions

View File

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

View File

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