[PATCH master 2/3] RISC-V: board-dt-2nd: ensure FDT doesn't overlap with early mem regions

Ahmad Fatoum a.fatoum at pengutronix.de
Wed Mar 24 08:23:03 GMT 2021


RISC-V PBL code currently reserves the last 2M of the memory for
firmware and places the stack before that. This serves virt, as qemu
places the FDT here, but negatively impacts normal targets with embedded
device tree as it increases fragmentation.

Add code to the generic DT entry point that cuts of a number of MiB from
the end of RAM, so the PBL arrives at a stack top that doesn't overlap
FDT.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
Prequisite for fix in next patch
---
 arch/riscv/boot/board-dt-2nd.c    | 20 ++++++++++++++++++--
 arch/riscv/boot/uncompress.c      |  5 +----
 arch/riscv/include/asm/sections.h |  9 +++++++++
 3 files changed, 28 insertions(+), 6 deletions(-)

diff --git a/arch/riscv/boot/board-dt-2nd.c b/arch/riscv/boot/board-dt-2nd.c
index 25fa7d4f2bef..be28ea23cd6d 100644
--- a/arch/riscv/boot/board-dt-2nd.c
+++ b/arch/riscv/boot/board-dt-2nd.c
@@ -1,8 +1,11 @@
 // SPDX-License-Identifier: GPL-2.0
 
 #include <common.h>
+#include <asm/sections.h>
+#include <linux/sizes.h>
 #include <debug_ll.h>
 #include <pbl.h>
+#include <fdt.h>
 
 #if __riscv_xlen == 64
 #define IMAGE_LOAD_OFFSET 0x200000 /* Image load offset(2MB) from start of RAM */
@@ -21,8 +24,8 @@
 
 ENTRY_FUNCTION(start_dt_2nd, a0, _fdt, a2)
 {
-	unsigned long membase, memsize;
-	void *fdt = (void *)_fdt;
+	unsigned long membase, memsize, endmem, endfdt, uncompressed_len;
+	struct fdt_header *fdt = (void *)_fdt;
 
 	if (!fdt)
 		hang();
@@ -31,6 +34,19 @@ ENTRY_FUNCTION(start_dt_2nd, a0, _fdt, a2)
 	setup_c();
 
 	fdt_find_mem(fdt, &membase, &memsize);
+	endmem = membase + memsize;
+	endfdt = _fdt + be32_to_cpu(fdt->totalsize);
+
+	/*
+	 * QEMU likes to place the FDT at the end of RAM, where barebox
+	 * would normally extract itself to. Accommodate this by moving
+	 * memory end, so it doesn't overlap FDT
+	 */
+	uncompressed_len = input_data_len() + MAX_BSS_SIZE;
+
+	if (riscv_mem_barebox_image(membase, endmem, uncompressed_len) < endfdt &&
+	    _fdt < riscv_mem_stack_top(membase, endmem))
+		memsize = ALIGN_DOWN(_fdt - membase, SZ_1M);
 
 	barebox_riscv_entry(membase, memsize, fdt);
 }
diff --git a/arch/riscv/boot/uncompress.c b/arch/riscv/boot/uncompress.c
index cf268bece1bf..411cefb0e31b 100644
--- a/arch/riscv/boot/uncompress.c
+++ b/arch/riscv/boot/uncompress.c
@@ -22,9 +22,6 @@
 unsigned long free_mem_ptr;
 unsigned long free_mem_end_ptr;
 
-extern unsigned char input_data[];
-extern unsigned char input_data_end[];
-
 void __noreturn barebox_pbl_start(unsigned long membase, unsigned long memsize,
 				  void *fdt)
 {
@@ -49,7 +46,7 @@ void __noreturn barebox_pbl_start(unsigned long membase, unsigned long memsize,
 		relocate_to_adr(membase);
 
 	pg_len = pg_end - pg_start;
-	uncompressed_len = get_unaligned((const u32 *)(pg_start + pg_len - 4));
+	uncompressed_len = input_data_len();
 
 	barebox_base = riscv_mem_barebox_image(membase, endmem,
 					       uncompressed_len + MAX_BSS_SIZE);
diff --git a/arch/riscv/include/asm/sections.h b/arch/riscv/include/asm/sections.h
index b5fbba8f165a..725fd8db474e 100644
--- a/arch/riscv/include/asm/sections.h
+++ b/arch/riscv/include/asm/sections.h
@@ -5,12 +5,21 @@
 #ifndef __ASSEMBLY__
 #include <asm-generic/sections.h>
 #include <linux/types.h>
+#include <asm/unaligned.h>
 
 extern char __rel_dyn_start[];
 extern char __rel_dyn_end[];
 extern char __dynsym_start[];
 extern char __dynsym_end[];
 
+extern char input_data[];
+extern char input_data_end[];
+
+static inline unsigned int input_data_len(void)
+{
+	return get_unaligned((const u32 *)(input_data_end - 4));
+}
+
 #endif
 
 #endif /* __ASM_SECTIONS_H */
-- 
2.29.2




More information about the barebox mailing list