Skip to content

Commit 922b037

Browse files
a0upaul-walmsley-sifive
authored andcommitted
riscv: Fix memblock reservation for device tree blob
This fixes an error with how the FDT blob is reserved in memblock. An incorrect physical address calculation exposed the FDT header to unintended corruption, which typically manifested with of_fdt_raw_init() faulting during late boot after fdt_totalsize() returned a wrong value. Systems with smaller physical memory sizes more frequently trigger this issue, as the kernel is more likely to allocate from the DMA32 zone where bbl places the DTB after the kernel image. Commit 671f9a3 ("RISC-V: Setup initial page tables in two stages") changed the mapping of the DTB to reside in the fixmap area. Consequently, early_init_fdt_reserve_self() cannot be used anymore in setup_bootmem() since it relies on __pa() to derive a physical address, which does not work with dtb_early_va that is no longer a valid kernel logical address. The reserved[0x1] region shows the effect of the pointer underflow resulting from the __pa(initial_boot_params) offset subtraction: [ 0.000000] MEMBLOCK configuration: [ 0.000000] memory size = 0x000000001fe00000 reserved size = 0x0000000000a2e514 [ 0.000000] memory.cnt = 0x1 [ 0.000000] memory[0x0] [0x0000000080200000-0x000000009fffffff], 0x000000001fe00000 bytes flags: 0x0 [ 0.000000] reserved.cnt = 0x2 [ 0.000000] reserved[0x0] [0x0000000080200000-0x0000000080c2dfeb], 0x0000000000a2dfec bytes flags: 0x0 [ 0.000000] reserved[0x1] [0xfffffff080100000-0xfffffff080100527], 0x0000000000000528 bytes flags: 0x0 With the fix applied: [ 0.000000] MEMBLOCK configuration: [ 0.000000] memory size = 0x000000001fe00000 reserved size = 0x0000000000a2e514 [ 0.000000] memory.cnt = 0x1 [ 0.000000] memory[0x0] [0x0000000080200000-0x000000009fffffff], 0x000000001fe00000 bytes flags: 0x0 [ 0.000000] reserved.cnt = 0x2 [ 0.000000] reserved[0x0] [0x0000000080200000-0x0000000080c2dfeb], 0x0000000000a2dfec bytes flags: 0x0 [ 0.000000] reserved[0x1] [0x0000000080e00000-0x0000000080e00527], 0x0000000000000528 bytes flags: 0x0 Fixes: 671f9a3 ("RISC-V: Setup initial page tables in two stages") Signed-off-by: Albert Ou <[email protected]> Tested-by: Bin Meng <[email protected]> Reviewed-by: Anup Patel <[email protected]> Signed-off-by: Paul Walmsley <[email protected]>
1 parent 1885660 commit 922b037

File tree

1 file changed

+11
-1
lines changed

1 file changed

+11
-1
lines changed

arch/riscv/mm/init.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <linux/swap.h>
1212
#include <linux/sizes.h>
1313
#include <linux/of_fdt.h>
14+
#include <linux/libfdt.h>
1415

1516
#include <asm/fixmap.h>
1617
#include <asm/tlbflush.h>
@@ -82,6 +83,8 @@ static void __init setup_initrd(void)
8283
}
8384
#endif /* CONFIG_BLK_DEV_INITRD */
8485

86+
static phys_addr_t dtb_early_pa __initdata;
87+
8588
void __init setup_bootmem(void)
8689
{
8790
struct memblock_region *reg;
@@ -117,7 +120,12 @@ void __init setup_bootmem(void)
117120
setup_initrd();
118121
#endif /* CONFIG_BLK_DEV_INITRD */
119122

120-
early_init_fdt_reserve_self();
123+
/*
124+
* Avoid using early_init_fdt_reserve_self() since __pa() does
125+
* not work for DTB pointers that are fixmap addresses
126+
*/
127+
memblock_reserve(dtb_early_pa, fdt_totalsize(dtb_early_va));
128+
121129
early_init_fdt_scan_reserved_mem();
122130
memblock_allow_resize();
123131
memblock_dump_all();
@@ -393,6 +401,8 @@ asmlinkage void __init setup_vm(uintptr_t dtb_pa)
393401

394402
/* Save pointer to DTB for early FDT parsing */
395403
dtb_early_va = (void *)fix_to_virt(FIX_FDT) + (dtb_pa & ~PAGE_MASK);
404+
/* Save physical address for memblock reservation */
405+
dtb_early_pa = dtb_pa;
396406
}
397407

398408
static void __init setup_vm_final(void)

0 commit comments

Comments
 (0)