[PATCH 03/10] arm64: mm: Use if-conditon to truncate external dependency

Pingfan Liu piliu at redhat.com
Wed Mar 13 05:57:01 PDT 2024


An outside callee can present some challenging issues for the early
boot stage, including posistion-dependent, instrumentation, alignment and
sub-component not being ready.

To mitigate these dependencies, leveraging compile-time optimization can
help truncate reliance, ensuring that mmu_head is self-contained.

Additionally, running checks against relocation and external
dependencies in the Makefile can further enhance the robustness of the
system.

Signed-off-by: Pingfan Liu <piliu at redhat.com>
Cc: Ard Biesheuvel <ardb at kernel.org>
Cc: Catalin Marinas <catalin.marinas at arm.com>
Cc: Will Deacon <will at kernel.org>
Cc: Mark Rutland <mark.rutland at arm.com>
To: linux-arm-kernel at lists.infradead.org
---
 arch/arm64/include/asm/pgtable.h | 11 +++++++++--
 arch/arm64/mm/Makefile           | 19 ++++++++++++++++++
 arch/arm64/mm/mmu_head.c         |  3 +++
 arch/arm64/mm/mmu_inc.c          | 33 ++++++++++++++++----------------
 4 files changed, 47 insertions(+), 19 deletions(-)

diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index 79ce70fbb751..f43a93d78454 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -625,10 +625,17 @@ extern pgd_t reserved_pg_dir[PTRS_PER_PGD];
 
 extern void set_swapper_pgd(pgd_t *pgdp, pgd_t pgd);
 
+#ifndef KERNEL_READY
+#define KERNEL_READY	true
+#endif
 static inline bool in_swapper_pgdir(void *addr)
 {
-	return ((unsigned long)addr & PAGE_MASK) ==
-	        ((unsigned long)swapper_pg_dir & PAGE_MASK);
+	/* The compiling time optimization screens the calls to set_swapper_pgd() */
+	if (KERNEL_READY)
+		return ((unsigned long)addr & PAGE_MASK) ==
+			((unsigned long)swapper_pg_dir & PAGE_MASK);
+	else
+		return false;
 }
 
 static inline void set_pmd(pmd_t *pmdp, pmd_t pmd)
diff --git a/arch/arm64/mm/Makefile b/arch/arm64/mm/Makefile
index 0d92fb24a398..89d496ca970b 100644
--- a/arch/arm64/mm/Makefile
+++ b/arch/arm64/mm/Makefile
@@ -14,3 +14,22 @@ KASAN_SANITIZE_physaddr.o	+= n
 
 obj-$(CONFIG_KASAN)		+= kasan_init.o
 KASAN_SANITIZE_kasan_init.o	:= n
+
+$(obj)/mmu_head_tmp.o: $(src)/mmu_head.c FORCE
+	$(call if_changed_rule,cc_o_c)
+OBJCOPYFLAGS_mmu_head.o	:= $(OBJCOPYFLAGS)
+$(obj)/mmu_head.o: $(obj)/mmu_head_tmp.o FORCE
+	$(call if_changed,stubcopy)
+
+quiet_cmd_stubcopy = STUBCPY $@
+      cmd_stubcopy =							\
+	$(STRIP) --strip-debug -o $@ $<;				\
+	if $(OBJDUMP) -r $@ | grep R_AARCH64_ABS; then		\
+		echo "$@: absolute symbol references not allowed in mmu_head.o" >&2; \
+		/bin/false;						\
+	fi;								\
+	if nm -u $@ | grep "U"; then					\
+		echo "$@: external dependency incur uncertainty of alignment and not-PIC" >&2; \
+		/bin/false;						\
+	fi;								\
+	$(OBJCOPY) $(OBJCOPYFLAGS) $< $@
diff --git a/arch/arm64/mm/mmu_head.c b/arch/arm64/mm/mmu_head.c
index 4d65b7368db3..ccdd0f079c49 100644
--- a/arch/arm64/mm/mmu_head.c
+++ b/arch/arm64/mm/mmu_head.c
@@ -1,5 +1,8 @@
 // SPDX-License-Identifier: GPL-2.0-only
 
+
+#define KERNEL_READY false
+
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <asm/barrier.h>
diff --git a/arch/arm64/mm/mmu_inc.c b/arch/arm64/mm/mmu_inc.c
index 2535927d30ec..196987c120bf 100644
--- a/arch/arm64/mm/mmu_inc.c
+++ b/arch/arm64/mm/mmu_inc.c
@@ -81,7 +81,7 @@ static void INSTRUMENT_OPTION init_pte(pmd_t *pmdp, unsigned long addr, unsigned
 		 * After the PTE entry has been populated once, we
 		 * only allow updates to the permission attributes.
 		 */
-		BUG_ON(!__pgattr_change_is_safe(pte_val(old_pte),
+		BUG_ON(KERNEL_READY && !__pgattr_change_is_safe(pte_val(old_pte),
 					      READ_ONCE(pte_val(*ptep))));
 
 		phys += PAGE_SIZE;
@@ -99,19 +99,19 @@ static void INSTRUMENT_OPTION alloc_init_cont_pte(pmd_t *pmdp, unsigned long add
 	unsigned long next;
 	pmd_t pmd = READ_ONCE(*pmdp);
 
-	BUG_ON(pmd_sect(pmd));
+	BUG_ON(KERNEL_READY && pmd_sect(pmd));
 	if (pmd_none(pmd)) {
 		pmdval_t pmdval = PMD_TYPE_TABLE | PMD_TABLE_UXN;
 		phys_addr_t pte_phys;
 
 		if (flags & NO_EXEC_MAPPINGS)
 			pmdval |= PMD_TABLE_PXN;
-		BUG_ON(!pgtable_alloc);
+		BUG_ON(KERNEL_READY && !pgtable_alloc);
 		pte_phys = pgtable_alloc(PAGE_SHIFT);
 		__pmd_populate(pmdp, pte_phys, pmdval);
 		pmd = READ_ONCE(*pmdp);
 	}
-	BUG_ON(pmd_bad(pmd));
+	BUG_ON(KERNEL_READY && pmd_bad(pmd));
 
 	do {
 		pgprot_t __prot = prot;
@@ -151,14 +151,13 @@ static void INSTRUMENT_OPTION init_pmd(pud_t *pudp, unsigned long addr, unsigned
 			 * After the PMD entry has been populated once, we
 			 * only allow updates to the permission attributes.
 			 */
-			BUG_ON(!__pgattr_change_is_safe(pmd_val(old_pmd),
+			BUG_ON(KERNEL_READY && !__pgattr_change_is_safe(pmd_val(old_pmd),
 						      READ_ONCE(pmd_val(*pmdp))));
 		} else {
 			alloc_init_cont_pte(pmdp, addr, next, phys, prot,
 					    pgtable_alloc, flags);
-
-			BUG_ON(pmd_val(old_pmd) != 0 &&
-			       pmd_val(old_pmd) != READ_ONCE(pmd_val(*pmdp)));
+			BUG_ON(KERNEL_READY && pmd_val(old_pmd) != 0 &&
+					pmd_val(old_pmd) != READ_ONCE(pmd_val(*pmdp)));
 		}
 		phys += next - addr;
 	} while (pmdp++, addr = next, addr != end);
@@ -177,19 +176,19 @@ static void INSTRUMENT_OPTION alloc_init_cont_pmd(pud_t *pudp, unsigned long add
 	/*
 	 * Check for initial section mappings in the pgd/pud.
 	 */
-	BUG_ON(pud_sect(pud));
+	BUG_ON(KERNEL_READY && pud_sect(pud));
 	if (pud_none(pud)) {
 		pudval_t pudval = PUD_TYPE_TABLE | PUD_TABLE_UXN;
 		phys_addr_t pmd_phys;
 
 		if (flags & NO_EXEC_MAPPINGS)
 			pudval |= PUD_TABLE_PXN;
-		BUG_ON(!pgtable_alloc);
+		BUG_ON(KERNEL_READY && !pgtable_alloc);
 		pmd_phys = pgtable_alloc(PMD_SHIFT);
 		__pud_populate(pudp, pmd_phys, pudval);
 		pud = READ_ONCE(*pudp);
 	}
-	BUG_ON(pud_bad(pud));
+	BUG_ON(KERNEL_READY && pud_bad(pud));
 
 	do {
 		pgprot_t __prot = prot;
@@ -223,12 +222,12 @@ static void INSTRUMENT_OPTION alloc_init_pud(pgd_t *pgdp, unsigned long addr, un
 
 		if (flags & NO_EXEC_MAPPINGS)
 			p4dval |= P4D_TABLE_PXN;
-		BUG_ON(!pgtable_alloc);
+		BUG_ON(KERNEL_READY && !pgtable_alloc);
 		pud_phys = pgtable_alloc(PUD_SHIFT);
 		__p4d_populate(p4dp, pud_phys, p4dval);
 		p4d = READ_ONCE(*p4dp);
 	}
-	BUG_ON(p4d_bad(p4d));
+	BUG_ON(KERNEL_READY && p4d_bad(p4d));
 
 	pudp = pud_set_fixmap_offset(p4dp, addr);
 	do {
@@ -248,14 +247,14 @@ static void INSTRUMENT_OPTION alloc_init_pud(pgd_t *pgdp, unsigned long addr, un
 			 * After the PUD entry has been populated once, we
 			 * only allow updates to the permission attributes.
 			 */
-			BUG_ON(!__pgattr_change_is_safe(pud_val(old_pud),
+			BUG_ON(KERNEL_READY && !__pgattr_change_is_safe(pud_val(old_pud),
 						      READ_ONCE(pud_val(*pudp))));
 		} else {
 			alloc_init_cont_pmd(pudp, addr, next, phys, prot,
 					    pgtable_alloc, flags);
 
-			BUG_ON(pud_val(old_pud) != 0 &&
-			       pud_val(old_pud) != READ_ONCE(pud_val(*pudp)));
+			BUG_ON(KERNEL_READY && pud_val(old_pud) != 0 &&
+					pud_val(old_pud) != READ_ONCE(pud_val(*pudp)));
 		}
 		phys += next - addr;
 	} while (pudp++, addr = next, addr != end);
@@ -276,7 +275,7 @@ static void INSTRUMENT_OPTION __create_pgd_mapping_locked(pgd_t *pgdir, phys_add
 	 * If the virtual and physical address don't have the same offset
 	 * within a page, we cannot map the region as the caller expects.
 	 */
-	if (WARN_ON((phys ^ virt) & ~PAGE_MASK))
+	if (KERNEL_READY && WARN_ON((phys ^ virt) & ~PAGE_MASK))
 		return;
 
 	phys &= PAGE_MASK;
-- 
2.41.0




More information about the linux-arm-kernel mailing list