From 3f6b4b41cca654ee6a18fc6e6e4aaa36aa59acf5 Mon Sep 17 00:00:00 2001 From: Javier Tia Date: Thu, 23 Jul 2026 11:35:43 -0600 Subject: [PATCH 01/12] field-notes: add device-tree overlays note Document the ENG-2134 device-tree-overlay feature as a draft field note: an extension declares an overlay under device_tree_overlays, and avocado build compiles it in the SDK and delivers the .dtbo into the OS bundle. Verified on raspberrypi5, where the FAT config.txt boot path lets stone write the overlay into boot.img and finalize os-bundle.aos end-to-end. qemuarm64 compiles and delivers the overlay but cannot finalize the bundle (no FAT boot medium; tracked in KOS-68), so the note stays draft until the clean-SDK image toolchain auto-provisions and the QEMU path closes. Signed-off-by: Javier Tia --- .../2026-07-21-device-tree-overlays.mdx | 119 ++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 src/field-notes/2026-07-21-device-tree-overlays.mdx diff --git a/src/field-notes/2026-07-21-device-tree-overlays.mdx b/src/field-notes/2026-07-21-device-tree-overlays.mdx new file mode 100644 index 00000000..0f013190 --- /dev/null +++ b/src/field-notes/2026-07-21-device-tree-overlays.mdx @@ -0,0 +1,119 @@ +--- +title: 'Device-tree overlays in Avocado OS' +description: 'Declare a device-tree overlay in an extension and let avocado build compile and deliver it into the OS bundle.' +date: 2026-07-21 +draft: true # PREVIEW: clean-SDK image toolchain still needs manual sdk.packages (KOS-68). raspberrypi5 finalizes end-to-end; keep draft until provisioning auto-lands, then finalize via the field-notes skill. +authors: [] # TODO: add your key from authors.yml before flipping draft:false +tags: [raspberrypi5, qemuarm64, device-tree] +category: 'Device tree' +featured: false +# --- internal drafting fields (not rendered) --- +tested_against: 'raspberrypi5 clean-room (CLI avocado 1.0.0-rc.1): avocado build compiled hello-overlay.dtbo, the delivery hook placed it in rootdisk/boot, and stone finalized os-bundle.aos with a FAT boot.img. Verified with avocado save (archive holds device-tree-overlays/hello-overlay.dtbo and os-bundle.aos). qemuarm64: compile + deliver succeed, but the .aos does not finalize (no FAT boot medium; KOS-68).' +poster: '' +lift_for_blog: 'Ship a board customization (a device-tree overlay) as a declarative part of your OS image, no manual dtc/boot surgery.' +promote_to_track: '' +--- + +import PullQuote from '@site/src/components/PullQuote' +import TestStatus from '@site/src/components/TestStatus' + + + +**TL;DR** — Declare a device-tree overlay in an extension and `avocado build` +compiles it in the SDK and delivers the `.dtbo` into the OS bundle under +`overlays/`. On raspberrypi5 the bundle finalizes end-to-end. No manual `dtc` +or boot-partition surgery. + +{/* truncate */} + +## What this is + +Avocado OS builds a complete, updatable OS image for your board. A device-tree +overlay is a small patch to the board's hardware description: enable a SPI +device, wire up a GPIO, add a sensor. This note shows how to make an overlay a +declarative part of your image instead of a manual boot-time step. + +## How it works / what we did + +Add `device_tree_overlays` to the extension that ships them: + +```yaml +extensions: + my-board: + types: + - sysext + device_tree_overlays: + - name: hello-overlay + src: overlays/hello-overlay.dtso +``` + +`name` is authoritative: it is the output basename (`overlays/.dtbo`) and +the boot-selection argument, so it must be a safe basename. `src` is your overlay +source. The source is a real overlay: it declares `/plugin/;` and targets a path +or phandle. + +```dts +/dts-v1/; +/plugin/; +/ { + fragment@0 { + target-path = "/"; + __overlay__ { + my-node { + compatible = "acme,widget"; + status = "okay"; + }; + }; + }; +}; +``` + +Then: + +```bash +avocado install +avocado build --target raspberrypi5 +``` + +Under the hood `avocado build` compiles each `.dtso` the way the kernel does +(`cpp` against the kernel's `dt-bindings` when the source `#include`s them, +`dtc -@` for overlay symbols), a per-board delivery step records where the blob +belongs on the boot medium, and the bundler places it at `overlays/.dtbo` +in the OS bundle. The feature is inert unless an overlay is declared. + +A board customization ships as **declared config**, not a manual dtc + boot-partition step. + +## Which targets finalize + +The overlay compiles and is delivered on every target. Whether the OS bundle +finalizes end-to-end depends on the boot medium. raspberrypi5 boots from a FAT +partition (the `config.txt` path), so `avocado build` writes the overlay into +`boot.img` and finalizes `os-bundle.aos` in a single pass. On `qemuarm64` the +same compile and delivery run, but the `.aos` does not finalize yet, because +there is no FAT boot medium to stage the kernel image into. That gap is tracked +in KOS-68 and does not affect FAT-booting hardware like the Pi. + +## Issues Encountered + +- **Clean SDK under-provisions the image toolchain (preview).** On a brand-new + SDK you currently must add a few image-build packages to `sdk.packages` + (erofs, btrfs, zstd, stone tooling) before a runtime image builds. + Auto-provisioning them is in progress (KOS-68). +- **qemuarm64 does not finalize the bundle yet (preview).** See "Which targets + finalize" above. FAT-booting targets (raspberrypi5) complete the flow; a + QEMU-only walkthrough waits on KOS-68. + +## Reproduce it + +On raspberrypi5 the flow above runs to a finalized bundle. Declare one overlay +in an extension, then run `avocado install` and `avocado build --target +raspberrypi5`. The build logs the three pipeline steps in order: the compile +(`avocado-dtc-overlay: built ... hello-overlay.dtbo`), the delivery +(`device-tree-overlay-deliver: delivered 1 overlay(s) to rootdisk/boot`), and +the finalized bundle (`OS bundle created: ... os-bundle.aos`). To inspect the +result, `avocado save` exports the build state; the archive holds both the +compiled `device-tree-overlays/hello-overlay.dtbo` and the finalized +`os-bundle.aos`. From c68785032794803ad0c1c716f8dddf1beae8f283 Mon Sep 17 00:00:00 2001 From: Javier Tia Date: Thu, 30 Jul 2026 12:08:09 -0600 Subject: [PATCH 02/12] field-notes/device-tree-overlays: flag reader-repro gates and SDK provisioning The draft pinned cli=1.0.0-rc.1, but that released version does not carry the device-tree-overlay support: the note was verified with a from-source eng-2134 CLI that merely reports 1.0.0-rc.1. A reader on the real 1.0.0-rc.1 would fail, and the example omitted the sdk.packages the runtime image needs to finalize on a clean SDK, so a copied example would stop short of the bundle. Record the release and publish chain that gates reader reproduction in an internal repro_blockers field, correct the tested_against CLI provenance, and add the erofs/btrfs/zstd/stone sdk.packages block to the reproduce steps so a copied example finalizes until KOS-68 auto-provisions them. Signed-off-by: Javier Tia --- .../2026-07-21-device-tree-overlays.mdx | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/field-notes/2026-07-21-device-tree-overlays.mdx b/src/field-notes/2026-07-21-device-tree-overlays.mdx index 0f013190..fa2e0c9b 100644 --- a/src/field-notes/2026-07-21-device-tree-overlays.mdx +++ b/src/field-notes/2026-07-21-device-tree-overlays.mdx @@ -8,7 +8,8 @@ tags: [raspberrypi5, qemuarm64, device-tree] category: 'Device tree' featured: false # --- internal drafting fields (not rendered) --- -tested_against: 'raspberrypi5 clean-room (CLI avocado 1.0.0-rc.1): avocado build compiled hello-overlay.dtbo, the delivery hook placed it in rootdisk/boot, and stone finalized os-bundle.aos with a FAT boot.img. Verified with avocado save (archive holds device-tree-overlays/hello-overlay.dtbo and os-bundle.aos). qemuarm64: compile + deliver succeed, but the .aos does not finalize (no FAT boot medium; KOS-68).' +tested_against: 'raspberrypi5 clean-room (from-source eng-2134 CLI: reports 1.0.0-rc.1 but carries the unreleased DTO commits - the released 1.0.0-rc.1 does NOT have DTO): avocado build compiled hello-overlay.dtbo, the delivery hook placed it in rootdisk/boot, and stone finalized os-bundle.aos with a FAT boot.img. Verified with avocado save (archive holds device-tree-overlays/hello-overlay.dtbo and os-bundle.aos). qemuarm64: compile + deliver succeed, but the .aos does not finalize (no FAT boot medium; KOS-68).' +repro_blockers: 'Reader reproduction is gated on released artifacts, not this local proof. Before draft:false - (1) merge stone#28, re-pin meta-avocado stone_2.2.0.bb SRCREV off the feature branch, merge meta-avocado#245, merge avocado-cli#183; (2) publish the SDK image (avocadolinux/sdk:2024-edge, must carry nativesdk-avocado-dtc-overlay + files_append nativesdk-stone) and the 2024/edge feed (must carry avocado-dtc-overlay-deliver); (3) cut an avocado-cli release and re-pin the cli= tag below to it (1.0.0-rc.1 lacks DTO); (4) resolve KOS-68 auto-provisioning or keep the sdk.packages block in Reproduce it; (5) record the on-device-apply MP4 (today the proof is bundle-level B only). Full chain in the ENG-2134 reproduce-from-scratch comment.' poster: '' lift_for_blog: 'Ship a board customization (a device-tree overlay) as a declarative part of your OS image, no manual dtc/boot surgery.' promote_to_track: '' @@ -110,7 +111,22 @@ in KOS-68 and does not affect FAT-booting hardware like the Pi. On raspberrypi5 the flow above runs to a finalized bundle. Declare one overlay in an extension, then run `avocado install` and `avocado build --target -raspberrypi5`. The build logs the three pipeline steps in order: the compile +raspberrypi5`. + +On a brand-new SDK, add the image-build packages to `sdk.packages` so the +runtime image finalizes (until KOS-68 provisions them automatically): + +```yaml +sdk: + packages: + nativesdk-erofs-utils: "*" + nativesdk-btrfs-tools: "*" + nativesdk-zstd: "*" + nativesdk-stone: "*" + avocado-sdk-target: "*" +``` + +The build logs the three pipeline steps in order: the compile (`avocado-dtc-overlay: built ... hello-overlay.dtbo`), the delivery (`device-tree-overlay-deliver: delivered 1 overlay(s) to rootdisk/boot`), and the finalized bundle (`OS bundle created: ... os-bundle.aos`). To inspect the From 5f577749a6e5dc7bed64b8a5d66909169b025919 Mon Sep 17 00:00:00 2001 From: Javier Tia Date: Sat, 15 Aug 2026 12:54:07 -0600 Subject: [PATCH 03/12] field-notes/device-tree-overlays: add the Jetson Orin on-device result The note claimed the feature at bundle level only: overlays compiled, were delivered, and the bundle finalized. Whether an overlay actually took effect on a running board was never shown, which is the claim a reader cares about. Jetson supplies it, and supplies the more interesting half of the argument. The platform has nowhere to put a loose .dtbo - no DTBO partition, an ESP carrying only the bootloader, and flash vars that the initrd-flash path never reads - so the overlay is merged into the device tree at build time instead. The project config does not change: same declaration, same .dtso, with the per-BSP hook absorbing the difference. That is a sharper illustration of the note's thesis than a second FAT-booting board would have been, because it shows the declaration surviving a mechanism swap. State the reflash consequence next to it. On the Pi an overlay change is an ordinary image update; on Jetson it changes the device tree and takes a reflash. A reader planning around this needs that before they plan, not after. Record the container-provisioning gap in repro_blockers as well. `avocado runtime provision` cannot flash a Jetson from its container today, so a reader-facing flash instruction cannot assume it works. Also mark what has cleared since the first draft - stone#28 and meta-avocado#245 are merged - so the remaining list is what actually still gates publication. Still draft: avocado-cli#183 and the two Jetson PRs are open, and the on-device MP4 is unrecorded. Signed-off-by: Javier Tia --- .../2026-07-21-device-tree-overlays.mdx | 38 +++++++++++++++++-- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/src/field-notes/2026-07-21-device-tree-overlays.mdx b/src/field-notes/2026-07-21-device-tree-overlays.mdx index fa2e0c9b..f153f1e9 100644 --- a/src/field-notes/2026-07-21-device-tree-overlays.mdx +++ b/src/field-notes/2026-07-21-device-tree-overlays.mdx @@ -4,12 +4,12 @@ description: 'Declare a device-tree overlay in an extension and let avocado buil date: 2026-07-21 draft: true # PREVIEW: clean-SDK image toolchain still needs manual sdk.packages (KOS-68). raspberrypi5 finalizes end-to-end; keep draft until provisioning auto-lands, then finalize via the field-notes skill. authors: [] # TODO: add your key from authors.yml before flipping draft:false -tags: [raspberrypi5, qemuarm64, device-tree] +tags: [raspberrypi5, qemuarm64, jetson-orin, device-tree] category: 'Device tree' featured: false # --- internal drafting fields (not rendered) --- -tested_against: 'raspberrypi5 clean-room (from-source eng-2134 CLI: reports 1.0.0-rc.1 but carries the unreleased DTO commits - the released 1.0.0-rc.1 does NOT have DTO): avocado build compiled hello-overlay.dtbo, the delivery hook placed it in rootdisk/boot, and stone finalized os-bundle.aos with a FAT boot.img. Verified with avocado save (archive holds device-tree-overlays/hello-overlay.dtbo and os-bundle.aos). qemuarm64: compile + deliver succeed, but the .aos does not finalize (no FAT boot medium; KOS-68).' -repro_blockers: 'Reader reproduction is gated on released artifacts, not this local proof. Before draft:false - (1) merge stone#28, re-pin meta-avocado stone_2.2.0.bb SRCREV off the feature branch, merge meta-avocado#245, merge avocado-cli#183; (2) publish the SDK image (avocadolinux/sdk:2024-edge, must carry nativesdk-avocado-dtc-overlay + files_append nativesdk-stone) and the 2024/edge feed (must carry avocado-dtc-overlay-deliver); (3) cut an avocado-cli release and re-pin the cli= tag below to it (1.0.0-rc.1 lacks DTO); (4) resolve KOS-68 auto-provisioning or keep the sdk.packages block in Reproduce it; (5) record the on-device-apply MP4 (today the proof is bundle-level B only). Full chain in the ENG-2134 reproduce-from-scratch comment.' +tested_against: 'raspberrypi5 clean-room (from-source eng-2134 CLI: reports 1.0.0-rc.1 but carries the unreleased DTO commits - the released 1.0.0-rc.1 does NOT have DTO): avocado build compiled hello-overlay.dtbo, the delivery hook placed it in rootdisk/boot, and stone finalized os-bundle.aos with a FAT boot.img. Verified with avocado save (archive holds device-tree-overlays/hello-overlay.dtbo and os-bundle.aos). qemuarm64: compile + deliver succeed, but the .aos does not finalize (no FAT boot medium; KOS-68). jetson-orin-nano-devkit (P3767-0005) 2026-08-15: ON-DEVICE, paired positive/negative. Build path reaches all three markers; flashed via tegraflash-sd; /proc/device-tree/hello-overlay/avocado,marker reads eng-2134-dto-e2e on the running board and the node is absent on a build with the declaration removed. Mechanism is a build-time fdtoverlay merge into the base DTB published as storage_devices.rootdisk.images.dtb - NOT loose .dtbo delivery, which Tegra has no boot-medium slot for.' +repro_blockers: 'Reader reproduction is gated on released artifacts, not this local proof. DONE since first draft: stone#28 merged and the SRCREV re-pin done; meta-avocado#245 merged as 563d462; on-device apply now PROVEN on Jetson Orin (2026-08-15, paired positive/negative), so the "bundle-level only" caveat no longer holds for that target. Before draft:false - (1) merge avocado-cli#183, plus the Jetson chain: meta-avocado#292 (overlay delivery) and #293 (stage the Tegra BSP into the SDK stone dir; #292 does not function without it); (2) publish the SDK image (avocadolinux/sdk:2024-edge, must carry nativesdk-avocado-dtc-overlay + files_append nativesdk-stone) and the 2024/edge feed (must carry avocado-dtc-overlay-deliver); (3) cut an avocado-cli release and re-pin the cli= tag below to it (1.0.0-rc.1 lacks DTO); (4) resolve KOS-68 auto-provisioning or keep the sdk.packages block in Reproduce it; (5) record the on-device-apply MP4 - the Jetson result above is the evidence it can be recorded, not a substitute for it. NOTE for the Jetson walkthrough: avocado runtime provision cannot flash a Jetson from its container today (no --privileged in the production path; with it added, RCM boot succeeds but the target never exports its LUN), so any reader-facing flash instruction must not assume it works until that is fixed on avocado-cli#183.' poster: '' lift_for_blog: 'Ship a board customization (a device-tree overlay) as a declarative part of your OS image, no manual dtc/boot surgery.' promote_to_track: '' @@ -97,6 +97,38 @@ same compile and delivery run, but the `.aos` does not finalize yet, because there is no FAT boot medium to stage the kernel image into. That gap is tracked in KOS-68 and does not affect FAT-booting hardware like the Pi. +## Jetson Orin: the same declaration, a different delivery + +Jetson has nowhere to put a loose `.dtbo`. The flashed partition set has no DTBO +partition, and the ESP carries only the bootloader. The overlay lists that do +exist in the Tegra flash vars are read by the classic `flash.sh` path, not by +the initrd-flash flow Avocado uses, which consumes binaries already signed at +build time. + +So on Jetson the overlay is merged into the board's device tree at build time +with `fdtoverlay`, and the merged tree is what gets flashed. The project config +is identical - the same `device_tree_overlays` block, the same `.dtso` - and the +per-board delivery hook absorbs the difference. That is the point of the hook +being per-BSP: the declaration is portable even when the mechanism underneath is +not. + +One consequence worth stating plainly, because it differs from the Pi: changing +an overlay on Jetson changes the device tree, so it takes a reflash rather than +an ordinary image update. + +Verified on a Jetson Orin Nano Developer Kit (module P3767-0005). With the +overlay declared, on the running board: + +```console +# tr -d '\0' < /proc/device-tree/hello-overlay/avocado,marker +eng-2134-dto-e2e +``` + +and with the declaration removed and nothing else changed, the node is absent. +`/proc/device-tree` is the tree the kernel is actually running, so this is the +overlay in effect rather than a build artifact - and the paired negative run is +what rules out a node that was in the base tree all along. + ## Issues Encountered - **Clean SDK under-provisions the image toolchain (preview).** On a brand-new From 0e8c032940bf34cf93f291d06e6ea80f9fb507d1 Mon Sep 17 00:00:00 2001 From: Javier Tia Date: Sat, 15 Aug 2026 13:20:11 -0600 Subject: [PATCH 04/12] developer-reference: add a device-tree overlays guide in draft The field note argues why declarative overlays matter and reports what was verified; it is not something a reader can follow to ship one. Several things a user needs are missing from it entirely: the `params` key, the name-uniqueness and basename rules, what happens on a target with no delivery hook, and the `avocado-runtime` package a runtime must declare - whose omission produces a `u-boot.bin not found` failure at bundling that reads like a broken BSP and already cost two weeks of chasing a product bug that was a project-config omission. Put those in a guide alongside custom-kernel, sourced from the CLI and BSP code rather than from the note, and give verification its own section: a green build path is not evidence an overlay applied, which is how a Jetson booted with nothing applied through two full build rounds. The section asks for a paired positive/negative reading of /proc/device-tree per platform, because the delivery mechanism differs per board and a pass on one proves nothing about another. Ship it `draft: true` with a Release status table naming every PR and publish step that gates it, so the undraft condition is tracked on the page instead of in an issue thread. Drafts are dropped from the production build and a sidebar item naming a dropped doc fails that build, so the sidebar entry is deliberately withheld and recorded as an item in the same table. Signed-off-by: Javier Tia --- src/docs-guides/device-tree-overlays.md | 316 ++++++++++++++++++++++++ src/sidebars-guides.js | 5 + 2 files changed, 321 insertions(+) create mode 100644 src/docs-guides/device-tree-overlays.md diff --git a/src/docs-guides/device-tree-overlays.md b/src/docs-guides/device-tree-overlays.md new file mode 100644 index 00000000..7e00f958 --- /dev/null +++ b/src/docs-guides/device-tree-overlays.md @@ -0,0 +1,316 @@ +--- +sidebar_position: 6.5 +title: 'Device-tree overlays' +copy_markdown: true +draft: true +description: 'Declare a device-tree overlay in an extension and let avocado build compile it in the SDK and deliver it to the boot medium - no manual dtc, no boot-partition surgery, no BSP fork.' +--- + +:::danger draft - not yet reproducible by a reader + +This guide documents behavior that is **not in a released Avocado CLI or SDK image**. Every command below has been run, but only against from-source builds of unmerged branches. Following it with released artifacts will fail at `avocado install`. + +See [Release status](#release-status) at the bottom for the exact list of what must merge and publish before this page can drop `draft: true`. + +::: + +A device-tree overlay is a small patch to your board's hardware description: enable a SPI bus, wire up a GPIO, add a sensor the base device tree does not know about. Traditionally that means compiling a `.dtbo` by hand with `dtc` and finding somewhere on the boot partition to put it - a per-board manual step that has to be repeated on every image. + +Avocado makes the overlay a declared part of the image. An extension names the overlays it ships, and `avocado build` compiles each one in the SDK and hands it to a per-board delivery step that knows where the blob belongs on that board's boot medium. + +This guide covers: + +- Declaring overlays in `avocado.yaml` +- Writing an overlay source the compiler will accept +- Which targets are supported, and what each one does with the blob +- Confirming on a booted board that the overlay actually applied +- Per-target update consequences (one target needs a reflash) + +## Target support + +The declaration is portable; the delivery mechanism is not. Each BSP layer installs its own delivery hook, so what happens to the compiled blob differs by board - including how you ship a _change_ to an overlay later. + +| Target | Delivery mechanism | Where the blob lands | Updating an overlay | +| ------------------------------------------- | -------------------------------------------------------------- | -------------------------------------------------- | ------------------------------------------------------------------------ | +| `raspberrypi5`, `raspberrypi4` | Loose `.dtbo` on the boot FAT, selected by a `dtoverlay=` line | `overlays/.dtbo` plus `avocado-overlays.txt` | Ordinary image update | +| `jetson-orin-nano-devkit` (and other Tegra) | Merged into the base DTB at build time with `fdtoverlay` | Replaces the flashed kernel DTB | **Reflash** - see [Jetson](#jetson-tegra) | +| `qemuarm64` | Loose `.dtbo` on the boot FAT | `overlays/.dtbo` | Delivered but **not applied at boot** yet | +| `qemux86-64` | None | - | Not applicable - x86 boots via ACPI and has no device tree | +| Any other target | None | - | Build fails, by design - see [Unsupported targets](#unsupported-targets) | + +:::info the declaration is the portable part +The same `device_tree_overlays` block and the same `.dtso` move between a Pi and a Jetson unchanged. Only the hook underneath differs. That is the point of the hook being per-BSP. +::: + +## Declaring an overlay + +Overlays are declared on the **extension** that ships them, not on the runtime and not on a package: + +```yaml +runtimes: + dev: + target: raspberrypi5 + extensions: + - my-board + packages: + avocado-runtime: '*' # required - see the note below + +extensions: + my-board: + types: + - sysext + device_tree_overlays: + - name: hello-overlay + src: overlays/hello-overlay.dtso +``` + +| Key | Required | Meaning | +| -------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `name` | yes | Authoritative. It is the output basename (`overlays/.dtbo`), the `dtoverlay=` argument on Raspberry Pi, and the u-boot overlay entry. Must be a safe basename: no `/`, no whitespace, not `.` or `..`. Names must be unique across the whole runtime - a duplicate is a hard error, not last-one-wins. | +| `src` | yes | Path to the overlay source, relative to the project root. | +| `params` | no | A mapping of per-overlay parameters. **Raspberry Pi only** - see [Parameters](#parameters-raspberry-pi-only). | + +:::warning declare `avocado-runtime` +The runtime must pull `avocado-runtime`, which is what installs `avocado-img-bootfiles` - the package shipping `u-boot.bin` and the `bootfiles/*` entries the bundler needs to build a boot image. A project that omits it fails late, at bundling, with `File 'u-boot.bin' not found in any input directory for FAT image`, which reads like a broken BSP rather than a missing declaration. It cost us two weeks of chasing a product bug that was a project-config omission. +::: + +The feature is inert unless an overlay is declared. A project with no `device_tree_overlays` anywhere builds exactly as before. + +## Writing the overlay source + +The source must be a real overlay, not a full device tree. Two rules the compiler enforces: + +**It must declare `/plugin/;`.** Without it, `dtc` happily compiles a complete device tree instead and you get a blob nothing will apply. The build rejects this up front. + +**It must materialize at least one fragment** - a top-level node with an `__overlay__` child. Both the `&label { }` shorthand and the explicit `fragment@N` form produce this. + +A path-targeted overlay, which works on any board: + +```dts +/dts-v1/; +/plugin/; + +/ { + fragment@0 { + target-path = "/"; + __overlay__ { + hello-overlay { + compatible = "acme,widget"; + status = "okay"; + }; + }; + }; +}; +``` + +A label-targeted overlay, which is what you usually want on real hardware: + +```dts +/dts-v1/; +/plugin/; + +&spi0 { + status = "okay"; + + sensor@0 { + compatible = "acme,sensor"; + reg = <0>; + spi-max-frequency = <12000000>; + }; +}; +``` + +:::caution label targets need `__symbols__` in the base tree +`&spi0` resolves through the base device tree's `__symbols__` node, which only exists if the BSP compiled its DTB with `dtc -@`. Most vendor BSPs do; QEMU's `virt` machine does not. If the label cannot resolve, a Raspberry Pi silently boots without the overlay, while a Jetson **fails the build** - `fdtoverlay` errors and the hook treats that as fatal rather than flashing an unmerged tree. Use `target-path` when you are unsure. +::: + +### Using `dt-bindings` macros + +If your source `#include`s kernel headers, the wrapper preprocesses it with `cpp` exactly as the kernel build does (`-nostdinc -undef -x assembler-with-cpp -D__DTS__`) against the kernel's `dt-bindings` tree: + +```dts +#include + +/dts-v1/; +/plugin/; + +&gpio { + my-pin { + gpios = <&gpio 17 GPIO_ACTIVE_HIGH>; + }; +}; +``` + +This requires `kernel-devsrc` in the target sysroot. It is installed automatically when the SDK is provisioned for a project declaring overlays. An overlay with no `#include` skips the preprocessor entirely and needs no kernel sources. + +A `/include/ "shared.dtsi"` (the native DTS include, not a cpp one) resolves relative to your source file and does **not** pull in the preprocessor. + +## Building + +```bash +avocado install +avocado build --target raspberrypi5 +``` + +The build logs three ordered markers. All three must appear: + +```text +avocado-dtc-overlay: built .../device-tree-overlays/hello-overlay.dtbo from hello-overlay +device-tree-overlay-deliver: delivered 1 overlay(s) to rootdisk/boot for avocado-raspberrypi5: hello-overlay +[SUCCESS] OS bundle created: .../os-bundle.aos +``` + +To inspect what was produced, `avocado save` exports the build state; the archive holds both the compiled `device-tree-overlays/.dtbo` and the finalized `os-bundle.aos`. + +### On a brand-new SDK + +Until SDK auto-provisioning lands (tracked as KOS-68), a clean SDK needs the image-build toolchain declared explicitly: + +```yaml +sdk: + packages: + nativesdk-erofs-utils: '*' + nativesdk-btrfs-tools: '*' + nativesdk-zstd: '*' + nativesdk-stone: '*' + avocado-sdk-target: '*' +``` + +## Confirming the overlay applied + +**A green build is not evidence that an overlay is applied.** This is the single most important thing on this page. Every build-path marker above can pass - the source compiles, the right blob is delivered, the bundle finalizes, the flash reports success - while the running kernel uses a device tree your overlay never touched. That exact failure happened on Jetson and went undetected for two full build rounds. + +The only evidence that counts is the tree the kernel is actually running. On the booted board: + +```console +# ls /proc/device-tree/ +# tr -d '\0' < /proc/device-tree/hello-overlay/compatible +acme,widget +``` + +`/proc/device-tree` is the live tree after every stage the bootloader applied, so a node present there is a node in effect. + +### Run the negative control + +One positive reading is not enough on its own: a node that was in the base tree all along looks identical to one an overlay added. Build the same project a second time with the `device_tree_overlays` block removed and nothing else changed, boot it on the same board, and confirm the node is **absent**: + +```console +# tr -d '\0' < /proc/device-tree/hello-overlay/compatible +sh: can't open /proc/device-tree/hello-overlay/compatible: no such file +``` + +With both halves, the declaration is the only variable that can explain the difference. Do this once per platform you ship on - the delivery mechanism differs per board, so a pass on one proves nothing about another. + +## Per-target details + +### Raspberry Pi + +The hook writes the `.dtbo` to `overlays/.dtbo` on the boot FAT and emits an `avocado-overlays.txt` alongside it holding one `dtoverlay=` line per overlay. The stock `config.txt` carries a static `include avocado-overlays.txt`, so the firmware picks these up at boot. + +`config.txt` itself is never rewritten. That keeps your own `config.txt` overrides and the generated overlay list from fighting over the same file. + +### Jetson (Tegra) + +Tegra has nowhere to put a loose `.dtbo`. The flashed partition set has no DTBO partition, the ESP carries only the bootloader, and the overlay lists that do exist in the Tegra flash variables are read by the classic `flash.sh` path - not by the `initrd-flash` flow Avocado uses, which consumes binaries already signed at build time. Anything written to those lists is inert. + +So the hook merges the declared overlays into the board's base DTB at build time with `fdtoverlay` and publishes the merged tree as the stone manifest's `storage_devices.rootdisk.images.dtb`. That merged DTB is what gets flashed. + +Two consequences: + +**Changing an overlay requires a reflash, not an image update.** The overlay is baked into a signed DTB living in a flash partition, so it only moves through the provisioning path. This is the one place the platforms genuinely diverge for a user, and it belongs in your own deployment planning. + +**Declaration order is load-bearing.** `fdtoverlay` applies overlays in the order declared, so an overlay targeting a node that an earlier overlay created must come after it. + +The base DTB is selected by the `DTBFILE` the BSP records, because a real Tegra BSP ships one base DTB per module SKU - five on an Orin Nano dev kit. You do not choose it; the board's own flash configuration does. + +### QEMU + +`qemuarm64` compiles and delivers the overlay to the boot FAT, but u-boot does not yet apply it at boot: the shipped `qemu_arm64_defconfig` does not set `CONFIG_OF_LIBFDT_OVERLAY`, so its u-boot carries every `fdt` subcommand except the one that applies an overlay. Wiring that up is tracked in meta-avocado#273. Until it merges, treat qemuarm64 as delivery-only. + +`qemux86-64` has no device tree at all - x86 boots via ACPI - so no hook is installed and declaring an overlay there fails the build. + +## Parameters (Raspberry Pi only) + +`params` renders into the `dtoverlay=` line as comma-separated `key=value` pairs: + +```yaml +device_tree_overlays: + - name: my-spi + src: overlays/my-spi.dtso + params: + speed: '12000000' + cs: '0' +``` + +produces `dtoverlay=my-spi,cs=0,speed=12000000` (keys are sorted, so the output is stable across builds). + +:::warning `params` is silently ignored off Raspberry Pi +Only the Raspberry Pi hook consumes `params` - it maps onto the Pi firmware's own overlay-parameter mechanism, which has no equivalent elsewhere. The Jetson and QEMU hooks accept a declaration carrying `params` and deliver the overlay without them, with no warning. On those targets, encode the values in the `.dtso` itself. +::: + +## Unsupported targets + +Declaring an overlay on a target whose BSP ships no delivery hook is a **hard error**, not a silent skip: + +```text +[ERROR] device-tree overlays are declared but this target provides no delivery hook. + Expected an executable at .../usr/libexec/avocado/device-tree-overlay-deliver +``` + +The same applies one level deeper: if the hook runs but does not claim an overlay, the build fails naming it. A declared overlay either reaches the boot medium or fails the build - it never quietly disappears into an image that looks fine. + +## Troubleshooting + +| Symptom | Cause | Fix | +| -------------------------------------------------------------------- | ------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------- | +| `source is not a device-tree overlay (missing '/plugin/;')` | Source is a full device tree | Add `/plugin/;` after `/dts-v1/;` | +| `device-tree overlay name '' is not a valid basename` | `name` has a `/`, whitespace, or is `.`/`..` | Use a plain basename; it becomes a filename and a boot-loader argument | +| `device-tree overlay name '' is declared by both '' and ''` | Two extensions on one runtime used the same name | Rename one; names are runtime-global | +| `this target provides no delivery hook` | Target's BSP has no hook (see the support matrix) | Remove the declaration for that target, or add a hook to the BSP layer | +| `device-tree overlays staged but not delivered by the BSP hook` | Hook ran but did not claim the overlay | A BSP bug - report it with the build log; the build correctly refused to ship a silently-dropped overlay | +| `no dt-bindings under ` | Source `#include`s kernel headers, `kernel-devsrc` missing or incomplete | Confirm the SDK was provisioned for a project declaring overlays; a no-`#include` overlay needs neither | +| `fdtoverlay failed to merge` (Jetson) | Overlay targets a label or path absent from the base DTB | Check the target resolves in that board's base tree; prefer `target-path` when unsure | +| `File 'u-boot.bin' not found in any input directory for FAT image` | Runtime does not declare `avocado-runtime` | Add `packages: avocado-runtime: '*'` to the runtime | +| Build fully green, node absent from `/proc/device-tree` | Overlay was delivered but not applied at boot | On qemuarm64 this is expected (#273). Elsewhere, run the negative control and report it | + +## Release status + +This page is `draft: true` because the feature is not reachable from released artifacts. Everything below must land before it publishes. + +### Pull requests + +| PR | Repo | Status | What it provides | Required for | +| -------------------------------------------------------------- | ------------ | --------------------------------- | --------------------------------------------------------------------- | ------------------------------------------------ | +| [#28](https://github.com/avocado-linux/stone/pull/28) | stone | **Merged** 2026-08-12 | `files_append` FAT primitive | All targets | +| [#245](https://github.com/avocado-linux/meta-avocado/pull/245) | meta-avocado | **Merged** 2026-08-12 (`563d462`) | SDK compile wrapper + RPi and QEMU delivery hooks | All targets | +| [#183](https://github.com/avocado-linux/avocado-cli/pull/183) | avocado-cli | Open, **draft** | The `device_tree_overlays` config surface and build orchestration | All targets | +| [#292](https://github.com/avocado-linux/meta-avocado/pull/292) | meta-avocado | Open, ready | Jetson delivery hook (`fdtoverlay` merge) | Jetson | +| [#293](https://github.com/avocado-linux/meta-avocado/pull/293) | meta-avocado | Open, ready | Stages the Tegra BSP into the SDK stone dir | Jetson - **#292 does not function without it** | +| [#291](https://github.com/avocado-linux/meta-avocado/pull/291) | meta-avocado | Open, ready | Makes four silent Jetson provisioning failures report their own cause | Jetson walkthrough being followable | +| [#273](https://github.com/avocado-linux/meta-avocado/pull/273) | meta-avocado | Open, **draft** | Applies delivered overlays at boot on qemuarm64 | qemuarm64 only - **not** a blocker for this page | + +Merge order is constrained: #28 before #245 (SRCREV re-pin), and #293 before or with #292. + +### Beyond the PRs + +| # | Item | Why it blocks | +| --- | ------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| 1 | Publish the SDK image `avocadolinux/sdk:2024-edge` carrying `nativesdk-avocado-dtc-overlay` and the `files_append` `nativesdk-stone` | `avocado install` cannot resolve the overlay compiler without it | +| 2 | Publish the `2024/edge` feed carrying `avocado-dtc-overlay-deliver` | The delivery hook is a target package; without it the build hard-errors on a missing hook | +| 3 | Cut an avocado-cli release and name it in this guide | The released `1.0.0-rc.1` does **not** carry the overlay work, despite the from-source build reporting the same version | +| 4 | Resolve KOS-68, or keep the [brand-new SDK](#on-a-brand-new-sdk) block | A clean SDK cannot finalize a runtime image without it | +| 5 | Raspberry Pi 5 paired positive/negative hardware run | The Pi path is proven only at build level; per [Confirming the overlay applied](#confirming-the-overlay-applied), that is not evidence | +| 6 | Fix container-mode provisioning on Jetson (part of avocado-cli#183) | `avocado runtime provision` cannot flash a Jetson from its container today. Every Jetson flash behind this page was run host-side, so the documented CLI path is not the path that was verified | +| 7 | Add this page to the Advanced category in `sidebars-guides.js` | Deliberately omitted while `draft: true` - a sidebar entry pointing at a draft doc breaks the production build | + +### What is already proven + +- **Jetson Orin Nano dev kit (P3767-0005), 2026-08-15**: on-device, paired positive and negative. `/proc/device-tree/hello-overlay/avocado,marker` reads the declared value on the running board and the node is absent with the declaration removed. +- **raspberrypi5**: build path green end to end - compile, deliver, finalized `os-bundle.aos`. No hardware run yet (item 5 above). +- **qemuarm64**: compile and deliver green; boot-time application pending #273. + +## What's next + +- [Custom kernel](./custom-kernel) - bring your own kernel tree, including the vendor trees that ship board device trees +- [Provisioning](./provisioning) - writing a built image to a board +- [Hardware-in-the-loop development](./hardware-in-the-loop) - iterating against a live device diff --git a/src/sidebars-guides.js b/src/sidebars-guides.js index 01d4330f..babdf6ff 100644 --- a/src/sidebars-guides.js +++ b/src/sidebars-guides.js @@ -45,6 +45,11 @@ const sidebars = { items: [ 'cross-compilation', 'custom-kernel', + // 'device-tree-overlays' belongs here, after custom-kernel, but stays + // unlisted while that page carries `draft: true`. Drafts are dropped + // from the production build, and a sidebar item naming a dropped doc + // fails the build. Add it in the same commit that flips the draft flag + // (tracked as item 7 of that page's "Release status" table). 'seeding-var', 'customizing-rootfs-initramfs', 'lockfiles-and-build-stamps', From f5287965ce6ebde96233ea6ffa3bac98a8754919 Mon Sep 17 00:00:00 2001 From: Javier Tia Date: Sat, 15 Aug 2026 13:26:21 -0600 Subject: [PATCH 05/12] field-notes: drop the device-tree overlays note Its mechanics are now in the developer reference, sourced from the CLI and BSP code rather than from the note, and they differ where the note was wrong: the example YAML omitted `avocado-runtime`, which is the omission that produces the `u-boot.bin not found` bundling failure a reader would then have to diagnose. Leaving a second, staler copy in place decides that outcome by whichever page the reader lands on first. The argument the note carried - that overlays are the interfaces-and-peripherals layer a board change actually costs you in - is not lost by deleting it. That framing has its own homes in ENG-2264 and ENG-2263, where it is the subject rather than a preamble to a mechanism walkthrough. Signed-off-by: Javier Tia --- .../2026-07-21-device-tree-overlays.mdx | 167 ------------------ 1 file changed, 167 deletions(-) delete mode 100644 src/field-notes/2026-07-21-device-tree-overlays.mdx diff --git a/src/field-notes/2026-07-21-device-tree-overlays.mdx b/src/field-notes/2026-07-21-device-tree-overlays.mdx deleted file mode 100644 index f153f1e9..00000000 --- a/src/field-notes/2026-07-21-device-tree-overlays.mdx +++ /dev/null @@ -1,167 +0,0 @@ ---- -title: 'Device-tree overlays in Avocado OS' -description: 'Declare a device-tree overlay in an extension and let avocado build compile and deliver it into the OS bundle.' -date: 2026-07-21 -draft: true # PREVIEW: clean-SDK image toolchain still needs manual sdk.packages (KOS-68). raspberrypi5 finalizes end-to-end; keep draft until provisioning auto-lands, then finalize via the field-notes skill. -authors: [] # TODO: add your key from authors.yml before flipping draft:false -tags: [raspberrypi5, qemuarm64, jetson-orin, device-tree] -category: 'Device tree' -featured: false -# --- internal drafting fields (not rendered) --- -tested_against: 'raspberrypi5 clean-room (from-source eng-2134 CLI: reports 1.0.0-rc.1 but carries the unreleased DTO commits - the released 1.0.0-rc.1 does NOT have DTO): avocado build compiled hello-overlay.dtbo, the delivery hook placed it in rootdisk/boot, and stone finalized os-bundle.aos with a FAT boot.img. Verified with avocado save (archive holds device-tree-overlays/hello-overlay.dtbo and os-bundle.aos). qemuarm64: compile + deliver succeed, but the .aos does not finalize (no FAT boot medium; KOS-68). jetson-orin-nano-devkit (P3767-0005) 2026-08-15: ON-DEVICE, paired positive/negative. Build path reaches all three markers; flashed via tegraflash-sd; /proc/device-tree/hello-overlay/avocado,marker reads eng-2134-dto-e2e on the running board and the node is absent on a build with the declaration removed. Mechanism is a build-time fdtoverlay merge into the base DTB published as storage_devices.rootdisk.images.dtb - NOT loose .dtbo delivery, which Tegra has no boot-medium slot for.' -repro_blockers: 'Reader reproduction is gated on released artifacts, not this local proof. DONE since first draft: stone#28 merged and the SRCREV re-pin done; meta-avocado#245 merged as 563d462; on-device apply now PROVEN on Jetson Orin (2026-08-15, paired positive/negative), so the "bundle-level only" caveat no longer holds for that target. Before draft:false - (1) merge avocado-cli#183, plus the Jetson chain: meta-avocado#292 (overlay delivery) and #293 (stage the Tegra BSP into the SDK stone dir; #292 does not function without it); (2) publish the SDK image (avocadolinux/sdk:2024-edge, must carry nativesdk-avocado-dtc-overlay + files_append nativesdk-stone) and the 2024/edge feed (must carry avocado-dtc-overlay-deliver); (3) cut an avocado-cli release and re-pin the cli= tag below to it (1.0.0-rc.1 lacks DTO); (4) resolve KOS-68 auto-provisioning or keep the sdk.packages block in Reproduce it; (5) record the on-device-apply MP4 - the Jetson result above is the evidence it can be recorded, not a substitute for it. NOTE for the Jetson walkthrough: avocado runtime provision cannot flash a Jetson from its container today (no --privileged in the production path; with it added, RCM boot succeeds but the target never exports its LUN), so any reader-facing flash instruction must not assume it works until that is fixed on avocado-cli#183.' -poster: '' -lift_for_blog: 'Ship a board customization (a device-tree overlay) as a declarative part of your OS image, no manual dtc/boot surgery.' -promote_to_track: '' ---- - -import PullQuote from '@site/src/components/PullQuote' -import TestStatus from '@site/src/components/TestStatus' - - - -**TL;DR** — Declare a device-tree overlay in an extension and `avocado build` -compiles it in the SDK and delivers the `.dtbo` into the OS bundle under -`overlays/`. On raspberrypi5 the bundle finalizes end-to-end. No manual `dtc` -or boot-partition surgery. - -{/* truncate */} - -## What this is - -Avocado OS builds a complete, updatable OS image for your board. A device-tree -overlay is a small patch to the board's hardware description: enable a SPI -device, wire up a GPIO, add a sensor. This note shows how to make an overlay a -declarative part of your image instead of a manual boot-time step. - -## How it works / what we did - -Add `device_tree_overlays` to the extension that ships them: - -```yaml -extensions: - my-board: - types: - - sysext - device_tree_overlays: - - name: hello-overlay - src: overlays/hello-overlay.dtso -``` - -`name` is authoritative: it is the output basename (`overlays/.dtbo`) and -the boot-selection argument, so it must be a safe basename. `src` is your overlay -source. The source is a real overlay: it declares `/plugin/;` and targets a path -or phandle. - -```dts -/dts-v1/; -/plugin/; -/ { - fragment@0 { - target-path = "/"; - __overlay__ { - my-node { - compatible = "acme,widget"; - status = "okay"; - }; - }; - }; -}; -``` - -Then: - -```bash -avocado install -avocado build --target raspberrypi5 -``` - -Under the hood `avocado build` compiles each `.dtso` the way the kernel does -(`cpp` against the kernel's `dt-bindings` when the source `#include`s them, -`dtc -@` for overlay symbols), a per-board delivery step records where the blob -belongs on the boot medium, and the bundler places it at `overlays/.dtbo` -in the OS bundle. The feature is inert unless an overlay is declared. - -A board customization ships as **declared config**, not a manual dtc + boot-partition step. - -## Which targets finalize - -The overlay compiles and is delivered on every target. Whether the OS bundle -finalizes end-to-end depends on the boot medium. raspberrypi5 boots from a FAT -partition (the `config.txt` path), so `avocado build` writes the overlay into -`boot.img` and finalizes `os-bundle.aos` in a single pass. On `qemuarm64` the -same compile and delivery run, but the `.aos` does not finalize yet, because -there is no FAT boot medium to stage the kernel image into. That gap is tracked -in KOS-68 and does not affect FAT-booting hardware like the Pi. - -## Jetson Orin: the same declaration, a different delivery - -Jetson has nowhere to put a loose `.dtbo`. The flashed partition set has no DTBO -partition, and the ESP carries only the bootloader. The overlay lists that do -exist in the Tegra flash vars are read by the classic `flash.sh` path, not by -the initrd-flash flow Avocado uses, which consumes binaries already signed at -build time. - -So on Jetson the overlay is merged into the board's device tree at build time -with `fdtoverlay`, and the merged tree is what gets flashed. The project config -is identical - the same `device_tree_overlays` block, the same `.dtso` - and the -per-board delivery hook absorbs the difference. That is the point of the hook -being per-BSP: the declaration is portable even when the mechanism underneath is -not. - -One consequence worth stating plainly, because it differs from the Pi: changing -an overlay on Jetson changes the device tree, so it takes a reflash rather than -an ordinary image update. - -Verified on a Jetson Orin Nano Developer Kit (module P3767-0005). With the -overlay declared, on the running board: - -```console -# tr -d '\0' < /proc/device-tree/hello-overlay/avocado,marker -eng-2134-dto-e2e -``` - -and with the declaration removed and nothing else changed, the node is absent. -`/proc/device-tree` is the tree the kernel is actually running, so this is the -overlay in effect rather than a build artifact - and the paired negative run is -what rules out a node that was in the base tree all along. - -## Issues Encountered - -- **Clean SDK under-provisions the image toolchain (preview).** On a brand-new - SDK you currently must add a few image-build packages to `sdk.packages` - (erofs, btrfs, zstd, stone tooling) before a runtime image builds. - Auto-provisioning them is in progress (KOS-68). -- **qemuarm64 does not finalize the bundle yet (preview).** See "Which targets - finalize" above. FAT-booting targets (raspberrypi5) complete the flow; a - QEMU-only walkthrough waits on KOS-68. - -## Reproduce it - -On raspberrypi5 the flow above runs to a finalized bundle. Declare one overlay -in an extension, then run `avocado install` and `avocado build --target -raspberrypi5`. - -On a brand-new SDK, add the image-build packages to `sdk.packages` so the -runtime image finalizes (until KOS-68 provisions them automatically): - -```yaml -sdk: - packages: - nativesdk-erofs-utils: "*" - nativesdk-btrfs-tools: "*" - nativesdk-zstd: "*" - nativesdk-stone: "*" - avocado-sdk-target: "*" -``` - -The build logs the three pipeline steps in order: the compile -(`avocado-dtc-overlay: built ... hello-overlay.dtbo`), the delivery -(`device-tree-overlay-deliver: delivered 1 overlay(s) to rootdisk/boot`), and -the finalized bundle (`OS bundle created: ... os-bundle.aos`). To inspect the -result, `avocado save` exports the build state; the archive holds both the -compiled `device-tree-overlays/hello-overlay.dtbo` and the finalized -`os-bundle.aos`. From c714b6796a3b1f7b9c8a23e967f037faeb3c55e7 Mon Sep 17 00:00:00 2001 From: Javier Tia Date: Sat, 15 Aug 2026 14:06:13 -0600 Subject: [PATCH 06/12] developer-reference/device-tree-overlays: correct the gating PR set The table listed #293 as a separate gate and #183 as draft. #293 is closed - its Tegra BSP staging is the first commit of #292 now - and #183 left draft once the Jetson work supplied the motivation its last unexplained commit was missing. A gate list that names a closed PR teaches a reader to distrust the rest of it. Adding #276 is the substantive part rather than bookkeeping. The verification section asks the reader to read /proc/device-tree on the booted board, and a stock image sets root's password field to `*`, so the board boots to a prompt that cannot be satisfied and the check cannot be run at all. The page was describing a procedure its own supported images block. The dev-login kas overlays are what unblock it, so they are a dependency of this page in the same way the delivery hooks are. Say plainly that this makes the verified image differ from the shipped one. Neither overlay touches the device tree, so the result still holds, but a reader who notices the gap deserves the reasoning rather than having to reconstruct whether it invalidates the check. Signed-off-by: Javier Tia --- src/docs-guides/device-tree-overlays.md | 38 ++++++++++++++++++------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/src/docs-guides/device-tree-overlays.md b/src/docs-guides/device-tree-overlays.md index 7e00f958..3434fea8 100644 --- a/src/docs-guides/device-tree-overlays.md +++ b/src/docs-guides/device-tree-overlays.md @@ -190,6 +190,22 @@ acme,widget `/proc/device-tree` is the live tree after every stage the bootloader applied, so a node present there is a node in effect. +:::caution you need a shell first, and a stock image will not give you one +A stock Avocado image sets root's password field in `/etc/shadow` to `*`, which no password can match. The board boots to a console prompt that cannot be satisfied - and this check is only readable from a shell on the board. + +Build the verification image with a dev-login kas overlay layered on: + +```bash +# console only, for a board on a serial cable +kas/machine/.yml:kas/feature/dev-root-login.yml + +# or, when you need a shell over the network instead +kas/machine/.yml:kas/feature/ssh-dev.yml +``` + +Both are dev-only and must never be composed into anything that ships. Note the asymmetry this creates: the image you verify is not byte-for-byte the image you ship. That is acceptable here because neither overlay touches the device tree - but it is the reason to keep the overlay list to exactly these, and to re-run the build without them before shipping. +::: + ### Run the negative control One positive reading is not enough on its own: a node that was in the base tree all along looks identical to one an overlay added. Build the same project a second time with the `device_tree_overlays` block removed and nothing else changed, boot it on the same board, and confirm the node is **absent**: @@ -279,17 +295,17 @@ This page is `draft: true` because the feature is not reachable from released ar ### Pull requests -| PR | Repo | Status | What it provides | Required for | -| -------------------------------------------------------------- | ------------ | --------------------------------- | --------------------------------------------------------------------- | ------------------------------------------------ | -| [#28](https://github.com/avocado-linux/stone/pull/28) | stone | **Merged** 2026-08-12 | `files_append` FAT primitive | All targets | -| [#245](https://github.com/avocado-linux/meta-avocado/pull/245) | meta-avocado | **Merged** 2026-08-12 (`563d462`) | SDK compile wrapper + RPi and QEMU delivery hooks | All targets | -| [#183](https://github.com/avocado-linux/avocado-cli/pull/183) | avocado-cli | Open, **draft** | The `device_tree_overlays` config surface and build orchestration | All targets | -| [#292](https://github.com/avocado-linux/meta-avocado/pull/292) | meta-avocado | Open, ready | Jetson delivery hook (`fdtoverlay` merge) | Jetson | -| [#293](https://github.com/avocado-linux/meta-avocado/pull/293) | meta-avocado | Open, ready | Stages the Tegra BSP into the SDK stone dir | Jetson - **#292 does not function without it** | -| [#291](https://github.com/avocado-linux/meta-avocado/pull/291) | meta-avocado | Open, ready | Makes four silent Jetson provisioning failures report their own cause | Jetson walkthrough being followable | -| [#273](https://github.com/avocado-linux/meta-avocado/pull/273) | meta-avocado | Open, **draft** | Applies delivered overlays at boot on qemuarm64 | qemuarm64 only - **not** a blocker for this page | - -Merge order is constrained: #28 before #245 (SRCREV re-pin), and #293 before or with #292. +| PR | Repo | Status | What it provides | Required for | +| -------------------------------------------------------------- | ------------ | --------------------------------- | -------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ | +| [#28](https://github.com/avocado-linux/stone/pull/28) | stone | **Merged** 2026-08-12 | `files_append` FAT primitive | All targets | +| [#245](https://github.com/avocado-linux/meta-avocado/pull/245) | meta-avocado | **Merged** 2026-08-12 (`563d462`) | SDK compile wrapper + RPi and QEMU delivery hooks | All targets | +| [#183](https://github.com/avocado-linux/avocado-cli/pull/183) | avocado-cli | Open, ready | The `device_tree_overlays` config surface and build orchestration | All targets | +| [#292](https://github.com/avocado-linux/meta-avocado/pull/292) | meta-avocado | Open, ready | Jetson delivery hook (`fdtoverlay` merge) **and** the Tegra BSP staging it reads | Jetson | +| [#291](https://github.com/avocado-linux/meta-avocado/pull/291) | meta-avocado | Open, ready | Makes five silent Jetson provisioning failures report their own cause | Jetson walkthrough being followable | +| [#276](https://github.com/avocado-linux/meta-avocado/pull/276) | meta-avocado | Open, ready | `dev-root-login` / `ssh-dev` kas overlays | [Confirming the overlay applied](#confirming-the-overlay-applied) on any board | +| [#273](https://github.com/avocado-linux/meta-avocado/pull/273) | meta-avocado | Open, **draft** | Applies delivered overlays at boot on qemuarm64 | qemuarm64 only - **not** a blocker for this page | + +Merge order is constrained only by #28 before #245 (SRCREV re-pin); both are merged. [#293](https://github.com/avocado-linux/meta-avocado/pull/293) is closed - its Tegra BSP staging is now the first commit of #292, because a hook that cannot find its input and a staging step with no consumer were never separately mergeable. ### Beyond the PRs From e1bc0e3b34196c3ae090c1f37d668511396f7d94 Mon Sep 17 00:00:00 2001 From: Javier Tia Date: Sat, 15 Aug 2026 15:42:24 -0600 Subject: [PATCH 07/12] developer-reference/device-tree-overlays: lead with Jetson, mark the rest WIP The page was written Pi-first because that is the order the work happened in, not because the Pi is the target a reader should follow. Jetson is the only one confirmed on hardware - paired positive and negative against a running kernel - while the Pi has never been booted with a declared overlay and qemuarm64 delivers a blob that its u-boot cannot apply. A reader picking the first worked example on the page was being pointed at the least finished path. So the walkthrough is Jetson throughout, and the support table leads with a status column rather than burying readiness in prose. The two unfinished targets move below a heading that says what they are, each stating what it is waiting on. Say explicitly that the Pi's evidence is a green build and nothing else. That reads like hedging until you notice it is the exact shape of the Jetson bug: two full rounds of passing build markers while the board applied nothing. A build that goes green is the failure mode here, not the reassurance, so a page that implies otherwise for an unbooted target is teaching the wrong lesson. Also drop the claim that `params` is simply Raspberry-Pi-only. That was true and useless - the hook that would honor it is itself unverified, so the key has no confirmed consumer on any board. Signed-off-by: Javier Tia --- src/docs-guides/device-tree-overlays.md | 90 +++++++++++++++---------- 1 file changed, 56 insertions(+), 34 deletions(-) diff --git a/src/docs-guides/device-tree-overlays.md b/src/docs-guides/device-tree-overlays.md index 3434fea8..887be9af 100644 --- a/src/docs-guides/device-tree-overlays.md +++ b/src/docs-guides/device-tree-overlays.md @@ -6,9 +6,11 @@ draft: true description: 'Declare a device-tree overlay in an extension and let avocado build compile it in the SDK and deliver it to the boot medium - no manual dtc, no boot-partition surgery, no BSP fork.' --- -:::danger draft - not yet reproducible by a reader +:::danger draft - Jetson only, and not yet reproducible by a reader -This guide documents behavior that is **not in a released Avocado CLI or SDK image**. Every command below has been run, but only against from-source builds of unmerged branches. Following it with released artifacts will fail at `avocado install`. +**NVIDIA Jetson (Tegra) is the one target where this is finished and proven on hardware.** Every other target is work in progress and is marked as such throughout this page - the Raspberry Pi path builds but has never been confirmed on a board, and `qemuarm64` delivers the overlay but does not apply it at boot. Read the [target support](#target-support) table before following anything here for a non-Jetson board. + +The guide also documents behavior that is **not in a released Avocado CLI or SDK image**. Every command below has been run, but only against from-source builds of unmerged branches. Following it with released artifacts will fail at `avocado install`. See [Release status](#release-status) at the bottom for the exact list of what must merge and publish before this page can drop `draft: true`. @@ -22,24 +24,26 @@ This guide covers: - Declaring overlays in `avocado.yaml` - Writing an overlay source the compiler will accept -- Which targets are supported, and what each one does with the blob +- Building and flashing on a Jetson, the worked example throughout - Confirming on a booted board that the overlay actually applied -- Per-target update consequences (one target needs a reflash) +- What is still work in progress on the other targets ## Target support -The declaration is portable; the delivery mechanism is not. Each BSP layer installs its own delivery hook, so what happens to the compiled blob differs by board - including how you ship a _change_ to an overlay later. +The declaration is portable; the delivery mechanism is not. Each BSP layer installs its own delivery hook, so what happens to the compiled blob differs by board - including how you ship a _change_ to an overlay later, and how far along each target is. + +| Target | Status | Delivery mechanism | Updating an overlay | +| ------------------------------------------- | ---------------------------------- | -------------------------------------------------------------- | --------------------------------------------------------- | +| `jetson-orin-nano-devkit` (and other Tegra) | **Working** - verified on hardware | Merged into the base DTB at build time with `fdtoverlay` | **Reflash** - see [Jetson](#jetson-tegra) | +| `raspberrypi5`, `raspberrypi4` | **WIP** - builds, never booted | Loose `.dtbo` on the boot FAT, selected by a `dtoverlay=` line | Ordinary image update | +| `qemuarm64` | **WIP** - delivered, never applied | Loose `.dtbo` on the boot FAT | n/a until the boot chain applies it | +| `qemux86-64` | Not applicable | None - x86 boots via ACPI and has no device tree | n/a | +| Any other target | Not supported | None | Build fails by design - see [below](#unsupported-targets) | -| Target | Delivery mechanism | Where the blob lands | Updating an overlay | -| ------------------------------------------- | -------------------------------------------------------------- | -------------------------------------------------- | ------------------------------------------------------------------------ | -| `raspberrypi5`, `raspberrypi4` | Loose `.dtbo` on the boot FAT, selected by a `dtoverlay=` line | `overlays/.dtbo` plus `avocado-overlays.txt` | Ordinary image update | -| `jetson-orin-nano-devkit` (and other Tegra) | Merged into the base DTB at build time with `fdtoverlay` | Replaces the flashed kernel DTB | **Reflash** - see [Jetson](#jetson-tegra) | -| `qemuarm64` | Loose `.dtbo` on the boot FAT | `overlays/.dtbo` | Delivered but **not applied at boot** yet | -| `qemux86-64` | None | - | Not applicable - x86 boots via ACPI and has no device tree | -| Any other target | None | - | Build fails, by design - see [Unsupported targets](#unsupported-targets) | +Only the Jetson row has been confirmed by reading the device tree of a running kernel. The other two rows describe what the build produces, which is a weaker claim than it looks - see [Confirming the overlay applied](#confirming-the-overlay-applied) for why a green build proves nothing about a board, and [Targets still in progress](#targets-still-in-progress) for what each one is waiting on. :::info the declaration is the portable part -The same `device_tree_overlays` block and the same `.dtso` move between a Pi and a Jetson unchanged. Only the hook underneath differs. That is the point of the hook being per-BSP. +The same `device_tree_overlays` block and the same `.dtso` move between a Jetson and a Pi unchanged. Only the hook underneath differs. That is the point of the hook being per-BSP - and it is why the WIP targets are held up by delivery and boot wiring rather than by anything you write. ::: ## Declaring an overlay @@ -49,7 +53,7 @@ Overlays are declared on the **extension** that ships them, not on the runtime a ```yaml runtimes: dev: - target: raspberrypi5 + target: jetson-orin-nano-devkit extensions: - my-board packages: @@ -66,9 +70,9 @@ extensions: | Key | Required | Meaning | | -------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `name` | yes | Authoritative. It is the output basename (`overlays/.dtbo`), the `dtoverlay=` argument on Raspberry Pi, and the u-boot overlay entry. Must be a safe basename: no `/`, no whitespace, not `.` or `..`. Names must be unique across the whole runtime - a duplicate is a hard error, not last-one-wins. | +| `name` | yes | Authoritative. It is the compiled blob's basename (`.dtbo`) and, on the targets that select overlays at boot, the selection argument. Must be a safe basename: no `/`, no whitespace, not `.` or `..`. Names must be unique across the whole runtime - a duplicate is a hard error, not last-one-wins. | | `src` | yes | Path to the overlay source, relative to the project root. | -| `params` | no | A mapping of per-overlay parameters. **Raspberry Pi only** - see [Parameters](#parameters-raspberry-pi-only). | +| `params` | no | A mapping of per-overlay parameters. Consumed **only** by the Raspberry Pi hook, which is itself WIP - see [Parameters](#parameters-raspberry-pi-only). | :::warning declare `avocado-runtime` The runtime must pull `avocado-runtime`, which is what installs `avocado-img-bootfiles` - the package shipping `u-boot.bin` and the `bootfiles/*` entries the bundler needs to build a boot image. A project that omits it fails late, at bundling, with `File 'u-boot.bin' not found in any input directory for FAT image`, which reads like a broken BSP rather than a missing declaration. It cost us two weeks of chasing a product bug that was a project-config omission. @@ -149,19 +153,23 @@ A `/include/ "shared.dtsi"` (the native DTS include, not a cpp one) resolves rel ```bash avocado install -avocado build --target raspberrypi5 +avocado build --target jetson-orin-nano-devkit ``` The build logs three ordered markers. All three must appear: ```text avocado-dtc-overlay: built .../device-tree-overlays/hello-overlay.dtbo from hello-overlay -device-tree-overlay-deliver: delivered 1 overlay(s) to rootdisk/boot for avocado-raspberrypi5: hello-overlay +device-tree-overlay-deliver: delivered 1 overlay(s) merged into tegra234-p3768-0000+p3767-0005-nv-super.dtb for avocado-jetson-orin-nano-devkit: hello-overlay [SUCCESS] OS bundle created: .../os-bundle.aos ``` +The middle line is the one that differs per target: on Jetson it names the base DTB the overlays were merged into, and on the loose-`.dtbo` targets it names the boot directory they were copied to instead. + To inspect what was produced, `avocado save` exports the build state; the archive holds both the compiled `device-tree-overlays/.dtbo` and the finalized `os-bundle.aos`. +Then flash the board. **Do this host-side, not through `avocado runtime provision`** - container-mode provisioning cannot currently reach a Jetson in recovery mode, which is item 6 of [Release status](#release-status). Every result on this page was obtained from a host-side flash. + ### On a brand-new SDK Until SDK auto-provisioning lands (tracked as KOS-68), a clean SDK needs the image-build toolchain declared explicitly: @@ -219,12 +227,6 @@ With both halves, the declaration is the only variable that can explain the diff ## Per-target details -### Raspberry Pi - -The hook writes the `.dtbo` to `overlays/.dtbo` on the boot FAT and emits an `avocado-overlays.txt` alongside it holding one `dtoverlay=` line per overlay. The stock `config.txt` carries a static `include avocado-overlays.txt`, so the firmware picks these up at boot. - -`config.txt` itself is never rewritten. That keeps your own `config.txt` overrides and the generated overlay list from fighting over the same file. - ### Jetson (Tegra) Tegra has nowhere to put a loose `.dtbo`. The flashed partition set has no DTBO partition, the ESP carries only the bootloader, and the overlay lists that do exist in the Tegra flash variables are read by the classic `flash.sh` path - not by the `initrd-flash` flow Avocado uses, which consumes binaries already signed at build time. Anything written to those lists is inert. @@ -239,11 +241,25 @@ Two consequences: The base DTB is selected by the `DTBFILE` the BSP records, because a real Tegra BSP ships one base DTB per module SKU - five on an Orin Nano dev kit. You do not choose it; the board's own flash configuration does. -### QEMU +## Targets still in progress + +Everything below builds. None of it has been confirmed on a running kernel, which per [Confirming the overlay applied](#confirming-the-overlay-applied) is the only evidence that counts. Treat these sections as a description of the intended mechanism rather than of observed behavior. -`qemuarm64` compiles and delivers the overlay to the boot FAT, but u-boot does not yet apply it at boot: the shipped `qemu_arm64_defconfig` does not set `CONFIG_OF_LIBFDT_OVERLAY`, so its u-boot carries every `fdt` subcommand except the one that applies an overlay. Wiring that up is tracked in meta-avocado#273. Until it merges, treat qemuarm64 as delivery-only. +### Raspberry Pi - WIP, builds but never booted -`qemux86-64` has no device tree at all - x86 boots via ACPI - so no hook is installed and declaring an overlay there fails the build. +The hook writes the `.dtbo` to `overlays/.dtbo` on the boot FAT and emits an `avocado-overlays.txt` alongside it holding one `dtoverlay=` line per overlay. The stock `config.txt` carries a static `include avocado-overlays.txt`, so the firmware should pick these up at boot. `config.txt` itself is never rewritten, which keeps your own overrides and the generated overlay list from fighting over the same file. + +The build path is green end to end - compile, deliver, finalized `os-bundle.aos` - and is re-run as a regression gate whenever the Jetson path changes. **That is the whole of the evidence.** No Pi has been booted with a declared overlay and had its device tree read, so whether the firmware actually applies the generated list is currently an assumption. The Jetson experience is the reason to say so plainly: there, every build marker passed for two full rounds while the board applied nothing. + +What it is waiting on: a paired positive/negative run on a Pi 5, item 5 of [Release status](#release-status). + +### QEMU - WIP, delivered but not applied + +`qemuarm64` compiles and delivers the overlay to the boot FAT, and then nothing applies it. The shipped `qemu_arm64_defconfig` does not set `CONFIG_OF_LIBFDT_OVERLAY` at u-boot 2026.01, so its u-boot carries every `fdt` subcommand except the one that applies an overlay - `fdt apply` prints its usage dump instead of running. + +This one is understood rather than merely unverified: the mechanism has been proven on a u-boot built from the same tree with the flag set, and the negative control on the shipped binary fails exactly where predicted. It needs three pieces (the config flag, an overlay list written next to the kernel, and an env block that applies them), tracked in meta-avocado#273, plus a full-image build and boot that has not happened. + +`qemux86-64` is a different case and will not be supported: x86 boots via ACPI and has no device tree anywhere in the chain, so no hook is installed and declaring an overlay there fails the build. ## Parameters (Raspberry Pi only) @@ -260,8 +276,10 @@ device_tree_overlays: produces `dtoverlay=my-spi,cs=0,speed=12000000` (keys are sorted, so the output is stable across builds). -:::warning `params` is silently ignored off Raspberry Pi -Only the Raspberry Pi hook consumes `params` - it maps onto the Pi firmware's own overlay-parameter mechanism, which has no equivalent elsewhere. The Jetson and QEMU hooks accept a declaration carrying `params` and deliver the overlay without them, with no warning. On those targets, encode the values in the `.dtso` itself. +:::warning `params` is silently ignored off Raspberry Pi - including on Jetson +Only the Raspberry Pi hook consumes `params`, because it maps onto the Pi firmware's own overlay-parameter mechanism and nothing else has an equivalent. The Jetson and QEMU hooks accept a declaration carrying `params` and deliver the overlay without them, with no warning. + +**On Jetson - the one working target - encode the values in the `.dtso` itself.** A `params` block there is silently inert, and since the Pi hook that would honor it is itself unverified on hardware, this key has no confirmed consumer on any board today. ::: ## Unsupported targets @@ -291,7 +309,7 @@ The same applies one level deeper: if the hook runs but does not claim an overla ## Release status -This page is `draft: true` because the feature is not reachable from released artifacts. Everything below must land before it publishes. +This page is `draft: true` for two reasons: the feature is not reachable from released artifacts, and only one target is finished. Items 1-4 and 6-7 gate publication; item 5 is what promotes the Raspberry Pi out of WIP, and meta-avocado#273 does the same for `qemuarm64`. ### Pull requests @@ -319,11 +337,15 @@ Merge order is constrained only by #28 before #245 (SRCREV re-pin); both are mer | 6 | Fix container-mode provisioning on Jetson (part of avocado-cli#183) | `avocado runtime provision` cannot flash a Jetson from its container today. Every Jetson flash behind this page was run host-side, so the documented CLI path is not the path that was verified | | 7 | Add this page to the Advanced category in `sidebars-guides.js` | Deliberately omitted while `draft: true` - a sidebar entry pointing at a draft doc breaks the production build | -### What is already proven +### Evidence, per target + +| Target | Build path | On hardware | Verdict | +| ----------- | ---------- | ------------------------------ | ----------- | +| Jetson Orin | Green | **Paired positive + negative** | **Working** | +| rpi5 | Green | Not run | WIP | +| qemuarm64 | Green | Applies nothing at boot | WIP | -- **Jetson Orin Nano dev kit (P3767-0005), 2026-08-15**: on-device, paired positive and negative. `/proc/device-tree/hello-overlay/avocado,marker` reads the declared value on the running board and the node is absent with the declaration removed. -- **raspberrypi5**: build path green end to end - compile, deliver, finalized `os-bundle.aos`. No hardware run yet (item 5 above). -- **qemuarm64**: compile and deliver green; boot-time application pending #273. +**Jetson Orin Nano dev kit (P3767-0005), 2026-08-15.** On-device, paired positive and negative: `/proc/device-tree/hello-overlay/avocado,marker` reads the declared value on the running board, and the node is absent on a build with the declaration removed and nothing else changed. This is the only row where the middle column is filled in, and it is the reason Jetson is the worked example throughout this page rather than the Pi it started as. ## What's next From 0f8244fddb394c4cade5cc7027fcd998cbc64b4a Mon Sep 17 00:00:00 2001 From: Javier Tia Date: Mon, 17 Aug 2026 07:38:24 -0600 Subject: [PATCH 08/12] developer-reference/device-tree-overlays: get a shell with avocado tooling The page told readers to layer a kas fragment to reach a login prompt. kas is the maintainer path; a developer reference has no business sending someone to BitBake to run one of its own verification steps. That instruction was mine, and it came from a fixture I had hand-minimized down past the extensions a real project carries - so I hit a locked board, reached for the maintainer tool I had, and wrote the workaround down as if it were the product's answer. The consumer path already existed, in two halves that had never been documented together. `avocado-ext-sshd-dev` configures sshd to read /var/lib/ssh/authorized_keys, and runtime `var_files` puts a project file on the var partition. Either alone is useless: the extension listens with no credential that works, and the key has nothing reading it. Say why the pairing matters rather than just listing it. A board missing only the key still boots, still runs sshd, still accepts connections, and refuses every credential - indistinguishable from the feature being broken. That is the failure this page exists to teach people to distrust, so it earns the explanation. Item 8 records what is still unproven. The key is confirmed landing at the right path at build time; sshd accepting it has not been observed on hardware, and StrictModes could still reject it on mode or ownership. Dropping #276 as a gate follows from the same finding - the kas overlays it adds are no longer on this page's critical path, though they remain useful on their own. Signed-off-by: Javier Tia --- src/docs-guides/device-tree-overlays.md | 64 +++++++++++++++---------- 1 file changed, 38 insertions(+), 26 deletions(-) diff --git a/src/docs-guides/device-tree-overlays.md b/src/docs-guides/device-tree-overlays.md index 887be9af..b9b7c33a 100644 --- a/src/docs-guides/device-tree-overlays.md +++ b/src/docs-guides/device-tree-overlays.md @@ -199,19 +199,31 @@ acme,widget `/proc/device-tree` is the live tree after every stage the bootloader applied, so a node present there is a node in effect. :::caution you need a shell first, and a stock image will not give you one -A stock Avocado image sets root's password field in `/etc/shadow` to `*`, which no password can match. The board boots to a console prompt that cannot be satisfied - and this check is only readable from a shell on the board. +A stock Avocado image ships no SSH server and leaves root's password field in `/etc/shadow` as `*`, which no password can match. Flash one and you get a console prompt nothing satisfies - and this check is only readable from a shell on the board. -Build the verification image with a dev-login kas overlay layered on: +Two declarations fix that, and they only work together: -```bash -# console only, for a board on a serial cable -kas/machine/.yml:kas/feature/dev-root-login.yml +```yaml +runtimes: + dev: + extensions: + - avocado-ext-sshd-dev # brings sshd and a permissive dev policy + var_files: + - source: 'files/authorized_keys' # your own public key + dest: 'lib/ssh/' # -> /var/lib/ssh/authorized_keys -# or, when you need a shell over the network instead -kas/machine/.yml:kas/feature/ssh-dev.yml +extensions: + avocado-ext-sshd-dev: + source: + type: package + version: '*' ``` -Both are dev-only and must never be composed into anything that ships. Note the asymmetry this creates: the image you verify is not byte-for-byte the image you ship. That is acceptable here because neither overlay touches the device tree - but it is the reason to keep the overlay list to exactly these, and to re-run the build without them before shipping. +`avocado init` already puts `avocado-ext-sshd-dev` in the `dev` runtime it generates, so a project started that way has the first half. The `var_files` entry is the half people miss: the extension configures sshd to read `/var/lib/ssh/authorized_keys`, but nothing puts a key there for you. Without it the board boots, runs sshd, listens - and refuses every credential, which looks identical to the feature being broken. + +Copy your public key to `files/authorized_keys` in the project, then `avocado build` and provision as usual. + +Both the extension and the key are **dev-only and must never ship**. That means the image you verify is not byte-for-byte the image you ship. Acceptable here, because neither touches the device tree - but it is the reason to keep the difference to exactly these two declarations and to rebuild without them before shipping. ::: ### Run the negative control @@ -313,29 +325,29 @@ This page is `draft: true` for two reasons: the feature is not reachable from re ### Pull requests -| PR | Repo | Status | What it provides | Required for | -| -------------------------------------------------------------- | ------------ | --------------------------------- | -------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ | -| [#28](https://github.com/avocado-linux/stone/pull/28) | stone | **Merged** 2026-08-12 | `files_append` FAT primitive | All targets | -| [#245](https://github.com/avocado-linux/meta-avocado/pull/245) | meta-avocado | **Merged** 2026-08-12 (`563d462`) | SDK compile wrapper + RPi and QEMU delivery hooks | All targets | -| [#183](https://github.com/avocado-linux/avocado-cli/pull/183) | avocado-cli | Open, ready | The `device_tree_overlays` config surface and build orchestration | All targets | -| [#292](https://github.com/avocado-linux/meta-avocado/pull/292) | meta-avocado | Open, ready | Jetson delivery hook (`fdtoverlay` merge) **and** the Tegra BSP staging it reads | Jetson | -| [#291](https://github.com/avocado-linux/meta-avocado/pull/291) | meta-avocado | Open, ready | Makes five silent Jetson provisioning failures report their own cause | Jetson walkthrough being followable | -| [#276](https://github.com/avocado-linux/meta-avocado/pull/276) | meta-avocado | Open, ready | `dev-root-login` / `ssh-dev` kas overlays | [Confirming the overlay applied](#confirming-the-overlay-applied) on any board | -| [#273](https://github.com/avocado-linux/meta-avocado/pull/273) | meta-avocado | Open, **draft** | Applies delivered overlays at boot on qemuarm64 | qemuarm64 only - **not** a blocker for this page | +| PR | Repo | Status | What it provides | Required for | +| -------------------------------------------------------------- | ------------ | --------------------------------- | -------------------------------------------------------------------------------- | ------------------------------------------------ | +| [#28](https://github.com/avocado-linux/stone/pull/28) | stone | **Merged** 2026-08-12 | `files_append` FAT primitive | All targets | +| [#245](https://github.com/avocado-linux/meta-avocado/pull/245) | meta-avocado | **Merged** 2026-08-12 (`563d462`) | SDK compile wrapper + RPi and QEMU delivery hooks | All targets | +| [#183](https://github.com/avocado-linux/avocado-cli/pull/183) | avocado-cli | Open, ready | The `device_tree_overlays` config surface and build orchestration | All targets | +| [#292](https://github.com/avocado-linux/meta-avocado/pull/292) | meta-avocado | Open, ready | Jetson delivery hook (`fdtoverlay` merge) **and** the Tegra BSP staging it reads | Jetson | +| [#291](https://github.com/avocado-linux/meta-avocado/pull/291) | meta-avocado | Open, ready | Makes five silent Jetson provisioning failures report their own cause | Jetson walkthrough being followable | +| [#273](https://github.com/avocado-linux/meta-avocado/pull/273) | meta-avocado | Open, **draft** | Applies delivered overlays at boot on qemuarm64 | qemuarm64 only - **not** a blocker for this page | Merge order is constrained only by #28 before #245 (SRCREV re-pin); both are merged. [#293](https://github.com/avocado-linux/meta-avocado/pull/293) is closed - its Tegra BSP staging is now the first commit of #292, because a hook that cannot find its input and a staging step with no consumer were never separately mergeable. ### Beyond the PRs -| # | Item | Why it blocks | -| --- | ------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| 1 | Publish the SDK image `avocadolinux/sdk:2024-edge` carrying `nativesdk-avocado-dtc-overlay` and the `files_append` `nativesdk-stone` | `avocado install` cannot resolve the overlay compiler without it | -| 2 | Publish the `2024/edge` feed carrying `avocado-dtc-overlay-deliver` | The delivery hook is a target package; without it the build hard-errors on a missing hook | -| 3 | Cut an avocado-cli release and name it in this guide | The released `1.0.0-rc.1` does **not** carry the overlay work, despite the from-source build reporting the same version | -| 4 | Resolve KOS-68, or keep the [brand-new SDK](#on-a-brand-new-sdk) block | A clean SDK cannot finalize a runtime image without it | -| 5 | Raspberry Pi 5 paired positive/negative hardware run | The Pi path is proven only at build level; per [Confirming the overlay applied](#confirming-the-overlay-applied), that is not evidence | -| 6 | Fix container-mode provisioning on Jetson (part of avocado-cli#183) | `avocado runtime provision` cannot flash a Jetson from its container today. Every Jetson flash behind this page was run host-side, so the documented CLI path is not the path that was verified | -| 7 | Add this page to the Advanced category in `sidebars-guides.js` | Deliberately omitted while `draft: true` - a sidebar entry pointing at a draft doc breaks the production build | +| # | Item | Why it blocks | +| --- | ------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| 1 | Publish the SDK image `avocadolinux/sdk:2024-edge` carrying `nativesdk-avocado-dtc-overlay` and the `files_append` `nativesdk-stone` | `avocado install` cannot resolve the overlay compiler without it | +| 2 | Publish the `2024/edge` feed carrying `avocado-dtc-overlay-deliver` | The delivery hook is a target package; without it the build hard-errors on a missing hook | +| 3 | Cut an avocado-cli release and name it in this guide | The released `1.0.0-rc.1` does **not** carry the overlay work, despite the from-source build reporting the same version | +| 4 | Resolve KOS-68, or keep the [brand-new SDK](#on-a-brand-new-sdk) block | A clean SDK cannot finalize a runtime image without it | +| 5 | Raspberry Pi 5 paired positive/negative hardware run | The Pi path is proven only at build level; per [Confirming the overlay applied](#confirming-the-overlay-applied), that is not evidence | +| 6 | Fix container-mode provisioning on Jetson (part of avocado-cli#183) | `avocado runtime provision` cannot flash a Jetson from its container today. Every Jetson flash behind this page was run host-side, so the documented CLI path is not the path that was verified | +| 7 | Add this page to the Advanced category in `sidebars-guides.js` | Deliberately omitted while `draft: true` - a sidebar entry pointing at a draft doc breaks the production build | +| 8 | Confirm the `var_files` key actually authenticates on a booted board | The pairing above is verified at build time only: the key is confirmed landing at `/var/lib/ssh/authorized_keys`. sshd accepting it is unobserved, and `StrictModes` could still reject the file on mode or ownership | ### Evidence, per target From 2885e05bee3c6ef1c4c503761d6a50061e91817e Mon Sep 17 00:00:00 2001 From: Javier Tia Date: Mon, 17 Aug 2026 08:58:40 -0600 Subject: [PATCH 09/12] developer-reference/device-tree-overlays: lead with the permissions profile The previous revision sent readers to stage an SSH public key through `var_files` to get a shell. That works, but it is not the answer the product gives: `avocado init` generates a `permissions` profile with an empty root password, and that alone yields a console login. A reader following the old text did extra work to reach a worse place than the default template already puts them. I reached for the key because I read the wrong file. `rootfs/image.rs` copies the sysroot to a work tree and applies the profile to the copy, so the sysroot's `root:*:` is the input to that step and says nothing about the result. Extracting the actual erofs shows `root::`, and a Jetson Orin Nano now boots to a root prompt on the console with no password, which is the evidence that should have been gathered before recommending anything. Keep the key as the network path rather than the primary one, and name the BSP extension alongside it. Dropping that extension to slim a project takes `kernel-module-realtek` with it, and the board then boots with no ethernet interface at all - confirmed on the same board, where `/sys/class/net` held only `lo` and `sit0` and dmesg never mentioned the NIC. Nothing about that symptom points back at a missing extension, so the warning is worth its line. Signed-off-by: Javier Tia --- src/docs-guides/device-tree-overlays.md | 60 ++++++++++++++----------- 1 file changed, 34 insertions(+), 26 deletions(-) diff --git a/src/docs-guides/device-tree-overlays.md b/src/docs-guides/device-tree-overlays.md index b9b7c33a..0546feb9 100644 --- a/src/docs-guides/device-tree-overlays.md +++ b/src/docs-guides/device-tree-overlays.md @@ -198,32 +198,40 @@ acme,widget `/proc/device-tree` is the live tree after every stage the bootloader applied, so a node present there is a node in effect. -:::caution you need a shell first, and a stock image will not give you one -A stock Avocado image ships no SSH server and leaves root's password field in `/etc/shadow` as `*`, which no password can match. Flash one and you get a console prompt nothing satisfies - and this check is only readable from a shell on the board. +:::caution you need a shell first +A raw image leaves root's password field in `/etc/shadow` as `*`, which no password can match, and this check is only readable from a shell on the board. -Two declarations fix that, and they only work together: +`avocado init` already solves it. The project it generates carries a `permissions` profile that gives root an empty password, and points the rootfs at it: + +```yaml +rootfs: + permissions: dev + +permissions: + dev: + users: + root: + password: '' +``` + +That is enough to log in on the serial console. If you started from `avocado init` you have it already; if you hand-wrote your `avocado.yaml`, this is the piece to add. **Verified on a Jetson Orin Nano**: with this profile the flashed rootfs carries `root::` and the console gives a root prompt. + +For a shell over the network instead, add the SSH extension and your own public key. The extension configures sshd to read `/var/lib/ssh/authorized_keys`; `var_files` is what puts a key there, and neither half is useful alone: ```yaml runtimes: dev: extensions: - - avocado-ext-sshd-dev # brings sshd and a permissive dev policy + - avocado-ext-sshd-dev + - avocado-bsp-{{ avocado.target.board }} # NIC driver lives here var_files: - - source: 'files/authorized_keys' # your own public key - dest: 'lib/ssh/' # -> /var/lib/ssh/authorized_keys - -extensions: - avocado-ext-sshd-dev: - source: - type: package - version: '*' + - source: 'files/authorized_keys' + dest: 'lib/ssh/' ``` -`avocado init` already puts `avocado-ext-sshd-dev` in the `dev` runtime it generates, so a project started that way has the first half. The `var_files` entry is the half people miss: the extension configures sshd to read `/var/lib/ssh/authorized_keys`, but nothing puts a key there for you. Without it the board boots, runs sshd, listens - and refuses every credential, which looks identical to the feature being broken. - -Copy your public key to `files/authorized_keys` in the project, then `avocado build` and provision as usual. +Do not drop the BSP extension to slim a test project. On a Jetson Orin Nano it carries `kernel-module-realtek`, and without it the board boots with no ethernet interface at all - so there is nothing to SSH to, and the cause looks nothing like a missing extension. -Both the extension and the key are **dev-only and must never ship**. That means the image you verify is not byte-for-byte the image you ship. Acceptable here, because neither touches the device tree - but it is the reason to keep the difference to exactly these two declarations and to rebuild without them before shipping. +The permissions profile, the SSH extension and the key are all **dev-only and must never ship**. That means the image you verify is not byte-for-byte the image you ship. Acceptable here, because none of them touches the device tree - but it is the reason to keep the difference to exactly these declarations and rebuild without them before shipping. ::: ### Run the negative control @@ -338,16 +346,16 @@ Merge order is constrained only by #28 before #245 (SRCREV re-pin); both are mer ### Beyond the PRs -| # | Item | Why it blocks | -| --- | ------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| 1 | Publish the SDK image `avocadolinux/sdk:2024-edge` carrying `nativesdk-avocado-dtc-overlay` and the `files_append` `nativesdk-stone` | `avocado install` cannot resolve the overlay compiler without it | -| 2 | Publish the `2024/edge` feed carrying `avocado-dtc-overlay-deliver` | The delivery hook is a target package; without it the build hard-errors on a missing hook | -| 3 | Cut an avocado-cli release and name it in this guide | The released `1.0.0-rc.1` does **not** carry the overlay work, despite the from-source build reporting the same version | -| 4 | Resolve KOS-68, or keep the [brand-new SDK](#on-a-brand-new-sdk) block | A clean SDK cannot finalize a runtime image without it | -| 5 | Raspberry Pi 5 paired positive/negative hardware run | The Pi path is proven only at build level; per [Confirming the overlay applied](#confirming-the-overlay-applied), that is not evidence | -| 6 | Fix container-mode provisioning on Jetson (part of avocado-cli#183) | `avocado runtime provision` cannot flash a Jetson from its container today. Every Jetson flash behind this page was run host-side, so the documented CLI path is not the path that was verified | -| 7 | Add this page to the Advanced category in `sidebars-guides.js` | Deliberately omitted while `draft: true` - a sidebar entry pointing at a draft doc breaks the production build | -| 8 | Confirm the `var_files` key actually authenticates on a booted board | The pairing above is verified at build time only: the key is confirmed landing at `/var/lib/ssh/authorized_keys`. sshd accepting it is unobserved, and `StrictModes` could still reject the file on mode or ownership | +| # | Item | Why it blocks | +| --- | ------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| 1 | Publish the SDK image `avocadolinux/sdk:2024-edge` carrying `nativesdk-avocado-dtc-overlay` and the `files_append` `nativesdk-stone` | `avocado install` cannot resolve the overlay compiler without it | +| 2 | Publish the `2024/edge` feed carrying `avocado-dtc-overlay-deliver` | The delivery hook is a target package; without it the build hard-errors on a missing hook | +| 3 | Cut an avocado-cli release and name it in this guide | The released `1.0.0-rc.1` does **not** carry the overlay work, despite the from-source build reporting the same version | +| 4 | Resolve KOS-68, or keep the [brand-new SDK](#on-a-brand-new-sdk) block | A clean SDK cannot finalize a runtime image without it | +| 5 | Raspberry Pi 5 paired positive/negative hardware run | The Pi path is proven only at build level; per [Confirming the overlay applied](#confirming-the-overlay-applied), that is not evidence | +| 6 | Fix container-mode provisioning on Jetson (part of avocado-cli#183) | `avocado runtime provision` cannot flash a Jetson from its container today. Every Jetson flash behind this page was run host-side, so the documented CLI path is not the path that was verified | +| 7 | Add this page to the Advanced category in `sidebars-guides.js` | Deliberately omitted while `draft: true` - a sidebar entry pointing at a draft doc breaks the production build | +| 8 | Confirm the `var_files` key actually authenticates over SSH | The console half is now proven on a Jetson Orin Nano (permissions profile, root prompt on `ttyTCU0`). The key half is verified only as far as placement at `/var/lib/ssh/authorized_keys`; sshd accepting it is still unobserved, and `StrictModes` could reject on mode or ownership. Testing it needs a board with a working NIC, so the BSP extension must be in the project | ### Evidence, per target From b426f34ed582348c55fa90e6bc255172c579c58a Mon Sep 17 00:00:00 2001 From: Javier Tia Date: Mon, 17 Aug 2026 13:48:30 -0600 Subject: [PATCH 10/12] developer-reference/device-tree-overlays: record the SSH result The page hedged the key half of network access as "verified only as far as placement", and listed confirming it as a release blocker. Both are now false: the key authenticates. Leaving the hedge in place would understate what a reader can rely on, and the blocker list is what decides when this page drops `draft: true`, so a stale entry there delays publication for nothing. The evidence is stated as `BatchMode=yes` rather than as a bare successful login. BatchMode refuses password and keyboard-interactive auth, so it distinguishes the key being accepted from a password prompt succeeding behind it - and this project has empty-password root enabled on the same image, which is exactly the confound a plain `ssh` result would leave open. Host-key churn is called out because it is the next thing a reader hits and it does not present as what it is: keys are generated on first boot rather than shipped, so every reflash makes the recorded entry stale and SSH reports that as a possible man-in-the-middle rather than as a new board. Signed-off-by: Javier Tia --- src/docs-guides/device-tree-overlays.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/docs-guides/device-tree-overlays.md b/src/docs-guides/device-tree-overlays.md index 0546feb9..640f1a84 100644 --- a/src/docs-guides/device-tree-overlays.md +++ b/src/docs-guides/device-tree-overlays.md @@ -231,6 +231,10 @@ runtimes: Do not drop the BSP extension to slim a test project. On a Jetson Orin Nano it carries `kernel-module-realtek`, and without it the board boots with no ethernet interface at all - so there is nothing to SSH to, and the cause looks nothing like a missing extension. +**Verified on a Jetson Orin Nano**: the key lands root-owned at `/var/lib/ssh/authorized_keys` mode `0644`, which is what `StrictModes` requires, and `ssh -o BatchMode=yes root@` connects. `BatchMode` refuses password and keyboard-interactive auth, so a connection under it is proof the key itself was accepted rather than a password prompt quietly succeeding behind it. + +Expect the host key to change on every reflash. Host keys are generated on first boot rather than shipped, so the entry your client recorded for that address is stale the moment you reflash, and SSH reports it as a possible man-in-the-middle rather than as a new board. Replace the recorded entry instead of adding to it - an append leaves the old key in place and the failure persists. + The permissions profile, the SSH extension and the key are all **dev-only and must never ship**. That means the image you verify is not byte-for-byte the image you ship. Acceptable here, because none of them touches the device tree - but it is the reason to keep the difference to exactly these declarations and rebuild without them before shipping. ::: @@ -355,7 +359,6 @@ Merge order is constrained only by #28 before #245 (SRCREV re-pin); both are mer | 5 | Raspberry Pi 5 paired positive/negative hardware run | The Pi path is proven only at build level; per [Confirming the overlay applied](#confirming-the-overlay-applied), that is not evidence | | 6 | Fix container-mode provisioning on Jetson (part of avocado-cli#183) | `avocado runtime provision` cannot flash a Jetson from its container today. Every Jetson flash behind this page was run host-side, so the documented CLI path is not the path that was verified | | 7 | Add this page to the Advanced category in `sidebars-guides.js` | Deliberately omitted while `draft: true` - a sidebar entry pointing at a draft doc breaks the production build | -| 8 | Confirm the `var_files` key actually authenticates over SSH | The console half is now proven on a Jetson Orin Nano (permissions profile, root prompt on `ttyTCU0`). The key half is verified only as far as placement at `/var/lib/ssh/authorized_keys`; sshd accepting it is still unobserved, and `StrictModes` could reject on mode or ownership. Testing it needs a board with a working NIC, so the BSP extension must be in the project | ### Evidence, per target @@ -367,6 +370,8 @@ Merge order is constrained only by #28 before #245 (SRCREV re-pin); both are mer **Jetson Orin Nano dev kit (P3767-0005), 2026-08-15.** On-device, paired positive and negative: `/proc/device-tree/hello-overlay/avocado,marker` reads the declared value on the running board, and the node is absent on a build with the declaration removed and nothing else changed. This is the only row where the middle column is filled in, and it is the reason Jetson is the worked example throughout this page rather than the Pi it started as. +**Same board, 2026-08-17** - the access mechanisms this page tells you to use, rather than the overlay pipeline. Console: the `permissions` profile yields `root::` in the flashed rootfs and a root prompt. Network: with the BSP extension present the NIC enumerates (`r8169`, `eth0` up at 1Gbps), and `ssh -o BatchMode=yes root@` connects against a key placed by `var_files`. Both were previously documented from the build output alone, which the [negative-control](#run-the-negative-control) argument says is not evidence. + ## What's next - [Custom kernel](./custom-kernel) - bring your own kernel tree, including the vendor trees that ship board device trees From 99874f2b41039dfa8849899949f752e50a389fbc Mon Sep 17 00:00:00 2001 From: Javier Tia Date: Mon, 17 Aug 2026 15:20:49 -0600 Subject: [PATCH 11/12] developer-reference/device-tree-overlays: state the gap, not a ticket The page pointed at a tracker ID for the SDK image-build toolchain gap, and listed resolving that ticket as a release blocker. The ID was wrong - it resolved to nothing in the workspace - but repointing it at a real one was still the wrong fix. A reader of a public docs site has no tracker access, so any ID is a dead end for them, and it decays independently of the page. Both references now name the condition: the SDK does not ship the toolchain, and the blocker is shipping it. That is checkable by anyone who can run the build, which is the audience the page actually has. --- src/docs-guides/device-tree-overlays.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/docs-guides/device-tree-overlays.md b/src/docs-guides/device-tree-overlays.md index 640f1a84..6fb2462d 100644 --- a/src/docs-guides/device-tree-overlays.md +++ b/src/docs-guides/device-tree-overlays.md @@ -172,7 +172,7 @@ Then flash the board. **Do this host-side, not through `avocado runtime provisio ### On a brand-new SDK -Until SDK auto-provisioning lands (tracked as KOS-68), a clean SDK needs the image-build toolchain declared explicitly: +The SDK does not yet ship the image-build toolchain, so a clean one needs it declared explicitly: ```yaml sdk: @@ -355,7 +355,7 @@ Merge order is constrained only by #28 before #245 (SRCREV re-pin); both are mer | 1 | Publish the SDK image `avocadolinux/sdk:2024-edge` carrying `nativesdk-avocado-dtc-overlay` and the `files_append` `nativesdk-stone` | `avocado install` cannot resolve the overlay compiler without it | | 2 | Publish the `2024/edge` feed carrying `avocado-dtc-overlay-deliver` | The delivery hook is a target package; without it the build hard-errors on a missing hook | | 3 | Cut an avocado-cli release and name it in this guide | The released `1.0.0-rc.1` does **not** carry the overlay work, despite the from-source build reporting the same version | -| 4 | Resolve KOS-68, or keep the [brand-new SDK](#on-a-brand-new-sdk) block | A clean SDK cannot finalize a runtime image without it | +| 4 | Ship the image-build toolchain in the SDK, or keep the [brand-new SDK](#on-a-brand-new-sdk) block | A clean SDK cannot finalize a runtime image without it | | 5 | Raspberry Pi 5 paired positive/negative hardware run | The Pi path is proven only at build level; per [Confirming the overlay applied](#confirming-the-overlay-applied), that is not evidence | | 6 | Fix container-mode provisioning on Jetson (part of avocado-cli#183) | `avocado runtime provision` cannot flash a Jetson from its container today. Every Jetson flash behind this page was run host-side, so the documented CLI path is not the path that was verified | | 7 | Add this page to the Advanced category in `sidebars-guides.js` | Deliberately omitted while `draft: true` - a sidebar entry pointing at a draft doc breaks the production build | From dbdb3aafdc94bebad5b2c41bd921b780f6e4d9fb Mon Sep 17 00:00:00 2001 From: Javier Tia Date: Mon, 17 Aug 2026 16:55:43 -0600 Subject: [PATCH 12/12] developer-reference/device-tree-overlays: document only what was tested Two review points, one change. The page carried step-by-step guidance for Raspberry Pi and qemuarm64 whose delivery paths have never been confirmed on a running kernel, and it carried a release-status section tracking pull requests, publication blockers and per-target evidence. Marking the untested targets WIP was not sufficient. The page's own argument is that a green build proves nothing about a board, so publishing a mechanism nobody has watched work contradicts the standard the page sets three sections earlier - and a reader who skips the label follows instructions no one has run. Those sections are removed rather than reworded; a board gets documented once it has been verified the way Jetson was. The release-status section was project tracking in a customer-facing page. Which PRs are open and what gates publication is real information, but its audience is the team, so it moves to the pull request instead. The support matrix keeps only rows that are settled: Jetson verified on hardware, x86 not applicable, everything else not documented yet. `params` is described as accepted-but-unconsumed, which is what it is on the one target this page now covers. Signed-off-by: Javier Tia --- src/docs-guides/device-tree-overlays.md | 113 +++--------------------- 1 file changed, 13 insertions(+), 100 deletions(-) diff --git a/src/docs-guides/device-tree-overlays.md b/src/docs-guides/device-tree-overlays.md index 6fb2462d..15880cfe 100644 --- a/src/docs-guides/device-tree-overlays.md +++ b/src/docs-guides/device-tree-overlays.md @@ -8,12 +8,10 @@ description: 'Declare a device-tree overlay in an extension and let avocado buil :::danger draft - Jetson only, and not yet reproducible by a reader -**NVIDIA Jetson (Tegra) is the one target where this is finished and proven on hardware.** Every other target is work in progress and is marked as such throughout this page - the Raspberry Pi path builds but has never been confirmed on a board, and `qemuarm64` delivers the overlay but does not apply it at boot. Read the [target support](#target-support) table before following anything here for a non-Jetson board. +**NVIDIA Jetson (Tegra) is the one target this page documents, and the only one proven on hardware.** Other targets are not covered here: their delivery paths have not been confirmed on a board, and this page does not describe a mechanism nobody has watched work. The guide also documents behavior that is **not in a released Avocado CLI or SDK image**. Every command below has been run, but only against from-source builds of unmerged branches. Following it with released artifacts will fail at `avocado install`. -See [Release status](#release-status) at the bottom for the exact list of what must merge and publish before this page can drop `draft: true`. - ::: A device-tree overlay is a small patch to your board's hardware description: enable a SPI bus, wire up a GPIO, add a sensor the base device tree does not know about. Traditionally that means compiling a `.dtbo` by hand with `dtc` and finding somewhere on the boot partition to put it - a per-board manual step that has to be repeated on every image. @@ -26,24 +24,21 @@ This guide covers: - Writing an overlay source the compiler will accept - Building and flashing on a Jetson, the worked example throughout - Confirming on a booted board that the overlay actually applied -- What is still work in progress on the other targets ## Target support -The declaration is portable; the delivery mechanism is not. Each BSP layer installs its own delivery hook, so what happens to the compiled blob differs by board - including how you ship a _change_ to an overlay later, and how far along each target is. +The declaration is portable; the delivery mechanism is not. Each BSP layer installs its own delivery hook, so what happens to the compiled blob differs by board - including how you ship a _change_ to an overlay later. -| Target | Status | Delivery mechanism | Updating an overlay | -| ------------------------------------------- | ---------------------------------- | -------------------------------------------------------------- | --------------------------------------------------------- | -| `jetson-orin-nano-devkit` (and other Tegra) | **Working** - verified on hardware | Merged into the base DTB at build time with `fdtoverlay` | **Reflash** - see [Jetson](#jetson-tegra) | -| `raspberrypi5`, `raspberrypi4` | **WIP** - builds, never booted | Loose `.dtbo` on the boot FAT, selected by a `dtoverlay=` line | Ordinary image update | -| `qemuarm64` | **WIP** - delivered, never applied | Loose `.dtbo` on the boot FAT | n/a until the boot chain applies it | -| `qemux86-64` | Not applicable | None - x86 boots via ACPI and has no device tree | n/a | -| Any other target | Not supported | None | Build fails by design - see [below](#unsupported-targets) | +| Target | Status | Delivery mechanism | Updating an overlay | +| ------------------------------------------- | ---------------------------------- | ---------------------------------------------------------- | --------------------------------------------------------- | +| `jetson-orin-nano-devkit` (and other Tegra) | **Working** - verified on hardware | Merged into the base DTB at build time with `fdtoverlay` | **Reflash** - see [Jetson](#jetson-tegra) | +| `qemux86-64` | Not applicable | None - x86 boots via ACPI and has no device tree | n/a | +| Any other target | Not documented yet | Varies by BSP | Build fails by design - see [below](#unsupported-targets) | -Only the Jetson row has been confirmed by reading the device tree of a running kernel. The other two rows describe what the build produces, which is a weaker claim than it looks - see [Confirming the overlay applied](#confirming-the-overlay-applied) for why a green build proves nothing about a board, and [Targets still in progress](#targets-still-in-progress) for what each one is waiting on. +The Jetson row has been confirmed by reading the device tree of a running kernel on the board. Other boards will be documented as each one is verified the same way - see [Confirming the overlay applied](#confirming-the-overlay-applied) for why a green build is not evidence that an overlay reached a kernel. :::info the declaration is the portable part -The same `device_tree_overlays` block and the same `.dtso` move between a Jetson and a Pi unchanged. Only the hook underneath differs. That is the point of the hook being per-BSP - and it is why the WIP targets are held up by delivery and boot wiring rather than by anything you write. +The same `device_tree_overlays` block and the same `.dtso` move between boards unchanged. Only the hook underneath differs, which is the point of the hook being per-BSP. ::: ## Declaring an overlay @@ -72,7 +67,7 @@ extensions: | -------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `name` | yes | Authoritative. It is the compiled blob's basename (`.dtbo`) and, on the targets that select overlays at boot, the selection argument. Must be a safe basename: no `/`, no whitespace, not `.` or `..`. Names must be unique across the whole runtime - a duplicate is a hard error, not last-one-wins. | | `src` | yes | Path to the overlay source, relative to the project root. | -| `params` | no | A mapping of per-overlay parameters. Consumed **only** by the Raspberry Pi hook, which is itself WIP - see [Parameters](#parameters-raspberry-pi-only). | +| `params` | no | A mapping of per-overlay parameters. Accepted by the schema, but no hook on a documented target consumes it - the Jetson hook ignores it silently. Encode the values in the `.dtso` instead. | :::warning declare `avocado-runtime` The runtime must pull `avocado-runtime`, which is what installs `avocado-img-bootfiles` - the package shipping `u-boot.bin` and the `bootfiles/*` entries the bundler needs to build a boot image. A project that omits it fails late, at bundling, with `File 'u-boot.bin' not found in any input directory for FAT image`, which reads like a broken BSP rather than a missing declaration. It cost us two weeks of chasing a product bug that was a project-config omission. @@ -125,7 +120,7 @@ A label-targeted overlay, which is what you usually want on real hardware: ``` :::caution label targets need `__symbols__` in the base tree -`&spi0` resolves through the base device tree's `__symbols__` node, which only exists if the BSP compiled its DTB with `dtc -@`. Most vendor BSPs do; QEMU's `virt` machine does not. If the label cannot resolve, a Raspberry Pi silently boots without the overlay, while a Jetson **fails the build** - `fdtoverlay` errors and the hook treats that as fatal rather than flashing an unmerged tree. Use `target-path` when you are unsure. +`&spi0` resolves through the base device tree's `__symbols__` node, which only exists if the BSP compiled its DTB with `dtc -@`. Most vendor BSPs do. If the label cannot resolve, a Jetson **fails the build** - `fdtoverlay` errors and the hook treats that as fatal rather than flashing an unmerged tree. On a board whose overlays are selected at boot instead, the same unresolved label is silent, and you get a board that boots without the overlay. Use `target-path` when you are unsure. ::: ### Using `dt-bindings` macros @@ -168,7 +163,7 @@ The middle line is the one that differs per target: on Jetson it names the base To inspect what was produced, `avocado save` exports the build state; the archive holds both the compiled `device-tree-overlays/.dtbo` and the finalized `os-bundle.aos`. -Then flash the board. **Do this host-side, not through `avocado runtime provision`** - container-mode provisioning cannot currently reach a Jetson in recovery mode, which is item 6 of [Release status](#release-status). Every result on this page was obtained from a host-side flash. +Then flash the board. **Do this host-side, not through `avocado runtime provision`** - container-mode provisioning cannot currently reach a Jetson in recovery mode, which is a known gap. Every result on this page was obtained from a host-side flash. ### On a brand-new SDK @@ -265,47 +260,6 @@ Two consequences: The base DTB is selected by the `DTBFILE` the BSP records, because a real Tegra BSP ships one base DTB per module SKU - five on an Orin Nano dev kit. You do not choose it; the board's own flash configuration does. -## Targets still in progress - -Everything below builds. None of it has been confirmed on a running kernel, which per [Confirming the overlay applied](#confirming-the-overlay-applied) is the only evidence that counts. Treat these sections as a description of the intended mechanism rather than of observed behavior. - -### Raspberry Pi - WIP, builds but never booted - -The hook writes the `.dtbo` to `overlays/.dtbo` on the boot FAT and emits an `avocado-overlays.txt` alongside it holding one `dtoverlay=` line per overlay. The stock `config.txt` carries a static `include avocado-overlays.txt`, so the firmware should pick these up at boot. `config.txt` itself is never rewritten, which keeps your own overrides and the generated overlay list from fighting over the same file. - -The build path is green end to end - compile, deliver, finalized `os-bundle.aos` - and is re-run as a regression gate whenever the Jetson path changes. **That is the whole of the evidence.** No Pi has been booted with a declared overlay and had its device tree read, so whether the firmware actually applies the generated list is currently an assumption. The Jetson experience is the reason to say so plainly: there, every build marker passed for two full rounds while the board applied nothing. - -What it is waiting on: a paired positive/negative run on a Pi 5, item 5 of [Release status](#release-status). - -### QEMU - WIP, delivered but not applied - -`qemuarm64` compiles and delivers the overlay to the boot FAT, and then nothing applies it. The shipped `qemu_arm64_defconfig` does not set `CONFIG_OF_LIBFDT_OVERLAY` at u-boot 2026.01, so its u-boot carries every `fdt` subcommand except the one that applies an overlay - `fdt apply` prints its usage dump instead of running. - -This one is understood rather than merely unverified: the mechanism has been proven on a u-boot built from the same tree with the flag set, and the negative control on the shipped binary fails exactly where predicted. It needs three pieces (the config flag, an overlay list written next to the kernel, and an env block that applies them), tracked in meta-avocado#273, plus a full-image build and boot that has not happened. - -`qemux86-64` is a different case and will not be supported: x86 boots via ACPI and has no device tree anywhere in the chain, so no hook is installed and declaring an overlay there fails the build. - -## Parameters (Raspberry Pi only) - -`params` renders into the `dtoverlay=` line as comma-separated `key=value` pairs: - -```yaml -device_tree_overlays: - - name: my-spi - src: overlays/my-spi.dtso - params: - speed: '12000000' - cs: '0' -``` - -produces `dtoverlay=my-spi,cs=0,speed=12000000` (keys are sorted, so the output is stable across builds). - -:::warning `params` is silently ignored off Raspberry Pi - including on Jetson -Only the Raspberry Pi hook consumes `params`, because it maps onto the Pi firmware's own overlay-parameter mechanism and nothing else has an equivalent. The Jetson and QEMU hooks accept a declaration carrying `params` and deliver the overlay without them, with no warning. - -**On Jetson - the one working target - encode the values in the `.dtso` itself.** A `params` block there is silently inert, and since the Pi hook that would honor it is itself unverified on hardware, this key has no confirmed consumer on any board today. -::: - ## Unsupported targets Declaring an overlay on a target whose BSP ships no delivery hook is a **hard error**, not a silent skip: @@ -329,48 +283,7 @@ The same applies one level deeper: if the hook runs but does not claim an overla | `no dt-bindings under ` | Source `#include`s kernel headers, `kernel-devsrc` missing or incomplete | Confirm the SDK was provisioned for a project declaring overlays; a no-`#include` overlay needs neither | | `fdtoverlay failed to merge` (Jetson) | Overlay targets a label or path absent from the base DTB | Check the target resolves in that board's base tree; prefer `target-path` when unsure | | `File 'u-boot.bin' not found in any input directory for FAT image` | Runtime does not declare `avocado-runtime` | Add `packages: avocado-runtime: '*'` to the runtime | -| Build fully green, node absent from `/proc/device-tree` | Overlay was delivered but not applied at boot | On qemuarm64 this is expected (#273). Elsewhere, run the negative control and report it | - -## Release status - -This page is `draft: true` for two reasons: the feature is not reachable from released artifacts, and only one target is finished. Items 1-4 and 6-7 gate publication; item 5 is what promotes the Raspberry Pi out of WIP, and meta-avocado#273 does the same for `qemuarm64`. - -### Pull requests - -| PR | Repo | Status | What it provides | Required for | -| -------------------------------------------------------------- | ------------ | --------------------------------- | -------------------------------------------------------------------------------- | ------------------------------------------------ | -| [#28](https://github.com/avocado-linux/stone/pull/28) | stone | **Merged** 2026-08-12 | `files_append` FAT primitive | All targets | -| [#245](https://github.com/avocado-linux/meta-avocado/pull/245) | meta-avocado | **Merged** 2026-08-12 (`563d462`) | SDK compile wrapper + RPi and QEMU delivery hooks | All targets | -| [#183](https://github.com/avocado-linux/avocado-cli/pull/183) | avocado-cli | Open, ready | The `device_tree_overlays` config surface and build orchestration | All targets | -| [#292](https://github.com/avocado-linux/meta-avocado/pull/292) | meta-avocado | Open, ready | Jetson delivery hook (`fdtoverlay` merge) **and** the Tegra BSP staging it reads | Jetson | -| [#291](https://github.com/avocado-linux/meta-avocado/pull/291) | meta-avocado | Open, ready | Makes five silent Jetson provisioning failures report their own cause | Jetson walkthrough being followable | -| [#273](https://github.com/avocado-linux/meta-avocado/pull/273) | meta-avocado | Open, **draft** | Applies delivered overlays at boot on qemuarm64 | qemuarm64 only - **not** a blocker for this page | - -Merge order is constrained only by #28 before #245 (SRCREV re-pin); both are merged. [#293](https://github.com/avocado-linux/meta-avocado/pull/293) is closed - its Tegra BSP staging is now the first commit of #292, because a hook that cannot find its input and a staging step with no consumer were never separately mergeable. - -### Beyond the PRs - -| # | Item | Why it blocks | -| --- | ------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| 1 | Publish the SDK image `avocadolinux/sdk:2024-edge` carrying `nativesdk-avocado-dtc-overlay` and the `files_append` `nativesdk-stone` | `avocado install` cannot resolve the overlay compiler without it | -| 2 | Publish the `2024/edge` feed carrying `avocado-dtc-overlay-deliver` | The delivery hook is a target package; without it the build hard-errors on a missing hook | -| 3 | Cut an avocado-cli release and name it in this guide | The released `1.0.0-rc.1` does **not** carry the overlay work, despite the from-source build reporting the same version | -| 4 | Ship the image-build toolchain in the SDK, or keep the [brand-new SDK](#on-a-brand-new-sdk) block | A clean SDK cannot finalize a runtime image without it | -| 5 | Raspberry Pi 5 paired positive/negative hardware run | The Pi path is proven only at build level; per [Confirming the overlay applied](#confirming-the-overlay-applied), that is not evidence | -| 6 | Fix container-mode provisioning on Jetson (part of avocado-cli#183) | `avocado runtime provision` cannot flash a Jetson from its container today. Every Jetson flash behind this page was run host-side, so the documented CLI path is not the path that was verified | -| 7 | Add this page to the Advanced category in `sidebars-guides.js` | Deliberately omitted while `draft: true` - a sidebar entry pointing at a draft doc breaks the production build | - -### Evidence, per target - -| Target | Build path | On hardware | Verdict | -| ----------- | ---------- | ------------------------------ | ----------- | -| Jetson Orin | Green | **Paired positive + negative** | **Working** | -| rpi5 | Green | Not run | WIP | -| qemuarm64 | Green | Applies nothing at boot | WIP | - -**Jetson Orin Nano dev kit (P3767-0005), 2026-08-15.** On-device, paired positive and negative: `/proc/device-tree/hello-overlay/avocado,marker` reads the declared value on the running board, and the node is absent on a build with the declaration removed and nothing else changed. This is the only row where the middle column is filled in, and it is the reason Jetson is the worked example throughout this page rather than the Pi it started as. - -**Same board, 2026-08-17** - the access mechanisms this page tells you to use, rather than the overlay pipeline. Console: the `permissions` profile yields `root::` in the flashed rootfs and a root prompt. Network: with the BSP extension present the NIC enumerates (`r8169`, `eth0` up at 1Gbps), and `ssh -o BatchMode=yes root@` connects against a key placed by `var_files`. Both were previously documented from the build output alone, which the [negative-control](#run-the-negative-control) argument says is not evidence. +| Build fully green, node absent from `/proc/device-tree` | Overlay was delivered but not applied at boot | Run the negative control and report it | ## What's next