cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

fdt_overlay.c (22164B)


      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		fixup_len /= sizeof(uint32_t);
    245
    246		tree_val = fdt_getprop(fdto, tree_node, name, &tree_len);
    247		if (!tree_val) {
    248			if (tree_len == -FDT_ERR_NOTFOUND)
    249				return -FDT_ERR_BADOVERLAY;
    250
    251			return tree_len;
    252		}
    253
    254		for (i = 0; i < fixup_len; i++) {
    255			fdt32_t adj_val;
    256			uint32_t poffset;
    257
    258			poffset = fdt32_to_cpu(fixup_val[i]);
    259
    260			/*
    261			 * phandles to fixup can be unaligned.
    262			 *
    263			 * Use a memcpy for the architectures that do
    264			 * not support unaligned accesses.
    265			 */
    266			memcpy(&adj_val, tree_val + poffset, sizeof(adj_val));
    267
    268			adj_val = cpu_to_fdt32(fdt32_to_cpu(adj_val) + delta);
    269
    270			ret = fdt_setprop_inplace_namelen_partial(fdto,
    271								  tree_node,
    272								  name,
    273								  strlen(name),
    274								  poffset,
    275								  &adj_val,
    276								  sizeof(adj_val));
    277			if (ret == -FDT_ERR_NOSPACE)
    278				return -FDT_ERR_BADOVERLAY;
    279
    280			if (ret)
    281				return ret;
    282		}
    283	}
    284
    285	fdt_for_each_subnode(fixup_child, fdto, fixup_node) {
    286		const char *fixup_child_name = fdt_get_name(fdto, fixup_child,
    287							    NULL);
    288		int tree_child;
    289
    290		tree_child = fdt_subnode_offset(fdto, tree_node,
    291						fixup_child_name);
    292		if (tree_child == -FDT_ERR_NOTFOUND)
    293			return -FDT_ERR_BADOVERLAY;
    294		if (tree_child < 0)
    295			return tree_child;
    296
    297		ret = overlay_update_local_node_references(fdto,
    298							   tree_child,
    299							   fixup_child,
    300							   delta);
    301		if (ret)
    302			return ret;
    303	}
    304
    305	return 0;
    306}
    307
    308/**
    309 * overlay_update_local_references - Adjust the overlay references
    310 * @fdto: Device tree overlay blob
    311 * @delta: Offset to shift the phandles of
    312 *
    313 * overlay_update_local_references() update all the phandles pointing
    314 * to a node within the device tree overlay by adding a constant
    315 * delta to not conflict with the base overlay.
    316 *
    317 * This is mainly used as part of a device tree application process,
    318 * where you want the device tree overlays phandles to not conflict
    319 * with the ones from the base device tree before merging them.
    320 *
    321 * returns:
    322 *      0 on success
    323 *      Negative error code on failure
    324 */
    325static int overlay_update_local_references(void *fdto, uint32_t delta)
    326{
    327	int fixups;
    328
    329	fixups = fdt_path_offset(fdto, "/__local_fixups__");
    330	if (fixups < 0) {
    331		/* There's no local phandles to adjust, bail out */
    332		if (fixups == -FDT_ERR_NOTFOUND)
    333			return 0;
    334
    335		return fixups;
    336	}
    337
    338	/*
    339	 * Update our local references from the root of the tree
    340	 */
    341	return overlay_update_local_node_references(fdto, 0, fixups,
    342						    delta);
    343}
    344
    345/**
    346 * overlay_fixup_one_phandle - Set an overlay phandle to the base one
    347 * @fdt: Base Device Tree blob
    348 * @fdto: Device tree overlay blob
    349 * @symbols_off: Node offset of the symbols node in the base device tree
    350 * @path: Path to a node holding a phandle in the overlay
    351 * @path_len: number of path characters to consider
    352 * @name: Name of the property holding the phandle reference in the overlay
    353 * @name_len: number of name characters to consider
    354 * @poffset: Offset within the overlay property where the phandle is stored
    355 * @label: Label of the node referenced by the phandle
    356 *
    357 * overlay_fixup_one_phandle() resolves an overlay phandle pointing to
    358 * a node in the base device tree.
    359 *
    360 * This is part of the device tree overlay application process, when
    361 * you want all the phandles in the overlay to point to the actual
    362 * base dt nodes.
    363 *
    364 * returns:
    365 *      0 on success
    366 *      Negative error code on failure
    367 */
    368static int overlay_fixup_one_phandle(void *fdt, void *fdto,
    369				     int symbols_off,
    370				     const char *path, uint32_t path_len,
    371				     const char *name, uint32_t name_len,
    372				     int poffset, const char *label)
    373{
    374	const char *symbol_path;
    375	uint32_t phandle;
    376	fdt32_t phandle_prop;
    377	int symbol_off, fixup_off;
    378	int prop_len;
    379
    380	if (symbols_off < 0)
    381		return symbols_off;
    382
    383	symbol_path = fdt_getprop(fdt, symbols_off, label,
    384				  &prop_len);
    385	if (!symbol_path)
    386		return prop_len;
    387
    388	symbol_off = fdt_path_offset(fdt, symbol_path);
    389	if (symbol_off < 0)
    390		return symbol_off;
    391
    392	phandle = fdt_get_phandle(fdt, symbol_off);
    393	if (!phandle)
    394		return -FDT_ERR_NOTFOUND;
    395
    396	fixup_off = fdt_path_offset_namelen(fdto, path, path_len);
    397	if (fixup_off == -FDT_ERR_NOTFOUND)
    398		return -FDT_ERR_BADOVERLAY;
    399	if (fixup_off < 0)
    400		return fixup_off;
    401
    402	phandle_prop = cpu_to_fdt32(phandle);
    403	return fdt_setprop_inplace_namelen_partial(fdto, fixup_off,
    404						   name, name_len, poffset,
    405						   &phandle_prop,
    406						   sizeof(phandle_prop));
    407};
    408
    409/**
    410 * overlay_fixup_phandle - Set an overlay phandle to the base one
    411 * @fdt: Base Device Tree blob
    412 * @fdto: Device tree overlay blob
    413 * @symbols_off: Node offset of the symbols node in the base device tree
    414 * @property: Property offset in the overlay holding the list of fixups
    415 *
    416 * overlay_fixup_phandle() resolves all the overlay phandles pointed
    417 * to in a __fixups__ property, and updates them to match the phandles
    418 * in use in the base device tree.
    419 *
    420 * This is part of the device tree overlay application process, when
    421 * you want all the phandles in the overlay to point to the actual
    422 * base dt nodes.
    423 *
    424 * returns:
    425 *      0 on success
    426 *      Negative error code on failure
    427 */
    428static int overlay_fixup_phandle(void *fdt, void *fdto, int symbols_off,
    429				 int property)
    430{
    431	const char *value;
    432	const char *label;
    433	int len;
    434
    435	value = fdt_getprop_by_offset(fdto, property,
    436				      &label, &len);
    437	if (!value) {
    438		if (len == -FDT_ERR_NOTFOUND)
    439			return -FDT_ERR_INTERNAL;
    440
    441		return len;
    442	}
    443
    444	do {
    445		const char *path, *name, *fixup_end;
    446		const char *fixup_str = value;
    447		uint32_t path_len, name_len;
    448		uint32_t fixup_len;
    449		char *sep, *endptr;
    450		int poffset, ret;
    451
    452		fixup_end = memchr(value, '\0', len);
    453		if (!fixup_end)
    454			return -FDT_ERR_BADOVERLAY;
    455		fixup_len = fixup_end - fixup_str;
    456
    457		len -= fixup_len + 1;
    458		value += fixup_len + 1;
    459
    460		path = fixup_str;
    461		sep = memchr(fixup_str, ':', fixup_len);
    462		if (!sep || *sep != ':')
    463			return -FDT_ERR_BADOVERLAY;
    464
    465		path_len = sep - path;
    466		if (path_len == (fixup_len - 1))
    467			return -FDT_ERR_BADOVERLAY;
    468
    469		fixup_len -= path_len + 1;
    470		name = sep + 1;
    471		sep = memchr(name, ':', fixup_len);
    472		if (!sep || *sep != ':')
    473			return -FDT_ERR_BADOVERLAY;
    474
    475		name_len = sep - name;
    476		if (!name_len)
    477			return -FDT_ERR_BADOVERLAY;
    478
    479		poffset = strtoul(sep + 1, &endptr, 10);
    480		if ((*endptr != '\0') || (endptr <= (sep + 1)))
    481			return -FDT_ERR_BADOVERLAY;
    482
    483		ret = overlay_fixup_one_phandle(fdt, fdto, symbols_off,
    484						path, path_len, name, name_len,
    485						poffset, label);
    486		if (ret)
    487			return ret;
    488	} while (len > 0);
    489
    490	return 0;
    491}
    492
    493/**
    494 * overlay_fixup_phandles - Resolve the overlay phandles to the base
    495 *                          device tree
    496 * @fdt: Base Device Tree blob
    497 * @fdto: Device tree overlay blob
    498 *
    499 * overlay_fixup_phandles() resolves all the overlay phandles pointing
    500 * to nodes in the base device tree.
    501 *
    502 * This is one of the steps of the device tree overlay application
    503 * process, when you want all the phandles in the overlay to point to
    504 * the actual base dt nodes.
    505 *
    506 * returns:
    507 *      0 on success
    508 *      Negative error code on failure
    509 */
    510static int overlay_fixup_phandles(void *fdt, void *fdto)
    511{
    512	int fixups_off, symbols_off;
    513	int property;
    514
    515	/* We can have overlays without any fixups */
    516	fixups_off = fdt_path_offset(fdto, "/__fixups__");
    517	if (fixups_off == -FDT_ERR_NOTFOUND)
    518		return 0; /* nothing to do */
    519	if (fixups_off < 0)
    520		return fixups_off;
    521
    522	/* And base DTs without symbols */
    523	symbols_off = fdt_path_offset(fdt, "/__symbols__");
    524	if ((symbols_off < 0 && (symbols_off != -FDT_ERR_NOTFOUND)))
    525		return symbols_off;
    526
    527	fdt_for_each_property_offset(property, fdto, fixups_off) {
    528		int ret;
    529
    530		ret = overlay_fixup_phandle(fdt, fdto, symbols_off, property);
    531		if (ret)
    532			return ret;
    533	}
    534
    535	return 0;
    536}
    537
    538/**
    539 * overlay_apply_node - Merges a node into the base device tree
    540 * @fdt: Base Device Tree blob
    541 * @target: Node offset in the base device tree to apply the fragment to
    542 * @fdto: Device tree overlay blob
    543 * @node: Node offset in the overlay holding the changes to merge
    544 *
    545 * overlay_apply_node() merges a node into a target base device tree
    546 * node pointed.
    547 *
    548 * This is part of the final step in the device tree overlay
    549 * application process, when all the phandles have been adjusted and
    550 * resolved and you just have to merge overlay into the base device
    551 * tree.
    552 *
    553 * returns:
    554 *      0 on success
    555 *      Negative error code on failure
    556 */
    557static int overlay_apply_node(void *fdt, int target,
    558			      void *fdto, int node)
    559{
    560	int property;
    561	int subnode;
    562
    563	fdt_for_each_property_offset(property, fdto, node) {
    564		const char *name;
    565		const void *prop;
    566		int prop_len;
    567		int ret;
    568
    569		prop = fdt_getprop_by_offset(fdto, property, &name,
    570					     &prop_len);
    571		if (prop_len == -FDT_ERR_NOTFOUND)
    572			return -FDT_ERR_INTERNAL;
    573		if (prop_len < 0)
    574			return prop_len;
    575
    576		ret = fdt_setprop(fdt, target, name, prop, prop_len);
    577		if (ret)
    578			return ret;
    579	}
    580
    581	fdt_for_each_subnode(subnode, fdto, node) {
    582		const char *name = fdt_get_name(fdto, subnode, NULL);
    583		int nnode;
    584		int ret;
    585
    586		nnode = fdt_add_subnode(fdt, target, name);
    587		if (nnode == -FDT_ERR_EXISTS) {
    588			nnode = fdt_subnode_offset(fdt, target, name);
    589			if (nnode == -FDT_ERR_NOTFOUND)
    590				return -FDT_ERR_INTERNAL;
    591		}
    592
    593		if (nnode < 0)
    594			return nnode;
    595
    596		ret = overlay_apply_node(fdt, nnode, fdto, subnode);
    597		if (ret)
    598			return ret;
    599	}
    600
    601	return 0;
    602}
    603
    604/**
    605 * overlay_merge - Merge an overlay into its base device tree
    606 * @fdt: Base Device Tree blob
    607 * @fdto: Device tree overlay blob
    608 *
    609 * overlay_merge() merges an overlay into its base device tree.
    610 *
    611 * This is the next to last step in the device tree overlay application
    612 * process, when all the phandles have been adjusted and resolved and
    613 * you just have to merge overlay into the base device tree.
    614 *
    615 * returns:
    616 *      0 on success
    617 *      Negative error code on failure
    618 */
    619static int overlay_merge(void *fdt, void *fdto)
    620{
    621	int fragment;
    622
    623	fdt_for_each_subnode(fragment, fdto, 0) {
    624		int overlay;
    625		int target;
    626		int ret;
    627
    628		/*
    629		 * Each fragments will have an __overlay__ node. If
    630		 * they don't, it's not supposed to be merged
    631		 */
    632		overlay = fdt_subnode_offset(fdto, fragment, "__overlay__");
    633		if (overlay == -FDT_ERR_NOTFOUND)
    634			continue;
    635
    636		if (overlay < 0)
    637			return overlay;
    638
    639		target = overlay_get_target(fdt, fdto, fragment, NULL);
    640		if (target < 0)
    641			return target;
    642
    643		ret = overlay_apply_node(fdt, target, fdto, overlay);
    644		if (ret)
    645			return ret;
    646	}
    647
    648	return 0;
    649}
    650
    651static int get_path_len(const void *fdt, int nodeoffset)
    652{
    653	int len = 0, namelen;
    654	const char *name;
    655
    656	FDT_RO_PROBE(fdt);
    657
    658	for (;;) {
    659		name = fdt_get_name(fdt, nodeoffset, &namelen);
    660		if (!name)
    661			return namelen;
    662
    663		/* root? we're done */
    664		if (namelen == 0)
    665			break;
    666
    667		nodeoffset = fdt_parent_offset(fdt, nodeoffset);
    668		if (nodeoffset < 0)
    669			return nodeoffset;
    670		len += namelen + 1;
    671	}
    672
    673	/* in case of root pretend it's "/" */
    674	if (len == 0)
    675		len++;
    676	return len;
    677}
    678
    679/**
    680 * overlay_symbol_update - Update the symbols of base tree after a merge
    681 * @fdt: Base Device Tree blob
    682 * @fdto: Device tree overlay blob
    683 *
    684 * overlay_symbol_update() updates the symbols of the base tree with the
    685 * symbols of the applied overlay
    686 *
    687 * This is the last step in the device tree overlay application
    688 * process, allowing the reference of overlay symbols by subsequent
    689 * overlay operations.
    690 *
    691 * returns:
    692 *      0 on success
    693 *      Negative error code on failure
    694 */
    695static int overlay_symbol_update(void *fdt, void *fdto)
    696{
    697	int root_sym, ov_sym, prop, path_len, fragment, target;
    698	int len, frag_name_len, ret, rel_path_len;
    699	const char *s, *e;
    700	const char *path;
    701	const char *name;
    702	const char *frag_name;
    703	const char *rel_path;
    704	const char *target_path;
    705	char *buf;
    706	void *p;
    707
    708	ov_sym = fdt_subnode_offset(fdto, 0, "__symbols__");
    709
    710	/* if no overlay symbols exist no problem */
    711	if (ov_sym < 0)
    712		return 0;
    713
    714	root_sym = fdt_subnode_offset(fdt, 0, "__symbols__");
    715
    716	/* it no root symbols exist we should create them */
    717	if (root_sym == -FDT_ERR_NOTFOUND)
    718		root_sym = fdt_add_subnode(fdt, 0, "__symbols__");
    719
    720	/* any error is fatal now */
    721	if (root_sym < 0)
    722		return root_sym;
    723
    724	/* iterate over each overlay symbol */
    725	fdt_for_each_property_offset(prop, fdto, ov_sym) {
    726		path = fdt_getprop_by_offset(fdto, prop, &name, &path_len);
    727		if (!path)
    728			return path_len;
    729
    730		/* verify it's a string property (terminated by a single \0) */
    731		if (path_len < 1 || memchr(path, '\0', path_len) != &path[path_len - 1])
    732			return -FDT_ERR_BADVALUE;
    733
    734		/* keep end marker to avoid strlen() */
    735		e = path + path_len;
    736
    737		if (*path != '/')
    738			return -FDT_ERR_BADVALUE;
    739
    740		/* get fragment name first */
    741		s = strchr(path + 1, '/');
    742		if (!s) {
    743			/* Symbol refers to something that won't end
    744			 * up in the target tree */
    745			continue;
    746		}
    747
    748		frag_name = path + 1;
    749		frag_name_len = s - path - 1;
    750
    751		/* verify format; safe since "s" lies in \0 terminated prop */
    752		len = sizeof("/__overlay__/") - 1;
    753		if ((e - s) > len && (memcmp(s, "/__overlay__/", len) == 0)) {
    754			/* /<fragment-name>/__overlay__/<relative-subnode-path> */
    755			rel_path = s + len;
    756			rel_path_len = e - rel_path - 1;
    757		} else if ((e - s) == len
    758			   && (memcmp(s, "/__overlay__", len - 1) == 0)) {
    759			/* /<fragment-name>/__overlay__ */
    760			rel_path = "";
    761			rel_path_len = 0;
    762		} else {
    763			/* Symbol refers to something that won't end
    764			 * up in the target tree */
    765			continue;
    766		}
    767
    768		/* find the fragment index in which the symbol lies */
    769		ret = fdt_subnode_offset_namelen(fdto, 0, frag_name,
    770					       frag_name_len);
    771		/* not found? */
    772		if (ret < 0)
    773			return -FDT_ERR_BADOVERLAY;
    774		fragment = ret;
    775
    776		/* an __overlay__ subnode must exist */
    777		ret = fdt_subnode_offset(fdto, fragment, "__overlay__");
    778		if (ret < 0)
    779			return -FDT_ERR_BADOVERLAY;
    780
    781		/* get the target of the fragment */
    782		ret = overlay_get_target(fdt, fdto, fragment, &target_path);
    783		if (ret < 0)
    784			return ret;
    785		target = ret;
    786
    787		/* if we have a target path use */
    788		if (!target_path) {
    789			ret = get_path_len(fdt, target);
    790			if (ret < 0)
    791				return ret;
    792			len = ret;
    793		} else {
    794			len = strlen(target_path);
    795		}
    796
    797		ret = fdt_setprop_placeholder(fdt, root_sym, name,
    798				len + (len > 1) + rel_path_len + 1, &p);
    799		if (ret < 0)
    800			return ret;
    801
    802		if (!target_path) {
    803			/* again in case setprop_placeholder changed it */
    804			ret = overlay_get_target(fdt, fdto, fragment, &target_path);
    805			if (ret < 0)
    806				return ret;
    807			target = ret;
    808		}
    809
    810		buf = p;
    811		if (len > 1) { /* target is not root */
    812			if (!target_path) {
    813				ret = fdt_get_path(fdt, target, buf, len + 1);
    814				if (ret < 0)
    815					return ret;
    816			} else
    817				memcpy(buf, target_path, len + 1);
    818
    819		} else
    820			len--;
    821
    822		buf[len] = '/';
    823		memcpy(buf + len + 1, rel_path, rel_path_len);
    824		buf[len + 1 + rel_path_len] = '\0';
    825	}
    826
    827	return 0;
    828}
    829
    830int fdt_overlay_apply(void *fdt, void *fdto)
    831{
    832	uint32_t delta;
    833	int ret;
    834
    835	FDT_RO_PROBE(fdt);
    836	FDT_RO_PROBE(fdto);
    837
    838	ret = fdt_find_max_phandle(fdt, &delta);
    839	if (ret)
    840		goto err;
    841
    842	ret = overlay_adjust_local_phandles(fdto, delta);
    843	if (ret)
    844		goto err;
    845
    846	ret = overlay_update_local_references(fdto, delta);
    847	if (ret)
    848		goto err;
    849
    850	ret = overlay_fixup_phandles(fdt, fdto);
    851	if (ret)
    852		goto err;
    853
    854	ret = overlay_merge(fdt, fdto);
    855	if (ret)
    856		goto err;
    857
    858	ret = overlay_symbol_update(fdt, fdto);
    859	if (ret)
    860		goto err;
    861
    862	/*
    863	 * The overlay has been damaged, erase its magic.
    864	 */
    865	fdt_set_magic(fdto, ~0);
    866
    867	return 0;
    868
    869err:
    870	/*
    871	 * The overlay might have been damaged, erase its magic.
    872	 */
    873	fdt_set_magic(fdto, ~0);
    874
    875	/*
    876	 * The base device tree might have been damaged, erase its
    877	 * magic.
    878	 */
    879	fdt_set_magic(fdt, ~0);
    880
    881	return ret;
    882}