Re: u-boot places device-tree in bss

Nick Hudson <[email protected]> Sun, 14 Dec 2025 20:39:39 +0000
Newsgroups gmane.os.netbsd.ports.arm
Message-ID <[email protected]>
On 14/12/2025 18:56, Yuri Honegger wrote:
> Hello,
> When the memory address for the device tree isn't provided to u-boot, u-boot
> decides where to place the device tree by itself. For me, it chooses to place it
> right after the code, overlapping the bss section. This means the device tree
> gets overwritten when clearing the bss and a bit later, NetBSD rightfully panics
> because of a corrupt device tree.
> 
> Since u-boot leaves some space between the code and the device tree, it works
> with a small kernel, but as soon as I enable more features and bss grows, I run
> into this issue.

I'm a little surprised that NetBSD's GENERIC_V5 is bloated compared to 
your u-boot's idea of how big the kernel is, but not completely.

> 
> I can work around this by giving u-boot a boot.scr that manually places the
> device tree, but I'm wondering if this could be fixed in NetBSD.
> 
> We could add a panic if we encounter this situation. That would be a bit more
> helpful than the current error:
> [ 1.0000000] panic: fdt_check_header failed: FDT_ERR_BADMAGIC

Sure... something like the attached. Oh, looking at arm32_bootmem_init 
it's a bit more complicated, but you get the idea.


> 
> Another option would be to add some logic that preserves the device tree in this
> scenario. For example, we could move the device tree out of the way of the bss
> if they overlap. The question is where would we move it though? Perhaps
> beyond the end of the bss section?

This isn't possible. the fdt needs to be loaded outside of the kernel 
text, data and bss.
diff (text/plain, 685 B)
diff --git a/sys/arch/evbarm/fdt/fdt_machdep.c b/sys/arch/evbarm/fdt/fdt_machdep.c
index 89a1d4a06f5e..576f432982d6 100644
--- a/sys/arch/evbarm/fdt/fdt_machdep.c
+++ b/sys/arch/evbarm/fdt/fdt_machdep.c
@@ -257,10 +257,16 @@ initarm(void *arg)
 {
 	const struct fdt_platform *plat;
 	uint64_t memory_start, memory_end;
+	extern char etext[];
+	extern char _end[];
 
 	/* set temporally to work printf()/panic() even before consinit() */
 	cn_tab = &earlycons;
 
+	vaddr_t fdt_va = (vaddr_t)fdt_addr_r;
+	if ((vaddr_t)etext < fdt_va && fdt_va < (vaddr_t)_end)
+		panic("FDT placed within loaded kernel");
+
 	/* Load FDT */
 	int error = fdt_check_header(fdt_addr_r);
 	if (error != 0)