Hi Carlo, On Tue, 30 Jun 2026 at 20:20, Carlo Caione <[email protected]> wrote: > > Hi all, > > This is a design RFC, not a patch series. I would like to agree the approach > and the devicetree binding on the list before posting code, because the > mechanism touches both bootstd and the EFI loader and introduces a new > binding. > > A working implementation exists and has been validated on hardware (details at > the end); I will post it as patches once the design here is acceptable. > > > 1. The problem > ============== > > Platforms that follow EBBR / Arm SystemReady IR treat the OS devicetree as > part > of the firmware rather than part of the OS: the base DTB and its overlays live > on a firmware-owned partition and are updated independently of the operating > system, instead of being shipped in the OS image or on the EFI System > Partition > (ESP). The firmware is expected to load that devicetree and hand it to the OS > (via the EFI configuration table). > > U-Boot today can source the OS devicetree from its own control DT, from the > ESP, > or from an EFI Boot#### load option, but it has no generic way to assemble it > from a firmware-owned partition. As a result vendors carry out-of-tree > machinery > for exactly this. For example, MediaTek ships downstream `dtbprobe` (assemble > the > DT from a partition) and `fdt authndtb` (authenticate it) commands. The goal > of > this work is to provide one reusable, vendor-neutral mechanism in mainline so > those downstream commands can be dropped. >
For Mediatek specifically, I am hoping to eventually upstream support for a load-only FIT (the spec supports it) so that you can load the DT from a firmware partition, then still boot the OS (without a DT). This works with FIT, but would need adjustment if the OS is actually an EFI app. I wrote a post about this challenge: https://www-concept.deinde.dev/blog/devicetree-in-firmware-or-packaged-with-the-os/ > > 2. What a solution has to do > ============================ > > - Assemble the OS devicetree (a base DTB plus a list of overlays) from a > firmware-owned partition and install it for the OS. > - Install it on *every* EFI launch path, not just one. SystemReady IR boots > through the UEFI boot manager, which in U-Boot does not go through the > per-device EFI bootmeth, so a per-device-only hook is not enough. > - Support secure boot: when the firmware devicetree is signed, verify it, > and > never silently fall back to an unverified devicetree. > - Support A/B firmware partitions. > > > 3. Proposed design > =================== > > A new bootstd helper, `firmware_fdt_load()` (`CONFIG_BOOTSTD_FIRMWARE_FDT`), > assembles the devicetree and returns it; the EFI launch paths install it via > `efi_install_fdt()`, exactly like any other devicetree source. This sounds reasonable to me. > > 3.1 Where the source is described (new binding) > ----------------------------------------------- > > The *location* is described in the control devicetree. The bootstd node > carries > a `firmware-fdt-source` phandle to a node that is a child of the media device > that owns the partition, and identifies the partition by GPT type UUID and/or > name: > > bootstd { > compatible = "u-boot,boot-std"; > firmware-fdt-source = <&fw_fdt>; > }; > > &mmc0 { > fw_fdt: firmware-fdt { > compatible = "u-boot,firmware-fdt-block"; Does the -block suffix indicate that it is a block device, rather than a filesystem? How does this cope with the fast where multiple DTs are provided for different models? > partition-type-uuid = "...."; /* GPT type UUID */ > partition-name = "firmware"; /* optional */ > extra-size = <0x3000>; /* overlay headroom */ This seems like a parameter which would be better handled by U-Boot itself? > }; > }; > > 3.2 The dynamic parameters (environment) and board defaults > ----------------------------------------------------------- > > The source and its partition policy stay in the control devicetree (section > 3.1). The values that change with the OS image rather than with the hardware > are > layered: > > - the control DT describes the source and the partition policy; > - the board default environment carries factory defaults for the static > values > (`fdtfile` and `dtb_path` for the base DTB, and the `fdt_addr_r` / > `fdtoverlay_addr_r` working addresses), so a from-source build boots and > `env default` restores a loadable configuration; I wish we could move away from filenames and use compatible strings instead, as FIT does - this is how the FDT spec is written. > - the (firmware-owned) stored environment overrides those at runtime, and > carries the genuinely dynamic values: the overlay list (`list_dtbo`) and > the > A/B partition pin (`boot_dtb`). > > As an alternative, the stable defaults (`fdtfile` and the path) could instead > be > expressed as optional properties on the source node, keeping them in the > control > devicetree rather than in the board default environment. See the open > questions. > > 3.3 Where it is installed (both EFI paths) > ------------------------------------------ > > The helper is consumed by both: > > - the per-device EFI bootmeth (`bootmeth_efi`), and > - the EFI boot manager (`efi_bootmgr_run()`), > > each installing the result through `efi_install_fdt()`. That is the > convergence > point all EFI launches pass through, so the firmware devicetree is installed > regardless of how the EFI application was started, including the boot-manager > autoboot path that SystemReady IR uses. What if you run GRUB? > > 3.4 Fail-closed error semantics > ------------------------------- > > Once a source is configured (the node is present), the result must be > deterministic. Yes, this is very important. `-ENOENT` means *only* that no source is configured, in which > case the caller falls back to its normal devicetree. Any other failure to > assemble a configured source (unresolvable device, no matching partition, read > error, invalid blob, failed signature) is fatal for that EFI launch path: a > missing or bad firmware devicetree is never silently replaced by another > source. > Missing environment metadata for a configured source is treated as a > configuration error (fail closed, or satisfied from the board default), never > as > "no source". > > 3.5 Optional secure boot > ------------------------ > > With `CONFIG_BOOTSTD_FIRMWARE_FDT_FIT` the base DTB and overlays are signed > FIT > images. Each is verified by reusing U-Boot's existing verified-boot policy > (`fit_image_load()` with verification enabled and a required key in the > control > FDT), and the verified flat devicetree is extracted in place. A non-FIT file > is > rejected so an unsigned devicetree cannot be installed. This reuses the > existing > trust model rather than adding new crypto, and replaces the downstream > `fdt authndtb`. OK. > > > 4. Why these choices > ==================== > > - Describing the source in the control DT, as a child of the media device, > follows the existing bootstd guidance ("if a bootdev needs configuration, > add it to the DT as a child of the media device") and the VBE precedent. > It > keeps the mechanism generic: no GPT UUID or board constant in the C code. > - Splitting identity (control DT) from dynamic values (environment) and > static > defaults (board default env) keeps the firmware in control of what changes > per OS image, while still letting a plain `make <board>_defconfig` build > boot. > - Installing at `efi_install_fdt()` rather than in one bootmeth is what > makes > this SystemReady-IR-grade: the boot-manager path carries the firmware > devicetree too. A per-device-only hook leaves the autoboot path on the > control DT. > - Fail-closed is required for secure boot: there must be no path where a > configured, signed devicetree silently degrades to an unverified one. > - Reusing `fit_image_load()` keeps a single, reviewed verified-boot path. Agreed on all of these. > > > 5. Alternatives considered > ========================== > > - A global bootmeth ordered ahead of the EFI boot manager (a structure used > in > an earlier proof of concept). It works for autoboot but does not converge > all launch paths; `efi_install_fdt()` is the real single point. > - A per-device bootmeth hook only. Simpler, but misses the boot-manager > autoboot path, which is the one SystemReady IR uses. > - Keeping the mechanism vendor-specific (the status quo). Does not help > anyone > else and keeps the command out of tree. > > > 6. Open questions for the list > ============================== > > 1. Binding naming: are `firmware-fdt-source` and the > `u-boot,firmware-fdt-block` > compatible acceptable, and is the control-DT-described-source shape the > one > you want? Seems OK. > 2. The configuration boundary. The proposal keeps the source and partition > policy in the control DT, puts factory defaults for the filenames and the > working addresses in the board default environment, and lets the > firmware-owned stored environment override at runtime (and hold the > dynamic > `list_dtbo` / `boot_dtb`). An alternative is to express the stable > defaults > (`fdtfile`, a path) as optional properties on the source node, so they > live > in the control DT rather than the board environment. Which does the > project > prefer? See above...better to store a compatible string than a filename. > 3. The `efi_bootmgr_run()` hook: is installing the firmware devicetree on > the > boot-manager path acceptable to the EFI maintainers, and is that the > right > place? > 4. The fail-closed semantics: a configured source that cannot be assembled > is > fatal; only an absent source falls back. Agree? Yes > 5. Should the signed-FIT verification be part of this series or a follow-up? You likely get this for free, so I suggest including it. > > Thanks for any feedback. I will follow up with the patch series once the > binding > and approach are agreed. Regards, Simon

