fdt_overlay.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677
  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 fdt32_t *val;
  22. int len;
  23. val = fdt_getprop(fdto, fragment, "target", &len);
  24. if (!val)
  25. return 0;
  26. if ((len != sizeof(*val)) || (fdt32_to_cpu(*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 fdt32_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 fdt32_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. fdt32_t adj_val;
  207. uint32_t poffset;
  208. poffset = fdt32_to_cpu(fixup_val[i]);
  209. /*
  210. * phandles to fixup can be unaligned.
  211. *
  212. * Use a memcpy for the architectures that do
  213. * not support unaligned accesses.
  214. */
  215. memcpy(&adj_val, tree_val + poffset, sizeof(adj_val));
  216. adj_val = cpu_to_fdt32(fdt32_to_cpu(adj_val) + delta);
  217. ret = fdt_setprop_inplace_namelen_partial(fdto,
  218. tree_node,
  219. name,
  220. strlen(name),
  221. poffset,
  222. &adj_val,
  223. sizeof(adj_val));
  224. if (ret == -FDT_ERR_NOSPACE)
  225. return -FDT_ERR_BADOVERLAY;
  226. if (ret)
  227. return ret;
  228. }
  229. }
  230. fdt_for_each_subnode(fixup_child, fdto, fixup_node) {
  231. const char *fixup_child_name = fdt_get_name(fdto, fixup_child,
  232. NULL);
  233. int tree_child;
  234. tree_child = fdt_subnode_offset(fdto, tree_node,
  235. fixup_child_name);
  236. if (tree_child == -FDT_ERR_NOTFOUND)
  237. return -FDT_ERR_BADOVERLAY;
  238. if (tree_child < 0)
  239. return tree_child;
  240. ret = overlay_update_local_node_references(fdto,
  241. tree_child,
  242. fixup_child,
  243. delta);
  244. if (ret)
  245. return ret;
  246. }
  247. return 0;
  248. }
  249. /**
  250. * overlay_update_local_references - Adjust the overlay references
  251. * @fdto: Device tree overlay blob
  252. * @delta: Offset to shift the phandles of
  253. *
  254. * overlay_update_local_references() update all the phandles pointing
  255. * to a node within the device tree overlay by adding a constant
  256. * delta to not conflict with the base overlay.
  257. *
  258. * This is mainly used as part of a device tree application process,
  259. * where you want the device tree overlays phandles to not conflict
  260. * with the ones from the base device tree before merging them.
  261. *
  262. * returns:
  263. * 0 on success
  264. * Negative error code on failure
  265. */
  266. static int overlay_update_local_references(void *fdto, uint32_t delta)
  267. {
  268. int fixups;
  269. fixups = fdt_path_offset(fdto, "/__local_fixups__");
  270. if (fixups < 0) {
  271. /* There's no local phandles to adjust, bail out */
  272. if (fixups == -FDT_ERR_NOTFOUND)
  273. return 0;
  274. return fixups;
  275. }
  276. /*
  277. * Update our local references from the root of the tree
  278. */
  279. return overlay_update_local_node_references(fdto, 0, fixups,
  280. delta);
  281. }
  282. /**
  283. * overlay_fixup_one_phandle - Set an overlay phandle to the base one
  284. * @fdt: Base Device Tree blob
  285. * @fdto: Device tree overlay blob
  286. * @symbols_off: Node offset of the symbols node in the base device tree
  287. * @path: Path to a node holding a phandle in the overlay
  288. * @path_len: number of path characters to consider
  289. * @name: Name of the property holding the phandle reference in the overlay
  290. * @name_len: number of name characters to consider
  291. * @poffset: Offset within the overlay property where the phandle is stored
  292. * @label: Label of the node referenced by the phandle
  293. *
  294. * overlay_fixup_one_phandle() resolves an overlay phandle pointing to
  295. * a node in the base device tree.
  296. *
  297. * This is part of the device tree overlay application process, when
  298. * you want all the phandles in the overlay to point to the actual
  299. * base dt nodes.
  300. *
  301. * returns:
  302. * 0 on success
  303. * Negative error code on failure
  304. */
  305. static int overlay_fixup_one_phandle(void *fdt, void *fdto,
  306. int symbols_off,
  307. const char *path, uint32_t path_len,
  308. const char *name, uint32_t name_len,
  309. int poffset, const char *label)
  310. {
  311. const char *symbol_path;
  312. uint32_t phandle;
  313. fdt32_t phandle_prop;
  314. int symbol_off, fixup_off;
  315. int prop_len;
  316. if (symbols_off < 0)
  317. return symbols_off;
  318. symbol_path = fdt_getprop(fdt, symbols_off, label,
  319. &prop_len);
  320. if (!symbol_path)
  321. return prop_len;
  322. symbol_off = fdt_path_offset(fdt, symbol_path);
  323. if (symbol_off < 0)
  324. return symbol_off;
  325. phandle = fdt_get_phandle(fdt, symbol_off);
  326. if (!phandle)
  327. return -FDT_ERR_NOTFOUND;
  328. fixup_off = fdt_path_offset_namelen(fdto, path, path_len);
  329. if (fixup_off == -FDT_ERR_NOTFOUND)
  330. return -FDT_ERR_BADOVERLAY;
  331. if (fixup_off < 0)
  332. return fixup_off;
  333. phandle_prop = cpu_to_fdt32(phandle);
  334. return fdt_setprop_inplace_namelen_partial(fdto, fixup_off,
  335. name, name_len, poffset,
  336. &phandle_prop,
  337. sizeof(phandle_prop));
  338. };
  339. /**
  340. * overlay_fixup_phandle - Set an overlay phandle to the base one
  341. * @fdt: Base Device Tree blob
  342. * @fdto: Device tree overlay blob
  343. * @symbols_off: Node offset of the symbols node in the base device tree
  344. * @property: Property offset in the overlay holding the list of fixups
  345. *
  346. * overlay_fixup_phandle() resolves all the overlay phandles pointed
  347. * to in a __fixups__ property, and updates them to match the phandles
  348. * in use in the base device tree.
  349. *
  350. * This is part of the device tree overlay application process, when
  351. * you want all the phandles in the overlay to point to the actual
  352. * base dt nodes.
  353. *
  354. * returns:
  355. * 0 on success
  356. * Negative error code on failure
  357. */
  358. static int overlay_fixup_phandle(void *fdt, void *fdto, int symbols_off,
  359. int property)
  360. {
  361. const char *value;
  362. const char *label;
  363. int len;
  364. value = fdt_getprop_by_offset(fdto, property,
  365. &label, &len);
  366. if (!value) {
  367. if (len == -FDT_ERR_NOTFOUND)
  368. return -FDT_ERR_INTERNAL;
  369. return len;
  370. }
  371. do {
  372. const char *path, *name, *fixup_end;
  373. const char *fixup_str = value;
  374. uint32_t path_len, name_len;
  375. uint32_t fixup_len;
  376. char *sep, *endptr;
  377. int poffset, ret;
  378. fixup_end = memchr(value, '\0', len);
  379. if (!fixup_end)
  380. return -FDT_ERR_BADOVERLAY;
  381. fixup_len = fixup_end - fixup_str;
  382. len -= fixup_len + 1;
  383. value += fixup_len + 1;
  384. path = fixup_str;
  385. sep = memchr(fixup_str, ':', fixup_len);
  386. if (!sep || *sep != ':')
  387. return -FDT_ERR_BADOVERLAY;
  388. path_len = sep - path;
  389. if (path_len == (fixup_len - 1))
  390. return -FDT_ERR_BADOVERLAY;
  391. fixup_len -= path_len + 1;
  392. name = sep + 1;
  393. sep = memchr(name, ':', fixup_len);
  394. if (!sep || *sep != ':')
  395. return -FDT_ERR_BADOVERLAY;
  396. name_len = sep - name;
  397. if (!name_len)
  398. return -FDT_ERR_BADOVERLAY;
  399. poffset = strtoul(sep + 1, &endptr, 10);
  400. if ((*endptr != '\0') || (endptr <= (sep + 1)))
  401. return -FDT_ERR_BADOVERLAY;
  402. ret = overlay_fixup_one_phandle(fdt, fdto, symbols_off,
  403. path, path_len, name, name_len,
  404. poffset, label);
  405. if (ret)
  406. return ret;
  407. } while (len > 0);
  408. return 0;
  409. }
  410. /**
  411. * overlay_fixup_phandles - Resolve the overlay phandles to the base
  412. * device tree
  413. * @fdt: Base Device Tree blob
  414. * @fdto: Device tree overlay blob
  415. *
  416. * overlay_fixup_phandles() resolves all the overlay phandles pointing
  417. * to nodes in the base device tree.
  418. *
  419. * This is one of the steps of the device tree overlay application
  420. * process, when you want all the phandles in the overlay to point to
  421. * the actual base dt nodes.
  422. *
  423. * returns:
  424. * 0 on success
  425. * Negative error code on failure
  426. */
  427. static int overlay_fixup_phandles(void *fdt, void *fdto)
  428. {
  429. int fixups_off, symbols_off;
  430. int property;
  431. /* We can have overlays without any fixups */
  432. fixups_off = fdt_path_offset(fdto, "/__fixups__");
  433. if (fixups_off == -FDT_ERR_NOTFOUND)
  434. return 0; /* nothing to do */
  435. if (fixups_off < 0)
  436. return fixups_off;
  437. /* And base DTs without symbols */
  438. symbols_off = fdt_path_offset(fdt, "/__symbols__");
  439. if ((symbols_off < 0 && (symbols_off != -FDT_ERR_NOTFOUND)))
  440. return symbols_off;
  441. fdt_for_each_property_offset(property, fdto, fixups_off) {
  442. int ret;
  443. ret = overlay_fixup_phandle(fdt, fdto, symbols_off, property);
  444. if (ret)
  445. return ret;
  446. }
  447. return 0;
  448. }
  449. /**
  450. * overlay_apply_node - Merges a node into the base device tree
  451. * @fdt: Base Device Tree blob
  452. * @target: Node offset in the base device tree to apply the fragment to
  453. * @fdto: Device tree overlay blob
  454. * @node: Node offset in the overlay holding the changes to merge
  455. *
  456. * overlay_apply_node() merges a node into a target base device tree
  457. * node pointed.
  458. *
  459. * This is part of the final step in the device tree overlay
  460. * application process, when all the phandles have been adjusted and
  461. * resolved and you just have to merge overlay into the base device
  462. * tree.
  463. *
  464. * returns:
  465. * 0 on success
  466. * Negative error code on failure
  467. */
  468. static int overlay_apply_node(void *fdt, int target,
  469. void *fdto, int node)
  470. {
  471. int property;
  472. int subnode;
  473. fdt_for_each_property_offset(property, fdto, node) {
  474. const char *name;
  475. const void *prop;
  476. int prop_len;
  477. int ret;
  478. prop = fdt_getprop_by_offset(fdto, property, &name,
  479. &prop_len);
  480. if (prop_len == -FDT_ERR_NOTFOUND)
  481. return -FDT_ERR_INTERNAL;
  482. if (prop_len < 0)
  483. return prop_len;
  484. ret = fdt_setprop(fdt, target, name, prop, prop_len);
  485. if (ret)
  486. return ret;
  487. }
  488. fdt_for_each_subnode(subnode, fdto, node) {
  489. const char *name = fdt_get_name(fdto, subnode, NULL);
  490. int nnode;
  491. int ret;
  492. nnode = fdt_add_subnode(fdt, target, name);
  493. if (nnode == -FDT_ERR_EXISTS) {
  494. nnode = fdt_subnode_offset(fdt, target, name);
  495. if (nnode == -FDT_ERR_NOTFOUND)
  496. return -FDT_ERR_INTERNAL;
  497. }
  498. if (nnode < 0)
  499. return nnode;
  500. ret = overlay_apply_node(fdt, nnode, fdto, subnode);
  501. if (ret)
  502. return ret;
  503. }
  504. return 0;
  505. }
  506. /**
  507. * overlay_merge - Merge an overlay into its base device tree
  508. * @fdt: Base Device Tree blob
  509. * @fdto: Device tree overlay blob
  510. *
  511. * overlay_merge() merges an overlay into its base device tree.
  512. *
  513. * This is the final step in the device tree overlay application
  514. * process, when all the phandles have been adjusted and resolved and
  515. * you just have to merge overlay into the base device tree.
  516. *
  517. * returns:
  518. * 0 on success
  519. * Negative error code on failure
  520. */
  521. static int overlay_merge(void *fdt, void *fdto)
  522. {
  523. int fragment;
  524. fdt_for_each_subnode(fragment, fdto, 0) {
  525. int overlay;
  526. int target;
  527. int ret;
  528. /*
  529. * Each fragments will have an __overlay__ node. If
  530. * they don't, it's not supposed to be merged
  531. */
  532. overlay = fdt_subnode_offset(fdto, fragment, "__overlay__");
  533. if (overlay == -FDT_ERR_NOTFOUND)
  534. continue;
  535. if (overlay < 0)
  536. return overlay;
  537. target = overlay_get_target(fdt, fdto, fragment);
  538. if (target < 0)
  539. return target;
  540. ret = overlay_apply_node(fdt, target, fdto, overlay);
  541. if (ret)
  542. return ret;
  543. }
  544. return 0;
  545. }
  546. int fdt_overlay_apply(void *fdt, void *fdto)
  547. {
  548. uint32_t delta = fdt_get_max_phandle(fdt);
  549. int ret;
  550. FDT_CHECK_HEADER(fdt);
  551. FDT_CHECK_HEADER(fdto);
  552. ret = overlay_adjust_local_phandles(fdto, delta);
  553. if (ret)
  554. goto err;
  555. ret = overlay_update_local_references(fdto, delta);
  556. if (ret)
  557. goto err;
  558. ret = overlay_fixup_phandles(fdt, fdto);
  559. if (ret)
  560. goto err;
  561. ret = overlay_merge(fdt, fdto);
  562. if (ret)
  563. goto err;
  564. /*
  565. * The overlay has been damaged, erase its magic.
  566. */
  567. fdt_set_magic(fdto, ~0);
  568. return 0;
  569. err:
  570. /*
  571. * The overlay might have been damaged, erase its magic.
  572. */
  573. fdt_set_magic(fdto, ~0);
  574. /*
  575. * The base device tree might have been damaged, erase its
  576. * magic.
  577. */
  578. fdt_set_magic(fdt, ~0);
  579. return ret;
  580. }