fdt_overlay.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671
  1. #include "libfdt_env.h"
  2. #include <fdt.h>
  3. #include <libfdt.h>
  4. #include "libfdt_internal.h"
  5. /**
  6. * overlay_get_target_phandle - retrieves the target phandle of a fragment
  7. * @fdto: pointer to the device tree overlay blob
  8. * @fragment: node offset of the fragment in the overlay
  9. *
  10. * overlay_get_target_phandle() retrieves the target phandle of an
  11. * overlay fragment when that fragment uses a phandle (target
  12. * property) instead of a path (target-path property).
  13. *
  14. * returns:
  15. * the phandle pointed by the target property
  16. * 0, if the phandle was not found
  17. * -1, if the phandle was malformed
  18. */
  19. static uint32_t overlay_get_target_phandle(const void *fdto, int fragment)
  20. {
  21. const uint32_t *val;
  22. int len;
  23. val = fdt_getprop(fdto, fragment, "target", &len);
  24. if (!val)
  25. return 0;
  26. if ((len != sizeof(*val)) || (*val == (uint32_t)-1))
  27. return (uint32_t)-1;
  28. return fdt32_to_cpu(*val);
  29. }
  30. /**
  31. * overlay_get_target - retrieves the offset of a fragment's target
  32. * @fdt: Base device tree blob
  33. * @fdto: Device tree overlay blob
  34. * @fragment: node offset of the fragment in the overlay
  35. *
  36. * overlay_get_target() retrieves the target offset in the base
  37. * device tree of a fragment, no matter how the actual targetting is
  38. * done (through a phandle or a path)
  39. *
  40. * returns:
  41. * the targetted node offset in the base device tree
  42. * Negative error code on error
  43. */
  44. static int overlay_get_target(const void *fdt, const void *fdto,
  45. int fragment)
  46. {
  47. uint32_t phandle;
  48. const char *path;
  49. int path_len;
  50. /* Try first to do a phandle based lookup */
  51. phandle = overlay_get_target_phandle(fdto, fragment);
  52. if (phandle == (uint32_t)-1)
  53. return -FDT_ERR_BADPHANDLE;
  54. if (phandle)
  55. return fdt_node_offset_by_phandle(fdt, phandle);
  56. /* And then a path based lookup */
  57. path = fdt_getprop(fdto, fragment, "target-path", &path_len);
  58. if (!path) {
  59. /*
  60. * If we haven't found either a target or a
  61. * target-path property in a node that contains a
  62. * __overlay__ subnode (we wouldn't be called
  63. * otherwise), consider it a improperly written
  64. * overlay
  65. */
  66. if (path_len == -FDT_ERR_NOTFOUND)
  67. return -FDT_ERR_BADOVERLAY;
  68. return path_len;
  69. }
  70. return fdt_path_offset(fdt, path);
  71. }
  72. /**
  73. * overlay_phandle_add_offset - Increases a phandle by an offset
  74. * @fdt: Base device tree blob
  75. * @node: Device tree overlay blob
  76. * @name: Name of the property to modify (phandle or linux,phandle)
  77. * @delta: offset to apply
  78. *
  79. * overlay_phandle_add_offset() increments a node phandle by a given
  80. * offset.
  81. *
  82. * returns:
  83. * 0 on success.
  84. * Negative error code on error
  85. */
  86. static int overlay_phandle_add_offset(void *fdt, int node,
  87. const char *name, uint32_t delta)
  88. {
  89. const uint32_t *val;
  90. uint32_t adj_val;
  91. int len;
  92. val = fdt_getprop(fdt, node, name, &len);
  93. if (!val)
  94. return len;
  95. if (len != sizeof(*val))
  96. return -FDT_ERR_BADPHANDLE;
  97. adj_val = fdt32_to_cpu(*val);
  98. if ((adj_val + delta) < adj_val)
  99. return -FDT_ERR_NOPHANDLES;
  100. adj_val += delta;
  101. if (adj_val == (uint32_t)-1)
  102. return -FDT_ERR_NOPHANDLES;
  103. return fdt_setprop_inplace_u32(fdt, node, name, adj_val);
  104. }
  105. /**
  106. * overlay_adjust_node_phandles - Offsets the phandles of a node
  107. * @fdto: Device tree overlay blob
  108. * @node: Offset of the node we want to adjust
  109. * @delta: Offset to shift the phandles of
  110. *
  111. * overlay_adjust_node_phandles() adds a constant to all the phandles
  112. * of a given node. This is mainly use as part of the overlay
  113. * application process, when we want to update all the overlay
  114. * phandles to not conflict with the overlays of the base device tree.
  115. *
  116. * returns:
  117. * 0 on success
  118. * Negative error code on failure
  119. */
  120. static int overlay_adjust_node_phandles(void *fdto, int node,
  121. uint32_t delta)
  122. {
  123. int child;
  124. int ret;
  125. ret = overlay_phandle_add_offset(fdto, node, "phandle", delta);
  126. if (ret && ret != -FDT_ERR_NOTFOUND)
  127. return ret;
  128. ret = overlay_phandle_add_offset(fdto, node, "linux,phandle", delta);
  129. if (ret && ret != -FDT_ERR_NOTFOUND)
  130. return ret;
  131. fdt_for_each_subnode(child, fdto, node) {
  132. ret = overlay_adjust_node_phandles(fdto, child, delta);
  133. if (ret)
  134. return ret;
  135. }
  136. return 0;
  137. }
  138. /**
  139. * overlay_adjust_local_phandles - Adjust the phandles of a whole overlay
  140. * @fdto: Device tree overlay blob
  141. * @delta: Offset to shift the phandles of
  142. *
  143. * overlay_adjust_local_phandles() adds a constant to all the
  144. * phandles of an overlay. This is mainly use as part of the overlay
  145. * application process, when we want to update all the overlay
  146. * phandles to not conflict with the overlays of the base device tree.
  147. *
  148. * returns:
  149. * 0 on success
  150. * Negative error code on failure
  151. */
  152. static int overlay_adjust_local_phandles(void *fdto, uint32_t delta)
  153. {
  154. /*
  155. * Start adjusting the phandles from the overlay root
  156. */
  157. return overlay_adjust_node_phandles(fdto, 0, delta);
  158. }
  159. /**
  160. * overlay_update_local_node_references - Adjust the overlay references
  161. * @fdto: Device tree overlay blob
  162. * @tree_node: Node offset of the node to operate on
  163. * @fixup_node: Node offset of the matching local fixups node
  164. * @delta: Offset to shift the phandles of
  165. *
  166. * overlay_update_local_nodes_references() update the phandles
  167. * pointing to a node within the device tree overlay by adding a
  168. * constant delta.
  169. *
  170. * This is mainly used as part of a device tree application process,
  171. * where you want the device tree overlays phandles to not conflict
  172. * with the ones from the base device tree before merging them.
  173. *
  174. * returns:
  175. * 0 on success
  176. * Negative error code on failure
  177. */
  178. static int overlay_update_local_node_references(void *fdto,
  179. int tree_node,
  180. int fixup_node,
  181. uint32_t delta)
  182. {
  183. int fixup_prop;
  184. int fixup_child;
  185. int ret;
  186. fdt_for_each_property_offset(fixup_prop, fdto, fixup_node) {
  187. const uint32_t *fixup_val;
  188. const char *tree_val;
  189. const char *name;
  190. int fixup_len;
  191. int tree_len;
  192. int i;
  193. fixup_val = fdt_getprop_by_offset(fdto, fixup_prop,
  194. &name, &fixup_len);
  195. if (!fixup_val)
  196. return fixup_len;
  197. if (fixup_len % sizeof(uint32_t))
  198. return -FDT_ERR_BADOVERLAY;
  199. tree_val = fdt_getprop(fdto, tree_node, name, &tree_len);
  200. if (!tree_val) {
  201. if (tree_len == -FDT_ERR_NOTFOUND)
  202. return -FDT_ERR_BADOVERLAY;
  203. return tree_len;
  204. }
  205. for (i = 0; i < (fixup_len / sizeof(uint32_t)); i++) {
  206. uint32_t adj_val, poffset;
  207. poffset = fdt32_to_cpu(fixup_val[i]);
  208. /*
  209. * phandles to fixup can be unaligned.
  210. *
  211. * Use a memcpy for the architectures that do
  212. * not support unaligned accesses.
  213. */
  214. memcpy(&adj_val, tree_val + poffset, sizeof(adj_val));
  215. adj_val = fdt32_to_cpu(adj_val);
  216. adj_val += delta;
  217. adj_val = cpu_to_fdt32(adj_val);
  218. ret = fdt_setprop_inplace_namelen_partial(fdto,
  219. tree_node,
  220. name,
  221. strlen(name),
  222. poffset,
  223. &adj_val,
  224. sizeof(adj_val));
  225. if (ret == -FDT_ERR_NOSPACE)
  226. return -FDT_ERR_BADOVERLAY;
  227. if (ret)
  228. return ret;
  229. }
  230. }
  231. fdt_for_each_subnode(fixup_child, fdto, fixup_node) {
  232. const char *fixup_child_name = fdt_get_name(fdto, fixup_child,
  233. NULL);
  234. int tree_child;
  235. tree_child = fdt_subnode_offset(fdto, tree_node,
  236. fixup_child_name);
  237. if (ret == -FDT_ERR_NOTFOUND)
  238. return -FDT_ERR_BADOVERLAY;
  239. if (tree_child < 0)
  240. return tree_child;
  241. ret = overlay_update_local_node_references(fdto,
  242. tree_child,
  243. fixup_child,
  244. delta);
  245. if (ret)
  246. return ret;
  247. }
  248. return 0;
  249. }
  250. /**
  251. * overlay_update_local_references - Adjust the overlay references
  252. * @fdto: Device tree overlay blob
  253. * @delta: Offset to shift the phandles of
  254. *
  255. * overlay_update_local_references() update all the phandles pointing
  256. * to a node within the device tree overlay by adding a constant
  257. * delta to not conflict with the base overlay.
  258. *
  259. * This is mainly used as part of a device tree application process,
  260. * where you want the device tree overlays phandles to not conflict
  261. * with the ones from the base device tree before merging them.
  262. *
  263. * returns:
  264. * 0 on success
  265. * Negative error code on failure
  266. */
  267. static int overlay_update_local_references(void *fdto, uint32_t delta)
  268. {
  269. int fixups;
  270. fixups = fdt_path_offset(fdto, "/__local_fixups__");
  271. if (fixups < 0) {
  272. /* There's no local phandles to adjust, bail out */
  273. if (fixups == -FDT_ERR_NOTFOUND)
  274. return 0;
  275. return fixups;
  276. }
  277. /*
  278. * Update our local references from the root of the tree
  279. */
  280. return overlay_update_local_node_references(fdto, 0, fixups,
  281. delta);
  282. }
  283. /**
  284. * overlay_fixup_one_phandle - Set an overlay phandle to the base one
  285. * @fdt: Base Device Tree blob
  286. * @fdto: Device tree overlay blob
  287. * @symbols_off: Node offset of the symbols node in the base device tree
  288. * @path: Path to a node holding a phandle in the overlay
  289. * @path_len: number of path characters to consider
  290. * @name: Name of the property holding the phandle reference in the overlay
  291. * @name_len: number of name characters to consider
  292. * @poffset: Offset within the overlay property where the phandle is stored
  293. * @label: Label of the node referenced by the phandle
  294. *
  295. * overlay_fixup_one_phandle() resolves an overlay phandle pointing to
  296. * a node in the base device tree.
  297. *
  298. * This is part of the device tree overlay application process, when
  299. * you want all the phandles in the overlay to point to the actual
  300. * base dt nodes.
  301. *
  302. * returns:
  303. * 0 on success
  304. * Negative error code on failure
  305. */
  306. static int overlay_fixup_one_phandle(void *fdt, void *fdto,
  307. int symbols_off,
  308. const char *path, uint32_t path_len,
  309. const char *name, uint32_t name_len,
  310. int poffset, const char *label)
  311. {
  312. const char *symbol_path;
  313. uint32_t phandle;
  314. int symbol_off, fixup_off;
  315. int prop_len;
  316. symbol_path = fdt_getprop(fdt, symbols_off, label,
  317. &prop_len);
  318. if (!symbol_path)
  319. return prop_len;
  320. symbol_off = fdt_path_offset(fdt, symbol_path);
  321. if (symbol_off < 0)
  322. return symbol_off;
  323. phandle = fdt_get_phandle(fdt, symbol_off);
  324. if (!phandle)
  325. return -FDT_ERR_NOTFOUND;
  326. fixup_off = fdt_path_offset_namelen(fdto, path, path_len);
  327. if (fixup_off == -FDT_ERR_NOTFOUND)
  328. return -FDT_ERR_BADOVERLAY;
  329. if (fixup_off < 0)
  330. return fixup_off;
  331. phandle = cpu_to_fdt32(phandle);
  332. return fdt_setprop_inplace_namelen_partial(fdto, fixup_off,
  333. name, name_len, poffset,
  334. &phandle, sizeof(phandle));
  335. };
  336. /**
  337. * overlay_fixup_phandle - Set an overlay phandle to the base one
  338. * @fdt: Base Device Tree blob
  339. * @fdto: Device tree overlay blob
  340. * @symbols_off: Node offset of the symbols node in the base device tree
  341. * @property: Property offset in the overlay holding the list of fixups
  342. *
  343. * overlay_fixup_phandle() resolves all the overlay phandles pointed
  344. * to in a __fixups__ property, and updates them to match the phandles
  345. * in use in the base device tree.
  346. *
  347. * This is part of the device tree overlay application process, when
  348. * you want all the phandles in the overlay to point to the actual
  349. * base dt nodes.
  350. *
  351. * returns:
  352. * 0 on success
  353. * Negative error code on failure
  354. */
  355. static int overlay_fixup_phandle(void *fdt, void *fdto, int symbols_off,
  356. int property)
  357. {
  358. const char *value;
  359. const char *label;
  360. int len;
  361. value = fdt_getprop_by_offset(fdto, property,
  362. &label, &len);
  363. if (!value) {
  364. if (len == -FDT_ERR_NOTFOUND)
  365. return -FDT_ERR_INTERNAL;
  366. return len;
  367. }
  368. do {
  369. const char *path, *name, *fixup_end;
  370. const char *fixup_str = value;
  371. uint32_t path_len, name_len;
  372. uint32_t fixup_len;
  373. char *sep, *endptr;
  374. int poffset, ret;
  375. fixup_end = memchr(value, '\0', len);
  376. if (!fixup_end)
  377. return -FDT_ERR_BADOVERLAY;
  378. fixup_len = fixup_end - fixup_str;
  379. len -= fixup_len + 1;
  380. value += fixup_len + 1;
  381. path = fixup_str;
  382. sep = memchr(fixup_str, ':', fixup_len);
  383. if (!sep || *sep != ':')
  384. return -FDT_ERR_BADOVERLAY;
  385. path_len = sep - path;
  386. if (path_len == (fixup_len - 1))
  387. return -FDT_ERR_BADOVERLAY;
  388. fixup_len -= path_len + 1;
  389. name = sep + 1;
  390. sep = memchr(name, ':', fixup_len);
  391. if (!sep || *sep != ':')
  392. return -FDT_ERR_BADOVERLAY;
  393. name_len = sep - name;
  394. if (!name_len)
  395. return -FDT_ERR_BADOVERLAY;
  396. poffset = strtoul(sep + 1, &endptr, 10);
  397. if ((*endptr != '\0') || (endptr <= (sep + 1)))
  398. return -FDT_ERR_BADOVERLAY;
  399. ret = overlay_fixup_one_phandle(fdt, fdto, symbols_off,
  400. path, path_len, name, name_len,
  401. poffset, label);
  402. if (ret)
  403. return ret;
  404. } while (len > 0);
  405. return 0;
  406. }
  407. /**
  408. * overlay_fixup_phandles - Resolve the overlay phandles to the base
  409. * device tree
  410. * @fdt: Base Device Tree blob
  411. * @fdto: Device tree overlay blob
  412. *
  413. * overlay_fixup_phandles() resolves all the overlay phandles pointing
  414. * to nodes in the base device tree.
  415. *
  416. * This is one of the steps of the device tree overlay application
  417. * process, when you want all the phandles in the overlay to point to
  418. * the actual base dt nodes.
  419. *
  420. * returns:
  421. * 0 on success
  422. * Negative error code on failure
  423. */
  424. static int overlay_fixup_phandles(void *fdt, void *fdto)
  425. {
  426. int fixups_off, symbols_off;
  427. int property;
  428. /* We can have overlays without any fixups */
  429. fixups_off = fdt_path_offset(fdto, "/__fixups__");
  430. if ((fixups_off < 0 && (fixups_off != -FDT_ERR_NOTFOUND)))
  431. return fixups_off;
  432. /* And base DTs without symbols */
  433. symbols_off = fdt_path_offset(fdt, "/__symbols__");
  434. if ((symbols_off < 0 && (symbols_off != -FDT_ERR_NOTFOUND)))
  435. return symbols_off;
  436. fdt_for_each_property_offset(property, fdto, fixups_off) {
  437. int ret;
  438. ret = overlay_fixup_phandle(fdt, fdto, symbols_off, property);
  439. if (ret)
  440. return ret;
  441. }
  442. return 0;
  443. }
  444. /**
  445. * overlay_apply_node - Merges a node into the base device tree
  446. * @fdt: Base Device Tree blob
  447. * @target: Node offset in the base device tree to apply the fragment to
  448. * @fdto: Device tree overlay blob
  449. * @node: Node offset in the overlay holding the changes to merge
  450. *
  451. * overlay_apply_node() merges a node into a target base device tree
  452. * node pointed.
  453. *
  454. * This is part of the final step in the device tree overlay
  455. * application process, when all the phandles have been adjusted and
  456. * resolved and you just have to merge overlay into the base device
  457. * tree.
  458. *
  459. * returns:
  460. * 0 on success
  461. * Negative error code on failure
  462. */
  463. static int overlay_apply_node(void *fdt, int target,
  464. void *fdto, int node)
  465. {
  466. int property;
  467. int subnode;
  468. fdt_for_each_property_offset(property, fdto, node) {
  469. const char *name;
  470. const void *prop;
  471. int prop_len;
  472. int ret;
  473. prop = fdt_getprop_by_offset(fdto, property, &name,
  474. &prop_len);
  475. if (prop_len == -FDT_ERR_NOTFOUND)
  476. return -FDT_ERR_INTERNAL;
  477. if (prop_len < 0)
  478. return prop_len;
  479. ret = fdt_setprop(fdt, target, name, prop, prop_len);
  480. if (ret)
  481. return ret;
  482. }
  483. fdt_for_each_subnode(subnode, fdto, node) {
  484. const char *name = fdt_get_name(fdto, subnode, NULL);
  485. int nnode;
  486. int ret;
  487. nnode = fdt_add_subnode(fdt, target, name);
  488. if (nnode == -FDT_ERR_EXISTS) {
  489. nnode = fdt_subnode_offset(fdt, target, name);
  490. if (nnode == -FDT_ERR_NOTFOUND)
  491. return -FDT_ERR_INTERNAL;
  492. }
  493. if (nnode < 0)
  494. return nnode;
  495. ret = overlay_apply_node(fdt, nnode, fdto, subnode);
  496. if (ret)
  497. return ret;
  498. }
  499. return 0;
  500. }
  501. /**
  502. * overlay_merge - Merge an overlay into its base device tree
  503. * @fdt: Base Device Tree blob
  504. * @fdto: Device tree overlay blob
  505. *
  506. * overlay_merge() merges an overlay into its base device tree.
  507. *
  508. * This is the final step in the device tree overlay application
  509. * process, when all the phandles have been adjusted and resolved and
  510. * you just have to merge overlay into the base device tree.
  511. *
  512. * returns:
  513. * 0 on success
  514. * Negative error code on failure
  515. */
  516. static int overlay_merge(void *fdt, void *fdto)
  517. {
  518. int fragment;
  519. fdt_for_each_subnode(fragment, fdto, 0) {
  520. int overlay;
  521. int target;
  522. int ret;
  523. /*
  524. * Each fragments will have an __overlay__ node. If
  525. * they don't, it's not supposed to be merged
  526. */
  527. overlay = fdt_subnode_offset(fdto, fragment, "__overlay__");
  528. if (overlay == -FDT_ERR_NOTFOUND)
  529. continue;
  530. if (overlay < 0)
  531. return overlay;
  532. target = overlay_get_target(fdt, fdto, fragment);
  533. if (target < 0)
  534. return target;
  535. ret = overlay_apply_node(fdt, target, fdto, overlay);
  536. if (ret)
  537. return ret;
  538. }
  539. return 0;
  540. }
  541. int fdt_overlay_apply(void *fdt, void *fdto)
  542. {
  543. uint32_t delta = fdt_get_max_phandle(fdt);
  544. int ret;
  545. FDT_CHECK_HEADER(fdt);
  546. FDT_CHECK_HEADER(fdto);
  547. ret = overlay_adjust_local_phandles(fdto, delta);
  548. if (ret)
  549. goto err;
  550. ret = overlay_update_local_references(fdto, delta);
  551. if (ret)
  552. goto err;
  553. ret = overlay_fixup_phandles(fdt, fdto);
  554. if (ret)
  555. goto err;
  556. ret = overlay_merge(fdt, fdto);
  557. if (ret)
  558. goto err;
  559. /*
  560. * The overlay has been damaged, erase its magic.
  561. */
  562. fdt_set_magic(fdto, ~0);
  563. return 0;
  564. err:
  565. /*
  566. * The overlay might have been damaged, erase its magic.
  567. */
  568. fdt_set_magic(fdto, ~0);
  569. /*
  570. * The base device tree might have been damaged, erase its
  571. * magic.
  572. */
  573. fdt_set_magic(fdt, ~0);
  574. return ret;
  575. }