fdt_overlay.c 15 KB

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