[PATCH] arm64: mark kernel text segment as MEMBLOCK_NOMAP

Ard Biesheuvel ard.biesheuvel at linaro.org
Mon Feb 15 01:28:32 PST 2016


Commit 752af28bd711 ("arm64: move kernel image to base of vmalloc area")
moves the mapping of the kernel text and data segments out of the linear
region, and takes care not to create a writable alias of the read-only
kernel text segment by checking each memblock against overlap when the
memblocks are mapped into the linear mapping.

However, it is more correct, and much simpler, to mark the [_stext, _etext]
interval as MEMBLOCK_NOMAP. This will also prevent the interval from being
omitted from the linear region, but this fact will now also be reflected
in the output of pfn_valid(), and so code that expects any pfn_valid()
page to be mapped and accessible (which is a reasonable assumption) does
not get surprised by the text segment being inaccessible via the linear
mapping.

Signed-off-by: Ard Biesheuvel <ard.biesheuvel at linaro.org>
---

This should hopefully address the issue reported by James, but I suppose
more work is required on the hibernate side to ensure the unmapped text
region is preserved, since it is no longer covered by the linear mapping.

 arch/arm64/mm/init.c |  1 +
 arch/arm64/mm/mmu.c  | 39 ++------------------
 2 files changed, 4 insertions(+), 36 deletions(-)

diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
index 023c41f22b5b..e895fb6ff9dd 100644
--- a/arch/arm64/mm/init.c
+++ b/arch/arm64/mm/init.c
@@ -218,6 +218,7 @@ void __init arm64_memblock_init(void)
 	 * pagetables with memblock.
 	 */
 	memblock_reserve(__pa(_text), _end - _text);
+	memblock_mark_nomap(__pa(_stext), _etext - _stext);
 #ifdef CONFIG_BLK_DEV_INITRD
 	if (initrd_start) {
 		memblock_reserve(initrd_start, initrd_end - initrd_start);
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index 5d7e0b801ab7..5ca2f315ba9d 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -352,41 +352,6 @@ static void create_mapping_late(phys_addr_t phys, unsigned long virt,
 			     late_pgtable_alloc);
 }
 
-static void __init __map_memblock(pgd_t *pgd, phys_addr_t start, phys_addr_t end)
-{
-
-	unsigned long kernel_start = __pa(_stext);
-	unsigned long kernel_end = __pa(_etext);
-
-	/*
-	 * Take care not to create a writable alias for the
-	 * read-only text and rodata sections of the kernel image.
-	 */
-
-	/* No overlap with the kernel text */
-	if (end < kernel_start || start >= kernel_end) {
-		__create_pgd_mapping(pgd, start, __phys_to_virt(start),
-				     end - start, PAGE_KERNEL,
-				     early_pgtable_alloc);
-		return;
-	}
-
-	/*
-	 * This block overlaps the kernel text mapping. Map the portion(s) which
-	 * don't overlap.
-	 */
-	if (start < kernel_start)
-		__create_pgd_mapping(pgd, start,
-				     __phys_to_virt(start),
-				     kernel_start - start, PAGE_KERNEL,
-				     early_pgtable_alloc);
-	if (kernel_end < end)
-		__create_pgd_mapping(pgd, kernel_end,
-				     __phys_to_virt(kernel_end),
-				     end - kernel_end, PAGE_KERNEL,
-				     early_pgtable_alloc);
-}
-
 static void __init map_mem(pgd_t *pgd)
 {
 	struct memblock_region *reg;
@@ -401,7 +366,9 @@ static void __init map_mem(pgd_t *pgd)
 		if (memblock_is_nomap(reg))
 			continue;
 
-		__map_memblock(pgd, start, end);
+		__create_pgd_mapping(pgd, start, __phys_to_virt(start),
+				     end - start, PAGE_KERNEL,
+				     early_pgtable_alloc);
 	}
 }
 
-- 
2.5.0




More information about the linux-arm-kernel mailing list