fdt_overlay.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881
  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. tree_val = fdt_getprop(fdto, tree_node, name, &tree_len);
  216. if (!tree_val) {
  217. if (tree_len == -FDT_ERR_NOTFOUND)
  218. return -FDT_ERR_BADOVERLAY;
  219. return tree_len;
  220. }
  221. for (i = 0; i < (fixup_len / sizeof(uint32_t)); i++) {
  222. fdt32_t adj_val;
  223. uint32_t poffset;
  224. poffset = fdt32_to_cpu(fixup_val[i]);
  225. /*
  226. * phandles to fixup can be unaligned.
  227. *
  228. * Use a memcpy for the architectures that do
  229. * not support unaligned accesses.
  230. */
  231. memcpy(&adj_val, tree_val + poffset, sizeof(adj_val));
  232. adj_val = cpu_to_fdt32(fdt32_to_cpu(adj_val) + delta);
  233. ret = fdt_setprop_inplace_namelen_partial(fdto,
  234. tree_node,
  235. name,
  236. strlen(name),
  237. poffset,
  238. &adj_val,
  239. sizeof(adj_val));
  240. if (ret == -FDT_ERR_NOSPACE)
  241. return -FDT_ERR_BADOVERLAY;
  242. if (ret)
  243. return ret;
  244. }
  245. }
  246. fdt_for_each_subnode(fixup_child, fdto, fixup_node) {
  247. const char *fixup_child_name = fdt_get_name(fdto, fixup_child,
  248. NULL);
  249. int tree_child;
  250. tree_child = fdt_subnode_offset(fdto, tree_node,
  251. fixup_child_name);
  252. if (tree_child == -FDT_ERR_NOTFOUND)
  253. return -FDT_ERR_BADOVERLAY;
  254. if (tree_child < 0)
  255. return tree_child;
  256. ret = overlay_update_local_node_references(fdto,
  257. tree_child,
  258. fixup_child,
  259. delta);
  260. if (ret)
  261. return ret;
  262. }
  263. return 0;
  264. }
  265. /**
  266. * overlay_update_local_references - Adjust the overlay references
  267. * @fdto: Device tree overlay blob
  268. * @delta: Offset to shift the phandles of
  269. *
  270. * overlay_update_local_references() update all the phandles pointing
  271. * to a node within the device tree overlay by adding a constant
  272. * delta to not conflict with the base overlay.
  273. *
  274. * This is mainly used as part of a device tree application process,
  275. * where you want the device tree overlays phandles to not conflict
  276. * with the ones from the base device tree before merging them.
  277. *
  278. * returns:
  279. * 0 on success
  280. * Negative error code on failure
  281. */
  282. static int overlay_update_local_references(void *fdto, uint32_t delta)
  283. {
  284. int fixups;
  285. fixups = fdt_path_offset(fdto, "/__local_fixups__");
  286. if (fixups < 0) {
  287. /* There's no local phandles to adjust, bail out */
  288. if (fixups == -FDT_ERR_NOTFOUND)
  289. return 0;
  290. return fixups;
  291. }
  292. /*
  293. * Update our local references from the root of the tree
  294. */
  295. return overlay_update_local_node_references(fdto, 0, fixups,
  296. delta);
  297. }
  298. /**
  299. * overlay_fixup_one_phandle - Set an overlay phandle to the base one
  300. * @fdt: Base Device Tree blob
  301. * @fdto: Device tree overlay blob
  302. * @symbols_off: Node offset of the symbols node in the base device tree
  303. * @path: Path to a node holding a phandle in the overlay
  304. * @path_len: number of path characters to consider
  305. * @name: Name of the property holding the phandle reference in the overlay
  306. * @name_len: number of name characters to consider
  307. * @poffset: Offset within the overlay property where the phandle is stored
  308. * @label: Label of the node referenced by the phandle
  309. *
  310. * overlay_fixup_one_phandle() resolves an overlay phandle pointing to
  311. * a node in the base device tree.
  312. *
  313. * This is part of the device tree overlay application process, when
  314. * you want all the phandles in the overlay to point to the actual
  315. * base dt nodes.
  316. *
  317. * returns:
  318. * 0 on success
  319. * Negative error code on failure
  320. */
  321. static int overlay_fixup_one_phandle(void *fdt, void *fdto,
  322. int symbols_off,
  323. const char *path, uint32_t path_len,
  324. const char *name, uint32_t name_len,
  325. int poffset, const char *label)
  326. {
  327. const char *symbol_path;
  328. uint32_t phandle;
  329. fdt32_t phandle_prop;
  330. int symbol_off, fixup_off;
  331. int prop_len;
  332. if (symbols_off < 0)
  333. return symbols_off;
  334. symbol_path = fdt_getprop(fdt, symbols_off, label,
  335. &prop_len);
  336. if (!symbol_path)
  337. return prop_len;
  338. symbol_off = fdt_path_offset(fdt, symbol_path);
  339. if (symbol_off < 0)
  340. return symbol_off;
  341. phandle = fdt_get_phandle(fdt, symbol_off);
  342. if (!phandle)
  343. return -FDT_ERR_NOTFOUND;
  344. fixup_off = fdt_path_offset_namelen(fdto, path, path_len);
  345. if (fixup_off == -FDT_ERR_NOTFOUND)
  346. return -FDT_ERR_BADOVERLAY;
  347. if (fixup_off < 0)
  348. return fixup_off;
  349. phandle_prop = cpu_to_fdt32(phandle);
  350. return fdt_setprop_inplace_namelen_partial(fdto, fixup_off,
  351. name, name_len, poffset,
  352. &phandle_prop,
  353. sizeof(phandle_prop));
  354. };
  355. /**
  356. * overlay_fixup_phandle - Set an overlay phandle to the base one
  357. * @fdt: Base Device Tree blob
  358. * @fdto: Device tree overlay blob
  359. * @symbols_off: Node offset of the symbols node in the base device tree
  360. * @property: Property offset in the overlay holding the list of fixups
  361. *
  362. * overlay_fixup_phandle() resolves all the overlay phandles pointed
  363. * to in a __fixups__ property, and updates them to match the phandles
  364. * in use in the base device tree.
  365. *
  366. * This is part of the device tree overlay application process, when
  367. * you want all the phandles in the overlay to point to the actual
  368. * base dt nodes.
  369. *
  370. * returns:
  371. * 0 on success
  372. * Negative error code on failure
  373. */
  374. static int overlay_fixup_phandle(void *fdt, void *fdto, int symbols_off,
  375. int property)
  376. {
  377. const char *value;
  378. const char *label;
  379. int len;
  380. value = fdt_getprop_by_offset(fdto, property,
  381. &label, &len);
  382. if (!value) {
  383. if (len == -FDT_ERR_NOTFOUND)
  384. return -FDT_ERR_INTERNAL;
  385. return len;
  386. }
  387. do {
  388. const char *path, *name, *fixup_end;
  389. const char *fixup_str = value;
  390. uint32_t path_len, name_len;
  391. uint32_t fixup_len;
  392. char *sep, *endptr;
  393. int poffset, ret;
  394. fixup_end = memchr(value, '\0', len);
  395. if (!fixup_end)
  396. return -FDT_ERR_BADOVERLAY;
  397. fixup_len = fixup_end - fixup_str;
  398. len -= fixup_len + 1;
  399. value += fixup_len + 1;
  400. path = fixup_str;
  401. sep = memchr(fixup_str, ':', fixup_len);
  402. if (!sep || *sep != ':')
  403. return -FDT_ERR_BADOVERLAY;
  404. path_len = sep - path;
  405. if (path_len == (fixup_len - 1))
  406. return -FDT_ERR_BADOVERLAY;
  407. fixup_len -= path_len + 1;
  408. name = sep + 1;
  409. sep = memchr(name, ':', fixup_len);
  410. if (!sep || *sep != ':')
  411. return -FDT_ERR_BADOVERLAY;
  412. name_len = sep - name;
  413. if (!name_len)
  414. return -FDT_ERR_BADOVERLAY;
  415. poffset = strtoul(sep + 1, &endptr, 10);
  416. if ((*endptr != '\0') || (endptr <= (sep + 1)))
  417. return -FDT_ERR_BADOVERLAY;
  418. ret = overlay_fixup_one_phandle(fdt, fdto, symbols_off,
  419. path, path_len, name, name_len,
  420. poffset, label);
  421. if (ret)
  422. return ret;
  423. } while (len > 0);
  424. return 0;
  425. }
  426. /**
  427. * overlay_fixup_phandles - Resolve the overlay phandles to the base
  428. * device tree
  429. * @fdt: Base Device Tree blob
  430. * @fdto: Device tree overlay blob
  431. *
  432. * overlay_fixup_phandles() resolves all the overlay phandles pointing
  433. * to nodes in the base device tree.
  434. *
  435. * This is one of the steps of the device tree overlay application
  436. * process, when you want all the phandles in the overlay to point to
  437. * the actual base dt nodes.
  438. *
  439. * returns:
  440. * 0 on success
  441. * Negative error code on failure
  442. */
  443. static int overlay_fixup_phandles(void *fdt, void *fdto)
  444. {
  445. int fixups_off, symbols_off;
  446. int property;
  447. /* We can have overlays without any fixups */
  448. fixups_off = fdt_path_offset(fdto, "/__fixups__");
  449. if (fixups_off == -FDT_ERR_NOTFOUND)
  450. return 0; /* nothing to do */
  451. if (fixups_off < 0)
  452. return fixups_off;
  453. /* And base DTs without symbols */
  454. symbols_off = fdt_path_offset(fdt, "/__symbols__");
  455. if ((symbols_off < 0 && (symbols_off != -FDT_ERR_NOTFOUND)))
  456. return symbols_off;
  457. fdt_for_each_property_offset(property, fdto, fixups_off) {
  458. int ret;
  459. ret = overlay_fixup_phandle(fdt, fdto, symbols_off, property);
  460. if (ret)
  461. return ret;
  462. }
  463. return 0;
  464. }
  465. /**
  466. * overlay_apply_node - Merges a node into the base device tree
  467. * @fdt: Base Device Tree blob
  468. * @target: Node offset in the base device tree to apply the fragment to
  469. * @fdto: Device tree overlay blob
  470. * @node: Node offset in the overlay holding the changes to merge
  471. *
  472. * overlay_apply_node() merges a node into a target base device tree
  473. * node pointed.
  474. *
  475. * This is part of the final step in the device tree overlay
  476. * application process, when all the phandles have been adjusted and
  477. * resolved and you just have to merge overlay into the base device
  478. * tree.
  479. *
  480. * returns:
  481. * 0 on success
  482. * Negative error code on failure
  483. */
  484. static int overlay_apply_node(void *fdt, int target,
  485. void *fdto, int node)
  486. {
  487. int property;
  488. int subnode;
  489. fdt_for_each_property_offset(property, fdto, node) {
  490. const char *name;
  491. const void *prop;
  492. int prop_len;
  493. int ret;
  494. prop = fdt_getprop_by_offset(fdto, property, &name,
  495. &prop_len);
  496. if (prop_len == -FDT_ERR_NOTFOUND)
  497. return -FDT_ERR_INTERNAL;
  498. if (prop_len < 0)
  499. return prop_len;
  500. ret = fdt_setprop(fdt, target, name, prop, prop_len);
  501. if (ret)
  502. return ret;
  503. }
  504. fdt_for_each_subnode(subnode, fdto, node) {
  505. const char *name = fdt_get_name(fdto, subnode, NULL);
  506. int nnode;
  507. int ret;
  508. nnode = fdt_add_subnode(fdt, target, name);
  509. if (nnode == -FDT_ERR_EXISTS) {
  510. nnode = fdt_subnode_offset(fdt, target, name);
  511. if (nnode == -FDT_ERR_NOTFOUND)
  512. return -FDT_ERR_INTERNAL;
  513. }
  514. if (nnode < 0)
  515. return nnode;
  516. ret = overlay_apply_node(fdt, nnode, fdto, subnode);
  517. if (ret)
  518. return ret;
  519. }
  520. return 0;
  521. }
  522. /**
  523. * overlay_merge - Merge an overlay into its base device tree
  524. * @fdt: Base Device Tree blob
  525. * @fdto: Device tree overlay blob
  526. *
  527. * overlay_merge() merges an overlay into its base device tree.
  528. *
  529. * This is the next to last step in the device tree overlay application
  530. * process, when all the phandles have been adjusted and resolved and
  531. * you just have to merge overlay into the base device tree.
  532. *
  533. * returns:
  534. * 0 on success
  535. * Negative error code on failure
  536. */
  537. static int overlay_merge(void *fdt, void *fdto)
  538. {
  539. int fragment;
  540. fdt_for_each_subnode(fragment, fdto, 0) {
  541. int overlay;
  542. int target;
  543. int ret;
  544. /*
  545. * Each fragments will have an __overlay__ node. If
  546. * they don't, it's not supposed to be merged
  547. */
  548. overlay = fdt_subnode_offset(fdto, fragment, "__overlay__");
  549. if (overlay == -FDT_ERR_NOTFOUND)
  550. continue;
  551. if (overlay < 0)
  552. return overlay;
  553. target = overlay_get_target(fdt, fdto, fragment, NULL);
  554. if (target < 0)
  555. return target;
  556. ret = overlay_apply_node(fdt, target, fdto, overlay);
  557. if (ret)
  558. return ret;
  559. }
  560. return 0;
  561. }
  562. static int get_path_len(const void *fdt, int nodeoffset)
  563. {
  564. int len = 0, namelen;
  565. const char *name;
  566. FDT_RO_PROBE(fdt);
  567. for (;;) {
  568. name = fdt_get_name(fdt, nodeoffset, &namelen);
  569. if (!name)
  570. return namelen;
  571. /* root? we're done */
  572. if (namelen == 0)
  573. break;
  574. nodeoffset = fdt_parent_offset(fdt, nodeoffset);
  575. if (nodeoffset < 0)
  576. return nodeoffset;
  577. len += namelen + 1;
  578. }
  579. /* in case of root pretend it's "/" */
  580. if (len == 0)
  581. len++;
  582. return len;
  583. }
  584. /**
  585. * overlay_symbol_update - Update the symbols of base tree after a merge
  586. * @fdt: Base Device Tree blob
  587. * @fdto: Device tree overlay blob
  588. *
  589. * overlay_symbol_update() updates the symbols of the base tree with the
  590. * symbols of the applied overlay
  591. *
  592. * This is the last step in the device tree overlay application
  593. * process, allowing the reference of overlay symbols by subsequent
  594. * overlay operations.
  595. *
  596. * returns:
  597. * 0 on success
  598. * Negative error code on failure
  599. */
  600. static int overlay_symbol_update(void *fdt, void *fdto)
  601. {
  602. int root_sym, ov_sym, prop, path_len, fragment, target;
  603. int len, frag_name_len, ret, rel_path_len;
  604. const char *s, *e;
  605. const char *path;
  606. const char *name;
  607. const char *frag_name;
  608. const char *rel_path;
  609. const char *target_path;
  610. char *buf;
  611. void *p;
  612. ov_sym = fdt_subnode_offset(fdto, 0, "__symbols__");
  613. /* if no overlay symbols exist no problem */
  614. if (ov_sym < 0)
  615. return 0;
  616. root_sym = fdt_subnode_offset(fdt, 0, "__symbols__");
  617. /* it no root symbols exist we should create them */
  618. if (root_sym == -FDT_ERR_NOTFOUND)
  619. root_sym = fdt_add_subnode(fdt, 0, "__symbols__");
  620. /* any error is fatal now */
  621. if (root_sym < 0)
  622. return root_sym;
  623. /* iterate over each overlay symbol */
  624. fdt_for_each_property_offset(prop, fdto, ov_sym) {
  625. path = fdt_getprop_by_offset(fdto, prop, &name, &path_len);
  626. if (!path)
  627. return path_len;
  628. /* verify it's a string property (terminated by a single \0) */
  629. if (path_len < 1 || memchr(path, '\0', path_len) != &path[path_len - 1])
  630. return -FDT_ERR_BADVALUE;
  631. /* keep end marker to avoid strlen() */
  632. e = path + path_len;
  633. if (*path != '/')
  634. return -FDT_ERR_BADVALUE;
  635. /* get fragment name first */
  636. s = strchr(path + 1, '/');
  637. if (!s) {
  638. /* Symbol refers to something that won't end
  639. * up in the target tree */
  640. continue;
  641. }
  642. frag_name = path + 1;
  643. frag_name_len = s - path - 1;
  644. /* verify format; safe since "s" lies in \0 terminated prop */
  645. len = sizeof("/__overlay__/") - 1;
  646. if ((e - s) > len && (memcmp(s, "/__overlay__/", len) == 0)) {
  647. /* /<fragment-name>/__overlay__/<relative-subnode-path> */
  648. rel_path = s + len;
  649. rel_path_len = e - rel_path;
  650. } else if ((e - s) == len
  651. && (memcmp(s, "/__overlay__", len - 1) == 0)) {
  652. /* /<fragment-name>/__overlay__ */
  653. rel_path = "";
  654. rel_path_len = 0;
  655. } else {
  656. /* Symbol refers to something that won't end
  657. * up in the target tree */
  658. continue;
  659. }
  660. /* find the fragment index in which the symbol lies */
  661. ret = fdt_subnode_offset_namelen(fdto, 0, frag_name,
  662. frag_name_len);
  663. /* not found? */
  664. if (ret < 0)
  665. return -FDT_ERR_BADOVERLAY;
  666. fragment = ret;
  667. /* an __overlay__ subnode must exist */
  668. ret = fdt_subnode_offset(fdto, fragment, "__overlay__");
  669. if (ret < 0)
  670. return -FDT_ERR_BADOVERLAY;
  671. /* get the target of the fragment */
  672. ret = overlay_get_target(fdt, fdto, fragment, &target_path);
  673. if (ret < 0)
  674. return ret;
  675. target = ret;
  676. /* if we have a target path use */
  677. if (!target_path) {
  678. ret = get_path_len(fdt, target);
  679. if (ret < 0)
  680. return ret;
  681. len = ret;
  682. } else {
  683. len = strlen(target_path);
  684. }
  685. ret = fdt_setprop_placeholder(fdt, root_sym, name,
  686. len + (len > 1) + rel_path_len + 1, &p);
  687. if (ret < 0)
  688. return ret;
  689. if (!target_path) {
  690. /* again in case setprop_placeholder changed it */
  691. ret = overlay_get_target(fdt, fdto, fragment, &target_path);
  692. if (ret < 0)
  693. return ret;
  694. target = ret;
  695. }
  696. buf = p;
  697. if (len > 1) { /* target is not root */
  698. if (!target_path) {
  699. ret = fdt_get_path(fdt, target, buf, len + 1);
  700. if (ret < 0)
  701. return ret;
  702. } else
  703. memcpy(buf, target_path, len + 1);
  704. } else
  705. len--;
  706. buf[len] = '/';
  707. memcpy(buf + len + 1, rel_path, rel_path_len);
  708. buf[len + 1 + rel_path_len] = '\0';
  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. }