ufdt_convert.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499
  1. /*
  2. * Copyright (C) 2016 The Android Open Source Project
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include "libufdt.h"
  17. #include "ufdt_prop_dict.h"
  18. struct ufdt *ufdt_construct(void *fdtp) {
  19. /* Inital size is 2, will be exponentially increased when it needed later.
  20. (2 -> 4 -> 8 -> ...) */
  21. const int DEFAULT_MEM_SIZE_FDTPS = 2;
  22. void **fdtps = NULL;
  23. struct ufdt *res_ufdt = NULL;
  24. fdtps = (void **)dto_malloc(sizeof(void *) * DEFAULT_MEM_SIZE_FDTPS);
  25. if (fdtps == NULL) goto error;
  26. fdtps[0] = fdtp;
  27. res_ufdt = dto_malloc(sizeof(struct ufdt));
  28. if (res_ufdt == NULL) goto error;
  29. res_ufdt->fdtps = fdtps;
  30. res_ufdt->mem_size_fdtps = DEFAULT_MEM_SIZE_FDTPS;
  31. res_ufdt->num_used_fdtps = (fdtp != NULL ? 1 : 0);
  32. res_ufdt->root = NULL;
  33. return res_ufdt;
  34. error:
  35. if (res_ufdt) dto_free(res_ufdt);
  36. if (fdtps) dto_free(fdtps);
  37. return NULL;
  38. }
  39. void ufdt_destruct(struct ufdt *tree) {
  40. if (tree == NULL) return;
  41. ufdt_node_destruct(tree->root);
  42. dto_free(tree->fdtps);
  43. dto_free(tree->phandle_table.data);
  44. dto_free(tree);
  45. }
  46. int ufdt_add_fdt(struct ufdt *tree, void *fdtp) {
  47. if (fdtp == NULL) {
  48. return -1;
  49. }
  50. int i = tree->num_used_fdtps;
  51. if (i >= tree->mem_size_fdtps) {
  52. int new_size = tree->mem_size_fdtps * 2;
  53. void **new_fdtps = dto_malloc(sizeof(void *) * new_size);
  54. if (new_fdtps == NULL) return -1;
  55. dto_memcpy(new_fdtps, tree->fdtps, sizeof(void *) * tree->mem_size_fdtps);
  56. dto_free(tree->fdtps);
  57. tree->fdtps = new_fdtps;
  58. tree->mem_size_fdtps = new_size;
  59. }
  60. tree->fdtps[i] = fdtp;
  61. tree->num_used_fdtps = i + 1;
  62. return 0;
  63. }
  64. int ufdt_get_string_off(const struct ufdt *tree, const char *s) {
  65. /* fdt_create() sets the dt_string_off to the end of fdt buffer,
  66. and _ufdt_output_strtab_to_fdt() copy all string tables in reversed order.
  67. So, here the return offset value is base on the end of all string buffers,
  68. and it should be a minus value. */
  69. int res_off = 0;
  70. for (int i = 0; i < tree->num_used_fdtps; i++) {
  71. void *fdt = tree->fdtps[i];
  72. const char *strtab_start = (const char *)fdt + fdt_off_dt_strings(fdt);
  73. int strtab_size = fdt_size_dt_strings(fdt);
  74. const char *strtab_end = strtab_start + strtab_size;
  75. /* Check if the string is in the string table */
  76. if (s >= strtab_start && s < strtab_end) {
  77. res_off += (s - strtab_end);
  78. return res_off;
  79. }
  80. res_off -= strtab_size;
  81. }
  82. /* Can not find the string, return 0 */
  83. return 0;
  84. }
  85. static struct ufdt_node *ufdt_new_node(void *fdtp, int node_offset) {
  86. if (fdtp == NULL) {
  87. dto_error("Failed to get new_node because tree is NULL\n");
  88. return NULL;
  89. }
  90. fdt32_t *fdt_tag_ptr =
  91. (fdt32_t *)fdt_offset_ptr(fdtp, node_offset, sizeof(fdt32_t));
  92. struct ufdt_node *res = ufdt_node_construct(fdtp, fdt_tag_ptr);
  93. return res;
  94. }
  95. static struct ufdt_node *fdt_to_ufdt_tree(void *fdtp, int cur_fdt_tag_offset,
  96. int *next_fdt_tag_offset,
  97. int cur_tag) {
  98. if (fdtp == NULL) {
  99. return NULL;
  100. }
  101. uint32_t tag;
  102. struct ufdt_node *res, *child_node;
  103. res = NULL;
  104. child_node = NULL;
  105. tag = cur_tag;
  106. switch (tag) {
  107. case FDT_END_NODE:
  108. case FDT_NOP:
  109. case FDT_END:
  110. break;
  111. case FDT_PROP:
  112. res = ufdt_new_node(fdtp, cur_fdt_tag_offset);
  113. break;
  114. case FDT_BEGIN_NODE:
  115. res = ufdt_new_node(fdtp, cur_fdt_tag_offset);
  116. do {
  117. cur_fdt_tag_offset = *next_fdt_tag_offset;
  118. tag = fdt_next_tag(fdtp, cur_fdt_tag_offset, next_fdt_tag_offset);
  119. child_node = fdt_to_ufdt_tree(fdtp, cur_fdt_tag_offset,
  120. next_fdt_tag_offset, tag);
  121. ufdt_node_add_child(res, child_node);
  122. } while (tag != FDT_END_NODE);
  123. break;
  124. default:
  125. break;
  126. }
  127. return res;
  128. }
  129. void ufdt_print(struct ufdt *tree) {
  130. ufdt_node_print(tree->root, 0);
  131. }
  132. struct ufdt_node *ufdt_get_node_by_path_len(struct ufdt *tree, const char *path,
  133. int len) {
  134. /*
  135. * RARE: aliases
  136. * In device tree, we can assign some alias to specific nodes by defining
  137. * these relation in "/aliases" node.
  138. * The node has the form:
  139. * {
  140. * a = "/a_for_apple";
  141. * b = "/b_for_banana";
  142. * };
  143. * So the path "a/subnode_1" should be expanded to "/a_for_apple/subnode_1".
  144. */
  145. if (*path != '/') {
  146. const char *end = path + len;
  147. const char *next_slash;
  148. next_slash = dto_memchr(path, '/', end - path);
  149. if (!next_slash) next_slash = end;
  150. struct ufdt_node *aliases_node =
  151. ufdt_node_get_node_by_path(tree->root, "/aliases");
  152. aliases_node = ufdt_node_get_property_by_name_len(aliases_node, path,
  153. next_slash - path);
  154. int path_len = 0;
  155. const char *alias_path =
  156. ufdt_node_get_fdt_prop_data(aliases_node, &path_len);
  157. if (alias_path == NULL) {
  158. dto_error("Failed to find alias %s\n", path);
  159. return NULL;
  160. }
  161. struct ufdt_node *target_node =
  162. ufdt_node_get_node_by_path_len(tree->root, alias_path, path_len);
  163. return ufdt_node_get_node_by_path_len(target_node, next_slash,
  164. end - next_slash);
  165. }
  166. return ufdt_node_get_node_by_path_len(tree->root, path, len);
  167. }
  168. struct ufdt_node *ufdt_get_node_by_path(struct ufdt *tree, const char *path) {
  169. return ufdt_get_node_by_path_len(tree, path, dto_strlen(path));
  170. }
  171. struct ufdt_node *ufdt_get_node_by_phandle(struct ufdt *tree,
  172. uint32_t phandle) {
  173. struct ufdt_node *res = NULL;
  174. /*
  175. * Do binary search in phandle_table.data.
  176. * [s, e) means the possible range which contains target node.
  177. */
  178. int s = 0, e = tree->phandle_table.len;
  179. while (e - s > 1) {
  180. int mid = s + ((e - s) >> 1);
  181. uint32_t mid_phandle = tree->phandle_table.data[mid].phandle;
  182. if (phandle < mid_phandle)
  183. e = mid;
  184. else
  185. s = mid;
  186. }
  187. if (e - s > 0) {
  188. res = tree->phandle_table.data[s].node;
  189. }
  190. return res;
  191. }
  192. int merge_children(struct ufdt_node *node_a, struct ufdt_node *node_b) {
  193. int err = 0;
  194. struct ufdt_node *it;
  195. for (it = ((struct fdt_node_ufdt_node *)node_b)->child; it;) {
  196. struct ufdt_node *cur_node = it;
  197. it = it->sibling;
  198. cur_node->sibling = NULL;
  199. struct ufdt_node *target_node = NULL;
  200. if (tag_of(cur_node) == FDT_BEGIN_NODE) {
  201. target_node = ufdt_node_get_subnode_by_name(node_a, name_of(cur_node));
  202. } else {
  203. target_node = ufdt_node_get_property_by_name(node_a, name_of(cur_node));
  204. }
  205. if (target_node == NULL) {
  206. err = ufdt_node_add_child(node_a, cur_node);
  207. } else {
  208. err = merge_ufdt_into(target_node, cur_node);
  209. dto_free(cur_node);
  210. }
  211. if (err < 0) return -1;
  212. }
  213. /*
  214. * The ufdt_node* in node_b will be copied to node_a.
  215. * To prevent the ufdt_node from being freed twice
  216. * (main_tree and overlay_tree) at the end of function
  217. * ufdt_apply_overlay(), set this node in node_b
  218. * (overlay_tree) to NULL.
  219. */
  220. ((struct fdt_node_ufdt_node *)node_b)->child = NULL;
  221. return 0;
  222. }
  223. int merge_ufdt_into(struct ufdt_node *node_a, struct ufdt_node *node_b) {
  224. if (tag_of(node_a) == FDT_PROP) {
  225. node_a->fdt_tag_ptr = node_b->fdt_tag_ptr;
  226. return 0;
  227. }
  228. int err = 0;
  229. err = merge_children(node_a, node_b);
  230. if (err < 0) return -1;
  231. return 0;
  232. }
  233. void ufdt_map(struct ufdt *tree, struct ufdt_node_closure closure) {
  234. ufdt_node_map(tree->root, closure);
  235. }
  236. static int count_phandle_node(struct ufdt_node *node) {
  237. if (node == NULL) return 0;
  238. if (tag_of(node) != FDT_BEGIN_NODE) return 0;
  239. int res = 0;
  240. if (ufdt_node_get_phandle(node) > 0) res++;
  241. struct ufdt_node **it;
  242. for_each_child(it, node) { res += count_phandle_node(*it); }
  243. return res;
  244. }
  245. static void set_phandle_table_entry(struct ufdt_node *node,
  246. struct phandle_table_entry *data,
  247. int *cur) {
  248. if (node == NULL || tag_of(node) != FDT_BEGIN_NODE) return;
  249. int ph = ufdt_node_get_phandle(node);
  250. if (ph > 0) {
  251. data[*cur].phandle = ph;
  252. data[*cur].node = node;
  253. (*cur)++;
  254. }
  255. struct ufdt_node **it;
  256. for_each_node(it, node) set_phandle_table_entry(*it, data, cur);
  257. return;
  258. }
  259. int phandle_table_entry_cmp(const void *pa, const void *pb) {
  260. uint32_t ph_a = ((const struct phandle_table_entry *)pa)->phandle;
  261. uint32_t ph_b = ((const struct phandle_table_entry *)pb)->phandle;
  262. if (ph_a < ph_b)
  263. return -1;
  264. else if (ph_a == ph_b)
  265. return 0;
  266. else
  267. return 1;
  268. }
  269. struct static_phandle_table build_phandle_table(struct ufdt *tree) {
  270. struct static_phandle_table res;
  271. res.len = count_phandle_node(tree->root);
  272. res.data = dto_malloc(sizeof(struct phandle_table_entry) * res.len);
  273. int cur = 0;
  274. set_phandle_table_entry(tree->root, res.data, &cur);
  275. dto_qsort(res.data, res.len, sizeof(struct phandle_table_entry),
  276. phandle_table_entry_cmp);
  277. return res;
  278. }
  279. struct ufdt *fdt_to_ufdt(void *fdtp, size_t fdt_size) {
  280. (void)(fdt_size); /* unused parameter */
  281. int start_offset = fdt_path_offset(fdtp, "/");
  282. if (start_offset < 0) {
  283. return ufdt_construct(NULL);
  284. }
  285. struct ufdt *res_tree = ufdt_construct(fdtp);
  286. int end_offset;
  287. int start_tag = fdt_next_tag(fdtp, start_offset, &end_offset);
  288. res_tree->root = fdt_to_ufdt_tree(fdtp, start_offset, &end_offset, start_tag);
  289. res_tree->phandle_table = build_phandle_table(res_tree);
  290. return res_tree;
  291. }
  292. static int _ufdt_get_property_nameoff(const struct ufdt *tree, const char *name,
  293. const struct ufdt_prop_dict *dict) {
  294. int res;
  295. const struct fdt_property *same_name_prop = ufdt_prop_dict_find(dict, name);
  296. if (same_name_prop != NULL) {
  297. /* There is a property with same name, just use its string offset */
  298. res = fdt32_to_cpu(same_name_prop->nameoff);
  299. } else {
  300. /* Get the string offset from the string table of the current tree */
  301. res = ufdt_get_string_off(tree, name);
  302. if (res == 0) {
  303. dto_error("Cannot find property name in string table: %s\n", name);
  304. return 0;
  305. }
  306. }
  307. return res;
  308. }
  309. static int _ufdt_output_property_to_fdt(
  310. const struct ufdt *tree, void *fdtp,
  311. const struct fdt_prop_ufdt_node *prop_node, struct ufdt_prop_dict *dict) {
  312. int nameoff = _ufdt_get_property_nameoff(tree, prop_node->name, dict);
  313. if (nameoff == 0) return -1;
  314. int data_len = 0;
  315. void *data = ufdt_node_get_fdt_prop_data(&prop_node->parent, &data_len);
  316. int aligned_data_len = (data_len + (FDT_TAGSIZE - 1)) & ~(FDT_TAGSIZE - 1);
  317. int new_propoff = fdt_size_dt_struct(fdtp);
  318. int new_prop_size = sizeof(struct fdt_property) + aligned_data_len;
  319. struct fdt_property *new_prop =
  320. (struct fdt_property *)((char *)fdtp + fdt_off_dt_struct(fdtp) +
  321. new_propoff);
  322. char *fdt_end = (char *)fdtp + fdt_totalsize(fdtp);
  323. if ((char *)new_prop + new_prop_size > fdt_end) {
  324. dto_error("Not enough space for adding property.\n");
  325. return -1;
  326. }
  327. fdt_set_size_dt_struct(fdtp, new_propoff + new_prop_size);
  328. new_prop->tag = cpu_to_fdt32(FDT_PROP);
  329. new_prop->nameoff = cpu_to_fdt32(nameoff);
  330. new_prop->len = cpu_to_fdt32(data_len);
  331. dto_memcpy(new_prop->data, data, data_len);
  332. ufdt_prop_dict_add(dict, new_prop);
  333. return 0;
  334. }
  335. static int _ufdt_output_node_to_fdt(const struct ufdt *tree, void *fdtp,
  336. const struct ufdt_node *node,
  337. struct ufdt_prop_dict *dict) {
  338. uint32_t tag = tag_of(node);
  339. if (tag == FDT_PROP) {
  340. return _ufdt_output_property_to_fdt(
  341. tree, fdtp, (const struct fdt_prop_ufdt_node *)node, dict);
  342. }
  343. int err = fdt_begin_node(fdtp, name_of(node));
  344. if (err < 0) return -1;
  345. struct ufdt_node **it;
  346. for_each_prop(it, node) {
  347. err = _ufdt_output_node_to_fdt(tree, fdtp, *it, dict);
  348. if (err < 0) return -1;
  349. }
  350. for_each_node(it, node) {
  351. err = _ufdt_output_node_to_fdt(tree, fdtp, *it, dict);
  352. if (err < 0) return -1;
  353. }
  354. err = fdt_end_node(fdtp);
  355. if (err < 0) return -1;
  356. return 0;
  357. }
  358. static int _ufdt_output_strtab_to_fdt(const struct ufdt *tree, void *fdt) {
  359. /* Currently, we don't know the final dt_struct size, so we copy all
  360. string tables to the end of the target fdt buffer in reversed order.
  361. At last, fdt_finish() will adjust dt_string offset */
  362. const char *struct_top =
  363. (char *)fdt + fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
  364. char *dest = (char *)fdt + fdt_totalsize(fdt);
  365. int dest_size = 0;
  366. for (int i = 0; i < tree->num_used_fdtps; i++) {
  367. void *src_fdt = tree->fdtps[i];
  368. const char *src_strtab = (const char *)src_fdt + fdt_off_dt_strings(src_fdt);
  369. int strtab_size = fdt_size_dt_strings(src_fdt);
  370. dest -= strtab_size;
  371. if (dest < struct_top) {
  372. dto_error("Not enough space for string table.\n");
  373. return -1;
  374. }
  375. dto_memcpy(dest, src_strtab, strtab_size);
  376. dest_size += strtab_size;
  377. }
  378. fdt_set_size_dt_strings(fdt, dest_size);
  379. return 0;
  380. }
  381. int ufdt_to_fdt(const struct ufdt *tree, void *buf, int buf_size) {
  382. if (tree->num_used_fdtps == 0) return -1;
  383. int err;
  384. err = fdt_create(buf, buf_size);
  385. if (err < 0) return -1;
  386. /* Here we output the memory reserve map of the ONLY FIRST fdt,
  387. to be in compliance with the DTO behavior of libfdt. */
  388. int n_mem_rsv = fdt_num_mem_rsv(tree->fdtps[0]);
  389. for (int i = 0; i < n_mem_rsv; i++) {
  390. uint64_t addr, size;
  391. fdt_get_mem_rsv(tree->fdtps[0], i, &addr, &size);
  392. fdt_add_reservemap_entry(buf, addr, size);
  393. }
  394. err = fdt_finish_reservemap(buf);
  395. if (err < 0) return -1;
  396. err = _ufdt_output_strtab_to_fdt(tree, buf);
  397. if (err < 0) return -1;
  398. struct ufdt_prop_dict dict;
  399. err = ufdt_prop_dict_construct(&dict, buf);
  400. if (err < 0) return -1;
  401. err = _ufdt_output_node_to_fdt(tree, buf, tree->root, &dict);
  402. if (err < 0) return -1;
  403. ufdt_prop_dict_destruct(&dict);
  404. err = fdt_finish(buf);
  405. if (err < 0) return -1;
  406. /*
  407. * IMPORTANT: fdt_totalsize(buf) might be less than buf_size
  408. * so this is needed to make use of remain spaces.
  409. */
  410. return fdt_open_into(buf, buf, buf_size);
  411. }