The branch main has been updated by andrew:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=ea8dc498aa8ea91ce0364a3f0ccdb740a24dcfb4

commit ea8dc498aa8ea91ce0364a3f0ccdb740a24dcfb4
Author:     Andrew Turner <and...@freebsd.org>
AuthorDate: 2025-06-17 10:12:00 +0000
Commit:     Andrew Turner <and...@freebsd.org>
CommitDate: 2025-06-17 12:48:22 +0000

    arm64: Create an L3 table to limit permissions
    
    When building a 4k page kernel we use 2M blocks to map the kernel
    contents. As the .text section may not end on a 2M aligned address
    we need to split one block into level 3 pages and pad the end of the
    section to an appropriate boundary.
    
    With both these changes we can then mapjust the code as executable.
    While here also map it as read-only as none ofthis shouldbe written
    to directly.
    
    Reviewed by:    alc
    Sponsored by:   Arm Ltd
    Differential Revision:  https://reviews.freebsd.org/D45064
---
 sys/arm64/arm64/locore.S | 62 +++++++++++++++++++++++++++++++++++++++++-------
 sys/conf/ldscript.arm64  |  6 +++++
 2 files changed, 60 insertions(+), 8 deletions(-)

diff --git a/sys/arm64/arm64/locore.S b/sys/arm64/arm64/locore.S
index fcc3f948f00c..2f549a527f43 100644
--- a/sys/arm64/arm64/locore.S
+++ b/sys/arm64/arm64/locore.S
@@ -45,6 +45,12 @@
  * space, the same as a single level 2 page with 4k pages.
  */
 #define        L3_PAGE_COUNT   32
+#elif PAGE_SIZE == PAGE_SIZE_4K
+/*
+ * Space for a level 3 table holding the end of the executable memory and
+ * the start of the non-executable data.
+ */
+#define        L3_PAGE_COUNT   1
 #endif
 
 /*
@@ -600,22 +606,64 @@ common:
        /* Get the number of blocks/pages to allocate, rounded down */
        lsr     x14, x8, #(PTE_SHIFT)
 
-       ldr     x25, =etext
+       ldr     x26, =etext
+#if PAGE_SIZE != PAGE_SIZE_4K
        ldr     x8, =((1 << PTE_SHIFT) - 1)
-       add     x25, x25, x8
+       add     x26, x26, x8
+#endif
        mov     x8, #(KERNBASE)
-       sub     x25, x25, x8
+       sub     x25, x26, x8
        lsr     x25, x25, #(PTE_SHIFT)
 
+#if PAGE_SIZE == PAGE_SIZE_4K
+       /* Calculate the number of executable level 3 pages to create */
+       lsr     x26, x26, #(L3_SHIFT)
+       bfc     x26, #(Ln_ENTRIES_SHIFT), #(64 - Ln_ENTRIES_SHIFT)
+
+       /* Build the L3 table holding the end of the exectuable code */
+       lsl     x15, x25, #(PTE_SHIFT)
+       adrp    x6, pagetable_l3_ttbr1
+       add     x6, x6, :lo12:pagetable_l3_ttbr1
+       ldr     x7, =(ATTR_S1_IDX(VM_MEMATTR_WRITE_BACK) | \
+           ATTR_S1_AP(ATTR_S1_AP_RO))
+       ldr     x8, =(KERNBASE)
+       add     x8, x8, x15
+       add     x9, x28, x15
+       mov     x10, x26
+       bl      build_l3_page_pagetable
+
+       /* Build the remaining level 3 pages */
+       ldr     x7, =(ATTR_S1_IDX(VM_MEMATTR_WRITE_BACK) | ATTR_S1_XN)
+       lsl     x27, x26, #(L3_SHIFT)
+       add     x8, x8, x27
+       add     x9, x28, x15
+       add     x9, x9, x27
+       ldr     x10, =(Ln_ENTRIES)
+       sub     x10, x10, x26
+       bl      build_l3_page_pagetable
+
+       /* Link the l2 -> l3 table */
+       mov     x9, x6
+       adrp    x6, pagetable_l2_ttbr1
+       add     x6, x6, :lo12:pagetable_l2_ttbr1
+       bl      link_l2_pagetable
+#endif
+
        /* Create the kernel space PTE table */
        adrp    x6, LL_PAGE_TABLE
        add     x6, x6, :lo12:LL_PAGE_TABLE
-       mov     x7, #(ATTR_S1_IDX(VM_MEMATTR_WRITE_BACK))
+       ldr     x7, =(ATTR_S1_IDX(VM_MEMATTR_WRITE_BACK) | \
+           ATTR_S1_AP(ATTR_S1_AP_RO))
        mov     x8, #(KERNBASE)
        mov     x9, x28
        mov     x10, x25
        bl      BUILD_PTE_FUNC
 
+#if PAGE_SIZE == PAGE_SIZE_4K
+       /* Skip memory mapped through the L2 table */
+       add     x25, x25, #1
+#endif
+
        /* Create the kernel space XN PTE table */
        lsl     x10, x25, #(PTE_SHIFT)
        ldr     x7, =(ATTR_S1_IDX(VM_MEMATTR_WRITE_BACK) | ATTR_S1_XN)
@@ -837,7 +885,6 @@ LENTRY(build_l2_block_pagetable)
        ret
 LEND(build_l2_block_pagetable)
 
-#if PAGE_SIZE != PAGE_SIZE_4K
 /*
  * Builds an L2 -> L3 table descriptor
  *
@@ -881,6 +928,7 @@ LEND(link_l2_pagetable)
  * VA start (x8) modulo L3C_SIZE must equal PA start (x9) modulo L3C_SIZE.
  */
 LENTRY(build_l3_page_pagetable)
+       cbz     x10, 2f
        /*
         * Build the L3 table entry.
         */
@@ -920,10 +968,10 @@ LENTRY(build_l3_page_pagetable)
        add     x11, x11, #1
        add     x9, x9, #1
        cbnz    x10, 1b
+2:
 
        ret
 LEND(build_l3_page_pagetable)
-#endif
 
 LENTRY(start_mmu)
        dsb     sy
@@ -1054,10 +1102,8 @@ initstack_end:
         */
        .globl pagetable_l0_ttbr1
 pagetable:
-#if PAGE_SIZE != PAGE_SIZE_4K
 pagetable_l3_ttbr1:
        .space  (PAGE_SIZE * L3_PAGE_COUNT)
-#endif
 pagetable_l2_ttbr1:
        .space  PAGE_SIZE
 pagetable_l1_ttbr1:
diff --git a/sys/conf/ldscript.arm64 b/sys/conf/ldscript.arm64
index 0d50eef431cf..ae231c3037e6 100644
--- a/sys/conf/ldscript.arm64
+++ b/sys/conf/ldscript.arm64
@@ -15,6 +15,12 @@ SECTIONS
     *(.gnu.warning)
     *(.gnu.linkonce.t*)
   } =0x9090
+  /*
+   * Align to the the largest page size the kernel could be built for.
+   * If we don't then building page tables in locore.S could fail as it
+   * assumes the .text section is on a different page to later sections.
+   */
+  . = ALIGN(CONSTANT(MAXPAGESIZE));
   _etext = .;
   PROVIDE (etext = .);
 

Reply via email to