ANDROID: KVM: arm64: iommu: Fix tracking of MMIO

As MMIO can be donated, it's not safe to ignore tracking it anymore.
Taint any MMIO mapped in the IOMMU, so it can never be donated later.

Bug: 357781595
Bug: 384432312
Change-Id: I9dced4529cb7525ae06e475e599e29e060f89483
Signed-off-by: Mostafa Saleh <smostafa@google.com>
This commit is contained in:
Mostafa Saleh
2025-02-03 11:05:00 +00:00
committed by Treehugger Robot
parent bdb9c5d1b2
commit 2bf285b26c
2 changed files with 32 additions and 7 deletions
+2 -2
View File
@@ -14,13 +14,13 @@
* 01: The page is owned by the page-table owner, but is shared
* with another entity.
* 10: The page is shared with, but not owned by the page-table owner.
* 11: Reserved for future use (lending).
* 11: The page is tainted by host, and can't transition.
*/
enum pkvm_page_state {
PKVM_PAGE_OWNED = 0ULL,
PKVM_PAGE_SHARED_OWNED = BIT(0),
PKVM_PAGE_SHARED_BORROWED = BIT(1),
__PKVM_PAGE_RESERVED = BIT(0) | BIT(1),
PKVM_PAGE_TAINTED = BIT(0) | BIT(1),
/* Special non-meta state that only applies to host pages. Will not go in PTE SW bits. */
PKVM_MODULE_OWNED_PAGE = BIT(2),
+30 -5
View File
@@ -1747,12 +1747,37 @@ int __pkvm_host_use_dma(phys_addr_t phys_addr, size_t size)
return -EINVAL;
host_lock_component();
ret = ___host_check_page_state_range(phys_addr, size, PKVM_PAGE_OWNED, reg, false);
if (ret || !reg)
goto out_ret;
/*
* Some differences between handling of RAM and device memory:
* - The hyp vmemmap area for device memory is not backed by physical
* pages in the hyp page tables.
* - However, in some cases modules can donate MMIO, as they can't be
* refcounted, taint them by marking them as shared PKVM_PAGE_TAINTED, and that
* will prevent any future transition.
*/
if (!reg) {
enum kvm_pgtable_prot prot;
for (i = 0; i < nr_pages; i++)
__pkvm_host_use_dma_page(phys_addr + i * PAGE_SIZE);
ret = ___host_check_page_state_range(phys_addr, size,
PKVM_PAGE_TAINTED,
reg, false);
if (!ret)
goto out_ret;
ret = ___host_check_page_state_range(phys_addr, size,
PKVM_PAGE_OWNED,
reg, false);
if (ret)
goto out_ret;
prot = pkvm_mkstate(PKVM_HOST_MMIO_PROT, PKVM_PAGE_TAINTED);
ret = host_stage2_idmap_locked(phys_addr, size, prot, false);
} else {
ret = ___host_check_page_state_range(phys_addr, size, PKVM_PAGE_OWNED, reg, false);
if (ret)
goto out_ret;
for (i = 0; i < nr_pages; i++)
__pkvm_host_use_dma_page(phys_addr + i * PAGE_SIZE);
}
out_ret:
host_unlock_component();