Merge __fixups__, __local_fixups__ and __symbols__ section of both overlay blobs in the combined blob. Also copy over fragment nodes from overlay blob into base blob whose target could not yet be identified in base blob. Signed-off-by: Srivatsa Vaddagiri <vatsa@xxxxxxxxxxxxxx> --- libfdt/fdt_overlay.c | 234 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 233 insertions(+), 1 deletion(-) diff --git a/libfdt/fdt_overlay.c b/libfdt/fdt_overlay.c index ac07158..e5f90fd 100644 --- a/libfdt/fdt_overlay.c +++ b/libfdt/fdt_overlay.c @@ -1012,6 +1012,26 @@ static int overlay_apply_node(void *fdt, int target, return 0; } +char **copy_nodes; +int copy_idx; +int copy_size = 512; + +static void mark_for_copy(const char *nodename) +{ + int len = strlen(nodename) + 1; + + if (!copy_nodes) + copy_nodes = xmalloc(copy_size); + + copy_nodes[copy_idx] = xmalloc(len); + memcpy(copy_nodes[copy_idx], nodename, len); + + if (++copy_idx * sizeof(char *) >= copy_size) { + copy_nodes = xrealloc(copy_nodes, copy_size + 512); + copy_size += 512; + } +} + /** * overlay_merge - Merge an overlay into its base device tree * @fdt: Base Device Tree blob @@ -1048,8 +1068,15 @@ static int overlay_merge(void *fdt, void *fdto) return overlay; target = overlay_get_target(fdt, fdto, fragment, NULL); - if (target < 0) + if (target < 0) { + if (base_has_fixups) { + mark_for_copy(fdt_get_name(fdto, + fragment, NULL)); + continue; + } + return target; + } ret = overlay_apply_node(fdt, target, fdto, overlay); if (ret) @@ -1536,6 +1563,190 @@ static int rename_fragments(void **fdto, unsigned long delta) return 0; } +/* Copy 'section' properties from fdto to fdt */ +static int overlay_merge_section(void **fdt, void *fdto, const char *section) +{ + int fdt_offset, fdto_offset, err, property, len; + const char *value, *name; + void *p; + + fdto_offset = fdt_path_offset(fdto, section); + if (fdto_offset < 0) + return fdto_offset; + + fdt_offset = fdt_path_offset(*fdt, section); + if (fdt_offset < 0) { + if (fdt_offset != -FDT_ERR_NOTFOUND) + return fdt_offset; + + fdt_offset = fdt_add_subnode_memcheck(fdt, 0, section); + if (fdt_offset < 0) + return fdt_offset; + } + + fdt_for_each_property_offset(property, fdto, fdto_offset) { + int fdt_len = 0, orig_len = 0; + + value = fdt_getprop_by_offset(fdto, property, + &name, &len); + + /* fdt_len > 0 if property of same name exists, < 0 otherwise */ + if (fdt_getprop(*fdt, fdt_offset, name, &fdt_len) > 0) { + len += fdt_len; + orig_len = fdt_len; + } + + err = fdt_setprop_placeholder_memcheck(fdt, fdt_offset, name, + orig_len, len, &p); + if (err < 0) + return err; + + if (fdt_len > 0) { + len -= fdt_len; + p = (char *)p + fdt_len; + } + + memcpy(p, value, len); + } + + return 0; +} + +static int copy_fdto_node(void **fdt, void *fdto, + int parent_offset, int child_offset) +{ + const char *name, *value; + void *p; + int new_parent_offset, len, rc, prop, offset, err; + + name = fdt_get_name(fdto, child_offset, &len); + if (!name) + return len; + + new_parent_offset = fdt_add_subnode_memcheck(fdt, parent_offset, name); + if (new_parent_offset < 0) + return new_parent_offset; + + fdt_for_each_subnode(offset, fdto, child_offset) { + rc = copy_fdto_node(fdt, fdto, new_parent_offset, offset); + if (rc < 0) + return rc; + } + + fdt_for_each_property_offset(prop, fdto, child_offset) { + value = fdt_getprop_by_offset(fdto, prop, &name, &len); + if (!value) + return len; + + err = fdt_setprop_placeholder_memcheck(fdt, new_parent_offset, + name, 0, len, &p); + if (err < 0) + return err; + + memcpy(p, value, len); + } + + return 0; +} + +/* + * Copy nodes from overlay blob to base blob except those that could be overlaid + * earlier in 'overlay_merge' + */ +static int overlay_copy_nodes(void **fdt, void *fdto) +{ + int i, rc, offset; + char *name; + + for (i = 0; i < copy_idx; ++i) { + name = copy_nodes[i]; + + offset = fdt_subnode_offset(fdto, 0, name); + if (offset < 0) + return offset; + + rc = copy_fdto_node(fdt, fdto, 0, offset); + if (rc < 0) + return rc; + free(name); + } + + return 0; +} + +static int copy_subnode(void **fdt, void *fdto, int fdt_parent, int fdto_child) +{ + const char *name, *value; + int offset, len, rc, prop, err, 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_memcheck(fdt, fdt_parent, name); + if (offset < 0) + return offset; + } + + fdt_for_each_subnode(child, fdto, fdto_child) { + rc = copy_subnode(fdt, fdto, offset, child); + if (rc < 0) + return rc; + } + + 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; + + err = fdt_setprop_placeholder_memcheck(fdt, offset, name, + 0, len, &p); + if (err < 0) + return err; + + if (fdt_len > 0) { + p = (char *)p + fdt_len; + len -= fdt_len; + } + + memcpy(p, value, len); + } + + return 0; +} + +static int overlay_merge_local_fixups(void **fdt, void *fdto) +{ + int fdto_local_fixups, fdt_local_fixups, child, rc; + + fdto_local_fixups = fdt_path_offset(fdto, "/__local_fixups__"); + if (fdto_local_fixups < 0) + return fdto_local_fixups; + + fdt_local_fixups = fdt_path_offset(*fdt, "/__local_fixups__"); + if (fdt_local_fixups < 0) { + fdt_local_fixups = fdt_add_subnode_memcheck(fdt, + 0, "__local_fixups__"); + if (fdt_local_fixups < 0) + return fdt_local_fixups; + } + + fdt_for_each_subnode(child, fdto, fdto_local_fixups) { + rc = copy_subnode(fdt, fdto, fdt_local_fixups, child); + if (rc < 0) + return rc; + } + + return 0; +} + int fdt_overlay_apply(void **fdt, void **fdto) { uint32_t delta = fdt_get_max_phandle(*fdt); @@ -1595,6 +1806,27 @@ int fdt_overlay_apply(void **fdt, void **fdto) if (ret) goto err; + + if (base_has_fixups) { + dprintf(">> merging __fixups__ section\n"); + ret = overlay_merge_section(fdt, *fdto, "/__fixups__"); + if (ret) + dprintf("__fixups__ merge failed\n"); + + dprintf(">> merging __symbols__ section\n"); + ret = overlay_merge_section(fdt, *fdto, "/__symbols__"); + if (ret) + dprintf("__symbols__ merge failed %d\n", ret); + + dprintf(">> merging __local_fixups__ section\n"); + ret = overlay_merge_local_fixups(fdt, *fdto); + if (ret < 0) + return ret; + + dprintf(">> copying nodes\n"); + overlay_copy_nodes(fdt, *fdto); + } + /* * The overlay has been damaged, erase its magic. */ -- 2.7.4 -- QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation -- To unsubscribe from this list: send the line "unsubscribe devicetree-compiler" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html