From: Srivatsa Vaddagiri <vatsa@xxxxxxxxxxxxxx> Many overlay fragment nodes that don't have a target node to be overlaid in base device-tree will need to be copied over as-is into base-tree. This includes merging properties found in special nodes such as __fixups__, __symbols__ and __local_fixups__ Signed-off-by: Srivatsa Vaddagiri <vatsa@xxxxxxxxxxxxxx> --- libfdt/fdt_overlay.c | 98 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 94 insertions(+), 4 deletions(-) diff --git a/libfdt/fdt_overlay.c b/libfdt/fdt_overlay.c index 3c2ee88..d3a567f 100644 --- a/libfdt/fdt_overlay.c +++ b/libfdt/fdt_overlay.c @@ -795,9 +795,69 @@ 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 + * @fdt_parent - offset of parent node in base tree under which @fdto_child + * need to be copied + * + * 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) +{ + const char *name, *value; + int offset, len, ret, prop, child; + void *p; + + 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; + } + + fdt_for_each_subnode(child, fdto, fdto_child) { + ret = copy_node(fdt, fdto, offset, child); + if (ret < 0) + return ret; + } + + fdt_for_each_property_offset(prop, fdto, fdto_child) { + int fdt_len = 0; + + value = fdt_getprop_by_offset(fdto, prop, + &name, &len); + + if (fdt_getprop(fdt, offset, name, &fdt_len)) + len += fdt_len; + + ret = fdt_setprop_placeholder(fdt, offset, name, + len, &p); + if (ret < 0) + return ret; + + if (fdt_len > 0) { + p = (char *)p + fdt_len; + len -= fdt_len; + } + + memcpy(p, value, len); + } + + return 0; +} + +/** * overlay_merge - Merge an overlay into its base device tree * @fdt: Base Device Tree blob * @fdto: Device tree overlay blob + * @merge: Both input blobs are overlay blobs that are being merged * * overlay_merge() merges an overlay into its base device tree. * @@ -809,7 +869,7 @@ static int overlay_apply_node(void *fdt, int target, * 0 on success * Negative error code on failure */ -static int overlay_merge(void *fdt, void *fdto) +static int overlay_merge(void *fdt, void *fdto, int merge) { int fragment; @@ -830,8 +890,21 @@ static int overlay_merge(void *fdt, void *fdto) return overlay; target = overlay_get_target(fdt, fdto, fragment, NULL); - if (target < 0) + if (target < 0) { + /* + * No target found which is acceptable situation in case + * of merging two overlay blobs. Copy this fragment to + * base/combined blob, so that it can be considered for + * 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 = overlay_apply_node(fdt, target, fdto, overlay); if (ret) @@ -1081,7 +1154,7 @@ int fdt_overlay_apply(void *fdt, void *fdto) if (ret) goto err; - ret = overlay_merge(fdt, fdto); + ret = overlay_merge(fdt, fdto, 0); if (ret) goto err; @@ -1428,6 +1501,8 @@ static int overlay_merge_local_fixups(void *fdt, void *fdto) return fdto_local_fixups; ret = copy_node(fdt, fdto, 0, fdto_local_fixups); + + return ret; } int fdt_overlay_merge(void *fdt, void *fdto, int *fdto_nospace) @@ -1459,7 +1534,7 @@ int fdt_overlay_merge(void *fdt, void *fdto, int *fdto_nospace) if (ret) goto err; - ret = overlay_merge(fdt, fdto); + ret = overlay_merge(fdt, fdto, 1); if (ret) goto err; @@ -1467,6 +1542,21 @@ int fdt_overlay_merge(void *fdt, void *fdto, int *fdto_nospace) if (ret) goto err; + /* Can't have an overlay without __fixups__ ? */ + ret = overlay_merge_node_properties(fdt, fdto, "/__fixups__"); + if (ret) + goto err; + + /* __symbols__ node need not be present */ + ret = overlay_merge_node_properties(fdt, fdto, "/__symbols__"); + if (ret && ret != -FDT_ERR_NOTFOUND) + goto err; + + /* __local_fixups__ node need not be present */ + ret = overlay_merge_local_fixups(fdt, fdto); + if (ret < 0 && ret != -FDT_ERR_NOTFOUND) + goto err; + /* * The overlay has been damaged, erase its magic. */ -- 2.7.4