arm64: head: create a temporary FDT mapping in the initial ID map
authorArd Biesheuvel <ardb@kernel.org>
Fri, 24 Jun 2022 15:06:44 +0000 (17:06 +0200)
committerWill Deacon <will@kernel.org>
Fri, 24 Jun 2022 16:18:10 +0000 (17:18 +0100)
We need to access the DT very early to get at the command line and the
KASLR seed, which currently means we rely on some hacks to call into the
kernel before really calling into the kernel, which is undesirable.

So instead, let's create a mapping for the FDT in the initial ID map,
which is feasible now that it has been extended to cover more than a
single page or block, and can be updated in place to remap other output
addresses.

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

index 5395e5a..02e59fa 100644 (file)
@@ -8,6 +8,7 @@
 #ifndef __ASM_KERNEL_PGTABLE_H
 #define __ASM_KERNEL_PGTABLE_H
 
+#include <asm/boot.h>
 #include <asm/pgtable-hwdef.h>
 #include <asm/sparsemem.h>
 
 
 /* the initial ID map may need two extra pages if it needs to be extended */
 #if VA_BITS < 48
-#define INIT_IDMAP_DIR_SIZE    (INIT_DIR_SIZE + (2 * PAGE_SIZE))
+#define INIT_IDMAP_DIR_SIZE    ((INIT_IDMAP_DIR_PAGES + 2) * PAGE_SIZE)
 #else
-#define INIT_IDMAP_DIR_SIZE    INIT_DIR_SIZE
+#define INIT_IDMAP_DIR_SIZE    (INIT_IDMAP_DIR_PAGES * PAGE_SIZE)
 #endif
+#define INIT_IDMAP_DIR_PAGES   EARLY_PAGES(KIMAGE_VADDR, _end + MAX_FDT_SIZE + SWAPPER_BLOCK_SIZE)
 
 /* Initial memory map size */
 #if ARM64_KERNEL_USES_PMD_MAPS
index f1497f7..8283ff8 100644 (file)
@@ -83,6 +83,7 @@
         *
         *  Register   Scope                      Purpose
         *  x21        primary_entry() .. start_kernel()        FDT pointer passed at boot in x0
+        *  x22        create_idmap() .. start_kernel()         ID map VA of the DT blob
         *  x23        primary_entry() .. start_kernel()        physical misalignment/KASLR offset
         *  x28        clear_page_tables()                      callee preserved temp register
         *  x19/x20    __primary_switch()                       callee preserved temp registers
@@ -348,7 +349,7 @@ SYM_FUNC_START_LOCAL(create_idmap)
 #endif
        adrp    x0, init_idmap_pg_dir
        adrp    x3, _text
-       adrp    x6, _end
+       adrp    x6, _end + MAX_FDT_SIZE + SWAPPER_BLOCK_SIZE
        mov     x7, SWAPPER_RX_MMUFLAGS
 
        map_memory x0, x1, x3, x6, x7, x3, IDMAP_PGD_ORDER, x10, x11, x12, x13, x14, EXTRA_SHIFT
@@ -362,6 +363,17 @@ SYM_FUNC_START_LOCAL(create_idmap)
        mov     x6, #SWAPPER_BLOCK_SHIFT
        bl      remap_region
 
+       /* Remap the FDT after the kernel image */
+       adrp    x1, _text
+       adrp    x22, _end + SWAPPER_BLOCK_SIZE
+       bic     x2, x22, #SWAPPER_BLOCK_SIZE - 1
+       bfi     x22, x21, #0, #SWAPPER_BLOCK_SHIFT              // remapped FDT address
+       add     x3, x2, #MAX_FDT_SIZE + SWAPPER_BLOCK_SIZE
+       bic     x4, x21, #SWAPPER_BLOCK_SIZE - 1
+       mov     x5, SWAPPER_RW_MMUFLAGS
+       mov     x6, #SWAPPER_BLOCK_SHIFT
+       bl      remap_region
+
        /*
         * Since the page tables have been populated with non-cacheable
         * accesses (MMU disabled), invalidate those tables again to