From: Douglas Anderson <dianders@chromium.org>
To: Devicetree-compiler@vger.kernel.org,
Rob Herring <robh@kernel.org>,
Krzysztof Kozlowski <krzk+dt@kernel.org>,
Conor Dooley <conor+dt@kernel.org>,
Konrad Dybcio <konradybcio@kernel.org>
Cc: "Brian Norris" <briannorris@chromium.org>,
"Chen-Yu Tsai" <wenst@chromium.org>,
"André Draszik" <andre.draszik@linaro.org>,
Devicetree@vger.kernel.org, "Simon Glass" <sjg@chromium.org>,
"David Gibson" <david@gibson.dropbear.id.au>,
"Tudor Ambarus" <tudor.ambarus@linaro.org>,
linux-kernel@vger.kernel.org,
"Julius Werner" <jwerner@chromium.org>,
"Saravana Kannan" <saravanak@kernel.org>,
"Peter Griffin" <peter.griffin@linaro.org>,
"Douglas Anderson" <dianders@chromium.org>
Subject: [PATCH v2 06/10] libfdt: overlay: Update base /__local_fixups__ on apply
Date: Wed, 28 Oct 2026 14:46:55 -0700 [thread overview]
Message-ID: <20261028215600.1713475-7-dianders@chromium.org> (raw)
In-Reply-To: <20261028215600.1713475-1-dianders@chromium.org>
When a base device tree is compiled with `dtc -L` (`--local-fixups`), it
contains a root `/__local_fixups__` node recording the byte offsets of
all phandle references in its properties.
Previously, `fdt_overlay_apply()` updated the base tree's `/__symbols__`
via `overlay_symbol_update()`, but left the base tree's
`/__local_fixups__` untouched. As a result, applying an overlay to a
base tree with `/__local_fixups__` left `/__local_fixups__` missing the
phandle references introduced by the overlay (both from the overlay's
`/__local_fixups__` and from its resolved `/__fixups__`), and left stale
offsets if the overlay overwrote a base property that previously had
phandle references.
Add `overlay_local_fixups_update()` to update the base tree's
`/__local_fixups__` whenever `/__local_fixups__` is present in the base
tree:
- Remove pre-existing `/__local_fixups__` properties for any base
properties overwritten by overlay fragments.
- Merge the overlay's `/__local_fixups__` and `/__fixups__` offsets into
the base tree's `/__local_fixups__` in sorted ascending order.
- Prune any subnodes under `/__local_fixups__` that become empty after
overwriting properties.
When the base tree does not have a `/__local_fixups__` node,
`overlay_local_fixups_update()` is a no-op.
Assisted-by: Gemini:gemini-pro-prerelease
Signed-off-by: Douglas Anderson <dianders@chromium.org>
---
Changes in v2:
- New patch updating base /__local_fixups__ in libfdt
fdt_overlay_apply() instead of stripping /__local_fixups__ by default
(David Gibson)
libfdt/fdt_overlay.c | 621 ++++++++++++++++++++++++++++++++++++++++++-
tests/run_tests.sh | 19 ++
2 files changed, 636 insertions(+), 4 deletions(-)
diff --git a/libfdt/fdt_overlay.c b/libfdt/fdt_overlay.c
index eb87b356145f..47acab15041d 100644
--- a/libfdt/fdt_overlay.c
+++ b/libfdt/fdt_overlay.c
@@ -804,7 +804,7 @@ static int overlay_prevent_phandle_overwrite(void *fdt, void *fdto)
* Negative error code on failure
*/
static int overlay_apply_node(void *fdt, int target,
- void *fdto, int node)
+ const void *fdto, int node)
{
int property;
int subnode;
@@ -1003,9 +1003,8 @@ static int overlay_split_fragment_path(const char *path, int path_len,
* overlay_symbol_update() updates the symbols of the base tree with the
* symbols of the applied overlay
*
- * This is the last step in the device tree overlay application
- * process, allowing the reference of overlay symbols by subsequent
- * overlay operations.
+ * This step in the device tree overlay application process allows
+ * the reference of overlay symbols by subsequent overlay operations.
*
* returns:
* 0 on success
@@ -1122,6 +1121,616 @@ static int overlay_symbol_update(void *fdt, void *fdto)
return 0;
}
+/**
+ * overlay_create_path - Create a relative path under a parent node
+ * @fdt: Base Device Tree blob
+ * @parent: Node offset of the starting parent node
+ * @path: Relative or slash-prefixed path to traverse
+ * @path_len: Length of @path in bytes
+ *
+ * overlay_create_path() walks the slash-separated path components in @path
+ * starting at @parent, creating any missing intermediate subnodes along the
+ * way.
+ *
+ * returns:
+ * Node offset of the resolved or created subnode on success
+ * Negative error code on failure
+ */
+static int overlay_create_path(void *fdt, int parent, const char *path,
+ int path_len)
+{
+ const char *sep;
+ int node = parent;
+
+ while (path_len > 0 && *path == '/') {
+ path++;
+ path_len--;
+ }
+
+ while (path_len > 0) {
+ int comp_len;
+ int next;
+
+ sep = memchr(path, '/', path_len);
+ comp_len = sep ? (sep - path) : path_len;
+
+ if (comp_len > 0) {
+ next = fdt_subnode_offset_namelen(fdt, node, path,
+ comp_len);
+ if (next == -FDT_ERR_NOTFOUND)
+ next = fdt_add_subnode_namelen(fdt, node, path,
+ comp_len);
+ if (next < 0)
+ return next;
+ node = next;
+ }
+
+ path += comp_len;
+ path_len -= comp_len;
+ while (path_len > 0 && *path == '/') {
+ path++;
+ path_len--;
+ }
+ }
+
+ return node;
+}
+
+/**
+ * overlay_fragment_local_fixups - Find or create a fragment's target under /__local_fixups__
+ * @fdt: Base Device Tree blob
+ * @fdto: Device tree overlay blob
+ * @fragment: Node offset of the fragment in @fdto
+ * @create: Whether to create missing subnodes under /__local_fixups__
+ *
+ * overlay_fragment_local_fixups() resolves the target of @fragment in @fdt and
+ * locates (or creates, when @create is true) the corresponding node at the
+ * same path under @fdt's /__local_fixups__ subtree.
+ *
+ * returns:
+ * Node offset of the corresponding /__local_fixups__ node on success
+ * Negative error code on failure
+ */
+static int overlay_fragment_local_fixups(void *fdt, const void *fdto,
+ int fragment, bool create)
+{
+ int root_lf, target, cur_fdt, node;
+
+ root_lf = fdt_subnode_offset(fdt, 0, "__local_fixups__");
+ if (root_lf < 0)
+ return root_lf;
+
+ target = fdt_overlay_target_offset(fdt, fdto, fragment, NULL);
+ if (target < 0)
+ return target;
+
+ cur_fdt = 0;
+ node = root_lf;
+ while (cur_fdt != target) {
+ int subnode, ancestor = -FDT_ERR_INTERNAL;
+ const char *name;
+ int namelen, next_lf;
+
+ fdt_for_each_subnode(subnode, fdt, cur_fdt) {
+ if (subnode <= target)
+ ancestor = subnode;
+ else
+ break;
+ }
+ if (ancestor < 0)
+ return ancestor;
+
+ name = fdt_get_name(fdt, ancestor, &namelen);
+ if (!name)
+ return namelen;
+
+ next_lf = fdt_subnode_offset_namelen(fdt, node, name, namelen);
+ if (next_lf == -FDT_ERR_NOTFOUND && create) {
+ char namebuf[256];
+ int old_struct_size = fdt_size_dt_struct(fdt);
+
+ if ((size_t)namelen >= sizeof(namebuf))
+ return -FDT_ERR_INTERNAL;
+ memcpy(namebuf, name, namelen);
+ next_lf = fdt_add_subnode_namelen(fdt, node, namebuf,
+ namelen);
+ if (next_lf < 0)
+ return next_lf;
+ if (next_lf <= ancestor) {
+ int delta = fdt_size_dt_struct(fdt) -
+ old_struct_size;
+ target += delta;
+ ancestor += delta;
+ }
+ } else if (next_lf < 0) {
+ return next_lf;
+ }
+
+ cur_fdt = ancestor;
+ node = next_lf;
+ }
+
+ return node;
+}
+
+/**
+ * overlay_clear_overwritten_local_fixups - Remove local fixups for overwritten properties
+ * @fdt: Base Device Tree blob
+ * @target_lf: Node offset in @fdt's /__local_fixups__ subtree
+ * @fdto: Device tree overlay blob
+ * @overlay: Node offset in @fdto's __overlay__ subtree
+ *
+ * overlay_clear_overwritten_local_fixups() recursively deletes properties under
+ * @target_lf that correspond to properties overwritten by @overlay in @fdto.
+ *
+ * returns:
+ * 0 on success
+ * Negative error code on failure
+ */
+static int overlay_clear_overwritten_local_fixups(void *fdt, int target_lf,
+ const void *fdto, int overlay)
+{
+ int prop, subnode;
+
+ fdt_for_each_property_offset(prop, fdto, overlay) {
+ const char *name;
+ const void *val;
+ int len, ret;
+
+ val = fdt_getprop_by_offset(fdto, prop, &name, &len);
+ if (!val)
+ return len;
+
+ ret = fdt_delprop(fdt, target_lf, name);
+ if (ret && ret != -FDT_ERR_NOTFOUND)
+ return ret;
+ }
+
+ fdt_for_each_subnode(subnode, fdto, overlay) {
+ const char *name;
+ int namelen, sub_lf, ret;
+
+ name = fdt_get_name(fdto, subnode, &namelen);
+ if (!name)
+ return namelen;
+
+ sub_lf = fdt_subnode_offset_namelen(fdt, target_lf, name,
+ namelen);
+ if (sub_lf == -FDT_ERR_NOTFOUND)
+ continue;
+ if (sub_lf < 0)
+ return sub_lf;
+
+ ret = overlay_clear_overwritten_local_fixups(fdt, sub_lf,
+ fdto, subnode);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * overlay_add_local_fixup_offset - Insert a sorted u32 offset into a local fixup property
+ * @fdt: Base Device Tree blob
+ * @lf_node: Node offset in @fdt's /__local_fixups__ subtree
+ * @name: Property name to update
+ * @name_len: Length of @name in bytes
+ * @poffset: Byte offset of the phandle reference within the target property
+ *
+ * overlay_add_local_fixup_offset() inserts @poffset in ascending sorted order
+ * (ignoring duplicates) into the u32 array property @name on @lf_node.
+ *
+ * returns:
+ * 0 on success
+ * Negative error code on failure
+ */
+static int overlay_add_local_fixup_offset(void *fdt, int lf_node,
+ const char *name, int name_len,
+ uint32_t poffset)
+{
+ const fdt32_t *old_val;
+ fdt32_t *vals;
+ void *prop_data;
+ int old_len, count, i, idx, ret;
+
+ old_val = fdt_getprop_namelen(fdt, lf_node, name, name_len, &old_len);
+ if (!old_val && old_len != -FDT_ERR_NOTFOUND)
+ return old_len;
+
+ if (!old_val) {
+ old_len = 0;
+ count = 0;
+ idx = 0;
+ } else {
+ if (old_len % sizeof(uint32_t))
+ return -FDT_ERR_BADSTRUCTURE;
+ count = old_len / sizeof(uint32_t);
+ idx = count;
+ for (i = 0; i < count; i++) {
+ uint32_t cur = fdt32_ld(old_val + i);
+
+ if (cur == poffset)
+ return 0;
+ if (cur > poffset) {
+ idx = i;
+ break;
+ }
+ }
+ }
+
+ ret = fdt_setprop_placeholder_namelen(fdt, lf_node, name, name_len,
+ old_len + sizeof(uint32_t),
+ &prop_data);
+ if (ret)
+ return ret;
+
+ vals = prop_data;
+ if (idx < count)
+ memmove(vals + idx + 1, vals + idx,
+ (count - idx) * sizeof(uint32_t));
+ fdt32_st(vals + idx, poffset);
+
+ return 0;
+}
+
+/**
+ * overlay_merge_fixup_into_local_fixups - Record one /__fixups__ property for a fragment
+ * @fdt: Base Device Tree blob
+ * @fdto: Device tree overlay blob
+ * @property: Property offset in @fdto's /__fixups__ node
+ * @fragment: Node offset of the current fragment in @fdto
+ * @target_frag_name: Name of @fragment
+ * @target_frag_len: Length of @target_frag_name in bytes
+ * @target_lfp: In/out cached node offset of @fragment under @fdt's /__local_fixups__
+ *
+ * overlay_merge_fixup_into_local_fixups() parses all "path:prop:offset" entries
+ * in a single /__fixups__ property of @fdto and adds the resolved property
+ * byte offsets belonging to @fragment into @fdt's /__local_fixups__ subtree.
+ *
+ * returns:
+ * 0 on success
+ * Negative error code on failure
+ */
+static int overlay_merge_fixup_into_local_fixups(void *fdt, const void *fdto,
+ int property, int fragment,
+ const char *target_frag_name,
+ int target_frag_len,
+ int *target_lfp)
+{
+ const char *value, *label;
+ int len;
+
+ value = fdt_getprop_by_offset(fdto, property, &label, &len);
+ if (!value)
+ return len;
+
+ do {
+ const char *path, *name, *frag_name, *rel_path;
+ uint32_t path_len, name_len, poffset;
+ int frag_name_len, rel_path_len, lf_node, ret;
+ bool is_overlay;
+
+ ret = overlay_parse_fixup_entry(&value, &len, &path, &path_len,
+ &name, &name_len, &poffset);
+ if (ret)
+ return ret;
+
+ ret = overlay_split_fragment_path(path, path_len,
+ &frag_name, &frag_name_len,
+ &rel_path, &rel_path_len,
+ &is_overlay);
+ if (ret)
+ return ret;
+ if (!is_overlay)
+ continue;
+
+ if (frag_name_len != target_frag_len ||
+ memcmp(frag_name, target_frag_name, frag_name_len) != 0)
+ continue;
+
+ if (*target_lfp < 0) {
+ *target_lfp = overlay_fragment_local_fixups(
+ fdt, fdto, fragment, true);
+ if (*target_lfp < 0)
+ return *target_lfp;
+ }
+
+ lf_node = overlay_create_path(fdt, *target_lfp, rel_path,
+ rel_path_len);
+ if (lf_node < 0)
+ return lf_node;
+
+ ret = overlay_add_local_fixup_offset(fdt, lf_node, name,
+ name_len, poffset);
+ if (ret)
+ return ret;
+ } while (len > 0);
+
+ return 0;
+}
+
+/**
+ * overlay_merge_fixups_into_local_fixups - Record resolved /__fixups__ for a fragment
+ * @fdt: Base Device Tree blob
+ * @fdto: Device tree overlay blob
+ * @fragment: Node offset of the current fragment in @fdto
+ * @frag_name: Name of @fragment
+ * @frag_name_len: Length of @frag_name in bytes
+ * @target_lfp: In/out cached node offset of @fragment under @fdt's /__local_fixups__
+ *
+ * overlay_merge_fixups_into_local_fixups() parses external phandle references
+ * belonging to @fragment in @fdto's /__fixups__ node and records their resolved
+ * property byte offsets in @fdt's /__local_fixups__ subtree.
+ *
+ * returns:
+ * 0 on success
+ * Negative error code on failure
+ */
+static int overlay_merge_fixups_into_local_fixups(void *fdt, const void *fdto,
+ int fragment,
+ const char *frag_name,
+ int frag_name_len,
+ int *target_lfp)
+{
+ int fixups_off, prop;
+
+ fixups_off = fdt_subnode_offset(fdto, 0, "__fixups__");
+ if (fixups_off == -FDT_ERR_NOTFOUND)
+ return 0;
+ if (fixups_off < 0)
+ return fixups_off;
+
+ fdt_for_each_property_offset(prop, fdto, fixups_off) {
+ int ret;
+
+ ret = overlay_merge_fixup_into_local_fixups(
+ fdt, fdto, prop, fragment, frag_name, frag_name_len,
+ target_lfp);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * overlay_prune_empty_local_fixups - Remove empty subnodes from /__local_fixups__
+ * @fdt: Base Device Tree blob
+ * @lf_node: Node offset in @fdt's /__local_fixups__ subtree
+ *
+ * overlay_prune_empty_local_fixups() recursively deletes any child subnodes
+ * under @lf_node that have neither properties nor subnodes remaining.
+ *
+ * returns:
+ * 0 on success
+ * Negative error code on failure
+ */
+static int overlay_prune_empty_local_fixups(void *fdt, int lf_node)
+{
+ int subnode = fdt_first_subnode(fdt, lf_node);
+
+ while (subnode >= 0) {
+ int next, ret;
+
+ ret = overlay_prune_empty_local_fixups(fdt, subnode);
+ if (ret < 0)
+ return ret;
+
+ next = fdt_next_subnode(fdt, subnode);
+ if (fdt_first_property_offset(fdt, subnode) == -FDT_ERR_NOTFOUND &&
+ fdt_first_subnode(fdt, subnode) == -FDT_ERR_NOTFOUND) {
+ int old_struct_size = fdt_size_dt_struct(fdt);
+
+ ret = fdt_del_node(fdt, subnode);
+ if (ret < 0)
+ return ret;
+ if (next >= 0)
+ next += fdt_size_dt_struct(fdt) -
+ old_struct_size;
+ }
+ subnode = next;
+ }
+
+ return 0;
+}
+
+/**
+ * overlay_validate_local_fixups - Validate /__local_fixups__ fragment nodes in overlay
+ * @fdto: Device tree overlay blob
+ * @ov_lf_root: Node offset of /__local_fixups__ in @fdto
+ *
+ * overlay_validate_local_fixups() verifies that every fragment subnode under
+ * @ov_lf_root that contains an __overlay__ subnode corresponds to a valid
+ * fragment node at the root of @fdto.
+ *
+ * returns:
+ * 0 on success
+ * Negative error code on failure
+ */
+static int overlay_validate_local_fixups(const void *fdto, int ov_lf_root)
+{
+ int lf_frag;
+
+ fdt_for_each_subnode(lf_frag, fdto, ov_lf_root) {
+ const char *frag_name;
+ int frag_name_len, lf_overlay, fragment;
+
+ frag_name = fdt_get_name(fdto, lf_frag, &frag_name_len);
+ if (!frag_name)
+ return frag_name_len;
+
+ lf_overlay = fdt_subnode_offset(fdto, lf_frag, "__overlay__");
+ if (lf_overlay == -FDT_ERR_NOTFOUND)
+ continue;
+ if (lf_overlay < 0)
+ return lf_overlay;
+
+ fragment = fdt_subnode_offset_namelen(fdto, 0, frag_name,
+ frag_name_len);
+ if (fragment < 0)
+ return -FDT_ERR_BADOVERLAY;
+
+ if (fdt_subnode_offset(fdto, fragment, "__overlay__") < 0)
+ return -FDT_ERR_BADOVERLAY;
+ }
+
+ return 0;
+}
+
+/**
+ * overlay_fragment_local_fixups_src - Find a fragment's __overlay__ in overlay /__local_fixups__
+ * @fdto: Device tree overlay blob
+ * @ov_lf_root: Node offset of /__local_fixups__ in @fdto (or -FDT_ERR_NOTFOUND)
+ * @frag_name: Name of the fragment node
+ * @frag_name_len: Length of @frag_name in bytes
+ *
+ * overlay_fragment_local_fixups_src() locates the __overlay__ subnode for
+ * @frag_name under @ov_lf_root in @fdto.
+ *
+ * returns:
+ * Node offset of /__local_fixups__/<frag_name>/__overlay__ on success
+ * -FDT_ERR_NOTFOUND if @ov_lf_root, <frag_name>, or __overlay__ is absent
+ * Negative error code on other failures
+ */
+static int overlay_fragment_local_fixups_src(const void *fdto, int ov_lf_root,
+ const char *frag_name,
+ int frag_name_len)
+{
+ int lf_frag;
+
+ if (ov_lf_root < 0)
+ return -FDT_ERR_NOTFOUND;
+
+ lf_frag = fdt_subnode_offset_namelen(fdto, ov_lf_root, frag_name,
+ frag_name_len);
+ if (lf_frag < 0)
+ return lf_frag;
+
+ return fdt_subnode_offset(fdto, lf_frag, "__overlay__");
+}
+
+/**
+ * overlay_fragment_update_local_fixups - Update base /__local_fixups__ for one fragment
+ * @fdt: Base Device Tree blob
+ * @fdto: Device tree overlay blob
+ * @fragment: Node offset of the fragment in @fdto
+ * @ov_lf_root: Node offset of /__local_fixups__ in @fdto (or -FDT_ERR_NOTFOUND)
+ *
+ * overlay_fragment_update_local_fixups() clears any base /__local_fixups__
+ * entries overwritten by @fragment, then merges phandle offsets for @fragment
+ * from @fdto's /__local_fixups__ and /__fixups__ subtrees.
+ *
+ * returns:
+ * 0 on success
+ * Negative error code on failure
+ */
+static int overlay_fragment_update_local_fixups(void *fdt, const void *fdto,
+ int fragment, int ov_lf_root)
+{
+ const char *frag_name;
+ int frag_name_len, overlay, target_lf, lf_overlay, ret;
+
+ overlay = fdt_subnode_offset(fdto, fragment, "__overlay__");
+ if (overlay == -FDT_ERR_NOTFOUND)
+ return 0;
+ if (overlay < 0)
+ return overlay;
+
+ frag_name = fdt_get_name(fdto, fragment, &frag_name_len);
+ if (!frag_name)
+ return frag_name_len;
+
+ target_lf = overlay_fragment_local_fixups(fdt, fdto, fragment, false);
+ if (target_lf < 0 && target_lf != -FDT_ERR_NOTFOUND)
+ return target_lf;
+
+ if (target_lf >= 0) {
+ ret = overlay_clear_overwritten_local_fixups(fdt, target_lf,
+ fdto, overlay);
+ if (ret)
+ return ret;
+ }
+
+ lf_overlay = overlay_fragment_local_fixups_src(fdto, ov_lf_root,
+ frag_name,
+ frag_name_len);
+ if (lf_overlay < 0 && lf_overlay != -FDT_ERR_NOTFOUND)
+ return lf_overlay;
+
+ if (lf_overlay >= 0) {
+ if (target_lf < 0)
+ target_lf = overlay_fragment_local_fixups(fdt, fdto,
+ fragment,
+ true);
+ if (target_lf < 0)
+ return target_lf;
+
+ ret = overlay_apply_node(fdt, target_lf, fdto, lf_overlay);
+ if (ret)
+ return ret;
+ }
+
+ return overlay_merge_fixups_into_local_fixups(
+ fdt, fdto, fragment, frag_name, frag_name_len, &target_lf);
+}
+
+/**
+ * overlay_local_fixups_update - Update base /__local_fixups__ with overlay fixups
+ * @fdt: Base Device Tree blob
+ * @fdto: Device tree overlay blob
+ *
+ * overlay_local_fixups_update() updates the base device tree's
+ * /__local_fixups__ subtree (when present) by walking each overlay fragment in
+ * application order, clearing entries for properties overwritten by that
+ * fragment, and merging phandle reference offsets from @fdto's
+ * /__local_fixups__ and /__fixups__ subtrees.
+ *
+ * This is part of the device tree overlay application process, when you want
+ * the merged device tree to retain complete local phandle fixup metadata.
+ *
+ * returns:
+ * 0 on success
+ * Negative error code on failure
+ */
+static int overlay_local_fixups_update(void *fdt, const void *fdto)
+{
+ int root_lf, ov_lf_root, fragment, ret;
+
+ root_lf = fdt_subnode_offset(fdt, 0, "__local_fixups__");
+ if (root_lf == -FDT_ERR_NOTFOUND)
+ return 0;
+ if (root_lf < 0)
+ return root_lf;
+
+ ov_lf_root = fdt_subnode_offset(fdto, 0, "__local_fixups__");
+ if (ov_lf_root >= 0) {
+ ret = overlay_validate_local_fixups(fdto, ov_lf_root);
+ if (ret)
+ return ret;
+ } else if (ov_lf_root != -FDT_ERR_NOTFOUND) {
+ return ov_lf_root;
+ }
+
+ /*
+ * Process fragments in application order so that if a later fragment in
+ * fdto overwrites a property modified by an earlier fragment, the
+ * earlier fragment's local fixups for that property are cleared first.
+ */
+ fdt_for_each_subnode(fragment, fdto, 0) {
+ ret = overlay_fragment_update_local_fixups(fdt, fdto, fragment,
+ ov_lf_root);
+ if (ret)
+ return ret;
+ }
+
+ root_lf = fdt_subnode_offset(fdt, 0, "__local_fixups__");
+ if (root_lf < 0)
+ return root_lf;
+
+ return overlay_prune_empty_local_fixups(fdt, root_lf);
+}
+
int fdt_overlay_apply(void *fdt, void *fdto)
{
uint32_t delta;
@@ -1162,6 +1771,10 @@ int fdt_overlay_apply(void *fdt, void *fdto)
if (ret)
goto err;
+ ret = overlay_local_fixups_update(fdt, fdto);
+ if (ret)
+ goto err;
+
/*
* The overlay has been damaged, erase its magic.
*/
diff --git a/tests/run_tests.sh b/tests/run_tests.sh
index 842b543059bb..e232c86aab37 100755
--- a/tests/run_tests.sh
+++ b/tests/run_tests.sh
@@ -1089,6 +1089,25 @@ fdtoverlay_tests() {
shorten_echo "check phandle to noda d wasn't overwritten: "
run_wrap_test test "$bd" = "$pd"
+
+ # verify that /__local_fixups__ in a -L base blob is updated when applying an overlay
+ run_dtc_test -@ -L -I dts -O dtb -o overlay_base_phandle_lf.test.dtb "$SRCDIR/overlay_base_phandle.dts"
+ run_wrap_test $FDTOVERLAY -i overlay_base_phandle_lf.test.dtb -o overlay_base_phandle_lfO.test.dtb overlay_overlay_phandle.test.dtb
+ run_fdtget_test 0 overlay_base_phandle_lfO.test.dtb /__local_fixups__/b a
+ run_fdtget_test 0 overlay_base_phandle_lfO.test.dtb /__local_fixups__/b d
+ run_fdtget_test 0 overlay_base_phandle_lfO.test.dtb /__local_fixups__/c b
+ run_fdtget_test 0 overlay_base_phandle_lfO.test.dtb /__local_fixups__/d a
+ run_fdtget_test 0 overlay_base_phandle_lfO.test.dtb /__local_fixups__/d b
+ run_fdtget_test 0 overlay_base_phandle_lfO.test.dtb /__local_fixups__/d c
+
+ run_dtc_test -@ -L -I dts -O dtb -o overlay_base_lf.test.dtb "$SRCDIR/overlay_base.dts"
+ run_wrap_test $DTPUT overlay_base_lf.test.dtb -cp /__local_fixups__/test-node/sub-test-node
+ run_wrap_test $DTPUT overlay_base_lf.test.dtb /__local_fixups__/test-node/sub-test-node new-sub-test-property -tu 0
+ run_dtc_test -@ -I dts -O dtb -o overlay_overlay.fdtoverlay.test.dtb "$SRCDIR/overlay_overlay.dts"
+ run_wrap_test $FDTOVERLAY -i overlay_base_lf.test.dtb -o overlay_base_lfO.test.dtb overlay_overlay.fdtoverlay.test.dtb
+ run_fdtget_test "0 4" overlay_base_lfO.test.dtb /__local_fixups__/test-node test-phandle
+ run_fdtget_test "0 4" overlay_base_lfO.test.dtb /__local_fixups__/test-node test-several-phandle
+ run_test check_path overlay_base_lfO.test.dtb not-exists "/__local_fixups__/test-node/sub-test-node"
}
pylibfdt_tests () {
--
2.56.0.313.g2479322e68-goog
next prev parent reply other threads:[~2026-10-28 21:56 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-28 21:46 [PATCH v2 00/10] fdtfactor: Introduce fdtfactor to auto-factor overlays Douglas Anderson
2026-10-28 21:46 ` [PATCH v2 01/10] pylibfdt: Fix FdtSw.as_fdt() when buffer is nearly full Douglas Anderson
2026-10-28 21:46 ` [PATCH v2 02/10] pylibfdt: Add subnode/property iterators and get_mem_rsv_list() Douglas Anderson
2026-10-29 8:38 ` David Gibson
2026-10-28 21:46 ` [PATCH v2 03/10] pylibfdt: Add NodeTree live tree representation Douglas Anderson
2026-10-28 21:46 ` [PATCH v2 04/10] libfdt: overlay: Factor out fixup and fragment path parsing helpers Douglas Anderson
2026-10-28 21:46 ` [PATCH v2 05/10] libfdt: overlay: Prepare fixup and fragment path helpers for reuse Douglas Anderson
2026-10-28 21:46 ` Douglas Anderson [this message]
2026-10-28 21:46 ` [PATCH v2 07/10] fdtfactor: Add tool to split DTBs into a base DTB and overlays Douglas Anderson
2026-10-28 21:46 ` [PATCH v2 08/10] fdtfactor: Add -S/--strip-local-fixups option Douglas Anderson
2026-10-28 21:46 ` [PATCH v2 09/10] fdtfactor: Support compressed DTB inputs and outputs Douglas Anderson
2026-10-28 21:46 ` [PATCH v2 10/10] fdtfactor: Add compiled FIT image factoring support Douglas Anderson
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=20261028215600.1713475-7-dianders@chromium.org \
--to=dianders@chromium.org \
--cc=Devicetree-compiler@vger.kernel.org \
--cc=Devicetree@vger.kernel.org \
--cc=andre.draszik@linaro.org \
--cc=briannorris@chromium.org \
--cc=conor+dt@kernel.org \
--cc=david@gibson.dropbear.id.au \
--cc=jwerner@chromium.org \
--cc=konradybcio@kernel.org \
--cc=krzk+dt@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=peter.griffin@linaro.org \
--cc=robh@kernel.org \
--cc=saravanak@kernel.org \
--cc=sjg@chromium.org \
--cc=tudor.ambarus@linaro.org \
--cc=wenst@chromium.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®