File Index
Files and directories
Sign in
FILE

fdt_overlay.c

File preview with syntax highlighting.

linux-6.19.14/scripts/dtc/libfdt/fdt_overlay.c C
   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
  43int fdt_overlay_target_offset(const void *fdt, const void *fdto,
  44			      int fragment_offset, char const **pathp)
  45{
  46	uint32_t phandle;
  47	const char *path = NULL;
  48	int path_len = 0, ret;
  49
  50	/* Try first to do a phandle based lookup */
  51	phandle = overlay_get_target_phandle(fdto, fragment_offset);
  52	if (phandle == (uint32_t)-1)
  53		return -FDT_ERR_BADPHANDLE;
  54
  55	/* no phandle, try path */
  56	if (!phandle) {
  57		/* And then a path based lookup */
  58		path = fdt_getprop(fdto, fragment_offset, "target-path", &path_len);
  59		if (path)
  60			ret = fdt_path_offset(fdt, path);
  61		else
  62			ret = path_len;
  63	} else
  64		ret = fdt_node_offset_by_phandle(fdt, phandle);
  65
  66	/*
  67	* If we haven't found either a target or a
  68	* target-path property in a node that contains a
  69	* __overlay__ subnode (we wouldn't be called
  70	* otherwise), consider it a improperly written
  71	* overlay
  72	*/
  73	if (ret < 0 && path_len == -FDT_ERR_NOTFOUND)
  74		ret = -FDT_ERR_BADOVERLAY;
  75
  76	/* return on error */
  77	if (ret < 0)
  78		return ret;
  79
  80	/* return pointer to path (if available) */
  81	if (pathp)
  82		*pathp = path ? path : NULL;
  83
  84	return ret;
  85}
  86
  87/**
  88 * overlay_phandle_add_offset - Increases a phandle by an offset
  89 * @fdt: Base device tree blob
  90 * @node: Device tree overlay blob
  91 * @name: Name of the property to modify (phandle or linux,phandle)
  92 * @delta: offset to apply
  93 *
  94 * overlay_phandle_add_offset() increments a node phandle by a given
  95 * offset.
  96 *
  97 * returns:
  98 *      0 on success.
  99 *      Negative error code on error
 100 */
 101static int overlay_phandle_add_offset(void *fdt, int node,
 102				      const char *name, uint32_t delta)
 103{
 104	fdt32_t *valp, val;
 105	int len;
 106
 107	valp = fdt_getprop_w(fdt, node, name, &len);
 108	if (!valp)
 109		return len;
 110
 111	if (len != sizeof(val))
 112		return -FDT_ERR_BADPHANDLE;
 113
 114	val = fdt32_ld(valp);
 115	if (val + delta < val || val + delta == (uint32_t)-1)
 116		return -FDT_ERR_NOPHANDLES;
 117
 118	fdt32_st(valp, val + delta);
 119	return 0;
 120}
 121
 122/**
 123 * overlay_adjust_node_phandles - Offsets the phandles of a node
 124 * @fdto: Device tree overlay blob
 125 * @node: Offset of the node we want to adjust
 126 * @delta: Offset to shift the phandles of
 127 *
 128 * overlay_adjust_node_phandles() adds a constant to all the phandles
 129 * of a given node. This is mainly use as part of the overlay
 130 * application process, when we want to update all the overlay
 131 * phandles to not conflict with the overlays of the base device tree.
 132 *
 133 * returns:
 134 *      0 on success
 135 *      Negative error code on failure
 136 */
 137static int overlay_adjust_node_phandles(void *fdto, int node,
 138					uint32_t delta)
 139{
 140	int child;
 141	int ret;
 142
 143	ret = overlay_phandle_add_offset(fdto, node, "phandle", delta);
 144	if (ret && ret != -FDT_ERR_NOTFOUND)
 145		return ret;
 146
 147	ret = overlay_phandle_add_offset(fdto, node, "linux,phandle", delta);
 148	if (ret && ret != -FDT_ERR_NOTFOUND)
 149		return ret;
 150
 151	fdt_for_each_subnode(child, fdto, node) {
 152		ret = overlay_adjust_node_phandles(fdto, child, delta);
 153		if (ret)
 154			return ret;
 155	}
 156
 157	return 0;
 158}
 159
 160/**
 161 * overlay_adjust_local_phandles - Adjust the phandles of a whole overlay
 162 * @fdto: Device tree overlay blob
 163 * @delta: Offset to shift the phandles of
 164 *
 165 * overlay_adjust_local_phandles() adds a constant to all the
 166 * phandles of an overlay. This is mainly use as part of the overlay
 167 * application process, when we want to update all the overlay
 168 * phandles to not conflict with the overlays of the base device tree.
 169 *
 170 * returns:
 171 *      0 on success
 172 *      Negative error code on failure
 173 */
 174static int overlay_adjust_local_phandles(void *fdto, uint32_t delta)
 175{
 176	/*
 177	 * Start adjusting the phandles from the overlay root
 178	 */
 179	return overlay_adjust_node_phandles(fdto, 0, delta);
 180}
 181
 182/**
 183 * overlay_update_local_node_references - Adjust the overlay references
 184 * @fdto: Device tree overlay blob
 185 * @tree_node: Node offset of the node to operate on
 186 * @fixup_node: Node offset of the matching local fixups node
 187 * @delta: Offset to shift the phandles of
 188 *
 189 * overlay_update_local_nodes_references() update the phandles
 190 * pointing to a node within the device tree overlay by adding a
 191 * constant delta.
 192 *
 193 * This is mainly used as part of a device tree application process,
 194 * where you want the device tree overlays phandles to not conflict
 195 * with the ones from the base device tree before merging them.
 196 *
 197 * returns:
 198 *      0 on success
 199 *      Negative error code on failure
 200 */
 201static int overlay_update_local_node_references(void *fdto,
 202						int tree_node,
 203						int fixup_node,
 204						uint32_t delta)
 205{
 206	int fixup_prop;
 207	int fixup_child;
 208	int ret;
 209
 210	fdt_for_each_property_offset(fixup_prop, fdto, fixup_node) {
 211		const fdt32_t *fixup_val;
 212		const char *name;
 213		char *tree_val;
 214		int fixup_len;
 215		int tree_len;
 216		int i;
 217
 218		fixup_val = fdt_getprop_by_offset(fdto, fixup_prop,
 219						  &name, &fixup_len);
 220		if (!fixup_val)
 221			return fixup_len;
 222
 223		if (fixup_len % sizeof(uint32_t))
 224			return -FDT_ERR_BADOVERLAY;
 225		fixup_len /= sizeof(uint32_t);
 226
 227		tree_val = fdt_getprop_w(fdto, tree_node, name, &tree_len);
 228		if (!tree_val) {
 229			if (tree_len == -FDT_ERR_NOTFOUND)
 230				return -FDT_ERR_BADOVERLAY;
 231
 232			return tree_len;
 233		}
 234
 235		for (i = 0; i < fixup_len; i++) {
 236			fdt32_t *refp;
 237
 238			refp = (fdt32_t *)(tree_val + fdt32_ld_(fixup_val + i));
 239
 240			/*
 241			 * phandles to fixup can be unaligned, so use
 242			 * fdt32_{ld,st}() to read/write them.
 243			 */
 244			fdt32_st(refp, fdt32_ld(refp) + delta);
 245		}
 246	}
 247
 248	fdt_for_each_subnode(fixup_child, fdto, fixup_node) {
 249		const char *fixup_child_name = fdt_get_name(fdto, fixup_child,
 250							    NULL);
 251		int tree_child;
 252
 253		tree_child = fdt_subnode_offset(fdto, tree_node,
 254						fixup_child_name);
 255		if (tree_child == -FDT_ERR_NOTFOUND)
 256			return -FDT_ERR_BADOVERLAY;
 257		if (tree_child < 0)
 258			return tree_child;
 259
 260		ret = overlay_update_local_node_references(fdto,
 261							   tree_child,
 262							   fixup_child,
 263							   delta);
 264		if (ret)
 265			return ret;
 266	}
 267
 268	return 0;
 269}
 270
 271/**
 272 * overlay_update_local_references - Adjust the overlay references
 273 * @fdto: Device tree overlay blob
 274 * @delta: Offset to shift the phandles of
 275 *
 276 * overlay_update_local_references() update all the phandles pointing
 277 * to a node within the device tree overlay by adding a constant
 278 * delta to not conflict with the base overlay.
 279 *
 280 * This is mainly used as part of a device tree application process,
 281 * where you want the device tree overlays phandles to not conflict
 282 * with the ones from the base device tree before merging them.
 283 *
 284 * returns:
 285 *      0 on success
 286 *      Negative error code on failure
 287 */
 288static int overlay_update_local_references(void *fdto, uint32_t delta)
 289{
 290	int fixups;
 291
 292	fixups = fdt_path_offset(fdto, "/__local_fixups__");
 293	if (fixups < 0) {
 294		/* There's no local phandles to adjust, bail out */
 295		if (fixups == -FDT_ERR_NOTFOUND)
 296			return 0;
 297
 298		return fixups;
 299	}
 300
 301	/*
 302	 * Update our local references from the root of the tree
 303	 */
 304	return overlay_update_local_node_references(fdto, 0, fixups,
 305						    delta);
 306}
 307
 308/**
 309 * overlay_fixup_one_phandle - Set an overlay phandle to the base one
 310 * @fdto: Device tree overlay blob
 311 * @symbols_off: Node offset of the symbols node in the base device tree
 312 * @path: Path to a node holding a phandle in the overlay
 313 * @path_len: number of path characters to consider
 314 * @name: Name of the property holding the phandle reference in the overlay
 315 * @name_len: number of name characters to consider
 316 * @poffset: Offset within the overlay property where the phandle is stored
 317 * @phandle: Phandle referencing the node
 318 *
 319 * overlay_fixup_one_phandle() resolves an overlay phandle pointing to
 320 * a node in the base device tree.
 321 *
 322 * This is part of the device tree overlay application process, when
 323 * you want all the phandles in the overlay to point to the actual
 324 * base dt nodes.
 325 *
 326 * returns:
 327 *      0 on success
 328 *      Negative error code on failure
 329 */
 330static int overlay_fixup_one_phandle(void *fdto, int symbols_off,
 331				     const char *path, uint32_t path_len,
 332				     const char *name, uint32_t name_len,
 333				     int poffset, uint32_t phandle)
 334{
 335	fdt32_t phandle_prop;
 336	int fixup_off;
 337
 338	if (symbols_off < 0)
 339		return symbols_off;
 340
 341	fixup_off = fdt_path_offset_namelen(fdto, path, path_len);
 342	if (fixup_off == -FDT_ERR_NOTFOUND)
 343		return -FDT_ERR_BADOVERLAY;
 344	if (fixup_off < 0)
 345		return fixup_off;
 346
 347	phandle_prop = cpu_to_fdt32(phandle);
 348	return fdt_setprop_inplace_namelen_partial(fdto, fixup_off,
 349						   name, name_len, poffset,
 350						   &phandle_prop,
 351						   sizeof(phandle_prop));
 352}
 353
 354/**
 355 * overlay_fixup_phandle - Set an overlay phandle to the base one
 356 * @fdt: Base Device Tree blob
 357 * @fdto: Device tree overlay blob
 358 * @symbols_off: Node offset of the symbols node in the base device tree
 359 * @property: Property offset in the overlay holding the list of fixups
 360 *
 361 * overlay_fixup_phandle() resolves all the overlay phandles pointed
 362 * to in a __fixups__ property, and updates them to match the phandles
 363 * in use in the base device tree.
 364 *
 365 * This is part of the device tree overlay application process, when
 366 * you want all the phandles in the overlay to point to the actual
 367 * base dt nodes.
 368 *
 369 * returns:
 370 *      0 on success
 371 *      Negative error code on failure
 372 */
 373static int overlay_fixup_phandle(void *fdt, void *fdto, int symbols_off,
 374				 int property)
 375{
 376	const char *value;
 377	const char *label;
 378	int len;
 379	const char *symbol_path;
 380	int prop_len;
 381	int symbol_off;
 382	uint32_t phandle;
 383
 384	value = fdt_getprop_by_offset(fdto, property,
 385				      &label, &len);
 386	if (!value) {
 387		if (len == -FDT_ERR_NOTFOUND)
 388			return -FDT_ERR_INTERNAL;
 389
 390		return len;
 391	}
 392
 393	symbol_path = fdt_getprop(fdt, symbols_off, label, &prop_len);
 394	if (!symbol_path)
 395		return prop_len;
 396	
 397	symbol_off = fdt_path_offset(fdt, symbol_path);
 398	if (symbol_off < 0)
 399		return symbol_off;
 400	
 401	phandle = fdt_get_phandle(fdt, symbol_off);
 402	if (!phandle)
 403		return -FDT_ERR_NOTFOUND;
 404
 405	do {
 406		const char *path, *name, *fixup_end;
 407		const char *fixup_str = value;
 408		uint32_t path_len, name_len;
 409		uint32_t fixup_len;
 410		char *sep, *endptr;
 411		int poffset, ret;
 412
 413		fixup_end = memchr(value, '\0', len);
 414		if (!fixup_end)
 415			return -FDT_ERR_BADOVERLAY;
 416		fixup_len = fixup_end - fixup_str;
 417
 418		len -= fixup_len + 1;
 419		value += fixup_len + 1;
 420
 421		path = fixup_str;
 422		sep = memchr(fixup_str, ':', fixup_len);
 423		if (!sep || *sep != ':')
 424			return -FDT_ERR_BADOVERLAY;
 425
 426		path_len = sep - path;
 427		if (path_len == (fixup_len - 1))
 428			return -FDT_ERR_BADOVERLAY;
 429
 430		fixup_len -= path_len + 1;
 431		name = sep + 1;
 432		sep = memchr(name, ':', fixup_len);
 433		if (!sep || *sep != ':')
 434			return -FDT_ERR_BADOVERLAY;
 435
 436		name_len = sep - name;
 437		if (!name_len)
 438			return -FDT_ERR_BADOVERLAY;
 439
 440		poffset = strtoul(sep + 1, &endptr, 10);
 441		if ((*endptr != '\0') || (endptr <= (sep + 1)))
 442			return -FDT_ERR_BADOVERLAY;
 443
 444		ret = overlay_fixup_one_phandle(fdto, symbols_off,
 445						path, path_len, name, name_len,
 446						poffset, phandle);
 447		if (ret)
 448			return ret;
 449	} while (len > 0);
 450
 451	return 0;
 452}
 453
 454/**
 455 * overlay_fixup_phandles - Resolve the overlay phandles to the base
 456 *                          device tree
 457 * @fdt: Base Device Tree blob
 458 * @fdto: Device tree overlay blob
 459 *
 460 * overlay_fixup_phandles() resolves all the overlay phandles pointing
 461 * to nodes in the base device tree.
 462 *
 463 * This is one of the steps of the device tree overlay application
 464 * process, when you want all the phandles in the overlay to point to
 465 * the actual base dt nodes.
 466 *
 467 * returns:
 468 *      0 on success
 469 *      Negative error code on failure
 470 */
 471static int overlay_fixup_phandles(void *fdt, void *fdto)
 472{
 473	int fixups_off, symbols_off;
 474	int property;
 475
 476	/* We can have overlays without any fixups */
 477	fixups_off = fdt_path_offset(fdto, "/__fixups__");
 478	if (fixups_off == -FDT_ERR_NOTFOUND)
 479		return 0; /* nothing to do */
 480	if (fixups_off < 0)
 481		return fixups_off;
 482
 483	/* And base DTs without symbols */
 484	symbols_off = fdt_path_offset(fdt, "/__symbols__");
 485	if ((symbols_off < 0 && (symbols_off != -FDT_ERR_NOTFOUND)))
 486		return symbols_off;
 487
 488	fdt_for_each_property_offset(property, fdto, fixups_off) {
 489		int ret;
 490
 491		ret = overlay_fixup_phandle(fdt, fdto, symbols_off, property);
 492		if (ret)
 493			return ret;
 494	}
 495
 496	return 0;
 497}
 498
 499/**
 500 * overlay_adjust_local_conflicting_phandle: Changes a phandle value
 501 * @fdto: Device tree overlay
 502 * @node: The node the phandle is set for
 503 * @fdt_phandle: The new value for the phandle
 504 *
 505 * returns:
 506 *      0 on success
 507 *      Negative error code on failure
 508 */
 509static int overlay_adjust_local_conflicting_phandle(void *fdto, int node,
 510						    uint32_t fdt_phandle)
 511{
 512	const fdt32_t *php;
 513	int len, ret;
 514
 515	php = fdt_getprop(fdto, node, "phandle", &len);
 516	if (php && len == sizeof(*php)) {
 517		ret = fdt_setprop_inplace_u32(fdto, node, "phandle", fdt_phandle);
 518		if (ret)
 519			return ret;
 520	}
 521
 522	php = fdt_getprop(fdto, node, "linux,phandle", &len);
 523	if (php && len == sizeof(*php)) {
 524		ret = fdt_setprop_inplace_u32(fdto, node, "linux,phandle", fdt_phandle);
 525		if (ret)
 526			return ret;
 527	}
 528
 529	return 0;
 530}
 531
 532/**
 533 * overlay_update_node_conflicting_references - Recursively replace phandle values
 534 * @fdto: Device tree overlay blob
 535 * @tree_node: Node to recurse into
 536 * @fixup_node: Node offset of the matching local fixups node
 537 * @fdt_phandle: Value to replace phandles with
 538 * @fdto_phandle: Value to be replaced
 539 *
 540 * Replaces all phandles with value @fdto_phandle by @fdt_phandle.
 541 *
 542 * returns:
 543 *      0 on success
 544 *      Negative error code on failure
 545 */
 546static int overlay_update_node_conflicting_references(void *fdto, int tree_node,
 547						      int fixup_node,
 548						      uint32_t fdt_phandle,
 549						      uint32_t fdto_phandle)
 550{
 551	int fixup_prop;
 552	int fixup_child;
 553	int ret;
 554
 555	fdt_for_each_property_offset(fixup_prop, fdto, fixup_node) {
 556		const fdt32_t *fixup_val;
 557		const char *name;
 558		char *tree_val;
 559		int fixup_len;
 560		int tree_len;
 561		int i;
 562
 563		fixup_val = fdt_getprop_by_offset(fdto, fixup_prop,
 564						  &name, &fixup_len);
 565		if (!fixup_val)
 566			return fixup_len;
 567
 568		if (fixup_len % sizeof(uint32_t))
 569			return -FDT_ERR_BADOVERLAY;
 570		fixup_len /= sizeof(uint32_t);
 571
 572		tree_val = fdt_getprop_w(fdto, tree_node, name, &tree_len);
 573		if (!tree_val) {
 574			if (tree_len == -FDT_ERR_NOTFOUND)
 575				return -FDT_ERR_BADOVERLAY;
 576
 577			return tree_len;
 578		}
 579
 580		for (i = 0; i < fixup_len; i++) {
 581			fdt32_t *refp;
 582			uint32_t valp;
 583
 584			refp = (fdt32_t *)(tree_val + fdt32_ld_(fixup_val + i));
 585			valp = fdt32_ld(refp);
 586
 587			if (valp == fdto_phandle)
 588				fdt32_st(refp, fdt_phandle);
 589		}
 590	}
 591
 592	fdt_for_each_subnode(fixup_child, fdto, fixup_node) {
 593		const char *fixup_child_name = fdt_get_name(fdto, fixup_child, NULL);
 594		int tree_child;
 595
 596		tree_child = fdt_subnode_offset(fdto, tree_node, fixup_child_name);
 597
 598		if (tree_child == -FDT_ERR_NOTFOUND)
 599			return -FDT_ERR_BADOVERLAY;
 600		if (tree_child < 0)
 601			return tree_child;
 602
 603		ret = overlay_update_node_conflicting_references(fdto, tree_child,
 604								 fixup_child,
 605								 fdt_phandle,
 606								 fdto_phandle);
 607		if (ret)
 608			return ret;
 609	}
 610
 611	return 0;
 612}
 613
 614/**
 615 * overlay_update_local_conflicting_references - Recursively replace phandle values
 616 * @fdto: Device tree overlay blob
 617 * @fdt_phandle: Value to replace phandles with
 618 * @fdto_phandle: Value to be replaced
 619 *
 620 * Replaces all phandles with value @fdto_phandle by @fdt_phandle.
 621 *
 622 * returns:
 623 *      0 on success
 624 *      Negative error code on failure
 625 */
 626static int overlay_update_local_conflicting_references(void *fdto,
 627						       uint32_t fdt_phandle,
 628						       uint32_t fdto_phandle)
 629{
 630	int fixups;
 631
 632	fixups = fdt_path_offset(fdto, "/__local_fixups__");
 633	if (fixups == -FDT_ERR_NOTFOUND)
 634		return 0;
 635	if (fixups < 0)
 636		return fixups;
 637
 638	return overlay_update_node_conflicting_references(fdto, 0, fixups,
 639							  fdt_phandle,
 640							  fdto_phandle);
 641}
 642
 643/**
 644 * overlay_prevent_phandle_overwrite_node - Helper function for overlay_prevent_phandle_overwrite
 645 * @fdt: Base Device tree blob
 646 * @fdtnode: Node in fdt that is checked for an overwrite
 647 * @fdto: Device tree overlay blob
 648 * @fdtonode: Node in fdto matching @fdtnode
 649 *
 650 * returns:
 651 *      0 on success
 652 *      Negative error code on failure
 653 */
 654static int overlay_prevent_phandle_overwrite_node(void *fdt, int fdtnode,
 655						  void *fdto, int fdtonode)
 656{
 657	uint32_t fdt_phandle, fdto_phandle;
 658	int fdtochild;
 659
 660	fdt_phandle = fdt_get_phandle(fdt, fdtnode);
 661	fdto_phandle = fdt_get_phandle(fdto, fdtonode);
 662
 663	if (fdt_phandle && fdto_phandle) {
 664		int ret;
 665
 666		ret = overlay_adjust_local_conflicting_phandle(fdto, fdtonode,
 667							       fdt_phandle);
 668		if (ret)
 669			return ret;
 670
 671		ret = overlay_update_local_conflicting_references(fdto,
 672								  fdt_phandle,
 673								  fdto_phandle);
 674		if (ret)
 675			return ret;
 676	}
 677
 678	fdt_for_each_subnode(fdtochild, fdto, fdtonode) {
 679		const char *name = fdt_get_name(fdto, fdtochild, NULL);
 680		int fdtchild;
 681		int ret;
 682
 683		fdtchild = fdt_subnode_offset(fdt, fdtnode, name);
 684		if (fdtchild == -FDT_ERR_NOTFOUND)
 685			/*
 686			 * no further overwrites possible here as this node is
 687			 * new
 688			 */
 689			continue;
 690
 691		ret = overlay_prevent_phandle_overwrite_node(fdt, fdtchild,
 692							     fdto, fdtochild);
 693		if (ret)
 694			return ret;
 695	}
 696
 697	return 0;
 698}
 699
 700/**
 701 * overlay_prevent_phandle_overwrite - Fixes overlay phandles to not overwrite base phandles
 702 * @fdt: Base Device Tree blob
 703 * @fdto: Device tree overlay blob
 704 *
 705 * Checks recursively if applying fdto overwrites phandle values in the base
 706 * dtb. When such a phandle is found, the fdto is changed to use the fdt's
 707 * phandle value to not break references in the base.
 708 *
 709 * returns:
 710 *      0 on success
 711 *      Negative error code on failure
 712 */
 713static int overlay_prevent_phandle_overwrite(void *fdt, void *fdto)
 714{
 715	int fragment;
 716
 717	fdt_for_each_subnode(fragment, fdto, 0) {
 718		int overlay;
 719		int target;
 720		int ret;
 721
 722		overlay = fdt_subnode_offset(fdto, fragment, "__overlay__");
 723		if (overlay == -FDT_ERR_NOTFOUND)
 724			continue;
 725
 726		if (overlay < 0)
 727			return overlay;
 728
 729		target = fdt_overlay_target_offset(fdt, fdto, fragment, NULL);
 730		if (target == -FDT_ERR_NOTFOUND)
 731			/*
 732			 * The subtree doesn't exist in the base, so nothing
 733			 * will be overwritten.
 734			 */
 735			continue;
 736		else if (target < 0)
 737			return target;
 738
 739		ret = overlay_prevent_phandle_overwrite_node(fdt, target,
 740							     fdto, overlay);
 741		if (ret)
 742			return ret;
 743	}
 744
 745	return 0;
 746}
 747
 748/**
 749 * overlay_apply_node - Merges a node into the base device tree
 750 * @fdt: Base Device Tree blob
 751 * @target: Node offset in the base device tree to apply the fragment to
 752 * @fdto: Device tree overlay blob
 753 * @node: Node offset in the overlay holding the changes to merge
 754 *
 755 * overlay_apply_node() merges a node into a target base device tree
 756 * node pointed.
 757 *
 758 * This is part of the final step in the device tree overlay
 759 * application process, when all the phandles have been adjusted and
 760 * resolved and you just have to merge overlay into the base device
 761 * tree.
 762 *
 763 * returns:
 764 *      0 on success
 765 *      Negative error code on failure
 766 */
 767static int overlay_apply_node(void *fdt, int target,
 768			      void *fdto, int node)
 769{
 770	int property;
 771	int subnode;
 772
 773	fdt_for_each_property_offset(property, fdto, node) {
 774		const char *name;
 775		const void *prop;
 776		int prop_len;
 777		int ret;
 778
 779		prop = fdt_getprop_by_offset(fdto, property, &name,
 780					     &prop_len);
 781		if (prop_len == -FDT_ERR_NOTFOUND)
 782			return -FDT_ERR_INTERNAL;
 783		if (prop_len < 0)
 784			return prop_len;
 785
 786		ret = fdt_setprop(fdt, target, name, prop, prop_len);
 787		if (ret)
 788			return ret;
 789	}
 790
 791	fdt_for_each_subnode(subnode, fdto, node) {
 792		const char *name = fdt_get_name(fdto, subnode, NULL);
 793		int nnode;
 794		int ret;
 795
 796		nnode = fdt_add_subnode(fdt, target, name);
 797		if (nnode == -FDT_ERR_EXISTS) {
 798			nnode = fdt_subnode_offset(fdt, target, name);
 799			if (nnode == -FDT_ERR_NOTFOUND)
 800				return -FDT_ERR_INTERNAL;
 801		}
 802
 803		if (nnode < 0)
 804			return nnode;
 805
 806		ret = overlay_apply_node(fdt, nnode, fdto, subnode);
 807		if (ret)
 808			return ret;
 809	}
 810
 811	return 0;
 812}
 813
 814/**
 815 * overlay_merge - Merge an overlay into its base device tree
 816 * @fdt: Base Device Tree blob
 817 * @fdto: Device tree overlay blob
 818 *
 819 * overlay_merge() merges an overlay into its base device tree.
 820 *
 821 * This is the next to last step in the device tree overlay application
 822 * process, when all the phandles have been adjusted and resolved and
 823 * you just have to merge overlay into the base device tree.
 824 *
 825 * returns:
 826 *      0 on success
 827 *      Negative error code on failure
 828 */
 829static int overlay_merge(void *fdt, void *fdto)
 830{
 831	int fragment;
 832
 833	fdt_for_each_subnode(fragment, fdto, 0) {
 834		int overlay;
 835		int target;
 836		int ret;
 837
 838		/*
 839		 * Each fragments will have an __overlay__ node. If
 840		 * they don't, it's not supposed to be merged
 841		 */
 842		overlay = fdt_subnode_offset(fdto, fragment, "__overlay__");
 843		if (overlay == -FDT_ERR_NOTFOUND)
 844			continue;
 845
 846		if (overlay < 0)
 847			return overlay;
 848
 849		target = fdt_overlay_target_offset(fdt, fdto, fragment, NULL);
 850		if (target < 0)
 851			return target;
 852
 853		ret = overlay_apply_node(fdt, target, fdto, overlay);
 854		if (ret)
 855			return ret;
 856	}
 857
 858	return 0;
 859}
 860
 861static int get_path_len(const void *fdt, int nodeoffset)
 862{
 863	int len = 0, namelen;
 864	const char *name;
 865
 866	FDT_RO_PROBE(fdt);
 867
 868	for (;;) {
 869		name = fdt_get_name(fdt, nodeoffset, &namelen);
 870		if (!name)
 871			return namelen;
 872
 873		/* root? we're done */
 874		if (namelen == 0)
 875			break;
 876
 877		nodeoffset = fdt_parent_offset(fdt, nodeoffset);
 878		if (nodeoffset < 0)
 879			return nodeoffset;
 880		len += namelen + 1;
 881	}
 882
 883	/* in case of root pretend it's "/" */
 884	if (len == 0)
 885		len++;
 886	return len;
 887}
 888
 889/**
 890 * overlay_symbol_update - Update the symbols of base tree after a merge
 891 * @fdt: Base Device Tree blob
 892 * @fdto: Device tree overlay blob
 893 *
 894 * overlay_symbol_update() updates the symbols of the base tree with the
 895 * symbols of the applied overlay
 896 *
 897 * This is the last step in the device tree overlay application
 898 * process, allowing the reference of overlay symbols by subsequent
 899 * overlay operations.
 900 *
 901 * returns:
 902 *      0 on success
 903 *      Negative error code on failure
 904 */
 905static int overlay_symbol_update(void *fdt, void *fdto)
 906{
 907	int root_sym, ov_sym, prop, path_len, fragment, target;
 908	int len, frag_name_len, ret, rel_path_len;
 909	const char *s, *e;
 910	const char *path;
 911	const char *name;
 912	const char *frag_name;
 913	const char *rel_path;
 914	const char *target_path;
 915	char *buf;
 916	void *p;
 917
 918	ov_sym = fdt_subnode_offset(fdto, 0, "__symbols__");
 919
 920	/* if no overlay symbols exist no problem */
 921	if (ov_sym < 0)
 922		return 0;
 923
 924	root_sym = fdt_subnode_offset(fdt, 0, "__symbols__");
 925
 926	/* it no root symbols exist we should create them */
 927	if (root_sym == -FDT_ERR_NOTFOUND)
 928		root_sym = fdt_add_subnode(fdt, 0, "__symbols__");
 929
 930	/* any error is fatal now */
 931	if (root_sym < 0)
 932		return root_sym;
 933
 934	/* iterate over each overlay symbol */
 935	fdt_for_each_property_offset(prop, fdto, ov_sym) {
 936		path = fdt_getprop_by_offset(fdto, prop, &name, &path_len);
 937		if (!path)
 938			return path_len;
 939
 940		/* verify it's a string property (terminated by a single \0) */
 941		if (path_len < 1 || memchr(path, '\0', path_len) != &path[path_len - 1])
 942			return -FDT_ERR_BADVALUE;
 943
 944		/* keep end marker to avoid strlen() */
 945		e = path + path_len;
 946
 947		if (*path != '/')
 948			return -FDT_ERR_BADVALUE;
 949
 950		/* get fragment name first */
 951		s = strchr(path + 1, '/');
 952		if (!s) {
 953			/* Symbol refers to something that won't end
 954			 * up in the target tree */
 955			continue;
 956		}
 957
 958		frag_name = path + 1;
 959		frag_name_len = s - path - 1;
 960
 961		/* verify format; safe since "s" lies in \0 terminated prop */
 962		len = sizeof("/__overlay__/") - 1;
 963		if ((e - s) > len && (memcmp(s, "/__overlay__/", len) == 0)) {
 964			/* /<fragment-name>/__overlay__/<relative-subnode-path> */
 965			rel_path = s + len;
 966			rel_path_len = e - rel_path - 1;
 967		} else if ((e - s) == len
 968			   && (memcmp(s, "/__overlay__", len - 1) == 0)) {
 969			/* /<fragment-name>/__overlay__ */
 970			rel_path = "";
 971			rel_path_len = 0;
 972		} else {
 973			/* Symbol refers to something that won't end
 974			 * up in the target tree */
 975			continue;
 976		}
 977
 978		/* find the fragment index in which the symbol lies */
 979		ret = fdt_subnode_offset_namelen(fdto, 0, frag_name,
 980					       frag_name_len);
 981		/* not found? */
 982		if (ret < 0)
 983			return -FDT_ERR_BADOVERLAY;
 984		fragment = ret;
 985
 986		/* an __overlay__ subnode must exist */
 987		ret = fdt_subnode_offset(fdto, fragment, "__overlay__");
 988		if (ret < 0)
 989			return -FDT_ERR_BADOVERLAY;
 990
 991		/* get the target of the fragment */
 992		ret = fdt_overlay_target_offset(fdt, fdto, fragment, &target_path);
 993		if (ret < 0)
 994			return ret;
 995		target = ret;
 996
 997		/* if we have a target path use */
 998		if (!target_path) {
 999			ret = get_path_len(fdt, target);
1000			if (ret < 0)
1001				return ret;
1002			len = ret;
1003		} else {
1004			len = strlen(target_path);
1005		}
1006
1007		ret = fdt_setprop_placeholder(fdt, root_sym, name,
1008				len + (len > 1) + rel_path_len + 1, &p);
1009		if (ret < 0)
1010			return ret;
1011
1012		if (!target_path) {
1013			/* again in case setprop_placeholder changed it */
1014			ret = fdt_overlay_target_offset(fdt, fdto, fragment, &target_path);
1015			if (ret < 0)
1016				return ret;
1017			target = ret;
1018		}
1019
1020		buf = p;
1021		if (len > 1) { /* target is not root */
1022			if (!target_path) {
1023				ret = fdt_get_path(fdt, target, buf, len + 1);
1024				if (ret < 0)
1025					return ret;
1026			} else
1027				memcpy(buf, target_path, len + 1);
1028
1029		} else
1030			len--;
1031
1032		buf[len] = '/';
1033		memcpy(buf + len + 1, rel_path, rel_path_len);
1034		buf[len + 1 + rel_path_len] = '\0';
1035	}
1036
1037	return 0;
1038}
1039
1040int fdt_overlay_apply(void *fdt, void *fdto)
1041{
1042	uint32_t delta;
1043	int ret;
1044
1045	FDT_RO_PROBE(fdt);
1046	FDT_RO_PROBE(fdto);
1047
1048	ret = fdt_find_max_phandle(fdt, &delta);
1049	if (ret)
1050		goto err;
1051
1052	/* Increase all phandles in the fdto by delta */
1053	ret = overlay_adjust_local_phandles(fdto, delta);
1054	if (ret)
1055		goto err;
1056
1057	/* Adapt the phandle values in fdto to the above increase */
1058	ret = overlay_update_local_references(fdto, delta);
1059	if (ret)
1060		goto err;
1061
1062	/* Update fdto's phandles using symbols from fdt */
1063	ret = overlay_fixup_phandles(fdt, fdto);
1064	if (ret)
1065		goto err;
1066
1067	/* Don't overwrite phandles in fdt */
1068	ret = overlay_prevent_phandle_overwrite(fdt, fdto);
1069	if (ret)
1070		goto err;
1071
1072	ret = overlay_merge(fdt, fdto);
1073	if (ret)
1074		goto err;
1075
1076	ret = overlay_symbol_update(fdt, fdto);
1077	if (ret)
1078		goto err;
1079
1080	/*
1081	 * The overlay has been damaged, erase its magic.
1082	 */
1083	fdt_set_magic(fdto, ~0);
1084
1085	return 0;
1086
1087err:
1088	/*
1089	 * The overlay might have been damaged, erase its magic.
1090	 */
1091	fdt_set_magic(fdto, ~0);
1092
1093	/*
1094	 * The base device tree might have been damaged, erase its
1095	 * magic.
1096	 */
1097	fdt_set_magic(fdt, ~0);
1098
1099	return ret;
1100}
~/ Read-only file preview.