ufdt_convert.c 13 KB

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