All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Vahid Gharaee" <vgharaee@gmail.com>
To: openembedded-core@lists.openembedded.org
Subject: [PATCH v3 6/6] kernel-fit-image: preserve vendored DTB aliases for external overrides
Date: Sat, 31 Oct 2026 17:26:49 +0100	[thread overview]
Message-ID: <20261031162649.944625-7-vgharaee@gmail.com> (raw)
In-Reply-To: <20261031162649.944625-1-vgharaee@gmail.com>

From: Vahid Gharaee <vgharaee@gmail.com>

When an external DTB overrides a kernel-provided DTB, the FIT
generation skips the kernel DTB. With KERNEL_DTBVENDORED enabled,
this also drops the vendored configuration name.

Preserve the vendored name by creating a configuration alias
referencing the external DTB image. Resolve external symlinks
to their actual DTB targets.

Add regression tests for regular and symlinked external DTB
overrides.

Signed-off-by: Vahid Gharaee <vgharaee@gmail.com>
---
 .../recipes-test/ext-dtb/test-dtbs-as-ext.bb  |  11 ++
 meta/classes-recipe/kernel-fit-image.bbclass  |   7 ++
 meta/lib/oeqa/selftest/cases/fitimage.py      | 105 ++++++++++++++++--
 3 files changed, 113 insertions(+), 10 deletions(-)

diff --git a/meta-selftest/recipes-test/ext-dtb/test-dtbs-as-ext.bb b/meta-selftest/recipes-test/ext-dtb/test-dtbs-as-ext.bb
index 217ca36235..de994cebce 100644
--- a/meta-selftest/recipes-test/ext-dtb/test-dtbs-as-ext.bb
+++ b/meta-selftest/recipes-test/ext-dtb/test-dtbs-as-ext.bb
@@ -8,6 +8,7 @@ LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda
 
 inherit devicetree
 
+TEST_EXTRA_DTB ?= ""
 COMPATIBLE_MACHINE = ".*"
 
 SRC_URI = "\
@@ -18,8 +19,18 @@ SRC_URI = "\
 # Sym-links are handled as extra configuration nodes in FIT images.
 do_install:append() {
     ln -sf test-ext.dtb "${D}/boot/devicetree/test-ext-alias.dtb"
+
+    if [ -n "${TEST_EXTRA_DTB}" ]; then
+        cp "${D}/boot/devicetree/test-ext.dtb" \
+           "${D}/boot/devicetree/${TEST_EXTRA_DTB}"
+    fi
 }
 
 do_deploy:append() {
     ln -sf test-ext.dtb "${DEPLOYDIR}/devicetree/test-ext-alias.dtb"
+
+    if [ -n "${TEST_EXTRA_DTB}" ]; then
+        cp "${DEPLOYDIR}/devicetree/test-ext.dtb" \
+           "${DEPLOYDIR}/devicetree/${TEST_EXTRA_DTB}"
+    fi
 }
diff --git a/meta/classes-recipe/kernel-fit-image.bbclass b/meta/classes-recipe/kernel-fit-image.bbclass
index ea4f39373d..1ef2717908 100644
--- a/meta/classes-recipe/kernel-fit-image.bbclass
+++ b/meta/classes-recipe/kernel-fit-image.bbclass
@@ -192,6 +192,7 @@ python do_compile() {
     # Prepare a DTB image section
     kernel_devicetree = d.getVar('KERNEL_DEVICETREE')
     external_kernel_devicetree = d.getVar("EXTERNAL_KERNEL_DEVICETREE")
+    external_dtb_aliases = {}
     if kernel_devicetree:
         for dtb in kernel_devicetree.split():
             # In deploy_dir the DTBs are without sub-directories also with KERNEL_DTBVENDORED = "1"
@@ -205,6 +206,8 @@ python do_compile() {
             if external_kernel_devicetree:
                 ext_dtb_path = os.path.join(external_kernel_devicetree, dtb_name)
                 if os.path.exists(ext_dtb_path) and os.path.getsize(ext_dtb_path) > 0:
+                    if conf_name != dtb_name:
+                        external_dtb_aliases[conf_name] = ext_dtb_path
                     continue
 
             # Copy the dtb or dtbo file into the FIT image assembly directory
@@ -229,6 +232,10 @@ python do_compile() {
                     root_node.fitimage_emit_section_dtb(dtb_name, dtb_name,
                         d.getVar("UBOOT_DTB_LOADADDRESS"), d.getVar("UBOOT_DTBO_LOADADDRESS"), True)
 
+        for alias, dtb_path in external_dtb_aliases.items():
+            symlink_target = oe.fitimage.symlink_points_below(os.path.basename(dtb_path), external_kernel_devicetree)
+            root_node.fitimage_emit_section_dtb_alias(alias, symlink_target or dtb_path)
+
     # Prepare a u-boot script section
     fit_uboot_env = d.getVar("FIT_UBOOT_ENV")
     if fit_uboot_env:
diff --git a/meta/lib/oeqa/selftest/cases/fitimage.py b/meta/lib/oeqa/selftest/cases/fitimage.py
index 6a0b0f82e9..90b7a20ad0 100644
--- a/meta/lib/oeqa/selftest/cases/fitimage.py
+++ b/meta/lib/oeqa/selftest/cases/fitimage.py
@@ -467,10 +467,9 @@ class FitImageTestCase(OESelftestTestCase):
         kernel_devicetree = bb_vars.get('KERNEL_DEVICETREE')
         all_dtbs = []
         dtb_aliases = {}
+        external_aliases = {}
+        kernel_dtbs = kernel_devicetree.split() if kernel_devicetree else []
 
-        if kernel_devicetree:
-            all_dtbs += [FitImageTestCase._apply_dtbvendored(bb_vars, dtb) for dtb in kernel_devicetree.split()]
-       
         if bb_vars.get("PREFERRED_PROVIDER_virtual/dtb") == "test-dtbs-as-ext":
             if bb_vars.get("_python_only_test"):
                 external_dtbs, external_aliases = FitImageTestCase._get_test_dtb_files()
@@ -481,6 +480,23 @@ class FitImageTestCase(OESelftestTestCase):
             all_dtbs.extend(external_dtbs)
             dtb_aliases.update(external_aliases)
 
+        for dtb in kernel_dtbs:
+            dtb_name = os.path.basename(dtb)
+            mapped_name = FitImageTestCase._apply_dtbvendored(bb_vars, dtb)
+
+            if dtb_name in all_dtbs:
+                target = dtb_name
+            elif dtb_name in external_aliases:
+                target = external_aliases[dtb_name]
+            else:
+                target = None
+
+            if target:
+                if mapped_name != target:
+                    dtb_aliases[mapped_name] = target
+            else:
+                all_dtbs.append(mapped_name)
+
         return all_dtbs, dtb_aliases
 
     @staticmethod
@@ -508,10 +524,10 @@ class FitImageTestCase(OESelftestTestCase):
         extra_configs = []
         for conf in configs:
             dtb = dtbs[conf]
-            if dtb in dtb_aliases:
-                dtb = dtb_aliases[dtb]
-            elif dtb:
+            if dtb:
                 dtb = FitImageTestCase._apply_dtbvendored(bb_vars, dtb)
+                dtb = dtb_aliases.get(dtb, dtb)
+
             extra_configs.append((conf, kernels[conf] or "kernel-1", dtb))
         return extra_configs
 
@@ -1379,6 +1395,58 @@ PREFERRED_PROVIDER_virtual/dtb = "test-dtbs-as-ext"
         self._gen_atf_tee_dummy_images(bb_vars)
         self._test_fitimage(bb_vars)
 
+    def test_fit_image_ext_dtb_vendored_override(self):
+        """Check that an external DTB overrides a vendored kernel DTB."""
+        machine = self._get_machine_or_skip()
+
+        if machine != "qemuarm64":
+            self.skipTest("This test requires the qemuarm64 foundation-v8.dtb")
+
+        config = """
+KERNEL_DTBVENDORED = "1"
+PREFERRED_PROVIDER_virtual/dtb = "test-dtbs-as-ext"
+TEST_EXTRA_DTB = "foundation-v8.dtb"
+FIT_CONF_DEFAULT_DTB = "arm/foundation-v8.dtb"
+FIT_CONFIGS = "external-override"
+FIT_CONFIG_DTB[external-override] = "arm/foundation-v8.dtb"
+"""
+        config = self._config_add_machine_settings(config, machine, keys=["KERNEL_DEVICETREE"])
+        config = self._config_add_kernel_classes(config)
+        config = self._config_add_uboot_env(config)
+
+        self.write_config(config)
+
+        bb_vars = self._fit_get_bb_vars()
+        self._gen_atf_tee_dummy_images(bb_vars)
+
+        its_path, fit_path = self._bitbake_fit_image(bb_vars)
+
+        self.assertExists(its_path)
+        self.assertExists(fit_path)
+
+        self.logger.info("Regression test ITS: %s", its_path)
+
+        with open(its_path, encoding="utf-8") as f:
+            its = f.read()
+
+        self.assertIn("fdt-foundation-v8.dtb", its)
+        self.assertIn("conf-arm_foundation-v8.dtb", its)
+        self.assertIn("conf-external-override", its)
+        self.assertNotIn("fdt-arm_foundation-v8.dtb {", its)
+        # The vendored configuration must be the default.
+        self.assertIn('default = "conf-arm_foundation-v8.dtb";', its)
+
+        # Both the vendored and custom configurations must reference
+        # the external DTB image.
+        for conf in ("conf-arm_foundation-v8.dtb", "conf-external-override"):
+            match = re.search(r'\b' + re.escape(conf) + r'\s*\{([^{}]*)', its)
+            self.assertIsNotNone(match, "Missing configuration: %s" % conf)
+            self.assertIn('fdt = "fdt-foundation-v8.dtb";', match.group(1))
+
+        self._check_its_file(bb_vars, its_path)
+
+        uboot_tools_bindir = self._setup_native('u-boot-tools-native')
+        self._check_fitimage(bb_vars, fit_path, uboot_tools_bindir)
 
     def test_sign_fit_image_configurations(self):
         """
@@ -1616,17 +1684,17 @@ class FitImagePyTests(KernelFitImageBase):
         root.fitimage_emit_section_dtb(
             "test-overlay.dtbo", "a-dir/test-overlay.dtbo"
         )
-        
+
         with self.assertRaises(bb.BBHandledException):
             root.fitimage_emit_section_config_custom(
                 "invalid", "kernel-1", "test-overlay.dtbo"
             )
-        
+
         # A regular DTB may explicitly select a kernel.
         root.fitimage_emit_section_dtb(
             "test-board.dtb", "a-dir/test-board.dtb"
         )
-        
+
         root.fitimage_emit_section_config_custom(
             "regular", "kernel-1", "test-board.dtb"
         )
@@ -1639,7 +1707,7 @@ class FitImagePyTests(KernelFitImageBase):
     def _test_fitimage_py(self, bb_vars_overrides=None):
         topdir = os.path.join(os.environ['BUILDDIR'])
         fitimage_its_path = os.path.join(topdir, self._testMethodName + '.its')
-        
+
         # Provide variables without calling bitbake
         bb_vars = {
             # image-fitimage.conf
@@ -1764,6 +1832,23 @@ class FitImagePyTests(KernelFitImageBase):
         self.logger.debug("Checking its: %s" % fitimage_its_path)
         self._check_its_file(bb_vars, fitimage_its_path)
 
+    def test_fitimage_py_vendored_external_dtb_symlink_override(self):
+        bb_vars = {
+            "KERNEL_DEVICETREE": "arm/test-ext-alias.dtb",
+            "KERNEL_DTBVENDORED": "1",
+            "PREFERRED_PROVIDER_virtual/dtb": "test-dtbs-as-ext",
+            "_python_only_test": True,
+        }
+
+        dtbs, aliases = FitImageTestCase._get_dtb_files(bb_vars)
+
+        self.assertIn("test-ext.dtb", dtbs)
+        self.assertNotIn("arm_test-ext-alias.dtb", dtbs)
+        self.assertEqual(aliases["arm_test-ext-alias.dtb"],"test-ext.dtb")
+
+        # Verify that the original external symlink alias is preserved
+        self.assertEqual(aliases["test-ext-alias.dtb"], "test-ext.dtb")
+
     def test_fitimage_py_default(self):
         self._test_fitimage_py()
 
-- 
2.55.0


  parent reply	other threads:[~2026-10-31 16:26 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-31 16:26 [PATCH v3 0/6] Add multi-kernel FIT image support Vahid Gharaee
2026-10-31 16:26 ` [PATCH v3 1/6] oe.fitimage: Support multiple kernel nodes and configuration selection Vahid Gharaee
2026-10-31 16:26 ` [PATCH v3 2/6] oe.fitimage: add metadata for multiple kernels Vahid Gharaee
2026-10-31 16:26 ` [PATCH v3 3/6] oe.selftest: Add tests for multi-kernel FIT config Vahid Gharaee
2026-10-31 16:26 ` [PATCH v3 4/6] oe.fitimage: Add custom configurations and harden multi-kernel handling Vahid Gharaee
2026-10-31 16:26 ` [PATCH v3 5/6] oe.selftest: Improve FIT DTB alias validation Vahid Gharaee
2026-10-31 16:26 ` Vahid Gharaee [this message]
2026-11-05 15:01 ` [OE-core] [PATCH v3 0/6] Add multi-kernel FIT image support Mathieu Dubois-Briand

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261031162649.944625-7-vgharaee@gmail.com \
    --to=vgharaee@gmail.com \
    --cc=openembedded-core@lists.openembedded.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.