fdt_overlay.c 22 KB

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