From 610db7058f1d9ed668aef7692f8f90f05e0923f8 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 17 Oct 2016 22:50:18 +0200 Subject: [PATCH] libfdt: Sync overlay with upstream Now that the overlay code has been merge upstream, update our copy to what's been merged, since a significant number of issues have been fixed during the merge process. Signed-off-by: Maxime Ripard Acked-by: Simon Glass --- include/libfdt.h | 24 +++-- lib/libfdt/fdt_overlay.c | 199 ++++++++++++++++++++++++-------------- lib/libfdt/fdt_strerror.c | 3 + 3 files changed, 147 insertions(+), 79 deletions(-) diff --git a/include/libfdt.h b/include/libfdt.h index 8746790a25..e2bc2e00c1 100644 --- a/include/libfdt.h +++ b/include/libfdt.h @@ -79,8 +79,10 @@ * (e.g. missing a leading / for a function which requires an * absolute path) */ #define FDT_ERR_BADPHANDLE 6 - /* FDT_ERR_BADPHANDLE: Function was passed an invalid phandle - * value. phandle values of 0 and -1 are not permitted. */ + /* FDT_ERR_BADPHANDLE: Function was passed an invalid phandle. + * This can be caused either by an invalid phandle property + * length, or the phandle value was either 0 or -1, which are + * not permitted. */ #define FDT_ERR_BADSTATE 7 /* FDT_ERR_BADSTATE: Function was passed an incomplete device * tree created by the sequential-write functions, which is @@ -126,12 +128,21 @@ * value. For example: a property expected to contain a string list * is not NUL-terminated within the length of its value. */ -#define FDT_ERR_TOODEEP 16 +#define FDT_ERR_BADOVERLAY 16 + /* FDT_ERR_BADOVERLAY: The device tree overlay, while + * correctly structured, cannot be applied due to some + * unexpected or missing value, property or node. */ + +#define FDT_ERR_NOPHANDLES 17 + /* FDT_ERR_NOPHANDLES: The device tree doesn't have any + * phandle available anymore without causing an overflow */ + +#define FDT_ERR_TOODEEP 18 /* FDT_ERR_TOODEEP: The depth of a node has exceeded the internal * libfdt limit. This can happen if you have more than * FDT_MAX_DEPTH nested nodes. */ -#define FDT_ERR_MAX 16 +#define FDT_ERR_MAX 18 /**********************************************************************/ /* Low-level functions (you probably don't need these) */ @@ -1789,8 +1800,9 @@ int fdt_del_node(void *fdt, int nodeoffset); * -FDT_ERR_NOSPACE, there's not enough space in the base device tree * -FDT_ERR_NOTFOUND, the overlay points to some inexistant nodes or * properties in the base DT - * -FDT_ERR_BADPHANDLE, the phandles in the overlay do not have the right - * magic + * -FDT_ERR_BADPHANDLE, + * -FDT_ERR_BADOVERLAY, + * -FDT_ERR_NOPHANDLES, * -FDT_ERR_INTERNAL, * -FDT_ERR_BADLAYOUT, * -FDT_ERR_BADMAGIC, diff --git a/lib/libfdt/fdt_overlay.c b/lib/libfdt/fdt_overlay.c index d35ceacbf0..bb41404129 100644 --- a/lib/libfdt/fdt_overlay.c +++ b/lib/libfdt/fdt_overlay.c @@ -28,19 +28,19 @@ static uint32_t overlay_get_target_phandle(const void *fdto, int fragment) if (!val) return 0; - if ((*val == (uint32_t)-1) || (len != sizeof(*val))) + if ((len != sizeof(*val)) || (*val == (uint32_t)-1)) return (uint32_t)-1; return fdt32_to_cpu(*val); } /** - * overlay_get_target - retrieves the target phandle of a fragment + * 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 * - * overlay_get_target() retrieves the target phandle in the base + * 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) * @@ -53,6 +53,7 @@ static int overlay_get_target(const void *fdt, const void *fdto, { uint32_t phandle; const char *path; + int path_len; /* Try first to do a phandle based lookup */ phandle = overlay_get_target_phandle(fdto, fragment); @@ -63,9 +64,20 @@ static int overlay_get_target(const void *fdt, const void *fdto, return fdt_node_offset_by_phandle(fdt, phandle); /* And then a path based lookup */ - path = fdt_getprop(fdto, fragment, "target-path", NULL); - if (!path) - return -FDT_ERR_NOTFOUND; + path = fdt_getprop(fdto, fragment, "target-path", &path_len); + if (!path) { + /* + * 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 (path_len == -FDT_ERR_NOTFOUND) + return -FDT_ERR_BADOVERLAY; + + return path_len; + } return fdt_path_offset(fdt, path); } @@ -96,13 +108,16 @@ static int overlay_phandle_add_offset(void *fdt, int node, return len; if (len != sizeof(*val)) - return -FDT_ERR_BADSTRUCTURE; + return -FDT_ERR_BADPHANDLE; adj_val = fdt32_to_cpu(*val); if ((adj_val + delta) < adj_val) - return -FDT_ERR_BADPHANDLE; + 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); } @@ -124,7 +139,6 @@ static int overlay_phandle_add_offset(void *fdt, int node, static int overlay_adjust_node_phandles(void *fdto, int node, uint32_t delta) { - bool found = false; int child; int ret; @@ -132,22 +146,15 @@ static int overlay_adjust_node_phandles(void *fdto, int node, if (ret && ret != -FDT_ERR_NOTFOUND) return ret; - if (!ret) - found = true; - ret = overlay_phandle_add_offset(fdto, node, "linux,phandle", delta); if (ret && ret != -FDT_ERR_NOTFOUND) return ret; - /* - * If neither phandle nor linux,phandle have been found return - * an error. - */ - if (!found && !ret) - return ret; - - fdt_for_each_subnode(child, fdto, node) - overlay_adjust_node_phandles(fdto, child, delta); + fdt_for_each_subnode(child, fdto, node) { + ret = overlay_adjust_node_phandles(fdto, child, delta); + if (ret) + return ret; + } return 0; } @@ -203,7 +210,8 @@ static int overlay_update_local_node_references(void *fdto, int ret; fdt_for_each_property_offset(fixup_prop, fdto, fixup_node) { - const unsigned char *fixup_val, *tree_val; + const uint32_t *fixup_val; + const char *tree_val; const char *name; int fixup_len; int tree_len; @@ -214,15 +222,21 @@ static int overlay_update_local_node_references(void *fdto, 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_val) { + if (tree_len == -FDT_ERR_NOTFOUND) + return -FDT_ERR_BADOVERLAY; + return tree_len; + } - for (i = 0; i < fixup_len; i += sizeof(uint32_t)) { - uint32_t adj_val, index; + for (i = 0; i < (fixup_len / sizeof(uint32_t)); i++) { + uint32_t adj_val, poffset; - index = *(uint32_t *)(fixup_val + i); - index = fdt32_to_cpu(index); + poffset = fdt32_to_cpu(fixup_val[i]); /* * phandles to fixup can be unaligned. @@ -230,7 +244,7 @@ static int overlay_update_local_node_references(void *fdto, * Use a memcpy for the architectures that do * not support unaligned accesses. */ - memcpy(&adj_val, tree_val + index, sizeof(uint32_t)); + memcpy(&adj_val, tree_val + poffset, sizeof(adj_val)); adj_val = fdt32_to_cpu(adj_val); adj_val += delta; @@ -240,9 +254,12 @@ static int overlay_update_local_node_references(void *fdto, tree_node, name, strlen(name), - index, + poffset, &adj_val, sizeof(adj_val)); + if (ret == -FDT_ERR_NOSPACE) + return -FDT_ERR_BADOVERLAY; + if (ret) return ret; } @@ -255,6 +272,8 @@ static int overlay_update_local_node_references(void *fdto, tree_child = fdt_subnode_offset(fdto, tree_node, fixup_child_name); + if (ret == -FDT_ERR_NOTFOUND) + return -FDT_ERR_BADOVERLAY; if (tree_child < 0) return tree_child; @@ -315,7 +334,7 @@ static int overlay_update_local_references(void *fdto, uint32_t delta) * @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 - * @index: Index in the overlay property where the phandle is stored + * @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 @@ -333,7 +352,7 @@ 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 index, const char *label) + int poffset, const char *label) { const char *symbol_path; uint32_t phandle; @@ -343,7 +362,7 @@ static int overlay_fixup_one_phandle(void *fdt, void *fdto, symbol_path = fdt_getprop(fdt, symbols_off, label, &prop_len); if (!symbol_path) - return -FDT_ERR_NOTFOUND; + return prop_len; symbol_off = fdt_path_offset(fdt, symbol_path); if (symbol_off < 0) @@ -354,12 +373,14 @@ static int overlay_fixup_one_phandle(void *fdt, void *fdto, 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 = cpu_to_fdt32(phandle); return fdt_setprop_inplace_namelen_partial(fdto, fixup_off, - name, name_len, index, + name, name_len, poffset, &phandle, sizeof(phandle)); }; @@ -371,8 +392,8 @@ static int overlay_fixup_one_phandle(void *fdt, void *fdto, * @property: Property offset in the overlay holding the list of fixups * * overlay_fixup_phandle() resolves all the overlay phandles pointed - * to in a __local_fixup__ property, and updates them to match the - * phandles in use in the base device tree. + * 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 @@ -391,40 +412,55 @@ static int overlay_fixup_phandle(void *fdt, void *fdto, int symbols_off, value = fdt_getprop_by_offset(fdto, property, &label, &len); - if (!value) + if (!value) { + if (len == -FDT_ERR_NOTFOUND) + return -FDT_ERR_INTERNAL; + return len; + } do { - const char *prop_string = value; - const char *path, *name; - uint32_t prop_len = strlen(value); + 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 index; - int ret; + 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 = prop_string; - sep = memchr(prop_string, ':', prop_len); - if (*sep != ':') - return -FDT_ERR_BADSTRUCTURE; 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, ':', prop_len); - if (*sep != ':') - return -FDT_ERR_BADSTRUCTURE; + sep = memchr(name, ':', fixup_len); + if (!sep || *sep != ':') + return -FDT_ERR_BADOVERLAY; + name_len = sep - name; + if (!name_len) + return -FDT_ERR_BADOVERLAY; - index = strtoul(sep + 1, &endptr, 10); + poffset = strtoul(sep + 1, &endptr, 10); if ((*endptr != '\0') || (endptr <= (sep + 1))) - return -FDT_ERR_BADSTRUCTURE; - - len -= prop_len + 1; - value += prop_len + 1; + return -FDT_ERR_BADOVERLAY; ret = overlay_fixup_one_phandle(fdt, fdto, symbols_off, path, path_len, name, name_len, - index, label); + poffset, label); if (ret) return ret; } while (len > 0); @@ -454,8 +490,15 @@ static int overlay_fixup_phandles(void *fdt, void *fdto) int fixups_off, symbols_off; int property; - symbols_off = fdt_path_offset(fdt, "/__symbols__"); + /* We can have overlays without any fixups */ fixups_off = fdt_path_offset(fdto, "/__fixups__"); + if ((fixups_off < 0 && (fixups_off != -FDT_ERR_NOTFOUND))) + 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; @@ -469,14 +512,14 @@ static int overlay_fixup_phandles(void *fdt, void *fdto) } /** - * overlay_apply_node - Merge an overlay fragment into the base device tree + * 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 - * @fragment: Node offset in the overlay holding the changes to merge + * @node: Node offset in the overlay holding the changes to merge * - * overlay_apply_node() merges an overlay fragment into a target base - * device tree node pointed. + * 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 @@ -488,12 +531,12 @@ static int overlay_fixup_phandles(void *fdt, void *fdto) * Negative error code on failure */ static int overlay_apply_node(void *fdt, int target, - void *fdto, int fragment) + void *fdto, int node) { int property; - int node; + int subnode; - fdt_for_each_property_offset(property, fdto, fragment) { + fdt_for_each_property_offset(property, fdto, node) { const char *name; const void *prop; int prop_len; @@ -511,19 +554,22 @@ static int overlay_apply_node(void *fdt, int target, return ret; } - fdt_for_each_subnode(node, fdto, fragment) { - const char *name = fdt_get_name(fdto, node, NULL); + 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) + 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, node); + ret = overlay_apply_node(fdt, nnode, fdto, subnode); if (ret) return ret; } @@ -546,24 +592,31 @@ static int overlay_apply_node(void *fdt, int target, * 0 on success * Negative error code on failure */ -static int overlay_merge(void *dt, void *dto) +static int overlay_merge(void *fdt, void *fdto) { int fragment; - fdt_for_each_subnode(fragment, dto, 0) { + fdt_for_each_subnode(fragment, fdto, 0) { int overlay; int target; int ret; - target = overlay_get_target(dt, dto, fragment); - if (target < 0) + /* + * 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; - overlay = fdt_subnode_offset(dto, fragment, "__overlay__"); if (overlay < 0) return overlay; - ret = overlay_apply_node(dt, target, dto, overlay); + target = overlay_get_target(fdt, fdto, fragment); + if (target < 0) + return target; + + ret = overlay_apply_node(fdt, target, fdto, overlay); if (ret) return ret; } @@ -573,7 +626,7 @@ static int overlay_merge(void *dt, void *dto) int fdt_overlay_apply(void *fdt, void *fdto) { - uint32_t delta = fdt_get_max_phandle(fdt) + 1; + uint32_t delta = fdt_get_max_phandle(fdt); int ret; FDT_CHECK_HEADER(fdt); diff --git a/lib/libfdt/fdt_strerror.c b/lib/libfdt/fdt_strerror.c index 3b7e1683d0..7f8e02b1ee 100644 --- a/lib/libfdt/fdt_strerror.c +++ b/lib/libfdt/fdt_strerror.c @@ -28,6 +28,7 @@ static struct fdt_errtabent fdt_errtable[] = { FDT_ERRTABENT(FDT_ERR_BADOFFSET), FDT_ERRTABENT(FDT_ERR_BADPATH), + FDT_ERRTABENT(FDT_ERR_BADPHANDLE), FDT_ERRTABENT(FDT_ERR_BADSTATE), FDT_ERRTABENT(FDT_ERR_TRUNCATED), @@ -35,6 +36,8 @@ static struct fdt_errtabent fdt_errtable[] = { FDT_ERRTABENT(FDT_ERR_BADVERSION), FDT_ERRTABENT(FDT_ERR_BADSTRUCTURE), FDT_ERRTABENT(FDT_ERR_BADLAYOUT), + FDT_ERRTABENT(FDT_ERR_BADOVERLAY), + FDT_ERRTABENT(FDT_ERR_NOPHANDLES), }; #define FDT_ERRTABSIZE (sizeof(fdt_errtable) / sizeof(fdt_errtable[0]))