summaryrefslogtreecommitdiff
path: root/libfdt/fdt_overlay.c
diff options
context:
space:
mode:
Diffstat (limited to 'libfdt/fdt_overlay.c')
-rw-r--r--libfdt/fdt_overlay.c1219
1 files changed, 689 insertions, 530 deletions
diff --git a/libfdt/fdt_overlay.c b/libfdt/fdt_overlay.c
index 52eabd1..d491f00 100644
--- a/libfdt/fdt_overlay.c
+++ b/libfdt/fdt_overlay.c
@@ -12,6 +12,17 @@
#include "libfdt_internal.h"
+#undef DEBUG
+
+#ifdef DEBUG
+#define dprintf(x...) printf(x)
+#else
+#define dprintf(x...)
+#endif
+
+#define MAX_BUF_SIZE 256
+#define MAX_ULONG ((unsigned long)~0UL)
+
/**
* overlay_get_target_phandle - retrieves the target phandle of a fragment
* @fdto: pointer to the device tree overlay blob
@@ -392,138 +403,6 @@ static int overlay_fixup_one_phandle(void *fdt, void *fdto,
sizeof(phandle_prop));
};
-static int overlay_add_to_local_fixups(void *fdt, const char *value, int len)
-{
- const char *path, *fixup_end, *prop, *fixup_str;
- uint32_t clen;
- uint32_t fixup_len;
- char *sep, *endptr;
- const char *c;
- int poffset, nodeoffset, ret, localfixup_off;
- int pathlen, proplen;
- char propname[PATH_MAX];
-
- localfixup_off = fdt_path_offset(fdt, "/__local_fixups__");
- if (localfixup_off < 0 && localfixup_off == -FDT_ERR_NOTFOUND)
- localfixup_off = fdt_add_subnode(fdt, 0, "__local_fixups__");
-
- if (localfixup_off < 0)
- return localfixup_off;
-
- while (len > 0) {
- fixup_str = value;
-
- /* Assumes null-terminated properties! */
- fixup_end = memchr(value, '\0', len);
- if (!fixup_end)
- return -FDT_ERR_BADOVERLAY;
-
- fixup_len = fixup_end - fixup_str;
-
- len -= (fixup_len + 1);
- value += fixup_len + 1;
-
- c = path = fixup_str;
- sep = memchr(c, ':', fixup_len);
- if (!sep || *sep != ':')
- return -FDT_ERR_BADOVERLAY;
- pathlen = sep - path;
- if (pathlen == (fixup_len - 1))
- return -FDT_ERR_BADOVERLAY;
-
- fixup_len -= (pathlen + 1);
- c = path + pathlen + 1;
-
- sep = memchr(c, ':', fixup_len);
- if (!sep || *sep != ':')
- return -FDT_ERR_BADOVERLAY;
-
- prop = c;
- proplen = sep - c;
-
- if (proplen >= PATH_MAX)
- return -FDT_ERR_BADOVERLAY;
-
- /*
- * Skip fixups that involves the special 'target' property found
- * in overlay fragments such as
- * /fragment@0:target:0
- *
- * The check for one node in path below is to ensure that we
- * handle 'target' properties present otherwise in any other
- * node, for ex:
- * /fragment@0/__overlay__/xyz:target:0
- */
-
- /* Does path have exactly one node? */
- c = path;
- clen = pathlen;
- if (*c == '/') {
- c++;
- clen -= 1;
- }
-
- sep = memchr(c, '/', clen);
- if (!sep && proplen >= 6 && !strncmp(prop, "target", 6))
- continue;
-
- memcpy(propname, prop, proplen);
- propname[proplen] = 0;
-
- fixup_len -= (proplen + 1);
- c = prop + proplen + 1;
- poffset = strtoul(c, &endptr, 10);
-
- nodeoffset = localfixup_off;
-
- c = path;
- clen = pathlen;
-
- if (*c == '/') {
- c++;
- clen -= 1;
- }
-
- while (clen > 0) {
- char nodename[PATH_MAX];
- int nodelen, childnode;
-
- sep = memchr(c, '/', clen);
- if (!sep)
- nodelen = clen;
- else
- nodelen = sep - c;
-
- if (nodelen + 1 >= PATH_MAX)
- return -FDT_ERR_BADSTRUCTURE;
- memcpy(nodename, c, nodelen);
- nodename[nodelen] = 0;
-
- childnode = fdt_add_subnode(fdt, nodeoffset, nodename);
- if (childnode == -FDT_ERR_EXISTS)
- childnode = fdt_subnode_offset(fdt,
- nodeoffset, nodename);
- nodeoffset = childnode;
- if (nodeoffset < 0)
- return nodeoffset;
-
- c += nodelen;
- clen -= nodelen;
-
- if (*c == '/') {
- c++;
- clen -= 1;
- }
- }
-
- ret = fdt_appendprop_u32(fdt, nodeoffset, propname, poffset);
- if (ret < 0)
- return ret;
- }
-
- return 0;
-}
-
/**
* overlay_fixup_phandle - Set an overlay phandle to the base one
* @fdt: Base Device Tree blob
@@ -531,7 +410,6 @@ static int overlay_add_to_local_fixups(void *fdt, const char *value, int len)
* @symbols_off: Node offset of the symbols node in the base device tree
* @property: Property offset in the overlay holding the list of fixups
* @fixups_off: Offset of __fixups__ node in @fdto
- * @merge: Both input blobs are overlay blobs that are being merged
*
* overlay_fixup_phandle() resolves all the overlay phandles pointed
* to in a __fixups__ property, and updates them to match the phandles
@@ -546,14 +424,13 @@ static int overlay_add_to_local_fixups(void *fdt, const char *value, int len)
* Negative error code on failure
*/
static int overlay_fixup_phandle(void *fdt, void *fdto, int symbols_off,
- int property, int fixups_off, int merge)
+ int property, int fixups_off)
{
- const char *value, *total_value;
+ const char *value;
const char *label;
- int len, total_len, ret = 0;
+ int len, ret = 0;
- total_value = value = fdt_getprop_by_offset(fdto, property,
- &label, &len);
+ value = fdt_getprop_by_offset(fdto, property, &label, &len);
if (!value) {
if (len == -FDT_ERR_NOTFOUND)
return -FDT_ERR_INTERNAL;
@@ -561,8 +438,6 @@ static int overlay_fixup_phandle(void *fdt, void *fdto, int symbols_off,
return len;
}
- total_len = len;
-
do {
const char *path, *name, *fixup_end;
const char *fixup_str = value;
@@ -609,35 +484,6 @@ static int overlay_fixup_phandle(void *fdt, void *fdto, int symbols_off,
return ret;
} while (len > 0);
- /*
- * Properties found in __fixups__ node are typically one of
- * these types:
- *
- * abc = "/fragment@2:target:0" (first type)
- * abc = "/fragment@2/__overlay__:xyz:0" (second type)
- *
- * Both types could also be present in some properties as well such as:
- *
- * abc = "/fragment@2:target:0", "/fragment@2/__overlay__:xyz:0"
- *
- * While merging two overlay blobs, a successfull overlay phandle fixup
- * of second type needs to be recorded in __local_fixups__ node of the
- * combined blob, so that the phandle value can be further updated via
- * overlay_update_local_references() when the combined overlay blob gets
- * overlaid on a different base blob.
- *
- * Further, since in the case of merging two overlay blobs, we will also
- * be merging contents of nodes such as __fixups__ from both overlay
- * blobs, delete this property in __fixup__ node, as it no longer
- * represents a external phandle reference that needs to be resolved
- * during a subsequent overlay of combined blob on a base blob.
- */
- if (merge) {
- ret = overlay_add_to_local_fixups(fdt, total_value, total_len);
- if (!ret)
- ret = fdt_delprop(fdto, fixups_off, label);
- }
-
return ret;
}
@@ -662,12 +508,12 @@ static int overlay_fixup_phandle(void *fdt, void *fdto, int symbols_off,
static int overlay_fixup_phandles(void *fdt, void *fdto, int merge)
{
int fixups_off, symbols_off;
- int property, ret = 0, next_property;
+ int property, ret = 0;
/* We can have overlays without any fixups */
fixups_off = fdt_path_offset(fdto, "/__fixups__");
if (fixups_off == -FDT_ERR_NOTFOUND)
- return 0; /* nothing to do */
+ return 0; /* nothing to do */
if (fixups_off < 0)
return fixups_off;
@@ -676,40 +522,13 @@ static int overlay_fixup_phandles(void *fdt, void *fdto, int merge)
if ((symbols_off < 0 && (symbols_off != -FDT_ERR_NOTFOUND)))
return symbols_off;
- /* Safeguard against property being deleted in below loop */
- property = fdt_first_property_offset(fdto, fixups_off);
- while (property >= 0) {
- next_property = fdt_next_property_offset(fdto, property);
+ fdt_for_each_property_offset(property, fdto, fixups_off) {
ret = overlay_fixup_phandle(fdt, fdto, symbols_off,
- property, fixups_off, merge);
+ property, fixups_off);
if (ret && (!merge || ret != -FDT_ERR_NOTFOUND))
return ret;
-
- if (merge && !ret) {
- /* Bail if this was the last property */
- if (next_property < 0)
- break;
-
- /*
- * Property is deleted in this case. Next property is
- * available at the same offset, so loop back with
- * 'property' offset unmodified. Also since @fdt would
- * have been modified in this case, refresh the offset
- * of /__symbols__ node
- */
- symbols_off = fdt_path_offset(fdt, "/__symbols__");
- if (symbols_off < 0)
- return symbols_off;
-
- continue;
- }
-
- property = next_property;
}
- if (merge && ret == -FDT_ERR_NOTFOUND)
- ret = 0;
-
return ret;
}
@@ -783,61 +602,176 @@ static int overlay_apply_node(void *fdt, int target,
* copy_node - copy a node hierarchically
* @fdt - pointer to base device tree
* @fdto - pointer to overlay device tree
- * @fdt_child - offset of node in overlay device tree which needs to be copied
+ * @fdto_child - offset of node in overlay device tree which needs to be copied
* @fdt_parent - offset of parent node in base tree under which @fdto_child
* need to be copied
+ * @name - if not NULL, (new) name of the child in base device tree
+ * @skip_fdto_child - if set, skips creation of @fdto_child under @fdt_parent.
+ * Instead copies everything under @fdto_child to @fdt_parent.
*
* This function copies a node in overlay tree along with its child-nodes and
* their properties, under a given parent node in base tree.
*/
-static int copy_node(void *fdt, void *fdto, int fdt_parent, int fdto_child)
+static int copy_node(void *fdt, void *fdto, int fdt_parent,
+ int fdto_child, const char *name, int skip_fdto_child)
{
- const char *name, *value;
- int offset, len, ret, prop, child;
- void *p;
+ int len, prop, parent, child;
- name = fdt_get_name(fdto, fdto_child, &len);
- if (!name)
- return len;
+ if (!skip_fdto_child) {
+ if (!name) {
+ name = fdt_get_name(fdto, fdto_child, &len);
+ if (!name)
+ return len;
+ }
- offset = fdt_subnode_offset(fdt, fdt_parent, name);
- if (offset < 0) {
- offset = fdt_add_subnode(fdt, fdt_parent, name);
- if (offset < 0)
- return offset;
- }
+ parent = fdt_subnode_offset(fdt, fdt_parent, name);
+ if (parent < 0) {
+ parent = fdt_add_subnode(fdt, fdt_parent, name);
+ }
- fdt_for_each_subnode(child, fdto, fdto_child) {
- ret = copy_node(fdt, fdto, offset, child);
- if (ret < 0)
- return ret;
+ if (parent < 0)
+ return parent;
+ } else {
+ parent = fdt_parent;
}
fdt_for_each_property_offset(prop, fdto, fdto_child) {
- int fdt_len = 0;
+ int ret, fdt_len = 0;
+ const char *value, *pname;
+ void *p;
- value = fdt_getprop_by_offset(fdto, prop,
- &name, &len);
+ value = fdt_getprop_by_offset(fdto, prop, &pname, &len);
+ if (!value)
+ return len;
- if (fdt_getprop(fdt, offset, name, &fdt_len))
+ if (fdt_getprop(fdt, parent, pname, &fdt_len))
len += fdt_len;
- ret = fdt_setprop_placeholder(fdt, offset, name,
- len, &p);
- if (ret < 0)
+ ret = fdt_setprop_placeholder(fdt, parent, pname, len, &p);
+ if (ret)
return ret;
- if (fdt_len > 0) {
- p = (char *)p + fdt_len;
- len -= fdt_len;
- }
-
memcpy(p, value, len);
}
+ fdt_for_each_subnode(child, fdto, fdto_child) {
+ int ret;
+
+ ret = copy_node(fdt, fdto, parent, child, NULL, 0);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int get_fragment_name(void *fdto, int fragment, char *name, int namelen)
+{
+ int len;
+ const char *nname;
+ int size = sizeof("fragment@") - 1;
+
+ nname = fdt_get_name(fdto, fragment, &len);
+ if (!nname)
+ return len;
+
+ if (len < size || len >= namelen || memcmp(nname, "fragment@", size))
+ return -FDT_ERR_BADVALUE;
+
+ memcpy(name, nname, len);
+ name[len] = 0;
+
return 0;
}
+static int get_fragment_index(char *name, unsigned long *idxp)
+{
+ char *idx;
+ int size = sizeof("fragment@") - 1;
+ int len = strlen(name);
+ char *stop;
+ unsigned long index;
+
+ if (len < size)
+ return -FDT_ERR_BADVALUE;
+
+ idx = name + size;
+ index = strtoul(idx, &stop, 10);
+ if (*stop != '\0' || stop <= idx)
+ return -FDT_ERR_BADVALUE;
+
+ *idxp = index;
+
+ return 0;
+}
+
+static int set_new_fragment_name(char *name, int namelen,
+ unsigned long base_fragment_count)
+{
+ unsigned long index;
+ int ret;
+
+ ret = get_fragment_index(name, &index);
+ if (ret)
+ return ret;
+
+ if (MAX_ULONG - base_fragment_count < index)
+ return -FDT_ERR_INTERNAL;
+
+ index += base_fragment_count;
+
+ ret = snprintf(name, namelen, "fragment@%lu", index);
+
+ return ret >= namelen ? -FDT_ERR_INTERNAL : 0;
+}
+
+static int add_phandle(void *fdt, char *node_name, uint32_t phandle)
+{
+ int offset;
+
+ offset = fdt_subnode_offset(fdt, 0, node_name);
+ if (offset < 0)
+ return offset;
+
+ return fdt_setprop_u32(fdt, offset, "phandle", phandle);
+}
+
+static int copy_fragment_to_base(void *fdt, void *fdto,
+ int fragment, uint32_t *max_phandle,
+ unsigned long *base_fragment_count)
+{
+ char name[MAX_BUF_SIZE];
+ int ret;
+ uint32_t target_phandle = *max_phandle;
+
+ ret = get_fragment_name(fdto, fragment, name, sizeof(name));
+ if (ret)
+ return ret;
+
+ ret = set_new_fragment_name(name, sizeof(name), *base_fragment_count);
+ if (ret)
+ return ret;
+
+ ret = copy_node(fdt, fdto, 0, fragment, name, 0);
+ if (ret)
+ return ret;
+
+ ret = add_phandle(fdt, name, target_phandle);
+ if (ret)
+ return ret;
+
+ // Fix target to point to new node in base
+ ret = fdt_setprop_inplace_u32(fdto, fragment, "target", target_phandle);
+ if (ret)
+ return ret;
+
+ return (++(*max_phandle) == UINT32_MAX ||
+ ++(*base_fragment_count) == ULONG_MAX) ?
+ -FDT_ERR_BADOVERLAY : 0;
+}
+
+static int count_fragments(void *fdt, unsigned long *max_base_fragments);
+
/**
* overlay_merge - Merge an overlay into its base device tree
* @fdt: Base Device Tree blob
@@ -854,14 +788,24 @@ static int copy_node(void *fdt, void *fdto, int fdt_parent, int fdto_child)
* 0 on success
* Negative error code on failure
*/
-static int overlay_merge(void *fdt, void *fdto, int merge)
+static int overlay_merge(void *fdt, void *fdto, int merge,
+ uint32_t *max_phandle)
{
- int fragment;
+ int fragment, ret;
+ unsigned long base_fragment_count = 0;
+
+ if (merge) {
+ ret = count_fragments(fdt, &base_fragment_count);
+ /* no fragments in base dtb? then nothing to rename */
+ if (ret && ret != -FDT_ERR_NOTFOUND)
+ return ret;
+
+ base_fragment_count++;
+ }
fdt_for_each_subnode(fragment, fdto, 0) {
int overlay;
int target;
- int ret;
/*
* Each fragments will have an __overlay__ node. If
@@ -876,6 +820,9 @@ static int overlay_merge(void *fdt, void *fdto, int merge)
target = fdt_overlay_target_offset(fdt, fdto, fragment, NULL);
if (target < 0) {
+ if (!merge || target != -FDT_ERR_BADPHANDLE)
+ return target;
+
/*
* No target found which is acceptable situation in case
* of merging two overlay blobs. Copy this fragment to
@@ -883,12 +830,13 @@ static int overlay_merge(void *fdt, void *fdto, int merge)
* overlay during a subsequent overlay operation of
* combined blob on another base blob.
*/
- if (target == -FDT_ERR_BADPHANDLE && merge) {
- target = copy_node(fdt, fdto, 0, fragment);
- if (!target)
- continue;
- }
- return target;
+ ret = copy_fragment_to_base(fdt, fdto, fragment,
+ max_phandle,
+ &base_fragment_count);
+ if (ret)
+ return ret;
+
+ continue;
}
ret = overlay_apply_node(fdt, target, fdto, overlay);
@@ -931,7 +879,6 @@ static int get_path_len(const void *fdt, int nodeoffset)
* overlay_symbol_update - Update the symbols of base tree after a merge
* @fdt: Base Device Tree blob
* @fdto: Device tree overlay blob
- * @merge: Both input blobs are overlay blobs that are being merged
*
* overlay_symbol_update() updates the symbols of the base tree with the
* symbols of the applied overlay
@@ -944,15 +891,15 @@ static int get_path_len(const void *fdt, int nodeoffset)
* 0 on success
* Negative error code on failure
*/
-static int overlay_symbol_update(void *fdt, void *fdto, int merge)
+static int overlay_symbol_update(void *fdt, void *fdto, uint32_t max_phandle)
{
int root_sym, ov_sym, prop, next_prop, path_len, fragment, target;
- int len, frag_name_len, ret, rel_path_len;
+ int len, frag_name_len, ret, rel_path_len, rel_path_len1 = 0;
const char *s, *e;
const char *path;
const char *name;
const char *frag_name;
- const char *rel_path;
+ const char *rel_path, *rel_path1 = NULL;
const char *target_path;
char *buf;
void *p;
@@ -985,7 +932,8 @@ static int overlay_symbol_update(void *fdt, void *fdto, int merge)
return path_len;
/* verify it's a string property (terminated by a single \0) */
- if (path_len < 1 || memchr(path, '\0', path_len) != &path[path_len - 1])
+ if (path_len < 1
+ || memchr(path, '\0', path_len) != &path[path_len - 1])
return -FDT_ERR_BADVALUE;
/* keep end marker to avoid strlen() */
@@ -1011,6 +959,11 @@ static int overlay_symbol_update(void *fdt, void *fdto, int merge)
/* /<fragment-name>/__overlay__/<relative-subnode-path> */
rel_path = s + len;
rel_path_len = e - rel_path - 1;
+
+ if (max_phandle != 0) {
+ rel_path1 = s + 1;
+ rel_path_len1 = e - rel_path1 - 1;
+ }
} else if ((e - s) == len
&& (memcmp(s, "/__overlay__", len - 1) == 0)) {
/* /<fragment-name>/__overlay__ */
@@ -1024,7 +977,7 @@ static int overlay_symbol_update(void *fdt, void *fdto, int merge)
/* find the fragment index in which the symbol lies */
ret = fdt_subnode_offset_namelen(fdto, 0, frag_name,
- frag_name_len);
+ frag_name_len);
/* not found? */
if (ret < 0)
return -FDT_ERR_BADOVERLAY;
@@ -1037,14 +990,20 @@ static int overlay_symbol_update(void *fdt, void *fdto, int merge)
/* get the target of the fragment */
ret = fdt_overlay_target_offset(fdt, fdto, fragment, &target_path);
- if (ret < 0) {
- if (ret == -FDT_ERR_BADPHANDLE && merge) {
- prop = next_prop;
- continue;
- }
-
+ if (ret < 0)
return ret;
+
+ if (rel_path1) {
+ uint32_t phandle =
+ overlay_get_target_phandle(fdto, fragment);
+ int base_symbol_found = (phandle < max_phandle);
+
+ if (!base_symbol_found) {
+ rel_path = rel_path1;
+ rel_path_len = rel_path_len1;
+ }
}
+
target = ret;
/* if we have a target path use */
@@ -1058,20 +1017,23 @@ static int overlay_symbol_update(void *fdt, void *fdto, int merge)
}
ret = fdt_setprop_placeholder(fdt, root_sym, name,
- len + (len > 1) + rel_path_len + 1, &p);
+ len + (len >
+ 1) + rel_path_len + 1, &p);
if (ret < 0)
return ret;
if (!target_path) {
/* again in case setprop_placeholder changed it */
- ret = fdt_overlay_target_offset(fdt, fdto, fragment, &target_path);
+ ret =
+ fdt_overlay_target_offset(fdt, fdto, fragment,
+ &target_path);
if (ret < 0)
return ret;
target = ret;
}
buf = p;
- if (len > 1) { /* target is not root */
+ if (len > 1) { /* target is not root */
if (!target_path) {
ret = fdt_get_path(fdt, target, buf, len + 1);
if (ret < 0)
@@ -1086,29 +1048,6 @@ static int overlay_symbol_update(void *fdt, void *fdto, int merge)
memcpy(buf + len + 1, rel_path, rel_path_len);
buf[len + 1 + rel_path_len] = '\0';
- /*
- * In case of merging two overlay blobs, we will be merging
- * contents of nodes such as __symbols__ from both overlay
- * blobs. Delete this property in __symbols__ node of second
- * overlay blob, as it has already been reflected in
- * first/combined blob's __symbols__ node.
- */
- if (merge) {
- ret = fdt_delprop(fdto, ov_sym, name);
- if (ret < 0)
- return ret;
-
- /* Bail if this was the last property */
- if (next_prop < 0)
- break;
-
- /*
- * Continue with same 'prop' offset, as the next
- * property is now available at the same offset
- */
- continue;
- }
-
prop = next_prop;
}
@@ -1139,7 +1078,7 @@ int fdt_overlay_apply(void *fdt, void *fdto)
if (ret)
goto err;
- ret = overlay_merge(fdt, fdto, 0);
+ ret = overlay_merge(fdt, fdto, 0, NULL);
if (ret)
goto err;
@@ -1169,333 +1108,545 @@ err:
return ret;
}
-/*
- * Property value could be in this format
- * fragment@M ...fragment@N....fragment@O..
- *
- * This needs to be converted to
- * fragment@M+delta...fragment@N+delta....fragment@O+delta
- */
-static int rename_fragments_in_property(void *fdto, int offset,
- int property, int delta)
+/* Return maximum count of overlay fragments */
+static int count_fragments(void *fdt, unsigned long *max_base_fragments)
{
- char *start, *sep, *end, *stop, *value;
- int needed = 0, ret, len, found = 0, available, diff;
- unsigned long index, new_index;
- void *p = NULL;
- const char *label;
+ int offset = -1, child_offset, child_len, len, found = 0;
+ const char *name, *child_name, *idx;
+ char *stop;
+ unsigned long index, max = 0;
- value = (char *)(uintptr_t)fdt_getprop_by_offset(fdto, property,
- &label, &len);
- if (!value)
- return len;
+ offset = fdt_first_subnode(fdt, 0);
+ while (offset >= 0) {
+ name = fdt_get_name(fdt, offset, &len);
+ if (!name)
+ return len;
- start = value;
- end = value + len;
+ if (len < 9 || memcmp(name, "fragment@", 9))
+ goto next_node;
- /* Find the required additional space */
- while (start < end) {
- sep = memchr(start, '@', (end - start));
- if (!sep) {
- needed += end - start;
- break;
- }
+ child_offset = fdt_first_subnode(fdt, offset);
+ if (child_offset < 0)
+ return child_offset;
- /* Check if string "fragment" exists */
- sep -= 8;
+ child_name = fdt_get_name(fdt, child_offset, &child_len);
+ if (!child_name)
+ return child_len;
- if (sep < start || strncmp(sep, "fragment", 8)) {
- /* Start scan again after '@' */
- sep = sep + 9;
- needed += (sep - start);
- start = sep;
- continue;
- }
+ if (child_len < 11 || memcmp(child_name, "__overlay__", 11))
+ goto next_node;
found = 1;
- sep += 9;
- needed += (sep - start);
- index = strtoul(sep, &stop, 10);
- if (ULONG_MAX - index < delta)
- return -FDT_ERR_BADVALUE;
-
- new_index = index + delta;
- needed += snprintf(NULL, 0, "%lu", new_index);
- start = stop;
+ idx = name + 9;
+ index = strtoul(idx, &stop, 10);
+ if (index > max)
+ max = index;
+next_node:
+ offset = fdt_next_subnode(fdt, offset);
}
if (!found)
- return 0;
+ return -FDT_ERR_NOTFOUND;
- p = value;
- if (needed > len) {
- ret = fdt_setprop_placeholder(fdto, offset, label, needed, &p);
- if (ret < 0)
- return ret;
- }
+ *max_base_fragments = max;
- start = p;
- end = start + len;
- ret = 0;
+ return 0;
+}
- while (start < end) {
- sep = memchr(start, '@', (end - start));
- if (!sep)
- break;
+static int find_add_subnode(void *fdt, int parent_off, char *node_name)
+{
+ int offset;
- /* Check if string "fragment" exists */
- sep -= 8;
- if (sep < start || strncmp(sep, "fragment", 8)) {
- /* Start scan again after '@' */
- start = sep + 9;
- continue;
- }
+ offset = fdt_subnode_offset(fdt, parent_off, node_name);
- sep += 9;
- index = strtoul(sep, &stop, 10);
- new_index = index + delta;
+ if (offset < 0)
+ offset = fdt_add_subnode(fdt, parent_off, node_name);
- needed = snprintf(NULL, 0, "%lu", new_index);
- available = stop - sep;
+ return offset;
+}
- if (available < needed) {
- diff = needed - available;
- memmove(stop + diff, stop, (end - stop));
- end += diff;
- }
+static int prop_exists_in_node(void *fdt, char *path, const char *prop_name)
+{
+ int offset;
+ const void *val;
- {
- /* +1 for NULL char */
- char buf[needed + 1];
+ offset = fdt_path_offset(fdt, path);
+ if (offset < 0)
+ return 0;
- snprintf(buf, needed + 1, "%lu", new_index);
- memcpy(sep, buf, needed);
- }
+ val = fdt_getprop(fdt, offset, prop_name, NULL);
- start = sep + needed;
- }
+ return val != NULL;
+}
- return 0;
+static void *get_next_component(const char **p, int *len, char sep)
+{
+ char *q;
+ int consumed;
+
+ q = memchr(*p, sep, *len);
+ if (!q)
+ return NULL;
+
+ q++;
+
+ // 1 for ':'
+ consumed = (q - *p);
+ if (*len <= consumed)
+ return NULL;
+
+ *len -= consumed;
+ *p = q;
+
+ return q;
}
-/**
- * rename_fragments_in_node - Rename fragment@xyz instances in a node's
- * properties
- *
- * @fdto - pointer to a device-tree blob
- * @nodename - Node in whose properties fragments need to be renamed
- * @delta - Increment to be applied to fragment index
- */
-static int rename_fragments_in_node(void *fdto, const char *nodename,
- unsigned long delta)
+static int lookup_target_path(void *fdt, void *fdto, const char *fragment,
+ int frag_name_len, char *buf, int buf_len,
+ int *target_phandle)
{
- int offset, property;
- int ret;
+ int offset, ret, target, len;
+ const char *target_path;
+ static const char fragstr[] = "fragment";
+ int fragstrlen = sizeof(fragstr) - 1;
- offset = fdt_path_offset(fdto, nodename);
- if (offset < 0)
- return offset;
+ memset(buf, 0, buf_len);
+
+ if (frag_name_len < fragstrlen || memcmp(fragment, fragstr, fragstrlen))
+ return -FDT_ERR_BADOVERLAY;
+
+ /* find the fragment index in which the symbol lies */
+ ret = fdt_subnode_offset_namelen(fdto, 0, fragment, frag_name_len);
+ /* not found? */
+ if (ret < 0)
+ return -FDT_ERR_BADOVERLAY;
+
+ offset = ret;
- fdt_for_each_property_offset(property, fdto, offset) {
- ret = rename_fragments_in_property(fdto, offset,
- property, delta);
+ /* an __overlay__ subnode must exist */
+ ret = fdt_subnode_offset(fdto, offset, "__overlay__");
+ if (ret < 0)
+ return -FDT_ERR_BADOVERLAY;
+
+ /* get the target of the fragment */
+ ret = fdt_overlay_target_offset(fdt, fdto, offset, &target_path);
+ if (ret < 0)
+ return ret;
+
+ target = ret;
+ if (target_phandle)
+ *target_phandle = ret;
+
+ /* if we have a target path use */
+ if (!target_path) {
+ ret = get_path_len(fdt, target);
if (ret < 0)
return ret;
+ len = ret;
+ } else {
+ len = strlen(target_path);
+ }
+ if (len >= buf_len)
+ return -FDT_ERR_INTERNAL;
+
+ if (len > 1) { /* target is not root */
+ if (!target_path) {
+ ret = fdt_get_path(fdt, target, buf, len + 1);
+ if (ret < 0)
+ return ret;
+ } else
+ memcpy(buf, target_path, len + 1);
+
}
return 0;
}
-/**
- * rename_nodes - Rename all fragement@xyz nodes
- *
- * @fdto - pointer to device-tree blob
- * @parent_node - node offset of parent whose child fragment nodes need to be
- * renamed
- * @delta - increment to be added to fragment number
- */
-static int rename_nodes(void *fdto, int parent_node, unsigned long delta)
+static int fixup_snippet_update(void *fdt, void *fdto, const char *snippet,
+ int snippet_len, char *buf, int buflen,
+ int *ignore, int base_symbol_found,
+ uint32_t max_phandle)
{
- int offset = -1, ret, len, strsize;
- int child_len, child_offset;
- const char *name, *child_name, *idx;
- char *stop = NULL;
- unsigned long index, new_index;
+ const char *snippet_o = snippet;
+ const char *path, *fragment, *prop_name, *prop_val, *rel_path;
+ char *sep;
+ int snippet_len_o = snippet_len, fragment_len, rel_path_len;
+ int prop_len, path_len, rem, ret;
+ static const char tprop[] = "target";
+ static const char frag[] = "/fragment";
+ static const char olay[] = "/__overlay__";
+
+ /* Validate format:
+ * path_to_node : prop_name : prop_offset
+ */
+ path = snippet;
+ prop_name = get_next_component(&snippet, &snippet_len, ':');
+ if (!prop_name)
+ return -FDT_ERR_BADOVERLAY;
- offset = fdt_first_subnode(fdto, parent_node);
- while (offset >= 0) {
- name = fdt_get_name(fdto, offset, &len);
- if (!name)
- return len;
+ prop_val = get_next_component(&snippet, &snippet_len, ':');
+ if (!prop_val)
+ return -FDT_ERR_BADOVERLAY;
- if (len < 9 || strncmp(name, "fragment@", 9))
- goto next_node;
+ path_len = prop_name - path - 1; // 1 for ':'
+ prop_len = prop_val - prop_name - 1; // 1 for ':'
- child_offset = fdt_first_subnode(fdto, offset);
- if (child_offset < 0)
- return child_offset;
+ if (path_len < sizeof(frag) - 1 || memcmp(path, frag, sizeof(frag) - 1))
+ return -FDT_ERR_BADOVERLAY;
- child_name = fdt_get_name(fdto, child_offset, &child_len);
- if (!child_name)
- return child_len;
+ if (base_symbol_found &&
+ prop_len == sizeof(tprop) - 1 &&
+ !memcmp(prop_name, tprop, sizeof(tprop) - 1)) {
+ *ignore = 1;
+ return 0;
+ }
- /* Extra FDT_TAGSIZE bytes for expanded node name */
- strsize = FDT_TAGALIGN(len+1+FDT_TAGSIZE);
+ fragment = path;
+ // check if there is a '/' besides the first one in node_path
+ sep = memchr(fragment + 1, '/', path_len - 1);
+ if (sep) {
+ int fragment_target_found = 0;
+
+ fragment_len = sep - fragment;
+ path_len -= (sep - fragment);
+ if (path_len < sizeof(olay) - 1
+ || memcmp(sep, olay, sizeof(olay) - 1))
+ return -FDT_ERR_BADOVERLAY;
- if (child_len >= 11 &&
- !strncmp(child_name, "__overlay__", 11))
{
- char new_name[strsize];
+ int frag_offset;
- idx = name + 9;
- stop = NULL;
- index = strtoul(idx, &stop, 10);
- if (ULONG_MAX - delta < index)
- return -FDT_ERR_BADVALUE;
+ frag_offset =
+ fdt_subnode_offset_namelen(fdto, 0, fragment + 1,
+ fragment_len - 1);
+ if (frag_offset < 0)
+ return -FDT_ERR_BADOVERLAY;
- new_index = index + delta;
- ret = snprintf(new_name, sizeof(new_name),
- "fragment@%lu", new_index);
- if (ret >= sizeof(new_name))
- return -FDT_ERR_BADVALUE;
+ /* an __overlay__ subnode must exist */
+ ret =
+ fdt_subnode_offset(fdto, frag_offset,
+ "__overlay__");
+ if (ret < 0)
+ return -FDT_ERR_BADOVERLAY;
- ret = fdt_set_name(fdto, offset, new_name);
+ /* get the target of the fragment */
+ ret = overlay_get_target(fdt, fdto, frag_offset, NULL);
if (ret < 0)
return ret;
+
+ fragment_target_found = (ret < max_phandle);
}
-next_node:
- offset = fdt_next_subnode(fdto, offset);
+ if (fragment_target_found)
+ rel_path = sep + sizeof(olay) - 1;
+ else
+ rel_path = sep;
+ } else {
+ rel_path = fragment + path_len;
+ fragment_len = path_len;
}
+ rel_path_len = snippet_len_o - (rel_path - snippet_o);
+
+ if (rel_path_len <= 0 || fragment_len >= buflen)
+ return -FDT_ERR_INTERNAL;
+
+ ret =
+ lookup_target_path(fdt, fdto, fragment + 1, fragment_len - 1, buf,
+ buflen, NULL);
+ if (ret)
+ return ret;
+
+ rem = buflen - strlen(buf);
+ if (rel_path_len >= rem)
+ return -FDT_ERR_INTERNAL;
+
+ sep = buf + strlen(buf);
+ memcpy(sep, rel_path, rel_path_len);
return 0;
}
-/* Return maximum count of overlay fragments */
-static int count_fragments(void *fdt, unsigned long *max_base_fragments)
+static const char *next_snippet(const char **prop,
+ int *prop_len, int *snippet_len)
{
- int offset = -1, child_offset, child_len, len, found = 0;
- const char *name, *child_name, *idx;
- char *stop;
- unsigned long index, max = 0;
+ const char *next = *prop;
+ const char *tmp;
+ int len;
- offset = fdt_first_subnode(fdt, 0);
- while (offset >= 0) {
- name = fdt_get_name(fdt, offset, &len);
- if (!name)
- return len;
+ if (*prop_len <= 0)
+ return NULL;
- if (len < 9 || strncmp(name, "fragment@", 9))
- goto next_node;
+ tmp = memchr(next, '\0', *prop_len);
+ if (!tmp)
+ return NULL;
- child_offset = fdt_first_subnode(fdt, offset);
- if (child_offset < 0)
- return child_offset;
+ tmp++;
- child_name = fdt_get_name(fdt, child_offset, &child_len);
- if (!child_name)
- return child_len;
+ len = tmp - next;
+ *snippet_len = len;
+ *prop += len;
+ *prop_len -= len;
- if (child_len < 11 || strncmp(child_name, "__overlay__", 11))
- goto next_node;
+ return next;
+}
- found = 1;
- idx = name + 9;
- index = strtoul(idx, &stop, 10);
- if (index > max)
- max = index;
-next_node:
- offset = fdt_next_subnode(fdt, offset);
- }
+static int add_to_fixups(void *fdt, char *v, const char *label)
+{
+ const char *val;
+ char *p;
+ int vlen = strlen(v) + 1; // 1 for NULL
+ int len, ret;
+ int root_fixup;
- if (!found)
- return -FDT_ERR_NOTFOUND;
+ root_fixup = fdt_subnode_offset(fdt, 0, "__fixups__");
+ if (root_fixup == -FDT_ERR_NOTFOUND)
+ root_fixup = fdt_add_subnode(fdt, 0, "__fixups__");
- *max_base_fragments = max;
+ if (root_fixup < 0)
+ return root_fixup;
+
+ val = fdt_getprop(fdt, root_fixup, label, &len);
+ if (val)
+ vlen += len;
+
+ ret = fdt_setprop_placeholder(fdt, root_fixup, label,
+ vlen, (void **)&p);
+ if (ret)
+ return ret;
+
+ if (val) {
+ p += len;
+ vlen -= len;
+ }
+ memcpy(p, v, vlen);
return 0;
}
-/*
- * Merging two overlay blobs involves copying some of the overlay fragment nodes
- * (named as fragment@xyz) from second overlay blob into first, which can lead
- * to naming conflicts (ex: two nodes of same name /fragment@0). To prevent such
- * naming conflicts, rename all occurences of fragment@xyz in second overlay
- * blob as fragment@xyz+delta, where delta is the maximum overlay fragments seen
- * in first overlay blob
- */
-static int overlay_rename_fragments(void *fdt, void *fdto)
+static int fdt_find_add_node(void *fdt, int parent_off, char *node)
{
- int ret, local_offset;
- unsigned long max_base_fragments = 0;
+ int offset;
- ret = count_fragments(fdt, &max_base_fragments);
- /* no fragments in base dtb? then nothing to rename */
- if (ret == -FDT_ERR_NOTFOUND)
- return 0;
- else if (ret < 0)
- return ret;
+ offset = fdt_subnode_offset(fdt, parent_off, node);
+ if (offset < 0)
+ offset = fdt_add_subnode(fdt, parent_off, node);
- max_base_fragments += 1;
- ret = rename_nodes(fdto, 0, max_base_fragments);
- if (ret < 0)
- return ret;
+ return offset;
+}
- ret = rename_fragments_in_node(fdto, "/__fixups__", max_base_fragments);
- if (ret < 0)
- return ret;
+/* path => /abc/def/ghi */
+static const char *next_node(const char **path, int *path_len, int *node_len)
+{
+ const char *sep = *path, *node;
- ret = rename_fragments_in_node(fdto, "/__symbols__",
- max_base_fragments);
- if (ret < 0 && ret != -FDT_ERR_NOTFOUND)
- return ret;
+ if (*sep != '/' || *path_len <= 0)
+ return NULL;
- /*
- * renaming fragments in __local_fixups__ node's properties should be
- * covered by rename_nodes()
+ *path = *path + 1;
+ node = *path;
+ *path_len = *path_len - 1;
+
+ sep = memchr(node, '/', *path_len);
+ if (sep)
+ *node_len = sep - node;
+ else
+ *node_len = *path_len;
+
+ *path_len -= *node_len;
+ *path += *node_len;
+
+ return node;
+}
+
+static int convert_to_u32(const char *p, uint32_t *val)
+{
+ char *endptr;
+ unsigned long prop_val;
+
+ prop_val = strtoul(p, &endptr, 10);
+ if ((*endptr != '\0') || (endptr <= p))
+ return -FDT_ERR_BADOVERLAY;
+
+ *val = prop_val; // size mis-match?
+
+ return 0;
+}
+
+static int add_to_local_fixups(void *fdt, const char *snippet)
+{
+ const char *path, *prop_name, *prop_val, *node;
+ int path_len, parent, ret, node_len, prop_len = 0;
+ int snippet_len = strlen(snippet);
+ uint32_t val = 0;
+ char buf[MAX_BUF_SIZE];
+
+ /* Validate format:
+ * path_to_node : prop_name : prop_offset
+ * OR
+ * path_to_node
*/
- local_offset = fdt_path_offset(fdto, "/__local_fixups__");
- if (local_offset >= 0)
- ret = rename_nodes(fdto, local_offset, max_base_fragments);
+ path = snippet;
+ prop_name = get_next_component(&snippet, &snippet_len, ':');
+ if (prop_name) {
+ prop_val = get_next_component(&snippet, &snippet_len, ':');
+ if (!prop_val)
+ return -FDT_ERR_BADOVERLAY;
- if (ret == -FDT_ERR_NOTFOUND)
- ret = 0;
+ path_len = prop_name - path - 1; // 1 for ':'
+ prop_len = prop_val - prop_name - 1; // 1 for ':'
- return ret;
+ ret = convert_to_u32(prop_val, &val);
+ if (ret)
+ return ret;
+ } else
+ path_len = strlen(snippet);
+
+ parent = fdt_find_add_node(fdt, 0, "__local_fixups__");
+ if (parent < 0)
+ return parent;
+
+ while ((node = next_node(&path, &path_len, &node_len))) {
+ int offset;
+
+ offset =
+ fdt_subnode_offset_namelen(fdt, parent, node, node_len);
+ if (offset < 0)
+ offset =
+ fdt_add_subnode_namelen(fdt, parent, node,
+ node_len);
+ if (offset < 0)
+ return offset;
+ parent = offset;
+ }
+
+ if (!prop_name)
+ return parent;
+
+ if (prop_len >= sizeof(buf))
+ return -FDT_ERR_INTERNAL;
+ memcpy(buf, prop_name, prop_len);
+ buf[prop_len] = 0;
+ if (ret >= prop_len)
+ return -FDT_ERR_INTERNAL;
+
+ return fdt_appendprop_u32(fdt, parent, buf, val);
}
-/* merge a node's properties from fdto to fdt */
-static int overlay_merge_node_properties(void *fdt,
- void *fdto, const char *nodename)
+static int overlay_fixups_update(void *fdt, void *fdto, uint32_t max_phandle)
{
- int fdto_offset, ret;
+ int ov_fixup, root_fixup, prop;
- fdto_offset = fdt_path_offset(fdto, nodename);
- if (fdto_offset < 0)
- return fdto_offset;
+ ov_fixup = fdt_subnode_offset(fdto, 0, "__fixups__");
+ if (ov_fixup < 0)
+ return 0;
- ret = copy_node(fdt, fdto, 0, fdto_offset);
+ root_fixup = find_add_subnode(fdt, 0, "__fixups__");
+ if (root_fixup < 0)
+ return root_fixup;
- return ret;
+ fdt_for_each_property_offset(prop, fdto, ov_fixup) {
+ int snippet_len, prop_len, base_symbol_found;
+ const char *label, *snippet, *prop_val;
+
+ prop_val = fdt_getprop_by_offset(fdto, prop, &label, &prop_len);
+ if (prop_val == NULL)
+ return -FDT_ERR_BADOVERLAY;
+
+ base_symbol_found =
+ prop_exists_in_node(fdt, "/__symbols__", label);
+ dprintf
+ ("%s: Checking prop label %s val %s base_symbol_found %d\n",
+ __func__, label, prop_val, base_symbol_found);
+
+ while ((snippet =
+ next_snippet(&prop_val, &prop_len, &snippet_len))) {
+ char new_val[MAX_BUF_SIZE];
+ int ignore = 0, ret;
+
+ ret =
+ fixup_snippet_update(fdt, fdto, snippet,
+ snippet_len, new_val,
+ sizeof(new_val), &ignore,
+ base_symbol_found,
+ max_phandle);
+ dprintf
+ ("%s: fixup_snippet %s new_val %s ret %d ignore %d\n",
+ __func__, snippet, new_val, ret, ignore);
+ if (ret)
+ return ret;
+
+ if (ignore)
+ continue;
+
+ if (!base_symbol_found)
+ ret = add_to_fixups(fdt, new_val, label);
+ else
+ ret = add_to_local_fixups(fdt, new_val);
+
+ if (ret)
+ return ret;
+ }
+ }
+
+ return 0;
}
-static int overlay_merge_local_fixups(void *fdt, void *fdto)
+static int overlay_local_fixups_update(void *fdt, void *fdto,
+ uint32_t max_phandle)
{
- int fdto_local_fixups, ret;
+ int ov_lfixups, root_lfixups, node, ret;
- fdto_local_fixups = fdt_path_offset(fdto, "/__local_fixups__");
- if (fdto_local_fixups < 0)
- return fdto_local_fixups;
+ ov_lfixups = fdt_subnode_offset(fdto, 0, "__local_fixups__");
+ if (ov_lfixups == -FDT_ERR_NOTFOUND)
+ return 0;
- ret = copy_node(fdt, fdto, 0, fdto_local_fixups);
+ root_lfixups = fdt_subnode_offset(fdt, 0, "__local_fixups__");
+ if (root_lfixups == -FDT_ERR_NOTFOUND)
+ root_lfixups = fdt_add_subnode(fdt, 0, "__local_fixups__");
- return ret;
+ if (root_lfixups < 0)
+ return root_lfixups;
+
+ fdt_for_each_subnode(node, fdto, ov_lfixups) {
+ int len, child_node, target_phandle, parent_node;
+ int skip_fdto_child = 0;
+ int base_symbol_found;
+ const char *name = fdt_get_name(fdto, node, &len);
+ char buf[MAX_BUF_SIZE];
+
+ ret = lookup_target_path(fdt, fdto, name, strlen(name),
+ buf, sizeof(buf), &target_phandle);
+ if (ret)
+ return ret;
+
+ base_symbol_found = !(target_phandle >= max_phandle);
+
+ parent_node = add_to_local_fixups(fdt, buf);
+ if (parent_node < 0)
+ return parent_node;
+
+ child_node = fdt_subnode_offset(fdto, node, "__overlay__");
+ if (child_node < 0)
+ return -FDT_ERR_BADOVERLAY;
+
+ if (base_symbol_found)
+ skip_fdto_child = 1;
+
+ ret = copy_node(fdt, fdto, parent_node, child_node,
+ NULL, skip_fdto_child);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
}
int fdt_overlay_merge(void *fdt, void *fdto, int *fdto_nospace)
{
uint32_t delta = fdt_get_max_phandle(fdt);
+ uint32_t delta0 = fdt_get_max_phandle(fdto);
+ uint32_t max_phandle;
int ret;
fdt_check_header(fdt);
@@ -1503,45 +1654,52 @@ int fdt_overlay_merge(void *fdt, void *fdto, int *fdto_nospace)
*fdto_nospace = 0;
- ret = overlay_rename_fragments(fdt, fdto);
+ if (UINT32_MAX - delta < delta0)
+ return -FDT_ERR_BADOVERLAY;
+ max_phandle = delta + delta0 + 1;
+ dprintf("delta %u max_phandle %u\n", delta, max_phandle);
+
+ ret = overlay_adjust_local_phandles(fdto, delta);
+ dprintf("adjust_local_phandles %d\n", ret);
if (ret) {
if (ret == -FDT_ERR_NOSPACE)
*fdto_nospace = 1;
goto err;
}
- ret = overlay_adjust_local_phandles(fdto, delta);
- if (ret)
- goto err;
-
ret = overlay_update_local_references(fdto, delta);
- if (ret)
+ dprintf("update_local_references %d\n", ret);
+ if (ret) {
+ if (ret == -FDT_ERR_NOSPACE)
+ *fdto_nospace = 1;
goto err;
+ }
ret = overlay_fixup_phandles(fdt, fdto, 1);
- if (ret)
- goto err;
-
- ret = overlay_merge(fdt, fdto, 1);
- if (ret)
+ dprintf("fixup_phandles %d\n", ret);
+ if (ret && ret != -FDT_ERR_NOTFOUND)
goto err;
- ret = overlay_symbol_update(fdt, fdto, 1);
+ ret = overlay_merge(fdt, fdto, 1, &max_phandle);
+ dprintf("overlay_merge %d\n", ret);
if (ret)
goto err;
- /* Can't have an overlay without __fixups__ ? */
- ret = overlay_merge_node_properties(fdt, fdto, "/__fixups__");
+ /* local_fixups node is optional */
+ max_phandle = delta + delta0 + 1;
+ ret = overlay_symbol_update(fdt, fdto, max_phandle);
+ dprintf("overlay_symbol_update %d\n", ret);
if (ret)
goto err;
- /* __symbols__ node need not be present */
- ret = overlay_merge_node_properties(fdt, fdto, "/__symbols__");
- if (ret && ret != -FDT_ERR_NOTFOUND)
+ /* fixups node is optional */
+ ret = overlay_fixups_update(fdt, fdto, max_phandle);
+ dprintf("overlay_fixups_update %d\n", ret);
+ if (ret < 0 && ret != -FDT_ERR_NOTFOUND)
goto err;
- /* __local_fixups__ node need not be present */
- ret = overlay_merge_local_fixups(fdt, fdto);
+ ret = overlay_local_fixups_update(fdt, fdto, max_phandle);
+ dprintf("overlay_local_fixups_update %d\n", ret);
if (ret < 0 && ret != -FDT_ERR_NOTFOUND)
goto err;
@@ -1550,6 +1708,7 @@ int fdt_overlay_merge(void *fdt, void *fdto, int *fdto_nospace)
*/
fdt_set_magic(fdto, ~0);
+ dprintf("overlay_merge completed successfully!\n");
return 0;
err: