From 346b74c8fb8f43b4c3ace040409f27174b4f33a0 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 30 Jun 2021 13:24:32 +0100 Subject: [PATCH] ANDROID: mm/vmalloc: Add arch-specific callbacks to track io{remap,unmap} physical pages Add a pair of hooks (ioremap_phys_range_hook/iounmap_phys_range_hook) that can be implemented by an architecture. Contrary to the existing arch_sync_kernel_mappings(), this one tracks things at the physical address level. This is specially useful in these virtualised environments where the guest has to tell the host whether (and how) it intends to use a MMIO device. Signed-off-by: Marc Zyngier Bug: 233587962 Change-Id: I970c2e632cb2b01060d5e66e4194fa9248188f43 Signed-off-by: Will Deacon [ qperret: Fixed conflict in vmalloc.c due to call to kmsan_ioremap_page_range ] Signed-off-by: Quentin Perret --- include/linux/io.h | 2 ++ mm/Kconfig | 5 +++++ mm/vmalloc.c | 12 +++++++++++- 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/include/linux/io.h b/include/linux/io.h index 308f4f0cfb93..f63b0968047e 100644 --- a/include/linux/io.h +++ b/include/linux/io.h @@ -21,6 +21,8 @@ void __ioread32_copy(void *to, const void __iomem *from, size_t count); void __iowrite64_copy(void __iomem *to, const void *from, size_t count); #ifdef CONFIG_MMU +void ioremap_phys_range_hook(phys_addr_t phys_addr, size_t size, pgprot_t prot); +void iounmap_phys_range_hook(phys_addr_t phys_addr, size_t size); int ioremap_page_range(unsigned long addr, unsigned long end, phys_addr_t phys_addr, pgprot_t prot); #else diff --git a/mm/Kconfig b/mm/Kconfig index 57e1d8c5b505..9e8261dd622a 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -1073,6 +1073,11 @@ config KMAP_LOCAL_NON_LINEAR_PTE_ARRAY config IO_MAPPING bool +# Some architectures want callbacks for all IO mappings in order to +# track the physical addresses that get used as devices. +config ARCH_HAS_IOREMAP_PHYS_HOOKS + bool + config SECRETMEM def_bool ARCH_HAS_SET_DIRECT_MAP && !EMBEDDED diff --git a/mm/vmalloc.c b/mm/vmalloc.c index ccaa461998f3..bdcbde04caa8 100644 --- a/mm/vmalloc.c +++ b/mm/vmalloc.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -317,12 +318,17 @@ int ioremap_page_range(unsigned long addr, unsigned long end, { int err; - err = vmap_range_noflush(addr, end, phys_addr, pgprot_nx(prot), + prot = pgprot_nx(prot); + err = vmap_range_noflush(addr, end, phys_addr, prot, ioremap_max_page_shift); flush_cache_vmap(addr, end); if (!err) kmsan_ioremap_page_range(addr, end, phys_addr, prot, ioremap_max_page_shift); + + if (IS_ENABLED(CONFIG_ARCH_HAS_IOREMAP_PHYS_HOOKS) && !err) + ioremap_phys_range_hook(phys_addr, end - addr, prot); + return err; } @@ -2696,6 +2702,10 @@ static void __vunmap(const void *addr, int deallocate_pages) kasan_poison_vmalloc(area->addr, get_vm_area_size(area)); + if (IS_ENABLED(CONFIG_ARCH_HAS_IOREMAP_PHYS_HOOKS) && + area->flags & VM_IOREMAP) + iounmap_phys_range_hook(area->phys_addr, get_vm_area_size(area)); + vm_remove_mappings(area, deallocate_pages); if (deallocate_pages) {