xref: /linux/scripts/dtc/libfdt/fdt_overlay.c (revision d3603f4c30c24b43f49bf9c1dbc93b06f7a7775d)
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