[PATCH v2 3/8] binman: android_boot: vendor-dt support
Simon Glass
sjg at chromium.org
Mon Jun 8 15:26:54 CEST 2026
Hi Sam,
On 2026-06-07T23:37:09, Sam Day via B4 Relay
<devnull+me.samcday.com at kernel.org> wrote:
> binman: android_boot: vendor-dt support
>
> There's many Android bootloaders out there that expect non-standard
> abootimgs. Samsung and Qualcomm, and likely many others. This quirk has
> been codified in the widely used osm0sis fork/rewrite of mkbootimg.
>
> Presumably, these vendor-specific abootimgs were conceived before the v2
> format was widely available or specified. The evidence for this is their
> hijacking of the header_version field to specify the length of a payload
> that follows the main abootimg.
>
> At least QCDT and DTBH (both of which will be implemented as binman
> etypes in following commits) use this approach.
>
> Link: https://github.com/osm0sis/mkbootimg
> Signed-off-by: Sam Day <me at samcday.com>
>
> tools/binman/etype/android_boot.py | 37 ++++++++++++++++++++--
> tools/binman/ftest.py | 11 ++++++-
> .../binman/test/vendor/android_boot_vendor_dt.dts | 27 ++++++++++++++++
> 3 files changed, 72 insertions(+), 3 deletions(-)
> diff --git a/tools/binman/etype/android_boot.py b/tools/binman/etype/android_boot.py
> @@ -131,17 +136,26 @@ class Entry_android_boot(Entry_section):
> self.Raise('page-size must fit the Android boot image header')
> if 'dtb' in self._entries:
> self.Raise("Subnode 'dtb' requires header-version 2")
> + if self.vendor_dt_node and self.os_version:
> + self.Raise("os_version not allowed when vendor-dt is in use")
Two things. The message uses the Python attribute name; users see the
DT property, so this should read 'os-version'. Second, the commit
message doesn't explain why os-version becomes invalid in this mode -
in the v0 header layout, dt_size (the field we hijack) and os_version
are separate u32 fields, so there's no obvious conflict.
If a downstream bootloader interprets os_version differently when
dt_size is set, please document that - otherwise I'd drop the
restriction. Either way, please add a test for the Raise().
> diff --git a/tools/binman/etype/android_boot.py b/tools/binman/etype/android_boot.py
> @@ -152,6 +166,15 @@ class Entry_android_boot(Entry_section):
> entry.SetPrefix(self._name_prefix)
> self._entries[node.name] = entry
>
> + def _ReadVendorDtEntries(self, vendor_dt_node):
> + entry = Entry.Create(self, vendor_dt_node, etype='section',
> + expanded=self.GetImage().use_expanded,
> + missing_etype=self.GetImage().missing_etype)
> + entry.page_size = fdt_util.GetInt(self._node, 'page-size', 2048)
> + entry.ReadNode()
> + entry.SetPrefix(self._name_prefix)
> + self._entries[vendor_dt_node.name] = entry
Forcing etype='section' here works only because qcdt/dtbh later walks
up via getattr(self.section, 'page_size', 2048). That coupling is
invisible from this file. Please add a comment noting this attribute
is consumed by child etypes (qcdt/dtbh in later patches) - otherwise
it looks like dead code. A cleaner alternative would be for the child
etype to look up the android-boot ancestor directly, so page-size
doesn't need to be smuggled through an unrelated attribute.
Also 'page-size' is re-read from self._node here, but ReadNode() has
already cached it in self.page_size. Just use that.
> diff --git a/tools/binman/etype/android_boot.py b/tools/binman/etype/android_boot.py
> @@ -246,7 +278,7 @@ class Entry_android_boot(Entry_section):
> 0, # second_offset
> self._GetAddr(self.tags_offset, 'tags'),
> self.page_size,
> - self.header_version,
> + len(vendor_dt),
This conflates two distinct fields. For a plain v0 image the slot is
header_version; for a vendor-dt image it's dt_size. The current code
only produces the right bytes because both collapse to 0 when there is
no vendor-dt. Please make it explicit:
dt_size = len(vendor_dt) if self.vendor_dt_node else self.header_version
and add a comment that this slot is overloaded. As written, anyone
adding a new v0 header_version in future will silently break vendor-dt
builds.
> diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
> @@ -5662,7 +5662,16 @@ fdt fdtmap Extract the devicetree blob from the fdtmap
> self.assertEqual(U_BOOT_DTB_DATA,
> data[0x1000:0x1000 + len(U_BOOT_DTB_DATA)])
>
> - self.assertEqual(U_BOOT_DATA, data[0x800:0x800 + len(U_BOOT_DATA)])
> + def testAndroidBootVendorDt(self):
You're silently dropping a duplicated assertion left over from patch
1/8. That cleanup belongs in its own patch (or a fixup to 1/8), not
buried in the vendor-dt commit.
> diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py
> @@ -5662,7 +5662,16 @@ fdt fdtmap Extract the devicetree blob from the fdtmap
> + def testAndroidBootVendorDt(self):
> + """Test that android-boot can embed an arbitrary vendor-dt section"""
> + data = self._DoReadFile('vendor/android_boot_vendor_dt.dts')
> + header = struct.unpack_from('<8s10I16s512s32s', data, 0)
> + vendor_dt = b'howdy'
> + self.assertEqual(len(vendor_dt), header[9])
> + self.assertEqual(0, header[10])
> + self.assertEqual(self._AndroidBootId(U_BOOT_DATA, b'\0', b'',
> + vendor_dt), header[13])
> + self.assertEqual(vendor_dt, data[0x1800:0x1805])
Coverage is thin. Please add tests for the two new Raise() paths
('vendor-dt' on v2, os-version with vendor-dt), and assert that
vendor_dt is padded to page-size - slicing [0x1800:0x1805] only proves
the first five bytes landed, not that the next 0x7fb bytes are zero or
that the overall image length is right.
Regards,
Simon
More information about the U-Boot
mailing list