diff --git a/buildroot-external/patches/barebox/0001-drivers-of-implement-overlay-support.patch b/buildroot-external/patches/barebox/0001-drivers-of-implement-overlay-support.patch index 3dd6fb4b4..c510a91f0 100644 --- a/buildroot-external/patches/barebox/0001-drivers-of-implement-overlay-support.patch +++ b/buildroot-external/patches/barebox/0001-drivers-of-implement-overlay-support.patch @@ -1,19 +1,23 @@ -From 059762285f200a6e2527a4447d35f34d66b07bc2 Mon Sep 17 00:00:00 2001 +From 0ea63818330f3ebe989a56df89c1f49c63e7d761 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli -Date: Sun, 27 May 2018 09:33:20 +0000 +Date: Sun, 27 May 2018 14:40:45 +0000 Subject: [PATCH 1/2] drivers: of: implement overlay support Signed-off-by: Pascal Vizeli --- - Documentation/user/devicetree.rst | 101 +++++++++++++++++++++++++++++- + Documentation/user/devicetree.rst | 101 ++++++++- arch/sandbox/dts/Makefile | 5 +- - arch/sandbox/dts/sandbox.dts | 6 ++ - commands/oftree.c | 65 +++++++++++++++++-- - drivers/of/Kconfig | 6 ++ + arch/sandbox/dts/sandbox.dts | 6 + + commands/oftree.c | 65 +++++- + drivers/of/Kconfig | 6 + drivers/of/Makefile | 1 + - include/of.h | 71 +++++++++++++++++++++ + drivers/of/overlay.c | 234 ++++++++++++++++++++ + drivers/of/resolver.c | 346 ++++++++++++++++++++++++++++++ + include/of.h | 71 ++++++ scripts/Makefile.lib | 5 +- - 8 files changed, 251 insertions(+), 9 deletions(-) + 10 files changed, 831 insertions(+), 9 deletions(-) + create mode 100644 drivers/of/overlay.c + create mode 100644 drivers/of/resolver.c diff --git a/Documentation/user/devicetree.rst b/Documentation/user/devicetree.rst index 17934d86e..b2220997d 100644 @@ -314,6 +318,598 @@ index ec4387006..323543461 100644 obj-$(CONFIG_MTD) += of_mtd.o obj-$(CONFIG_OF_BAREBOX_DRIVERS) += barebox.o +obj-$(CONFIG_OFTREE_OVERLAY) += resolver.o overlay.o +diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c +new file mode 100644 +index 000000000..a711a353f +--- /dev/null ++++ b/drivers/of/overlay.c +@@ -0,0 +1,234 @@ ++/* ++ * Functions for working with device tree overlays ++ * ++ * Copyright (C) 2012 Pantelis Antoniou ++ * Copyright (C) 2012 Texas Instruments Inc. ++ * Copyright (C) 2015 Pengutronix, Jan Luebbe ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * version 2 as published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/** ++ * Apply a single overlay node recursively. ++ * ++ * All the property notifiers are appropriately called. ++ * Note that the in case of an error the target node is left ++ * in a inconsistent state. Error recovery should be performed ++ * by recording the modification using the of notifiers. ++ */ ++static int of_overlay_apply_one(struct device_node *target, ++ const struct device_node *overlay) ++{ ++ struct device_node *child, *tchild; ++ struct property *prop; ++ int ret; ++ ++ /* sanity checks */ ++ if (target == NULL || overlay == NULL) ++ return -EINVAL; ++ ++ for_each_property_of_node(overlay, prop) { ++ /* don't touch, 'name' */ ++ if (of_prop_cmp(prop->name, "name") == 0) ++ continue; ++ ++ of_delete_property(of_find_property(target, prop->name, NULL)); ++ ++ if (of_new_property(target, prop->name, prop->value, prop->length) == NULL) ++ return -ENOMEM; ++ } ++ ++ for_each_child_of_node(overlay, child) { ++ tchild = of_get_child_by_name(target, child->name); ++ if (tchild != NULL) { ++ /* apply overlay recursively */ ++ ret = of_overlay_apply_one(tchild, child); ++ ++ if (ret != 0) ++ return ret; ++ } else { ++ /* create new child */ ++ tchild = of_new_node(target, child->name); ++ if (tchild == NULL) ++ return -ENOMEM; ++ ++ /* apply the overlay */ ++ ret = of_overlay_apply_one(tchild, child); ++ if (ret != 0) { ++ of_delete_node(tchild); ++ return ret; ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++/** ++ * of_overlay - Apply @count overlays pointed at by @ovinfo_tab ++ * @count: Number of of_overlay_info's ++ * @ovinfo_tab: Array of overlay_info's to apply ++ * ++ * Applies the overlays given, while handling all error conditions ++ * appropriately. Either the operation succeeds, or if it fails the ++ * live tree is reverted to the state before the attempt. ++ * Returns 0, or an error if the overlay attempt failed. ++ */ ++int of_overlay(int count, struct of_overlay_info *ovinfo_tab) ++{ ++ struct of_overlay_info *ovinfo; ++ int i, err; ++ ++ if (!ovinfo_tab) ++ return -EINVAL; ++ ++ for (i = 0; i < count; i++) { ++ ovinfo = &ovinfo_tab[i]; ++ err = of_overlay_apply_one(ovinfo->target, ovinfo->overlay); ++ if (err != 0) { ++ pr_err("%s: overlay failed '%s'\n", ++ __func__, ovinfo->target->full_name); ++ goto err_fail; ++ } ++ } ++ ++ return 0; ++ ++err_fail: ++ return err; ++} ++ ++/** ++ * of_fill_overlay_info - Fill an overlay info structure ++ * @info_node: Device node containing the overlay ++ * @ovinfo: Pointer to the overlay info structure to fill ++ * ++ * Fills an overlay info structure with the overlay information ++ * from a device node. This device node must have a target property ++ * which contains a phandle of the overlay target node, and an ++ * __overlay__ child node which has the overlay contents. ++ * Both ovinfo->target & ovinfo->overlay have their references taken. ++ * ++ * Returns 0 on success, or a negative error value. ++ */ ++int of_fill_overlay_info(struct device_node *info_node, ++ struct of_overlay_info *ovinfo) ++{ ++ const char *target_path; ++ u32 target_handle; ++ int ret; ++ ++ if (!info_node || !ovinfo) ++ return -EINVAL; ++ ++ ret = of_property_read_u32(info_node, "target", &target_handle); ++ if (ret == 0) { ++ ovinfo->target = of_find_node_by_phandle(target_handle); ++ } else { ++ ret = of_property_read_string(info_node, "target-path", &target_path); ++ if (ret == 0) { ++ ovinfo->target = of_find_node_by_path(target_path); ++ } ++ } ++ if (ovinfo->target == NULL) ++ goto err_fail; ++ ++ ovinfo->overlay = of_get_child_by_name(info_node, "__overlay__"); ++ if (ovinfo->overlay == NULL) ++ goto err_fail; ++ ++ return 0; ++ ++err_fail: ++ memset(ovinfo, 0, sizeof(*ovinfo)); ++ return -EINVAL; ++} ++ ++/** ++ * of_build_overlay_info - Build an overlay info array ++ * @tree: Device node containing all the overlays ++ * @cntp: Pointer to where the overlay info count will be help ++ * @ovinfop: Pointer to the pointer of an overlay info structure. ++ * ++ * Helper function that given a tree containing overlay information, ++ * allocates and builds an overlay info array containing it, ready ++ * for use using of_overlay. ++ * ++ * Returns 0 on success with the @cntp @ovinfop pointers valid, ++ * while on error a negative error value is returned. ++ */ ++int of_build_overlay_info(struct device_node *tree, ++ int *cntp, struct of_overlay_info **ovinfop) ++{ ++ struct device_node *node; ++ struct of_overlay_info *ovinfo; ++ int cnt, err; ++ ++ if (tree == NULL || cntp == NULL || ovinfop == NULL) ++ return -EINVAL; ++ ++ /* worst case; every child is a node */ ++ cnt = 0; ++ for_each_child_of_node(tree, node) ++ cnt++; ++ ++ ovinfo = kzalloc(cnt * sizeof(*ovinfo), GFP_KERNEL); ++ if (ovinfo == NULL) ++ return -ENOMEM; ++ ++ cnt = 0; ++ for_each_child_of_node(tree, node) { ++ memset(&ovinfo[cnt], 0, sizeof(*ovinfo)); ++ err = of_fill_overlay_info(node, &ovinfo[cnt]); ++ if (err == 0) ++ cnt++; ++ } ++ ++ /* if nothing filled, return error */ ++ if (cnt == 0) { ++ kfree(ovinfo); ++ return -ENODEV; ++ } ++ ++ *cntp = cnt; ++ *ovinfop = ovinfo; ++ ++ return 0; ++} ++ ++/** ++ * of_free_overlay_info - Free an overlay info array ++ * @count: Number of of_overlay_info's ++ * @ovinfo_tab: Array of overlay_info's to free ++ * ++ * Releases the memory of a previously allocate ovinfo array ++ * by of_build_overlay_info. ++ * Returns 0, or an error if the arguments are bogus. ++ */ ++int of_free_overlay_info(int count, struct of_overlay_info *ovinfo_tab) ++{ ++ struct of_overlay_info *ovinfo; ++ int i; ++ ++ if (!ovinfo_tab || count < 0) ++ return -EINVAL; ++ ++ /* do it in reverse */ ++ for (i = count - 1; i >= 0; i--) ++ ovinfo = &ovinfo_tab[i]; ++ ++ kfree(ovinfo_tab); ++ ++ return 0; ++} +diff --git a/drivers/of/resolver.c b/drivers/of/resolver.c +new file mode 100644 +index 000000000..62476093c +--- /dev/null ++++ b/drivers/of/resolver.c +@@ -0,0 +1,346 @@ ++/* ++ * Functions for dealing with DT resolution ++ * ++ * Copyright (C) 2012 Pantelis Antoniou ++ * Copyright (C) 2012 Texas Instruments Inc. ++ * Copyright (C) 2015 Pengutronix, Jan Luebbe ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * version 2 as published by the Free Software Foundation. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/** ++ * Adjust a subtree's phandle values by a given delta. ++ * Makes sure not to just adjust the device node's phandle value, ++ * but modify the phandle properties values as well. ++ */ ++static void of_adjust_tree_phandles(struct device_node *node, ++ int phandle_delta) ++{ ++ struct device_node *child; ++ struct property *prop; ++ phandle phandle; ++ ++ /* first adjust the node's phandle direct value */ ++ if (node->phandle != 0 && node->phandle != OF_PHANDLE_ILLEGAL) ++ node->phandle += phandle_delta; ++ ++ /* now adjust phandle & linux,phandle values */ ++ for_each_property_of_node(node, prop) { ++ /* only look for these two */ ++ if (of_prop_cmp(prop->name, "phandle") != 0 && ++ of_prop_cmp(prop->name, "linux,phandle") != 0) ++ continue; ++ ++ /* must be big enough */ ++ if (prop->length < 4) ++ continue; ++ ++ /* read phandle value */ ++ phandle = be32_to_cpu(*(uint32_t *)prop->value); ++ if (phandle == OF_PHANDLE_ILLEGAL) /* unresolved */ ++ continue; ++ ++ /* adjust */ ++ *(uint32_t *)prop->value = cpu_to_be32(node->phandle); ++ } ++ ++ /* now do the children recursively */ ++ for_each_child_of_node(node, child) ++ of_adjust_tree_phandles(child, phandle_delta); ++} ++ ++/** ++ * Adjust the local phandle references by the given phandle delta. ++ * Assumes the existances of a __local_fixups__ node at the root ++ * of the tree. Does not take any devtree locks so make sure you ++ * call this on a tree which is at the detached state. ++ */ ++static int of_adjust_tree_phandle_references(struct device_node *node, ++ int phandle_delta) ++{ ++ phandle phandle; ++ struct device_node *refnode, *child; ++ struct property *rprop, *sprop; ++ char *propval, *propcur, *propend, *nodestr, *propstr, *s; ++ int offset, propcurlen; ++ int err; ++ bool found = false; ++ ++ /* locate the symbols & fixups nodes on resolve */ ++ for_each_child_of_node(node, child) ++ if (of_node_cmp(child->name, "__local_fixups__") == 0) { ++ found = true; ++ break; ++ } ++ ++ /* no local fixups */ ++ if (!found) ++ return 0; ++ ++ /* find the local fixups property */ ++ for_each_property_of_node(child, rprop) { ++ /* skip properties added automatically */ ++ if (of_prop_cmp(rprop->name, "name") == 0) ++ continue; ++ ++ /* make a copy */ ++ propval = kmalloc(rprop->length, GFP_KERNEL); ++ if (propval == NULL) { ++ pr_err("%s: Could not copy value of '%s'\n", ++ __func__, rprop->name); ++ return -ENOMEM; ++ } ++ memcpy(propval, rprop->value, rprop->length); ++ ++ propend = propval + rprop->length; ++ for (propcur = propval; propcur < propend; ++ propcur += propcurlen + 1) { ++ ++ propcurlen = strlen(propcur); ++ ++ nodestr = propcur; ++ s = strchr(propcur, ':'); ++ if (s == NULL) { ++ pr_err("%s: Illegal symbol entry '%s' (1)\n", ++ __func__, propcur); ++ err = -EINVAL; ++ goto err_fail; ++ } ++ *s++ = '\0'; ++ ++ propstr = s; ++ s = strchr(s, ':'); ++ if (s == NULL) { ++ pr_err("%s: Illegal symbol entry '%s' (2)\n", ++ __func__, (char *)rprop->value); ++ err = -EINVAL; ++ goto err_fail; ++ } ++ ++ *s++ = '\0'; ++ offset = simple_strtoul(s, NULL, 10); ++ ++ /* look into the resolve node for the full path */ ++ refnode = of_find_node_by_path_from(node, nodestr); ++ if (refnode == NULL) { ++ pr_warn("%s: Could not find refnode '%s'\n", ++ __func__, (char *)rprop->value); ++ continue; ++ } ++ ++ /* now find the property */ ++ found = false; ++ for_each_property_of_node(refnode, sprop) ++ if (of_prop_cmp(sprop->name, propstr) == 0) { ++ found = true; ++ break; ++ } ++ ++ if (!found) { ++ pr_err("%s: Could not find property '%s'\n", ++ __func__, (char *)rprop->value); ++ err = -ENOENT; ++ goto err_fail; ++ } ++ ++ phandle = be32_to_cpu(*(uint32_t *) ++ (sprop->value + offset)); ++ *(uint32_t *)(sprop->value + offset) = ++ cpu_to_be32(phandle + phandle_delta); ++ } ++ ++ kfree(propval); ++ } ++ ++ return 0; ++ ++err_fail: ++ kfree(propval); ++ return err; ++} ++ ++/** ++ * of_resolve - Resolve the given node against the live tree. ++ * ++ * @resolve: Node to resolve ++ * ++ * Perform dynamic Device Tree resolution against the live tree ++ * to the given node to resolve. This depends on the live tree ++ * having a __symbols__ node, and the resolve node the __fixups__ & ++ * __local_fixups__ nodes (if needed). ++ * The result of the operation is a resolve node that it's contents ++ * are fit to be inserted or operate upon the live tree. ++ * Returns 0 on success or a negative error value on error. ++ */ ++int of_resolve(struct device_node *resolve) ++{ ++ struct device_node *child, *refnode; ++ struct device_node *root_sym, *resolve_sym, *resolve_fix; ++ struct property *rprop, *sprop; ++ const char *refpath; ++ char *propval, *propcur, *propend, *nodestr, *propstr, *s; ++ int offset, propcurlen; ++ phandle phandle, phandle_delta; ++ int err; ++ bool found = false; ++ ++ /* the resolve node must exist */ ++ if (resolve == NULL) { ++ return -EINVAL; ++ } ++ ++ /* first we need to adjust the phandles */ ++ phandle_delta = of_get_tree_max_phandle(NULL) + 1; ++ of_adjust_tree_phandles(resolve, phandle_delta); ++ err = of_adjust_tree_phandle_references(resolve, phandle_delta); ++ if (err != 0) ++ return err; ++ ++ root_sym = NULL; ++ resolve_sym = NULL; ++ resolve_fix = NULL; ++ ++ /* this may fail (if no fixups are required) */ ++ root_sym = of_find_node_by_path("/__symbols__"); ++ ++ /* locate the symbols & fixups nodes on resolve */ ++ for_each_child_of_node(resolve, child) { ++ if (resolve_sym == NULL && ++ of_node_cmp(child->name, "__symbols__") == 0) ++ resolve_sym = child; ++ ++ if (resolve_fix == NULL && ++ of_node_cmp(child->name, "__fixups__") == 0) ++ resolve_fix = child; ++ ++ /* both found, don't bother anymore */ ++ if (resolve_sym != NULL && resolve_fix != NULL) ++ break; ++ } ++ ++ /* we do allow for the case where no fixups are needed */ ++ if (resolve_fix == NULL) ++ goto merge_sym; ++ ++ /* we need to fixup, but no root symbols... */ ++ if (root_sym == NULL) ++ return -EINVAL; ++ ++ for_each_property_of_node(resolve_fix, rprop) { ++ /* skip properties added automatically */ ++ if (of_prop_cmp(rprop->name, "name") == 0) ++ continue; ++ ++ err = of_property_read_string(root_sym, ++ rprop->name, &refpath); ++ if (err != 0) { ++ pr_err("%s: Could not find symbol '%s'\n", ++ __func__, rprop->name); ++ goto err_fail; ++ } ++ ++ refnode = of_find_node_by_path(refpath); ++ if (refnode == NULL) { ++ pr_err("%s: Could not find node by path '%s'\n", ++ __func__, refpath); ++ err = -ENOENT; ++ goto err_fail; ++ } ++ ++ phandle = refnode->phandle; ++ ++ pr_debug("%s: %s phandle is 0x%08x\n", ++ __func__, rprop->name, phandle); ++ ++ /* make a copy */ ++ propval = kmalloc(rprop->length, GFP_KERNEL); ++ if (propval == NULL) { ++ pr_err("%s: Could not copy value of '%s'\n", ++ __func__, rprop->name); ++ err = -ENOMEM; ++ goto err_fail; ++ } ++ ++ memcpy(propval, rprop->value, rprop->length); ++ ++ propend = propval + rprop->length; ++ for (propcur = propval; propcur < propend; ++ propcur += propcurlen + 1) { ++ propcurlen = strlen(propcur); ++ ++ nodestr = propcur; ++ s = strchr(propcur, ':'); ++ if (s == NULL) { ++ pr_err("%s: Illegal symbol " ++ "entry '%s' (1)\n", ++ __func__, (char *)rprop->value); ++ kfree(propval); ++ err = -EINVAL; ++ goto err_fail; ++ } ++ *s++ = '\0'; ++ ++ propstr = s; ++ s = strchr(s, ':'); ++ if (s == NULL) { ++ pr_err("%s: Illegal symbol " ++ "entry '%s' (2)\n", ++ __func__, (char *)rprop->value); ++ kfree(propval); ++ err = -EINVAL; ++ goto err_fail; ++ } ++ ++ *s++ = '\0'; ++ offset = simple_strtoul(s, NULL, 10); ++ ++ /* look into the resolve node for the full path */ ++ refnode = of_find_node_by_path_from(resolve, nodestr); ++ if (refnode == NULL) { ++ pr_err("%s: Could not find refnode '%s'\n", ++ __func__, (char *)rprop->value); ++ kfree(propval); ++ err = -ENOENT; ++ goto err_fail; ++ } ++ ++ /* now find the property */ ++ found = false; ++ for_each_property_of_node(refnode, sprop) ++ if (of_prop_cmp(sprop->name, propstr) == 0) { ++ found = true; ++ break; ++ } ++ ++ if (!found) { ++ pr_err("%s: Could not find property '%s'\n", ++ __func__, (char *)rprop->value); ++ kfree(propval); ++ err = -ENOENT; ++ goto err_fail; ++ } ++ ++ *(uint32_t *)(sprop->value + offset) = ++ cpu_to_be32(phandle); ++ } ++ ++ kfree(propval); ++ } ++ ++merge_sym: ++ return 0; ++ ++err_fail: ++ return err; ++} diff --git a/include/of.h b/include/of.h index fec51bb94..91476ae47 100644 --- a/include/of.h diff --git a/buildroot-external/patches/barebox/0002-scripts-dtc-Update-to-upstream-version-1.4.6.patch b/buildroot-external/patches/barebox/0002-scripts-dtc-Update-to-upstream-version-1.4.6.patch index 2635cc8ee..438fd6d14 100644 --- a/buildroot-external/patches/barebox/0002-scripts-dtc-Update-to-upstream-version-1.4.6.patch +++ b/buildroot-external/patches/barebox/0002-scripts-dtc-Update-to-upstream-version-1.4.6.patch @@ -1,6 +1,6 @@ -From b283776d26027ce237276f57e4522f5d0b6aab3f Mon Sep 17 00:00:00 2001 +From d898e0f7e552b781b767bb9edabb66d0a6cbb019 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli -Date: Sun, 27 May 2018 09:34:21 +0000 +Date: Sun, 27 May 2018 14:41:33 +0000 Subject: [PATCH 2/2] scripts/dtc: Update to upstream version 1.4.6 Signed-off-by: Pascal Vizeli @@ -19,6 +19,7 @@ Signed-off-by: Pascal Vizeli scripts/dtc/fdt.c | 24 +- scripts/dtc/fdt.h | 6 +- scripts/dtc/fdt_empty_tree.c | 1 - + scripts/dtc/fdt_overlay.c | 912 ++++++++++++++++++++ scripts/dtc/fdt_ro.c | 288 ++++++- scripts/dtc/fdt_rw.c | 121 +-- scripts/dtc/fdt_strerror.c | 6 + @@ -40,7 +41,8 @@ Signed-off-by: Pascal Vizeli scripts/dtc/util.c | 44 +- scripts/dtc/util.h | 33 +- scripts/dtc/version_gen.h | 2 +- - 35 files changed, 3666 insertions(+), 1728 deletions(-) + 36 files changed, 4578 insertions(+), 1728 deletions(-) + create mode 100644 scripts/dtc/fdt_overlay.c diff --git a/scripts/dtc/.gitignore b/scripts/dtc/.gitignore index 80f6b50fd..cdabdc95a 100644 @@ -5679,6 +5681,924 @@ index f72d13b1d..f2ae9b77c 100644 return fdt_open_into(buf, buf, bufsize); } - +diff --git a/scripts/dtc/fdt_overlay.c b/scripts/dtc/fdt_overlay.c +new file mode 100644 +index 000000000..bf75388ec +--- /dev/null ++++ b/scripts/dtc/fdt_overlay.c +@@ -0,0 +1,912 @@ ++/* ++ * libfdt - Flat Device Tree manipulation ++ * Copyright (C) 2016 Free Electrons ++ * Copyright (C) 2016 NextThing Co. ++ * ++ * libfdt is dual licensed: you can use it either under the terms of ++ * the GPL, or the BSD license, at your option. ++ * ++ * a) This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License as ++ * published by the Free Software Foundation; either version 2 of the ++ * License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public ++ * License along with this library; if not, write to the Free ++ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, ++ * MA 02110-1301 USA ++ * ++ * Alternatively, ++ * ++ * b) Redistribution and use in source and binary forms, with or ++ * without modification, are permitted provided that the following ++ * conditions are met: ++ * ++ * 1. Redistributions of source code must retain the above ++ * copyright notice, this list of conditions and the following ++ * disclaimer. ++ * 2. Redistributions in binary form must reproduce the above ++ * copyright notice, this list of conditions and the following ++ * disclaimer in the documentation and/or other materials ++ * provided with the distribution. ++ * ++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND ++ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, ++ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE ++ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR ++ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ++ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR ++ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, ++ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ */ ++#include "libfdt_env.h" ++ ++#include ++#include ++ ++#include "libfdt_internal.h" ++ ++/** ++ * overlay_get_target_phandle - retrieves the target phandle of a fragment ++ * @fdto: pointer to the device tree overlay blob ++ * @fragment: node offset of the fragment in the overlay ++ * ++ * overlay_get_target_phandle() retrieves the target phandle of an ++ * overlay fragment when that fragment uses a phandle (target ++ * property) instead of a path (target-path property). ++ * ++ * returns: ++ * the phandle pointed by the target property ++ * 0, if the phandle was not found ++ * -1, if the phandle was malformed ++ */ ++static uint32_t overlay_get_target_phandle(const void *fdto, int fragment) ++{ ++ const fdt32_t *val; ++ int len; ++ ++ val = fdt_getprop(fdto, fragment, "target", &len); ++ if (!val) ++ return 0; ++ ++ if ((len != sizeof(*val)) || (fdt32_to_cpu(*val) == (uint32_t)-1)) ++ return (uint32_t)-1; ++ ++ return fdt32_to_cpu(*val); ++} ++ ++/** ++ * overlay_get_target - retrieves the offset of a fragment's target ++ * @fdt: Base device tree blob ++ * @fdto: Device tree overlay blob ++ * @fragment: node offset of the fragment in the overlay ++ * @pathp: pointer which receives the path of the target (or NULL) ++ * ++ * overlay_get_target() retrieves the target offset in the base ++ * device tree of a fragment, no matter how the actual targetting is ++ * done (through a phandle or a path) ++ * ++ * returns: ++ * the targetted node offset in the base device tree ++ * Negative error code on error ++ */ ++static int overlay_get_target(const void *fdt, const void *fdto, ++ int fragment, char const **pathp) ++{ ++ uint32_t phandle; ++ const char *path = NULL; ++ int path_len = 0, ret; ++ ++ /* Try first to do a phandle based lookup */ ++ phandle = overlay_get_target_phandle(fdto, fragment); ++ if (phandle == (uint32_t)-1) ++ return -FDT_ERR_BADPHANDLE; ++ ++ /* no phandle, try path */ ++ if (!phandle) { ++ /* And then a path based lookup */ ++ path = fdt_getprop(fdto, fragment, "target-path", &path_len); ++ if (path) ++ ret = fdt_path_offset(fdt, path); ++ else ++ ret = path_len; ++ } else ++ ret = fdt_node_offset_by_phandle(fdt, phandle); ++ ++ /* ++ * If we haven't found either a target or a ++ * target-path property in a node that contains a ++ * __overlay__ subnode (we wouldn't be called ++ * otherwise), consider it a improperly written ++ * overlay ++ */ ++ if (ret < 0 && path_len == -FDT_ERR_NOTFOUND) ++ ret = -FDT_ERR_BADOVERLAY; ++ ++ /* return on error */ ++ if (ret < 0) ++ return ret; ++ ++ /* return pointer to path (if available) */ ++ if (pathp) ++ *pathp = path ? path : NULL; ++ ++ return ret; ++} ++ ++/** ++ * overlay_phandle_add_offset - Increases a phandle by an offset ++ * @fdt: Base device tree blob ++ * @node: Device tree overlay blob ++ * @name: Name of the property to modify (phandle or linux,phandle) ++ * @delta: offset to apply ++ * ++ * overlay_phandle_add_offset() increments a node phandle by a given ++ * offset. ++ * ++ * returns: ++ * 0 on success. ++ * Negative error code on error ++ */ ++static int overlay_phandle_add_offset(void *fdt, int node, ++ const char *name, uint32_t delta) ++{ ++ const fdt32_t *val; ++ uint32_t adj_val; ++ int len; ++ ++ val = fdt_getprop(fdt, node, name, &len); ++ if (!val) ++ return len; ++ ++ if (len != sizeof(*val)) ++ return -FDT_ERR_BADPHANDLE; ++ ++ adj_val = fdt32_to_cpu(*val); ++ if ((adj_val + delta) < adj_val) ++ return -FDT_ERR_NOPHANDLES; ++ ++ adj_val += delta; ++ if (adj_val == (uint32_t)-1) ++ return -FDT_ERR_NOPHANDLES; ++ ++ return fdt_setprop_inplace_u32(fdt, node, name, adj_val); ++} ++ ++/** ++ * overlay_adjust_node_phandles - Offsets the phandles of a node ++ * @fdto: Device tree overlay blob ++ * @node: Offset of the node we want to adjust ++ * @delta: Offset to shift the phandles of ++ * ++ * overlay_adjust_node_phandles() adds a constant to all the phandles ++ * of a given node. This is mainly use as part of the overlay ++ * application process, when we want to update all the overlay ++ * phandles to not conflict with the overlays of the base device tree. ++ * ++ * returns: ++ * 0 on success ++ * Negative error code on failure ++ */ ++static int overlay_adjust_node_phandles(void *fdto, int node, ++ uint32_t delta) ++{ ++ int child; ++ int ret; ++ ++ ret = overlay_phandle_add_offset(fdto, node, "phandle", delta); ++ if (ret && ret != -FDT_ERR_NOTFOUND) ++ return ret; ++ ++ ret = overlay_phandle_add_offset(fdto, node, "linux,phandle", delta); ++ if (ret && ret != -FDT_ERR_NOTFOUND) ++ return ret; ++ ++ fdt_for_each_subnode(child, fdto, node) { ++ ret = overlay_adjust_node_phandles(fdto, child, delta); ++ if (ret) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++/** ++ * overlay_adjust_local_phandles - Adjust the phandles of a whole overlay ++ * @fdto: Device tree overlay blob ++ * @delta: Offset to shift the phandles of ++ * ++ * overlay_adjust_local_phandles() adds a constant to all the ++ * phandles of an overlay. This is mainly use as part of the overlay ++ * application process, when we want to update all the overlay ++ * phandles to not conflict with the overlays of the base device tree. ++ * ++ * returns: ++ * 0 on success ++ * Negative error code on failure ++ */ ++static int overlay_adjust_local_phandles(void *fdto, uint32_t delta) ++{ ++ /* ++ * Start adjusting the phandles from the overlay root ++ */ ++ return overlay_adjust_node_phandles(fdto, 0, delta); ++} ++ ++/** ++ * overlay_update_local_node_references - Adjust the overlay references ++ * @fdto: Device tree overlay blob ++ * @tree_node: Node offset of the node to operate on ++ * @fixup_node: Node offset of the matching local fixups node ++ * @delta: Offset to shift the phandles of ++ * ++ * overlay_update_local_nodes_references() update the phandles ++ * pointing to a node within the device tree overlay by adding a ++ * constant delta. ++ * ++ * This is mainly used as part of a device tree application process, ++ * where you want the device tree overlays phandles to not conflict ++ * with the ones from the base device tree before merging them. ++ * ++ * returns: ++ * 0 on success ++ * Negative error code on failure ++ */ ++static int overlay_update_local_node_references(void *fdto, ++ int tree_node, ++ int fixup_node, ++ uint32_t delta) ++{ ++ int fixup_prop; ++ int fixup_child; ++ int ret; ++ ++ fdt_for_each_property_offset(fixup_prop, fdto, fixup_node) { ++ const fdt32_t *fixup_val; ++ const char *tree_val; ++ const char *name; ++ int fixup_len; ++ int tree_len; ++ int i; ++ ++ fixup_val = fdt_getprop_by_offset(fdto, fixup_prop, ++ &name, &fixup_len); ++ if (!fixup_val) ++ return fixup_len; ++ ++ if (fixup_len % sizeof(uint32_t)) ++ return -FDT_ERR_BADOVERLAY; ++ ++ tree_val = fdt_getprop(fdto, tree_node, name, &tree_len); ++ if (!tree_val) { ++ if (tree_len == -FDT_ERR_NOTFOUND) ++ return -FDT_ERR_BADOVERLAY; ++ ++ return tree_len; ++ } ++ ++ for (i = 0; i < (fixup_len / sizeof(uint32_t)); i++) { ++ fdt32_t adj_val; ++ uint32_t poffset; ++ ++ poffset = fdt32_to_cpu(fixup_val[i]); ++ ++ /* ++ * phandles to fixup can be unaligned. ++ * ++ * Use a memcpy for the architectures that do ++ * not support unaligned accesses. ++ */ ++ memcpy(&adj_val, tree_val + poffset, sizeof(adj_val)); ++ ++ adj_val = cpu_to_fdt32(fdt32_to_cpu(adj_val) + delta); ++ ++ ret = fdt_setprop_inplace_namelen_partial(fdto, ++ tree_node, ++ name, ++ strlen(name), ++ poffset, ++ &adj_val, ++ sizeof(adj_val)); ++ if (ret == -FDT_ERR_NOSPACE) ++ return -FDT_ERR_BADOVERLAY; ++ ++ if (ret) ++ return ret; ++ } ++ } ++ ++ fdt_for_each_subnode(fixup_child, fdto, fixup_node) { ++ const char *fixup_child_name = fdt_get_name(fdto, fixup_child, ++ NULL); ++ int tree_child; ++ ++ tree_child = fdt_subnode_offset(fdto, tree_node, ++ fixup_child_name); ++ if (tree_child == -FDT_ERR_NOTFOUND) ++ return -FDT_ERR_BADOVERLAY; ++ if (tree_child < 0) ++ return tree_child; ++ ++ ret = overlay_update_local_node_references(fdto, ++ tree_child, ++ fixup_child, ++ delta); ++ if (ret) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++/** ++ * overlay_update_local_references - Adjust the overlay references ++ * @fdto: Device tree overlay blob ++ * @delta: Offset to shift the phandles of ++ * ++ * overlay_update_local_references() update all the phandles pointing ++ * to a node within the device tree overlay by adding a constant ++ * delta to not conflict with the base overlay. ++ * ++ * This is mainly used as part of a device tree application process, ++ * where you want the device tree overlays phandles to not conflict ++ * with the ones from the base device tree before merging them. ++ * ++ * returns: ++ * 0 on success ++ * Negative error code on failure ++ */ ++static int overlay_update_local_references(void *fdto, uint32_t delta) ++{ ++ int fixups; ++ ++ fixups = fdt_path_offset(fdto, "/__local_fixups__"); ++ if (fixups < 0) { ++ /* There's no local phandles to adjust, bail out */ ++ if (fixups == -FDT_ERR_NOTFOUND) ++ return 0; ++ ++ return fixups; ++ } ++ ++ /* ++ * Update our local references from the root of the tree ++ */ ++ return overlay_update_local_node_references(fdto, 0, fixups, ++ delta); ++} ++ ++/** ++ * overlay_fixup_one_phandle - Set an overlay phandle to the base one ++ * @fdt: Base Device Tree blob ++ * @fdto: Device tree overlay blob ++ * @symbols_off: Node offset of the symbols node in the base device tree ++ * @path: Path to a node holding a phandle in the overlay ++ * @path_len: number of path characters to consider ++ * @name: Name of the property holding the phandle reference in the overlay ++ * @name_len: number of name characters to consider ++ * @poffset: Offset within the overlay property where the phandle is stored ++ * @label: Label of the node referenced by the phandle ++ * ++ * overlay_fixup_one_phandle() resolves an overlay phandle pointing to ++ * a node in the base device tree. ++ * ++ * This is part of the device tree overlay application process, when ++ * you want all the phandles in the overlay to point to the actual ++ * base dt nodes. ++ * ++ * returns: ++ * 0 on success ++ * Negative error code on failure ++ */ ++static int overlay_fixup_one_phandle(void *fdt, void *fdto, ++ int symbols_off, ++ const char *path, uint32_t path_len, ++ const char *name, uint32_t name_len, ++ int poffset, const char *label) ++{ ++ const char *symbol_path; ++ uint32_t phandle; ++ fdt32_t phandle_prop; ++ int symbol_off, fixup_off; ++ int prop_len; ++ ++ if (symbols_off < 0) ++ return symbols_off; ++ ++ symbol_path = fdt_getprop(fdt, symbols_off, label, ++ &prop_len); ++ if (!symbol_path) ++ return prop_len; ++ ++ symbol_off = fdt_path_offset(fdt, symbol_path); ++ if (symbol_off < 0) ++ return symbol_off; ++ ++ phandle = fdt_get_phandle(fdt, symbol_off); ++ if (!phandle) ++ return -FDT_ERR_NOTFOUND; ++ ++ fixup_off = fdt_path_offset_namelen(fdto, path, path_len); ++ if (fixup_off == -FDT_ERR_NOTFOUND) ++ return -FDT_ERR_BADOVERLAY; ++ if (fixup_off < 0) ++ return fixup_off; ++ ++ phandle_prop = cpu_to_fdt32(phandle); ++ return fdt_setprop_inplace_namelen_partial(fdto, fixup_off, ++ name, name_len, poffset, ++ &phandle_prop, ++ sizeof(phandle_prop)); ++}; ++ ++/** ++ * overlay_fixup_phandle - Set an overlay phandle to the base one ++ * @fdt: Base Device Tree blob ++ * @fdto: Device tree overlay blob ++ * @symbols_off: Node offset of the symbols node in the base device tree ++ * @property: Property offset in the overlay holding the list of fixups ++ * ++ * overlay_fixup_phandle() resolves all the overlay phandles pointed ++ * to in a __fixups__ property, and updates them to match the phandles ++ * in use in the base device tree. ++ * ++ * This is part of the device tree overlay application process, when ++ * you want all the phandles in the overlay to point to the actual ++ * base dt nodes. ++ * ++ * returns: ++ * 0 on success ++ * Negative error code on failure ++ */ ++static int overlay_fixup_phandle(void *fdt, void *fdto, int symbols_off, ++ int property) ++{ ++ const char *value; ++ const char *label; ++ int len; ++ ++ value = fdt_getprop_by_offset(fdto, property, ++ &label, &len); ++ if (!value) { ++ if (len == -FDT_ERR_NOTFOUND) ++ return -FDT_ERR_INTERNAL; ++ ++ return len; ++ } ++ ++ do { ++ const char *path, *name, *fixup_end; ++ const char *fixup_str = value; ++ uint32_t path_len, name_len; ++ uint32_t fixup_len; ++ char *sep, *endptr; ++ int poffset, ret; ++ ++ 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; ++ ++ path = fixup_str; ++ sep = memchr(fixup_str, ':', fixup_len); ++ if (!sep || *sep != ':') ++ return -FDT_ERR_BADOVERLAY; ++ ++ path_len = sep - path; ++ if (path_len == (fixup_len - 1)) ++ return -FDT_ERR_BADOVERLAY; ++ ++ fixup_len -= path_len + 1; ++ name = sep + 1; ++ sep = memchr(name, ':', fixup_len); ++ if (!sep || *sep != ':') ++ return -FDT_ERR_BADOVERLAY; ++ ++ name_len = sep - name; ++ if (!name_len) ++ return -FDT_ERR_BADOVERLAY; ++ ++ poffset = strtoul(sep + 1, &endptr, 10); ++ if ((*endptr != '\0') || (endptr <= (sep + 1))) ++ return -FDT_ERR_BADOVERLAY; ++ ++ ret = overlay_fixup_one_phandle(fdt, fdto, symbols_off, ++ path, path_len, name, name_len, ++ poffset, label); ++ if (ret) ++ return ret; ++ } while (len > 0); ++ ++ return 0; ++} ++ ++/** ++ * overlay_fixup_phandles - Resolve the overlay phandles to the base ++ * device tree ++ * @fdt: Base Device Tree blob ++ * @fdto: Device tree overlay blob ++ * ++ * overlay_fixup_phandles() resolves all the overlay phandles pointing ++ * to nodes in the base device tree. ++ * ++ * This is one of the steps of the device tree overlay application ++ * process, when you want all the phandles in the overlay to point to ++ * the actual base dt nodes. ++ * ++ * returns: ++ * 0 on success ++ * Negative error code on failure ++ */ ++static int overlay_fixup_phandles(void *fdt, void *fdto) ++{ ++ int fixups_off, symbols_off; ++ int property; ++ ++ /* 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 */ ++ if (fixups_off < 0) ++ return fixups_off; ++ ++ /* And base DTs without symbols */ ++ symbols_off = fdt_path_offset(fdt, "/__symbols__"); ++ if ((symbols_off < 0 && (symbols_off != -FDT_ERR_NOTFOUND))) ++ return symbols_off; ++ ++ fdt_for_each_property_offset(property, fdto, fixups_off) { ++ int ret; ++ ++ ret = overlay_fixup_phandle(fdt, fdto, symbols_off, property); ++ if (ret) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++/** ++ * overlay_apply_node - Merges a node into the base device tree ++ * @fdt: Base Device Tree blob ++ * @target: Node offset in the base device tree to apply the fragment to ++ * @fdto: Device tree overlay blob ++ * @node: Node offset in the overlay holding the changes to merge ++ * ++ * overlay_apply_node() merges a node into a target base device tree ++ * node pointed. ++ * ++ * This is part of the final step in the device tree overlay ++ * application process, when all the phandles have been adjusted and ++ * resolved and you just have to merge overlay into the base device ++ * tree. ++ * ++ * returns: ++ * 0 on success ++ * Negative error code on failure ++ */ ++static int overlay_apply_node(void *fdt, int target, ++ void *fdto, int node) ++{ ++ int property; ++ int subnode; ++ ++ fdt_for_each_property_offset(property, fdto, node) { ++ const char *name; ++ const void *prop; ++ int prop_len; ++ int ret; ++ ++ prop = fdt_getprop_by_offset(fdto, property, &name, ++ &prop_len); ++ if (prop_len == -FDT_ERR_NOTFOUND) ++ return -FDT_ERR_INTERNAL; ++ if (prop_len < 0) ++ return prop_len; ++ ++ ret = fdt_setprop(fdt, target, name, prop, prop_len); ++ if (ret) ++ return ret; ++ } ++ ++ fdt_for_each_subnode(subnode, fdto, node) { ++ const char *name = fdt_get_name(fdto, subnode, NULL); ++ int nnode; ++ int ret; ++ ++ nnode = fdt_add_subnode(fdt, target, name); ++ if (nnode == -FDT_ERR_EXISTS) { ++ nnode = fdt_subnode_offset(fdt, target, name); ++ if (nnode == -FDT_ERR_NOTFOUND) ++ return -FDT_ERR_INTERNAL; ++ } ++ ++ if (nnode < 0) ++ return nnode; ++ ++ ret = overlay_apply_node(fdt, nnode, fdto, subnode); ++ if (ret) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++/** ++ * overlay_merge - Merge an overlay into its base device tree ++ * @fdt: Base Device Tree blob ++ * @fdto: Device tree overlay blob ++ * ++ * overlay_merge() merges an overlay into its base device tree. ++ * ++ * This is the next to last step in the device tree overlay application ++ * process, when all the phandles have been adjusted and resolved and ++ * you just have to merge overlay into the base device tree. ++ * ++ * returns: ++ * 0 on success ++ * Negative error code on failure ++ */ ++static int overlay_merge(void *fdt, void *fdto) ++{ ++ int fragment; ++ ++ fdt_for_each_subnode(fragment, fdto, 0) { ++ int overlay; ++ int target; ++ int ret; ++ ++ /* ++ * Each fragments will have an __overlay__ node. If ++ * they don't, it's not supposed to be merged ++ */ ++ overlay = fdt_subnode_offset(fdto, fragment, "__overlay__"); ++ if (overlay == -FDT_ERR_NOTFOUND) ++ continue; ++ ++ if (overlay < 0) ++ return overlay; ++ ++ target = overlay_get_target(fdt, fdto, fragment, NULL); ++ if (target < 0) ++ return target; ++ ++ ret = overlay_apply_node(fdt, target, fdto, overlay); ++ if (ret) ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int get_path_len(const void *fdt, int nodeoffset) ++{ ++ int len = 0, namelen; ++ const char *name; ++ ++ FDT_CHECK_HEADER(fdt); ++ ++ for (;;) { ++ name = fdt_get_name(fdt, nodeoffset, &namelen); ++ if (!name) ++ return namelen; ++ ++ /* root? we're done */ ++ if (namelen == 0) ++ break; ++ ++ nodeoffset = fdt_parent_offset(fdt, nodeoffset); ++ if (nodeoffset < 0) ++ return nodeoffset; ++ len += namelen + 1; ++ } ++ ++ /* in case of root pretend it's "/" */ ++ if (len == 0) ++ len++; ++ return len; ++} ++ ++/** ++ * overlay_symbol_update - Update the symbols of base tree after a merge ++ * @fdt: Base Device Tree blob ++ * @fdto: Device tree overlay blob ++ * ++ * 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. ++ * ++ * returns: ++ * 0 on success ++ * Negative error code on failure ++ */ ++static int overlay_symbol_update(void *fdt, void *fdto) ++{ ++ int root_sym, ov_sym, prop, path_len, fragment, target; ++ int len, frag_name_len, ret, rel_path_len; ++ const char *s, *e; ++ const char *path; ++ const char *name; ++ const char *frag_name; ++ const char *rel_path; ++ const char *target_path; ++ char *buf; ++ void *p; ++ ++ ov_sym = fdt_subnode_offset(fdto, 0, "__symbols__"); ++ ++ /* if no overlay symbols exist no problem */ ++ if (ov_sym < 0) ++ return 0; ++ ++ root_sym = fdt_subnode_offset(fdt, 0, "__symbols__"); ++ ++ /* it no root symbols exist we should create them */ ++ if (root_sym == -FDT_ERR_NOTFOUND) ++ root_sym = fdt_add_subnode(fdt, 0, "__symbols__"); ++ ++ /* any error is fatal now */ ++ if (root_sym < 0) ++ return root_sym; ++ ++ /* iterate over each overlay symbol */ ++ fdt_for_each_property_offset(prop, fdto, ov_sym) { ++ path = fdt_getprop_by_offset(fdto, prop, &name, &path_len); ++ if (!path) ++ 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]) ++ return -FDT_ERR_BADVALUE; ++ ++ /* keep end marker to avoid strlen() */ ++ e = path + path_len; ++ ++ /* format: //__overlay__/ */ ++ ++ if (*path != '/') ++ return -FDT_ERR_BADVALUE; ++ ++ /* get fragment name first */ ++ s = strchr(path + 1, '/'); ++ if (!s) ++ return -FDT_ERR_BADOVERLAY; ++ ++ frag_name = path + 1; ++ frag_name_len = s - path - 1; ++ ++ /* verify format; safe since "s" lies in \0 terminated prop */ ++ len = sizeof("/__overlay__/") - 1; ++ if ((e - s) < len || memcmp(s, "/__overlay__/", len)) ++ return -FDT_ERR_BADOVERLAY; ++ ++ rel_path = s + len; ++ rel_path_len = e - rel_path; ++ ++ /* find the fragment index in which the symbol lies */ ++ ret = fdt_subnode_offset_namelen(fdto, 0, frag_name, ++ frag_name_len); ++ /* not found? */ ++ if (ret < 0) ++ return -FDT_ERR_BADOVERLAY; ++ fragment = ret; ++ ++ /* an __overlay__ subnode must exist */ ++ ret = fdt_subnode_offset(fdto, fragment, "__overlay__"); ++ if (ret < 0) ++ return -FDT_ERR_BADOVERLAY; ++ ++ /* get the target of the fragment */ ++ ret = overlay_get_target(fdt, fdto, fragment, &target_path); ++ if (ret < 0) ++ return ret; ++ target = 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); ++ } ++ ++ ret = fdt_setprop_placeholder(fdt, root_sym, name, ++ len + (len > 1) + rel_path_len + 1, &p); ++ if (ret < 0) ++ return ret; ++ ++ if (!target_path) { ++ /* again in case setprop_placeholder changed it */ ++ ret = overlay_get_target(fdt, fdto, fragment, &target_path); ++ if (ret < 0) ++ return ret; ++ target = ret; ++ } ++ ++ buf = p; ++ 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); ++ ++ } else ++ len--; ++ ++ buf[len] = '/'; ++ memcpy(buf + len + 1, rel_path, rel_path_len); ++ buf[len + 1 + rel_path_len] = '\0'; ++ } ++ ++ return 0; ++} ++ ++int fdt_overlay_apply(void *fdt, void *fdto) ++{ ++ uint32_t delta = fdt_get_max_phandle(fdt); ++ int ret; ++ ++ FDT_CHECK_HEADER(fdt); ++ FDT_CHECK_HEADER(fdto); ++ ++ ret = overlay_adjust_local_phandles(fdto, delta); ++ if (ret) ++ goto err; ++ ++ ret = overlay_update_local_references(fdto, delta); ++ if (ret) ++ goto err; ++ ++ ret = overlay_fixup_phandles(fdt, fdto); ++ if (ret) ++ goto err; ++ ++ ret = overlay_merge(fdt, fdto); ++ if (ret) ++ goto err; ++ ++ ret = overlay_symbol_update(fdt, fdto); ++ if (ret) ++ goto err; ++ ++ /* ++ * The overlay has been damaged, erase its magic. ++ */ ++ fdt_set_magic(fdto, ~0); ++ ++ return 0; ++ ++err: ++ /* ++ * The overlay might have been damaged, erase its magic. ++ */ ++ fdt_set_magic(fdto, ~0); ++ ++ /* ++ * The base device tree might have been damaged, erase its ++ * magic. ++ */ ++ fdt_set_magic(fdt, ~0); ++ ++ return ret; ++} diff --git a/scripts/dtc/fdt_ro.c b/scripts/dtc/fdt_ro.c index 50007f61c..dfb3236da 100644 --- a/scripts/dtc/fdt_ro.c