Skip to content

qemuarm64: apply delivered device-tree overlays at boot - #273

Draft
jetm wants to merge 1 commit into
scarthgapfrom
qemuarm64-fdt-overlay-selection
Draft

jetm wants to merge 1 commit into
scarthgapfrom
qemuarm64-fdt-overlay-selection

Conversation

@jetm

@jetm jetm commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Problem

#245 delivers a declared device-tree overlay to the boot FAT on qemuarm64 and marks it claimed_by, but nothing applies it: the boot script runs booti against the DTB QEMU generates without touching it. A declared overlay produces a green build and has no effect on the running system, and because claimed_by is set, the CLI's undelivered check — the one gate that could have caught it — passes.

That gap was known and named when #245 merged; this is the follow-up that closes it.

Solution

Apply the overlays rather than withdraw the claim, which makes claimed_by accurate by making it true.

u-boot already receives QEMU's DTB at the base of RAM, which is exactly what fdt_addr points at, so there is a real tree to merge into. I confirmed that rather than assuming it: the magic and totalsize read at 0x40000000 match $fdtcontroladdr's header.

Key changes

  • avocado.cfg sets CONFIG_OF_LIBFDT_OVERLAY. Without it none of the rest runs — qemu_arm64_defconfig does not set it at 2026.01, so the shipped u-boot has every fdt subcommand except apply. The built .config reads # CONFIG_OF_LIBFDT_OVERLAY is not set, and fdt apply on that binary prints the usage dump.
  • The delivery hook writes an overlay list next to the kernel. A boot script cannot enumerate a directory, so it needs the names handed to it; the list carries names rather than filenames, keeping the overlays/ prefix and .dtbo suffix in one place.
  • The env gains avocado_apply_overlays, which imports that list, resizes the tree and applies each blob in turn.

Reviewer notes

avocado_apply_overlays runs before load_initramfs, not after. Every load overwrites ${filesize} and avocado_boot passes ${filesize} as the initramfs length, so applying overlays last would hand booti the size of the last .dtbo.

A failed apply is reported and does not stop the boot. An overlay is additive, and refusing to boot the machine over one is a worse outcome than booting without it.

claimed_by is deliberately unchanged. With selection wired the claim is truthful, so the alternative of suppressing it on this platform is no longer needed.

Verified on u-boot 2026.01, built from this tree's own source with the flag set, under qemu-system-aarch64: load of the list, env import -t (imported [ov ov2]), the for-loop over two names, and fdt apply for each, with fdt print showing both overlays' nodes merged into the live tree. The same sequence on the shipped binary fails at fdt apply with the usage dump — that is the negative control.

Not yet done: a full image build and boot on the produced artifact. The mechanism is proven on real u-boot; the assembled-image path is not.

Priority note (2026-08-15): this stays draft and is not on the ENG-2134 critical path. That work targets raspberrypi5 and Jetson Orin, both of which now deliver and apply overlays without this PR — Jetson through a build-time fdtoverlay merge that needs no boot-chain selection at all. The CONFIG_OF_LIBFDT_OVERLAY finding here is worth keeping regardless: anyone wiring overlays on another u-boot target hits it, and the defconfig does not warn them.

Delivery placed each .dtbo on the boot FAT and marked it claimed, but
nothing ever applied it: the boot script ran `booti` against the DTB QEMU
generates without touching it, so a declared overlay produced a green
build and had no effect on the running system. Claiming an overlay the
boot chain ignores also disarmed the CLI's undelivered check, which is
the one gate that could have caught the gap.

Wire the selection rather than withdraw the claim. u-boot already receives
QEMU's DTB at the base of RAM, which is what fdt_addr points at, so there
is a real tree to merge into - confirmed by reading the magic and
totalsize at that address and matching them against $fdtcontroladdr.

Three pieces. The hook now writes an overlay list next to the kernel,
because a boot script cannot enumerate a directory; it carries names, so
the overlays/ prefix and .dtbo suffix live in one place. The env grows an
avocado_apply_overlays block that imports that list, resizes the tree and
applies each blob in turn. And avocado.cfg sets CONFIG_OF_LIBFDT_OVERLAY,
without which none of it runs: qemu_arm64_defconfig does not set it at
2026.01, so the shipped u-boot had every fdt subcommand except apply -
the built .config reads `# CONFIG_OF_LIBFDT_OVERLAY is not set`, and
`fdt apply` on that binary prints the usage dump.

The block runs before load_initramfs, not after. Every load overwrites
${filesize} and avocado_boot passes ${filesize} as the initramfs length,
so applying overlays last would hand booti the size of the last .dtbo.

A failed apply is reported and does not stop the boot: an overlay is
additive, and refusing to boot the machine over one is worse than booting
without it.

Verified on u-boot 2026.01 built from this tree's own source with the
flag set, under qemu-system-aarch64: load of the list, `env import -t`,
the for-loop over two names, and `fdt apply` for each, with `fdt print`
showing both overlays' nodes merged into the live tree. The same sequence
on the shipped binary fails at `fdt apply` with the usage dump, which is
the negative control.

Signed-off-by: Javier Tia <floss@jetm.me>
@jetm
jetm requested a review from mobileoverlord August 12, 2026 20:56
@jetm

jetm commented Aug 12, 2026

Copy link
Copy Markdown
Contributor Author

Putting this back to draft. Two things are outstanding and both are the kind that should land before anyone spends a review pass on it.

Full-image verification. What is proven today is the mechanism, not the shipped artifact: u-boot 2026.01 built from this tree's own source with CONFIG_OF_LIBFDT_OVERLAY=y, booted under qemu-system-aarch64, loading the overlay list, env import -t, the for-loop over two names and fdt apply for each, with fdt print showing both overlays' nodes merged into the live tree - and the same sequence failing at fdt apply on the shipped binary as the negative control.

What that does not cover is the assembled image: a real avocado-qemuarm64 build with a declared overlay, booted end to end, confirming the kernel comes up with the overlaid DTB and that avocado_apply_overlays behaves as written once mkenvimage has rendered the escaped multi-line block. The ordering constraint in particular - the block runs before load_initramfs so the overlay loads cannot clobber the ${filesize} that avocado_boot passes as the initramfs length - is reasoned from the env, not yet observed on a boot.

Field notes. The u-boot side of this has a finding worth writing down rather than leaving in a PR description: qemu_arm64_defconfig does not set CONFIG_OF_LIBFDT_OVERLAY at 2026.01, so the shipped u-boot carried every fdt subcommand except the one that applies an overlay. That is invisible from the defconfig alone (a newer checkout does set it) and only shows up by reading the built .config or by watching fdt apply print the usage dump. Anyone wiring overlays on another u-boot target will hit it.

Marking draft rather than leaving it open so the review queue reflects that.

@jetm
jetm marked this pull request as draft August 12, 2026 21:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant