xref: /linux/scripts/dtc/libfdt/fdt_overlay.c (revision f8e17c17b81070f38062dce79ca7f4541851dadd)
1 // SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
2 /*
3  * libfdt - Flat Device Tree manipulation
4  * Copyright (C) 2016 Free Electrons
5  * Copyright (C) 2016 NextThing Co.
6  */
7 #include "libfdt_env.h"
8 
9 #include <fdt.h>
10 #include <libfdt.h>
11 
12 #include "libfdt_internal.h"
13 
14 /**
15  * overlay_get_target_phandle - retrieves the target phandle of a fragment
16  * @fdto: pointer to the device tree overlay blob
17  * @fragment: node offset of the fragment in the overlay
18  *
19  * overlay_get_target_phandle() retrieves the target phandle of an
20  * overlay fragment when that fragment uses a phandle (target
21  * property) instead of a path (target-path property).
22  *
23  * returns:
24  *      the phandle pointed by the target property
25  *      0, if the phandle was not found
26  *	-1, if the phandle was malformed
27  */
28 static uint32_t overlay_get_target_phandle(const void *fdto, int fragment)
29 {
30 	const fdt32_t *val;
31 	int len;
32 
33 	val = fdt_getprop(fdto, fragment, "target", &len);
34 	if (!val)
35 		return 0;
36 
37 	if ((len != sizeof(*val)) || (fdt32_to_cpu(*val) == (uint32_t)-1))
38 		return (uint32_t)-1;
39 
40 	return fdt32_to_cpu(*val);
41 }
42 
43 /**
44  * overlay_get_target - retrieves the offset of a fragment's target
45  * @fdt: Base device tree blob
46  * @fdto: Device tree overlay blob
47  * @fragment: node offset of the fragment in the overlay
48  * @pathp: pointer which receives the path of the target (or NULL)
49  *
50  * overlay_get_target() retrieves the target offset in the base
51  * device tree of a fragment, no matter how the actual targeting is
52  * done (through a phandle or a path)
53  *
54  * returns:
55  *      the targeted node offset in the base device tree
56  *      Negative error code on error
57  */
58 static int overlay_get_target(const void *fdt, const void *fdto,
59 			      int fragment, char const **pathp)
60 {
61 	uint32_t phandle;
62 	const char *path = NULL;
63 	int path_len = 0, ret;
64 
65 	/* Try first to do a phandle based lookup */
66 	phandle = overlay_get_target_phandle(fdto, fragment);
67 	if (phandle == (uint32_t)-1)
68 		return -FDT_ERR_BADPHANDLE;
69 
70 	/* no phandle, try path */
71 	if (!phandle) {
72 		/* And then a path based lookup */
73 		path = fdt_getprop(fdto, fragment, "target-path", &path_len);
74 		if (path)
75 			ret = fdt_path_offset(fdt, path);
76 		else
77 			ret = path_len;
78 	} else
79 		ret = fdt_node_offset_by_phandle(fdt, phandle);
80 
81 	/*
82 	* If we haven't found either a target or a
83 	* target-path property in a node that contains a
84 	* __overlay__ subnode (we wouldn't be called
85 	* otherwise), consider it a improperly written
86 	* overlay
87 	*/
88 	if (ret < 0 && path_len == -FDT_ERR_NOTFOUND)
89 		ret = -FDT_ERR_BADOVERLAY;
90 
91 	/* return on error */
92 	if (ret < 0)
93 		return ret;
94 
95 	/* return pointer to path (if available) */
96 	if (pathp)
97 		*pathp = path ? path : NULL;
98 
99 	return ret;
100 }
101 
102 /**
103  * overlay_phandle_add_offset - Increases a phandle by an offset
104  * @fdt: Base device tree blob
105  * @node: Device tree overlay blob
106  * @name: Name of the property to modify (phandle or linux,phandle)
107  * @delta: offset to apply
108  *
109  * overlay_phandle_add_offset() increments a node phandle by a given
110  * offset.
111  *
112  * returns:
113  *      0 on success.
114  *      Negative error code on error
115  */
116 static int overlay_phandle_add_offset(void *fdt, int node,
117 				      const char *name, uint32_t delta)
118 {
119 	const fdt32_t *val;
120 	uint32_t adj_val;
121 	int len;
122 
123 	val = fdt_getprop(fdt, node, name, &len);
124 	if (!val)
125 		return len;
126 
127 	if (len != sizeof(*val))
128 		return -FDT_ERR_BADPHANDLE;
129 
130 	adj_val = fdt32_to_cpu(*val);
131 	if ((adj_val + delta) < adj_val)
132 		return -FDT_ERR_NOPHANDLES;
133 
134 	adj_val += delta;
135 	if (adj_val == (uint32_t)-1)
136 		return -FDT_ERR_NOPHANDLES;
137 
138 	return fdt_setprop_inplace_u32(fdt, node, name, adj_val);
139 }
140 
141 /**
142  * overlay_adjust_node_phandles - Offsets the phandles of a node
143  * @fdto: Device tree overlay blob
144  * @node: Offset of the node we want to adjust
145  * @delta: Offset to shift the phandles of
146  *
147  * overlay_adjust_node_phandles() adds a constant to all the phandles
148  * of a given node. This is mainly use as part of the overlay
149  * application process, when we want to update all the overlay
150  * phandles to not conflict with the overlays of the base device tree.
151  *
152  * returns:
153  *      0 on success
154  *      Negative error code on failure
155  */
156 static int overlay_adjust_node_phandles(void *fdto, int node,
157 					uint32_t delta)
158 {
159 	int child;
160 	int ret;
161 
162 	ret = overlay_phandle_add_offset(fdto, node, "phandle", delta);
163 	if (ret && ret != -FDT_ERR_NOTFOUND)
164 		return ret;
165 
166 	ret = overlay_phandle_add_offset(fdto, node, "linux,phandle", delta);
167 	if (ret && ret != -FDT_ERR_NOTFOUND)
168 		return ret;
169 
170 	fdt_for_each_subnode(child, fdto, node) {
171 		ret = overlay_adjust_node_phandles(fdto, child, delta);
172 		if (ret)
173 			return ret;
174 	}
175 
176 	return 0;
177 }
178 
179 /**
180  * overlay_adjust_local_phandles - Adjust the phandles of a whole overlay
181  * @fdto: Device tree overlay blob
182  * @delta: Offset to shift the phandles of
183  *
184  * overlay_adjust_local_phandles() adds a constant to all the
185  * phandles of an overlay. This is mainly use as part of the overlay
186  * application process, when we want to update all the overlay
187  * phandles to not conflict with the overlays of the base device tree.
188  *
189  * returns:
190  *      0 on success
191  *      Negative error code on failure
192  */
193 static int overlay_adjust_local_phandles(void *fdto, uint32_t delta)
194 {
195 	/*
196 	 * Start adjusting the phandles from the overlay root
197 	 */
198 	return overlay_adjust_node_phandles(fdto, 0, delta);
199 }
200 
201 /**
202  * overlay_update_local_node_references - Adjust the overlay references
203  * @fdto: Device tree overlay blob
204  * @tree_node: Node offset of the node to operate on
205  * @fixup_node: Node offset of the matching local fixups node
206  * @delta: Offset to shift the phandles of
207  *
208  * overlay_update_local_nodes_references() update the phandles
209  * pointing to a node within the device tree overlay by adding a
210  * constant delta.
211  *
212  * This is mainly used as part of a device tree application process,
213  * where you want the device tree overlays phandles to not conflict
214  * with the ones from the base device tree before merging them.
215  *
216  * returns:
217  *      0 on success
218  *      Negative error code on failure
219  */
220 static int overlay_update_local_node_references(void *fdto,
221 						int tree_node,
222 						int fixup_node,
223 						uint32_t delta)
224 {
225 	int fixup_prop;
226 	int fixup_child;
227 	int ret;
228 
229 	fdt_for_each_property_offset(fixup_prop, fdto, fixup_node) {
230 		const fdt32_t *fixup_val;
231 		const char *tree_val;
232 		const char *name;
233 		int fixup_len;
234 		int tree_len;
235 		int i;
236 
237 		fixup_val = fdt_getprop_by_offset(fdto, fixup_prop,
238 						  &name, &fixup_len);
239 		if (!fixup_val)
240 			return fixup_len;
241 
242 		if (fixup_len % sizeof(uint32_t))
243 			return -FDT_ERR_BADOVERLAY;
244 
245 		tree_val = fdt_getprop(fdto, tree_node, name, &tree_len);
246 		if (!tree_val) {
247 			if (tree_len == -FDT_ERR_NOTFOUND)
248 				return -FDT_ERR_BADOVERLAY;
249 
250 			return tree_len;
251 		}
252 
253 		for (i = 0; i < (fixup_len / sizeof(uint32_t)); i++) {
254 			fdt32_t adj_val;
255 			uint32_t poffset;
256 
257 			poffset = fdt32_to_cpu(fixup_val[i]);
258 
259 			/*
260 			 * phandles to fixup can be unaligned.
261 			 *
262 			 * Use a memcpy for the architectures that do
263 			 * not support unaligned accesses.
264 			 */
265 			memcpy(&adj_val, tree_val + poffset, sizeof(adj_val));
266 
267 			adj_val = cpu_to_fdt32(fdt32_to_cpu(adj_val) + delta);
268 
269 			ret = fdt_setprop_inplace_namelen_partial(fdto,
270 								  tree_node,
271 								  name,
272 								  strlen(name),
273 								  poffset,
274 								  &adj_val,
275 								  sizeof(adj_val));
276 			if (ret == -FDT_ERR_NOSPACE)
277 				return -FDT_ERR_BADOVERLAY;
278 
279 			if (ret)
280 				return ret;
281 		}
282 	}
283 
284 	fdt_for_each_subnode(fixup_child, fdto, fixup_node) {
285 		const char *fixup_child_name = fdt_get_name(fdto, fixup_child,
286 							    NULL);
287 		int tree_child;
288 
289 		tree_child = fdt_subnode_offset(fdto, tree_node,
290 						fixup_child_name);
291 		if (tree_child == -FDT_ERR_NOTFOUND)
292 			return -FDT_ERR_BADOVERLAY;
293 		if (tree_child < 0)
294 			return tree_child;
295 
296 		ret = overlay_update_local_node_references(fdto,
297 							   tree_child,
298 							   fixup_child,
299 							   delta);
300 		if (ret)
301 			return ret;
302 	}
303 
304 	return 0;
305 }
306 
307 /**
308  * overlay_update_local_references - Adjust the overlay references
309  * @fdto: Device tree overlay blob
310  * @delta: Offset to shift the phandles of
311  *
312  * overlay_update_local_references() update all the phandles pointing
313  * to a node within the device tree overlay by adding a constant
314  * delta to not conflict with the base overlay.
315  *
316  * This is mainly used as part of a device tree application process,
317  * where you want the device tree overlays phandles to not conflict
318  * with the ones from the base device tree before merging them.
319  *
320  * returns:
321  *      0 on success
322  *      Negative error code on failure
323  */
324 static int overlay_update_local_references(void *fdto, uint32_t delta)
325 {
326 	int fixups;
327 
328 	fixups = fdt_path_offset(fdto, "/__local_fixups__");
329 	if (fixups < 0) {
330 		/* There's no local phandles to adjust, bail out */
331 		if (fixups == -FDT_ERR_NOTFOUND)
332 			return 0;
333 
334 		return fixups;
335 	}
336 
337 	/*
338 	 * Update our local references from the root of the tree
339 	 */
340 	return overlay_update_local_node_references(fdto, 0, fixups,
341 						    delta);
342 }
343 
344 /**
345  * overlay_fixup_one_phandle - Set an overlay phandle to the base one
346  * @fdt: Base Device Tree blob
347  * @fdto: Device tree overlay blob
348  * @symbols_off: Node offset of the symbols node in the base device tree
349  * @path: Path to a node holding a phandle in the overlay
350  * @path_len: number of path characters to consider
351  * @name: Name of the property holding the phandle reference in the overlay
352  * @name_len: number of name characters to consider
353  * @poffset: Offset within the overlay property where the phandle is stored
354  * @label: Label of the node referenced by the phandle
355  *
356  * overlay_fixup_one_phandle() resolves an overlay phandle pointing to
357  * a node in the base device tree.
358  *
359  * This is part of the device tree overlay application process, when
360  * you want all the phandles in the overlay to point to the actual
361  * base dt nodes.
362  *
363  * returns:
364  *      0 on success
365  *      Negative error code on failure
366  */
367 static int overlay_fixup_one_phandle(void *fdt, void *fdto,
368 				     int symbols_off,
369 				     const char *path, uint32_t path_len,
370 				     const char *name, uint32_t name_len,
371 				     int poffset, const char *label)
372 {
373 	const char *symbol_path;
374 	uint32_t phandle;
375 	fdt32_t phandle_prop;
376 	int symbol_off, fixup_off;
377 	int prop_len;
378 
379 	if (symbols_off < 0)
380 		return symbols_off;
381 
382 	symbol_path = fdt_getprop(fdt, symbols_off, label,
383 				  &prop_len);
384 	if (!symbol_path)
385 		return prop_len;
386 
387 	symbol_off = fdt_path_offset(fdt, symbol_path);
388 	if (symbol_off < 0)
389 		return symbol_off;
390 
391 	phandle = fdt_get_phandle(fdt, symbol_off);
392 	if (!phandle)
393 		return -FDT_ERR_NOTFOUND;
394 
395 	fixup_off = fdt_path_offset_namelen(fdto, path, path_len);
396 	if (fixup_off == -FDT_ERR_NOTFOUND)
397 		return -FDT_ERR_BADOVERLAY;
398 	if (fixup_off < 0)
399 		return fixup_off;
400 
401 	phandle_prop = cpu_to_fdt32(phandle);
402 	return fdt_setprop_inplace_namelen_partial(fdto, fixup_off,
403 						   name, name_len, poffset,
404 						   &phandle_prop,
405 						   sizeof(phandle_prop));
406 };
407 
408 /**
409  * overlay_fixup_phandle - Set an overlay phandle to the base one
410  * @fdt: Base Device Tree blob
411  * @fdto: Device tree overlay blob
412  * @symbols_off: Node offset of the symbols node in the base device tree
413  * @property: Property offset in the overlay holding the list of fixups
414  *
415  * overlay_fixup_phandle() resolves all the overlay phandles pointed
416  * to in a __fixups__ property, and updates them to match the phandles
417  * in use in the base device tree.
418  *
419  * This is part of the device tree overlay application process, when
420  * you want all the phandles in the overlay to point to the actual
421  * base dt nodes.
422  *
423  * returns:
424  *      0 on success
425  *      Negative error code on failure
426  */
427 static int overlay_fixup_phandle(void *fdt, void *fdto, int symbols_off,
428 				 int property)
429 {
430 	const char *value;
431 	const char *label;
432 	int len;
433 
434 	value = fdt_getprop_by_offset(fdto, property,
435 				      &label, &len);
436 	if (!value) {
437 		if (len == -FDT_ERR_NOTFOUND)
438 			return -FDT_ERR_INTERNAL;
439 
440 		return len;
441 	}
442 
443 	do {
444 		const char *path, *name, *fixup_end;
445 		const char *fixup_str = value;
446 		uint32_t path_len, name_len;
447 		uint32_t fixup_len;
448 		char *sep, *endptr;
449 		int poffset, ret;
450 
451 		fixup_end = memchr(value, '\0', len);
452 		if (!fixup_end)
453 			return -FDT_ERR_BADOVERLAY;
454 		fixup_len = fixup_end - fixup_str;
455 
456 		len -= fixup_len + 1;
457 		value += fixup_len + 1;
458 
459 		path = fixup_str;
460 		sep = memchr(fixup_str, ':', fixup_len);
461 		if (!sep || *sep != ':')
462 			return -FDT_ERR_BADOVERLAY;
463 
464 		path_len = sep - path;
465 		if (path_len == (fixup_len - 1))
466 			return -FDT_ERR_BADOVERLAY;
467 
468 		fixup_len -= path_len + 1;
469 		name = sep + 1;
470 		sep = memchr(name, ':', fixup_len);
471 		if (!sep || *sep != ':')
472 			return -FDT_ERR_BADOVERLAY;
473 
474 		name_len = sep - name;
475 		if (!name_len)
476 			return -FDT_ERR_BADOVERLAY;
477 
478 		poffset = strtoul(sep + 1, &endptr, 10);
479 		if ((*endptr != '\0') || (endptr <= (sep + 1)))
480 			return -FDT_ERR_BADOVERLAY;
481 
482 		ret = overlay_fixup_one_phandle(fdt, fdto, symbols_off,
483 						path, path_len, name, name_len,
484 						poffset, label);
485 		if (ret)
486 			return ret;
487 	} while (len > 0);
488 
489 	return 0;
490 }
491 
492 /**
493  * overlay_fixup_phandles - Resolve the overlay phandles to the base
494  *                          device tree
495  * @fdt: Base Device Tree blob
496  * @fdto: Device tree overlay blob
497  *
498  * overlay_fixup_phandles() resolves all the overlay phandles pointing
499  * to nodes in the base device tree.
500  *
501  * This is one of the steps of the device tree overlay application
502  * process, when you want all the phandles in the overlay to point to
503  * the actual base dt nodes.
504  *
505  * returns:
506  *      0 on success
507  *      Negative error code on failure
508  */
509 static int overlay_fixup_phandles(void *fdt, void *fdto)
510 {
511 	int fixups_off, symbols_off;
512 	int property;
513 
514 	/* We can have overlays without any fixups */
515 	fixups_off = fdt_path_offset(fdto, "/__fixups__");
516 	if (fixups_off == -FDT_ERR_NOTFOUND)
517 		return 0; /* nothing to do */
518 	if (fixups_off < 0)
519 		return fixups_off;
520 
521 	/* And base DTs without symbols */
522 	symbols_off = fdt_path_offset(fdt, "/__symbols__");
523 	if ((symbols_off < 0 && (symbols_off != -FDT_ERR_NOTFOUND)))
524 		return symbols_off;
525 
526 	fdt_for_each_property_offset(property, fdto, fixups_off) {
527 		int ret;
528 
529 		ret = overlay_fixup_phandle(fdt, fdto, symbols_off, property);
530 		if (ret)
531 			return ret;
532 	}
533 
534 	return 0;
535 }
536 
537 /**
538  * overlay_apply_node - Merges a node into the base device tree
539  * @fdt: Base Device Tree blob
540  * @target: Node offset in the base device tree to apply the fragment to
541  * @fdto: Device tree overlay blob
542  * @node: Node offset in the overlay holding the changes to merge
543  *
544  * overlay_apply_node() merges a node into a target base device tree
545  * node pointed.
546  *
547  * This is part of the final step in the device tree overlay
548  * application process, when all the phandles have been adjusted and
549  * resolved and you just have to merge overlay into the base device
550  * tree.
551  *
552  * returns:
553  *      0 on success
554  *      Negative error code on failure
555  */
556 static int overlay_apply_node(void *fdt, int target,
557 			      void *fdto, int node)
558 {
559 	int property;
560 	int subnode;
561 
562 	fdt_for_each_property_offset(property, fdto, node) {
563 		const char *name;
564 		const void *prop;
565 		int prop_len;
566 		int ret;
567 
568 		prop = fdt_getprop_by_offset(fdto, property, &name,
569 					     &prop_len);
570 		if (prop_len == -FDT_ERR_NOTFOUND)
571 			return -FDT_ERR_INTERNAL;
572 		if (prop_len < 0)
573 			return prop_len;
574 
575 		ret = fdt_setprop(fdt, target, name, prop, prop_len);
576 		if (ret)
577 			return ret;
578 	}
579 
580 	fdt_for_each_subnode(subnode, fdto, node) {
581 		const char *name = fdt_get_name(fdto, subnode, NULL);
582 		int nnode;
583 		int ret;
584 
585 		nnode = fdt_add_subnode(fdt, target, name);
586 		if (nnode == -FDT_ERR_EXISTS) {
587 			nnode = fdt_subnode_offset(fdt, target, name);
588 			if (nnode == -FDT_ERR_NOTFOUND)
589 				return -FDT_ERR_INTERNAL;
590 		}
591 
592 		if (nnode < 0)
593 			return nnode;
594 
595 		ret = overlay_apply_node(fdt, nnode, fdto, subnode);
596 		if (ret)
597 			return ret;
598 	}
599 
600 	return 0;
601 }
602 
603 /**
604  * overlay_merge - Merge an overlay into its base device tree
605  * @fdt: Base Device Tree blob
606  * @fdto: Device tree overlay blob
607  *
608  * overlay_merge() merges an overlay into its base device tree.
609  *
610  * This is the next to last step in the device tree overlay application
611  * process, when all the phandles have been adjusted and resolved and
612  * you just have to merge overlay into the base device tree.
613  *
614  * returns:
615  *      0 on success
616  *      Negative error code on failure
617  */
618 static int overlay_merge(void *fdt, void *fdto)
619 {
620 	int fragment;
621 
622 	fdt_for_each_subnode(fragment, fdto, 0) {
623 		int overlay;
624 		int target;
625 		int ret;
626 
627 		/*
628 		 * Each fragments will have an __overlay__ node. If
629 		 * they don't, it's not supposed to be merged
630 		 */
631 		overlay = fdt_subnode_offset(fdto, fragment, "__overlay__");
632 		if (overlay == -FDT_ERR_NOTFOUND)
633 			continue;
634 
635 		if (overlay < 0)
636 			return overlay;
637 
638 		target = overlay_get_target(fdt, fdto, fragment, NULL);
639 		if (target < 0)
640 			return target;
641 
642 		ret = overlay_apply_node(fdt, target, fdto, overlay);
643 		if (ret)
644 			return ret;
645 	}
646 
647 	return 0;
648 }
649 
650 static int get_path_len(const void *fdt, int nodeoffset)
651 {
652 	int len = 0, namelen;
653 	const char *name;
654 
655 	FDT_RO_PROBE(fdt);
656 
657 	for (;;) {
658 		name = fdt_get_name(fdt, nodeoffset, &namelen);
659 		if (!name)
660 			return namelen;
661 
662 		/* root? we're done */
663 		if (namelen == 0)
664 			break;
665 
666 		nodeoffset = fdt_parent_offset(fdt, nodeoffset);
667 		if (nodeoffset < 0)
668 			return nodeoffset;
669 		len += namelen + 1;
670 	}
671 
672 	/* in case of root pretend it's "/" */
673 	if (len == 0)
674 		len++;
675 	return len;
676 }
677 
678 /**
679  * overlay_symbol_update - Update the symbols of base tree after a merge
680  * @fdt: Base Device Tree blob
681  * @fdto: Device tree overlay blob
682  *
683  * overlay_symbol_update() updates the symbols of the base tree with the
684  * symbols of the applied overlay
685  *
686  * This is the last step in the device tree overlay application
687  * process, allowing the reference of overlay symbols by subsequent
688  * overlay operations.
689  *
690  * returns:
691  *      0 on success
692  *      Negative error code on failure
693  */
694 static int overlay_symbol_update(void *fdt, void *fdto)
695 {
696 	int root_sym, ov_sym, prop, path_len, fragment, target;
697 	int len, frag_name_len, ret, rel_path_len;
698 	const char *s, *e;
699 	const char *path;
700 	const char *name;
701 	const char *frag_name;
702 	const char *rel_path;
703 	const char *target_path;
704 	char *buf;
705 	void *p;
706 
707 	ov_sym = fdt_subnode_offset(fdto, 0, "__symbols__");
708 
709 	/* if no overlay symbols exist no problem */
710 	if (ov_sym < 0)
711 		return 0;
712 
713 	root_sym = fdt_subnode_offset(fdt, 0, "__symbols__");
714 
715 	/* it no root symbols exist we should create them */
716 	if (root_sym == -FDT_ERR_NOTFOUND)
717 		root_sym = fdt_add_subnode(fdt, 0, "__symbols__");
718 
719 	/* any error is fatal now */
720 	if (root_sym < 0)
721 		return root_sym;
722 
723 	/* iterate over each overlay symbol */
724 	fdt_for_each_property_offset(prop, fdto, ov_sym) {
725 		path = fdt_getprop_by_offset(fdto, prop, &name, &path_len);
726 		if (!path)
727 			return path_len;
728 
729 		/* verify it's a string property (terminated by a single \0) */
730 		if (path_len < 1 || memchr(path, '\0', path_len) != &path[path_len - 1])
731 			return -FDT_ERR_BADVALUE;
732 
733 		/* keep end marker to avoid strlen() */
734 		e = path + path_len;
735 
736 		if (*path != '/')
737 			return -FDT_ERR_BADVALUE;
738 
739 		/* get fragment name first */
740 		s = strchr(path + 1, '/');
741 		if (!s) {
742 			/* Symbol refers to something that won't end
743 			 * up in the target tree */
744 			continue;
745 		}
746 
747 		frag_name = path + 1;
748 		frag_name_len = s - path - 1;
749 
750 		/* verify format; safe since "s" lies in \0 terminated prop */
751 		len = sizeof("/__overlay__/") - 1;
752 		if ((e - s) > len && (memcmp(s, "/__overlay__/", len) == 0)) {
753 			/* /<fragment-name>/__overlay__/<relative-subnode-path> */
754 			rel_path = s + len;
755 			rel_path_len = e - rel_path - 1;
756 		} else if ((e - s) == len
757 			   && (memcmp(s, "/__overlay__", len - 1) == 0)) {
758 			/* /<fragment-name>/__overlay__ */
759 			rel_path = "";
760 			rel_path_len = 0;
761 		} else {
762 			/* Symbol refers to something that won't end
763 			 * up in the target tree */
764 			continue;
765 		}
766 
767 		/* find the fragment index in which the symbol lies */
768 		ret = fdt_subnode_offset_namelen(fdto, 0, frag_name,
769 					       frag_name_len);
770 		/* not found? */
771 		if (ret < 0)
772 			return -FDT_ERR_BADOVERLAY;
773 		fragment = ret;
774 
775 		/* an __overlay__ subnode must exist */
776 		ret = fdt_subnode_offset(fdto, fragment, "__overlay__");
777 		if (ret < 0)
778 			return -FDT_ERR_BADOVERLAY;
779 
780 		/* get the target of the fragment */
781 		ret = overlay_get_target(fdt, fdto, fragment, &target_path);
782 		if (ret < 0)
783 			return ret;
784 		target = ret;
785 
786 		/* if we have a target path use */
787 		if (!target_path) {
788 			ret = get_path_len(fdt, target);
789 			if (ret < 0)
790 				return ret;
791 			len = ret;
792 		} else {
793 			len = strlen(target_path);
794 		}
795 
796 		ret = fdt_setprop_placeholder(fdt, root_sym, name,
797 				len + (len > 1) + rel_path_len + 1, &p);
798 		if (ret < 0)
799 			return ret;
800 
801 		if (!target_path) {
802 			/* again in case setprop_placeholder changed it */
803 			ret = overlay_get_target(fdt, fdto, fragment, &target_path);
804 			if (ret < 0)
805 				return ret;
806 			target = ret;
807 		}
808 
809 		buf = p;
810 		if (len > 1) { /* target is not root */
811 			if (!target_path) {
812 				ret = fdt_get_path(fdt, target, buf, len + 1);
813 				if (ret < 0)
814 					return ret;
815 			} else
816 				memcpy(buf, target_path, len + 1);
817 
818 		} else
819 			len--;
820 
821 		buf[len] = '/';
822 		memcpy(buf + len + 1, rel_path, rel_path_len);
823 		buf[len + 1 + rel_path_len] = '\0';
824 	}
825 
826 	return 0;
827 }
828 
829 int fdt_overlay_apply(void *fdt, void *fdto)
830 {
831 	uint32_t delta;
832 	int ret;
833 
834 	FDT_RO_PROBE(fdt);
835 	FDT_RO_PROBE(fdto);
836 
837 	ret = fdt_find_max_phandle(fdt, &delta);
838 	if (ret)
839 		goto err;
840 
841 	ret = overlay_adjust_local_phandles(fdto, delta);
842 	if (ret)
843 		goto err;
844 
845 	ret = overlay_update_local_references(fdto, delta);
846 	if (ret)
847 		goto err;
848 
849 	ret = overlay_fixup_phandles(fdt, fdto);
850 	if (ret)
851 		goto err;
852 
853 	ret = overlay_merge(fdt, fdto);
854 	if (ret)
855 		goto err;
856 
857 	ret = overlay_symbol_update(fdt, fdto);
858 	if (ret)
859 		goto err;
860 
861 	/*
862 	 * The overlay has been damaged, erase its magic.
863 	 */
864 	fdt_set_magic(fdto, ~0);
865 
866 	return 0;
867 
868 err:
869 	/*
870 	 * The overlay might have been damaged, erase its magic.
871 	 */
872 	fdt_set_magic(fdto, ~0);
873 
874 	/*
875 	 * The base device tree might have been damaged, erase its
876 	 * magic.
877 	 */
878 	fdt_set_magic(fdt, ~0);
879 
880 	return ret;
881 }
882