[U-Boot] [PATCH] libfdt: Sync overlay with upstream

Maxime Ripard maxime.ripard at free-electrons.com
Mon Oct 17 22:50:18 CEST 2016


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 <maxime.ripard at free-electrons.com>
---
 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 8746790a2535..e2bc2e00c184 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 d35ceacbf001..bb4140412971 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 3b7e1683d0d0..7f8e02b1ee21 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]))
 
-- 
2.9.3



More information about the U-Boot mailing list