arm64: head: add helper function to remap regions in early page tables
authorArd Biesheuvel <ardb@kernel.org>
Fri, 24 Jun 2022 15:06:41 +0000 (17:06 +0200)
committerWill Deacon <will@kernel.org>
Fri, 24 Jun 2022 16:18:10 +0000 (17:18 +0100)
The asm macros used to create the initial ID map and kernel mappings
don't support randomly remapping parts of the address space after it has
been populated. What we can do, however, given that all block or page
mappings are created at the final level, is take a subset of the mapped
range and update its attributes or output address. This will permit us
to make parts of these page tables read-only, or remap a part of it to
cover the device tree.

So add a helper that encapsulates this.

Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Link: https://lore.kernel.org/r/20220624150651.1358849-12-ardb@kernel.org
Signed-off-by: Will Deacon <will@kernel.org>
arch/arm64/kernel/head.S

index 70c462bbd6bfd2aed7df5631c952342f923c87d1..7397555f84373a8a8618580aad793df79547b348 100644 (file)
@@ -263,6 +263,39 @@ SYM_FUNC_END(clear_page_tables)
        populate_entries \tbl, \rtbl, \istart, \iend, \flags, #SWAPPER_BLOCK_SIZE, \tmp
        .endm
 
+/*
+ * Remap a subregion created with the map_memory macro with modified attributes
+ * or output address. The entire remapped region must have been covered in the
+ * invocation of map_memory.
+ *
+ * x0: last level table address (returned in first argument to map_memory)
+ * x1: start VA of the existing mapping
+ * x2: start VA of the region to update
+ * x3: end VA of the region to update (exclusive)
+ * x4: start PA associated with the region to update
+ * x5: attributes to set on the updated region
+ * x6: order of the last level mappings
+ */
+SYM_FUNC_START_LOCAL(remap_region)
+       sub     x3, x3, #1              // make end inclusive
+
+       // Get the index offset for the start of the last level table
+       lsr     x1, x1, x6
+       bfi     x1, xzr, #0, #PAGE_SHIFT - 3
+
+       // Derive the start and end indexes into the last level table
+       // associated with the provided region
+       lsr     x2, x2, x6
+       lsr     x3, x3, x6
+       sub     x2, x2, x1
+       sub     x3, x3, x1
+
+       mov     x1, #1
+       lsl     x6, x1, x6              // block size at this level
+
+       populate_entries x0, x4, x2, x3, x5, x6, x7
+       ret
+SYM_FUNC_END(remap_region)
 
 SYM_FUNC_START_LOCAL(create_idmap)
        adrp    x0, idmap_pg_dir