arm64: mmu_change_region_attr() add an option not to break PTEs
authorIlias Apalodimas <ilias.apalodimas@linaro.org>
Thu, 20 Feb 2025 13:54:41 +0000 (15:54 +0200)
committerIlias Apalodimas <ilias.apalodimas@linaro.org>
Fri, 14 Mar 2025 11:37:54 +0000 (13:37 +0200)
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 <ilias.apalodimas@linaro.org>
arch/arm/cpu/armv8/cache_v8.c
arch/arm/include/asm/system.h

index c4b3da4..c9948e9 100644 (file)
@@ -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) */
index 0910822..849b3d0 100644 (file)
@@ -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
  *