From ff0a979fc3591dcfb28585ae97ed4078a3ed5ef4 Mon Sep 17 00:00:00 2001 From: Ilias Apalodimas Date: Thu, 20 Feb 2025 15:54:41 +0200 Subject: [PATCH] arm64: mmu_change_region_attr() add an option not to break PTEs The ARM ARM (Rev L.a) on section 8.17.1 describes the cases where break-before-make is required when changing live page tables. Since we can use a function to tweak block and page permissions, where BBM is not required split the existing mmu_change_region_attr() into two functions and create one that doesn't require BBM. Subsequent patches will use the new function to map the U-Boot binary with proper page permissions. While at it add function descriptions in their header files. Signed-off-by: Ilias Apalodimas --- arch/arm/cpu/armv8/cache_v8.c | 48 ++++++++++++++++++++--------------- arch/arm/include/asm/system.h | 18 +++++++++++++ 2 files changed, 46 insertions(+), 20 deletions(-) diff --git a/arch/arm/cpu/armv8/cache_v8.c b/arch/arm/cpu/armv8/cache_v8.c index c4b3da4a8da..c9948e99e2e 100644 --- a/arch/arm/cpu/armv8/cache_v8.c +++ b/arch/arm/cpu/armv8/cache_v8.c @@ -967,61 +967,69 @@ void mmu_set_region_dcache_behaviour(phys_addr_t start, size_t size, flush_dcache_range(real_start, real_start + real_size); } -/* - * Modify MMU table for a region with updated PXN/UXN/Memory type/valid bits. - * The procecess is break-before-make. The target region will be marked as - * invalid during the process of changing. - */ -void mmu_change_region_attr(phys_addr_t addr, size_t siz, u64 attrs) +void mmu_change_region_attr_nobreak(phys_addr_t addr, size_t siz, u64 attrs) { int level; u64 r, size, start; - start = addr; - size = siz; /* * Loop through the address range until we find a page granule that fits - * our alignment constraints, then set it to "invalid". + * our alignment constraints and set the new permissions */ + start = addr; + size = siz; while (size > 0) { for (level = 1; level < 4; level++) { - /* Set PTE to fault */ - r = set_one_region(start, size, PTE_TYPE_FAULT, true, - level); + /* Set PTE to new attributes */ + r = set_one_region(start, size, attrs, true, level); if (r) { - /* PTE successfully invalidated */ + /* PTE successfully updated */ size -= r; start += r; break; } } } - flush_dcache_range(gd->arch.tlb_addr, gd->arch.tlb_addr + gd->arch.tlb_size); __asm_invalidate_tlb_all(); +} +/* + * Modify MMU table for a region with updated PXN/UXN/Memory type/valid bits. + * The procecess is break-before-make. The target region will be marked as + * invalid during the process of changing. + */ +void mmu_change_region_attr(phys_addr_t addr, size_t siz, u64 attrs) +{ + int level; + u64 r, size, start; + + start = addr; + size = siz; /* * Loop through the address range until we find a page granule that fits - * our alignment constraints, then set it to the new cache attributes + * our alignment constraints, then set it to "invalid". */ - start = addr; - size = siz; while (size > 0) { for (level = 1; level < 4; level++) { - /* Set PTE to new attributes */ - r = set_one_region(start, size, attrs, true, level); + /* Set PTE to fault */ + r = set_one_region(start, size, PTE_TYPE_FAULT, true, + level); if (r) { - /* PTE successfully updated */ + /* PTE successfully invalidated */ size -= r; start += r; break; } } } + flush_dcache_range(gd->arch.tlb_addr, gd->arch.tlb_addr + gd->arch.tlb_size); __asm_invalidate_tlb_all(); + + mmu_change_region_attr_nobreak(addr, siz, attrs); } #else /* !CONFIG_IS_ENABLED(SYS_DCACHE_OFF) */ diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h index 091082281c7..849b3d0efb7 100644 --- a/arch/arm/include/asm/system.h +++ b/arch/arm/include/asm/system.h @@ -303,8 +303,26 @@ void flush_l3_cache(void); * @emerg: Also map the region in the emergency table */ void mmu_map_region(phys_addr_t start, u64 size, bool emerg); + +/** + * mmu_change_region_attr() - change a mapped region attributes + * + * @start: Start address of the region + * @size: Size of the region + * @aatrs: New attributes + */ void mmu_change_region_attr(phys_addr_t start, size_t size, u64 attrs); +/** + * mmu_change_region_attr_nobreak() - change a mapped region attributes without doing + * break-before-make + * + * @start: Start address of the region + * @size: Size of the region + * @aatrs: New attributes + */ +void mmu_change_region_attr_nobreak(phys_addr_t addr, size_t size, u64 attrs); + /* * smc_call() - issue a secure monitor call * -- 2.39.5