Linux Audio

Check our new training course

Loading...
v5.4
  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 */
 28static 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 */
 58static 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 */
116static 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 */
156static 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 */
193static 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 */
220static 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 */
324static 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 */
367static 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 */
427static 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 */
509static 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 */
556static 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 */
618static 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
650static 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 */
694static 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		/* format: /<fragment-name>/__overlay__/<relative-subnode-path> */
737
738		if (*path != '/')
739			return -FDT_ERR_BADVALUE;
740
741		/* get fragment name first */
742		s = strchr(path + 1, '/');
743		if (!s)
744			return -FDT_ERR_BADOVERLAY;
 
 
 
745
746		frag_name = path + 1;
747		frag_name_len = s - path - 1;
748
749		/* verify format; safe since "s" lies in \0 terminated prop */
750		len = sizeof("/__overlay__/") - 1;
751		if ((e - s) < len || memcmp(s, "/__overlay__/", len))
752			return -FDT_ERR_BADOVERLAY;
753
754		rel_path = s + len;
755		rel_path_len = e - rel_path;
 
 
 
 
 
 
 
 
 
756
757		/* find the fragment index in which the symbol lies */
758		ret = fdt_subnode_offset_namelen(fdto, 0, frag_name,
759					       frag_name_len);
760		/* not found? */
761		if (ret < 0)
762			return -FDT_ERR_BADOVERLAY;
763		fragment = ret;
764
765		/* an __overlay__ subnode must exist */
766		ret = fdt_subnode_offset(fdto, fragment, "__overlay__");
767		if (ret < 0)
768			return -FDT_ERR_BADOVERLAY;
769
770		/* get the target of the fragment */
771		ret = overlay_get_target(fdt, fdto, fragment, &target_path);
772		if (ret < 0)
773			return ret;
774		target = ret;
775
776		/* if we have a target path use */
777		if (!target_path) {
778			ret = get_path_len(fdt, target);
779			if (ret < 0)
780				return ret;
781			len = ret;
782		} else {
783			len = strlen(target_path);
784		}
785
786		ret = fdt_setprop_placeholder(fdt, root_sym, name,
787				len + (len > 1) + rel_path_len + 1, &p);
788		if (ret < 0)
789			return ret;
790
791		if (!target_path) {
792			/* again in case setprop_placeholder changed it */
793			ret = overlay_get_target(fdt, fdto, fragment, &target_path);
794			if (ret < 0)
795				return ret;
796			target = ret;
797		}
798
799		buf = p;
800		if (len > 1) { /* target is not root */
801			if (!target_path) {
802				ret = fdt_get_path(fdt, target, buf, len + 1);
803				if (ret < 0)
804					return ret;
805			} else
806				memcpy(buf, target_path, len + 1);
807
808		} else
809			len--;
810
811		buf[len] = '/';
812		memcpy(buf + len + 1, rel_path, rel_path_len);
813		buf[len + 1 + rel_path_len] = '\0';
814	}
815
816	return 0;
817}
818
819int fdt_overlay_apply(void *fdt, void *fdto)
820{
821	uint32_t delta;
822	int ret;
823
824	FDT_RO_PROBE(fdt);
825	FDT_RO_PROBE(fdto);
826
827	ret = fdt_find_max_phandle(fdt, &delta);
828	if (ret)
829		goto err;
830
831	ret = overlay_adjust_local_phandles(fdto, delta);
832	if (ret)
833		goto err;
834
835	ret = overlay_update_local_references(fdto, delta);
836	if (ret)
837		goto err;
838
839	ret = overlay_fixup_phandles(fdt, fdto);
840	if (ret)
841		goto err;
842
843	ret = overlay_merge(fdt, fdto);
844	if (ret)
845		goto err;
846
847	ret = overlay_symbol_update(fdt, fdto);
848	if (ret)
849		goto err;
850
851	/*
852	 * The overlay has been damaged, erase its magic.
853	 */
854	fdt_set_magic(fdto, ~0);
855
856	return 0;
857
858err:
859	/*
860	 * The overlay might have been damaged, erase its magic.
861	 */
862	fdt_set_magic(fdto, ~0);
863
864	/*
865	 * The base device tree might have been damaged, erase its
866	 * magic.
867	 */
868	fdt_set_magic(fdt, ~0);
869
870	return ret;
871}
v5.9
  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 */
 28static 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 */
 58static 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 */
116static 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 */
156static 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 */
193static 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 */
220static 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 */
324static 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 */
367static 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 */
427static 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 */
509static 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 */
556static 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 */
618static 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
650static 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 */
694static 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
829int 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
868err:
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}