[PATCH v3] arm: Support initrd with address in boot alias region

Matija Glavinic Pecotic matija.glavinic-pecotic.ext at nokia.com
Thu Aug 18 07:52:22 PDT 2022


When bootloader passes address of initrd in boot alias region, initrd
will fail on memblock_is_region_memory as memblock with such address
doesn't exist. Problem was uncovered by commit fe7db7570379 ("of/fdt:
Populate phys_initrd_start/phys_initrd_size from FDT") which removed
__virt_to_phys on the initrd physical address. Earlier, __virt_to_phys
on our platform coincidentally sanitized address.

Initrd address in bootalias region is valid to be passed by bootloader,
in our case it was done by kexec:

$ cat /proc/iomem
[cut]
c0000000-d4da1fff : System RAM (boot alias)
840000000-854da1fff : System RAM
  840008000-840bfffff : Kernel code
  840e00000-840ee56fb : Kernel data
[cut]
880000000-8ffffffff : System RAM

arch/arm/kernel/setup.c:
/*
 * Some systems have a special memory alias which is only
 * used for booting.  We need to advertise this region to
 * kexec-tools so they know where bootable RAM is located.
 */
boot_alias_start = phys_to_idmap(start);
if (arm_has_idmap_alias() && boot_alias_start != IDMAP_INVALID_ADDR) {
    res = memblock_alloc(sizeof(*res), SMP_CACHE_BYTES);
    if (!res)
        panic("%s: Failed to allocate %zu bytes\n",
            __func__, sizeof(*res));
    res->name = "System RAM (boot alias)";
    res->start = boot_alias_start;
    res->end = phys_to_idmap(res_end);
    res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
    request_resource(&iomem_resource, res);
}

Fix by trying to sanitize address in case of invalid physical address
for platforms (e.g. Keystone 2) supporting it.

Signed-off-by: Matija Glavinic Pecotic <matija.glavinic-pecotic.ext at nokia.com>
---

v2: Rebased against current tree, update commit message to capture
previous discussion (http://lists.infradead.org/pipermail/linux-arm-kernel/2020-September/605344.html)
v3: moved implementation from generic code to arm's mm

 arch/arm/mm/init.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index ce64bdb55a16..b248c2459f4d 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -180,11 +180,27 @@ void check_cpu_icache_size(int cpuid)
 }
 #endif
 
+static void sanitize_initrd_address(void)
+{
+	/*
+	 * If initrd is not on valid physical address, reason could
+	 * be due to bootloader passing address from bootalias region.
+	 * Try to sanitize such address for platforms supporting boot
+	 * aliases.
+	 */
+	if (!pfn_valid(__phys_to_pfn(phys_initrd_start))) {
+		pr_info("initrd at invalid address, trying to use boot alias\n");
+		if (arm_has_idmap_alias())
+			phys_initrd_start = idmap_to_phys(phys_initrd_start);
+	}
+}
+
 void __init arm_memblock_init(const struct machine_desc *mdesc)
 {
 	/* Register the kernel text, kernel data and initrd with memblock. */
 	memblock_reserve(__pa(KERNEL_START), KERNEL_END - KERNEL_START);
 
+	sanitize_initrd_address();
 	reserve_initrd_mem();
 
 	arm_mm_memblock_reserve();
-- 
2.26.0



More information about the linux-arm-kernel mailing list