2
0

device_tree.c 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. /*
  2. * Functions to help device tree manipulation using libfdt.
  3. * It also provides functions to read entries from device tree proc
  4. * interface.
  5. *
  6. * Copyright 2008 IBM Corporation.
  7. * Authors: Jerone Young <jyoung5@us.ibm.com>
  8. * Hollis Blanchard <hollisb@us.ibm.com>
  9. *
  10. * This work is licensed under the GNU GPL license version 2 or later.
  11. *
  12. */
  13. #include <stdio.h>
  14. #include <sys/types.h>
  15. #include <sys/stat.h>
  16. #include <fcntl.h>
  17. #include <unistd.h>
  18. #include <stdlib.h>
  19. #include "config.h"
  20. #include "qemu-common.h"
  21. #include "sysemu/device_tree.h"
  22. #include "sysemu/sysemu.h"
  23. #include "hw/loader.h"
  24. #include "qemu/option.h"
  25. #include "qemu/config-file.h"
  26. #include <libfdt.h>
  27. #define FDT_MAX_SIZE 0x10000
  28. void *create_device_tree(int *sizep)
  29. {
  30. void *fdt;
  31. int ret;
  32. *sizep = FDT_MAX_SIZE;
  33. fdt = g_malloc0(FDT_MAX_SIZE);
  34. ret = fdt_create(fdt, FDT_MAX_SIZE);
  35. if (ret < 0) {
  36. goto fail;
  37. }
  38. ret = fdt_finish_reservemap(fdt);
  39. if (ret < 0) {
  40. goto fail;
  41. }
  42. ret = fdt_begin_node(fdt, "");
  43. if (ret < 0) {
  44. goto fail;
  45. }
  46. ret = fdt_end_node(fdt);
  47. if (ret < 0) {
  48. goto fail;
  49. }
  50. ret = fdt_finish(fdt);
  51. if (ret < 0) {
  52. goto fail;
  53. }
  54. ret = fdt_open_into(fdt, fdt, *sizep);
  55. if (ret) {
  56. fprintf(stderr, "Unable to copy device tree in memory\n");
  57. exit(1);
  58. }
  59. return fdt;
  60. fail:
  61. fprintf(stderr, "%s Couldn't create dt: %s\n", __func__, fdt_strerror(ret));
  62. exit(1);
  63. }
  64. void *load_device_tree(const char *filename_path, int *sizep)
  65. {
  66. int dt_size;
  67. int dt_file_load_size;
  68. int ret;
  69. void *fdt = NULL;
  70. *sizep = 0;
  71. dt_size = get_image_size(filename_path);
  72. if (dt_size < 0) {
  73. printf("Unable to get size of device tree file '%s'\n",
  74. filename_path);
  75. goto fail;
  76. }
  77. /* Expand to 2x size to give enough room for manipulation. */
  78. dt_size += 10000;
  79. dt_size *= 2;
  80. /* First allocate space in qemu for device tree */
  81. fdt = g_malloc0(dt_size);
  82. dt_file_load_size = load_image(filename_path, fdt);
  83. if (dt_file_load_size < 0) {
  84. printf("Unable to open device tree file '%s'\n",
  85. filename_path);
  86. goto fail;
  87. }
  88. ret = fdt_open_into(fdt, fdt, dt_size);
  89. if (ret) {
  90. printf("Unable to copy device tree in memory\n");
  91. goto fail;
  92. }
  93. /* Check sanity of device tree */
  94. if (fdt_check_header(fdt)) {
  95. printf ("Device tree file loaded into memory is invalid: %s\n",
  96. filename_path);
  97. goto fail;
  98. }
  99. *sizep = dt_size;
  100. return fdt;
  101. fail:
  102. g_free(fdt);
  103. return NULL;
  104. }
  105. static int findnode_nofail(void *fdt, const char *node_path)
  106. {
  107. int offset;
  108. offset = fdt_path_offset(fdt, node_path);
  109. if (offset < 0) {
  110. fprintf(stderr, "%s Couldn't find node %s: %s\n", __func__, node_path,
  111. fdt_strerror(offset));
  112. exit(1);
  113. }
  114. return offset;
  115. }
  116. int qemu_fdt_setprop(void *fdt, const char *node_path,
  117. const char *property, const void *val, int size)
  118. {
  119. int r;
  120. r = fdt_setprop(fdt, findnode_nofail(fdt, node_path), property, val, size);
  121. if (r < 0) {
  122. fprintf(stderr, "%s: Couldn't set %s/%s: %s\n", __func__, node_path,
  123. property, fdt_strerror(r));
  124. exit(1);
  125. }
  126. return r;
  127. }
  128. int qemu_fdt_setprop_cell(void *fdt, const char *node_path,
  129. const char *property, uint32_t val)
  130. {
  131. int r;
  132. r = fdt_setprop_cell(fdt, findnode_nofail(fdt, node_path), property, val);
  133. if (r < 0) {
  134. fprintf(stderr, "%s: Couldn't set %s/%s = %#08x: %s\n", __func__,
  135. node_path, property, val, fdt_strerror(r));
  136. exit(1);
  137. }
  138. return r;
  139. }
  140. int qemu_fdt_setprop_u64(void *fdt, const char *node_path,
  141. const char *property, uint64_t val)
  142. {
  143. val = cpu_to_be64(val);
  144. return qemu_fdt_setprop(fdt, node_path, property, &val, sizeof(val));
  145. }
  146. int qemu_fdt_setprop_string(void *fdt, const char *node_path,
  147. const char *property, const char *string)
  148. {
  149. int r;
  150. r = fdt_setprop_string(fdt, findnode_nofail(fdt, node_path), property, string);
  151. if (r < 0) {
  152. fprintf(stderr, "%s: Couldn't set %s/%s = %s: %s\n", __func__,
  153. node_path, property, string, fdt_strerror(r));
  154. exit(1);
  155. }
  156. return r;
  157. }
  158. const void *qemu_fdt_getprop(void *fdt, const char *node_path,
  159. const char *property, int *lenp)
  160. {
  161. int len;
  162. const void *r;
  163. if (!lenp) {
  164. lenp = &len;
  165. }
  166. r = fdt_getprop(fdt, findnode_nofail(fdt, node_path), property, lenp);
  167. if (!r) {
  168. fprintf(stderr, "%s: Couldn't get %s/%s: %s\n", __func__,
  169. node_path, property, fdt_strerror(*lenp));
  170. exit(1);
  171. }
  172. return r;
  173. }
  174. uint32_t qemu_fdt_getprop_cell(void *fdt, const char *node_path,
  175. const char *property)
  176. {
  177. int len;
  178. const uint32_t *p = qemu_fdt_getprop(fdt, node_path, property, &len);
  179. if (len != 4) {
  180. fprintf(stderr, "%s: %s/%s not 4 bytes long (not a cell?)\n",
  181. __func__, node_path, property);
  182. exit(1);
  183. }
  184. return be32_to_cpu(*p);
  185. }
  186. uint32_t qemu_fdt_get_phandle(void *fdt, const char *path)
  187. {
  188. uint32_t r;
  189. r = fdt_get_phandle(fdt, findnode_nofail(fdt, path));
  190. if (r == 0) {
  191. fprintf(stderr, "%s: Couldn't get phandle for %s: %s\n", __func__,
  192. path, fdt_strerror(r));
  193. exit(1);
  194. }
  195. return r;
  196. }
  197. int qemu_fdt_setprop_phandle(void *fdt, const char *node_path,
  198. const char *property,
  199. const char *target_node_path)
  200. {
  201. uint32_t phandle = qemu_fdt_get_phandle(fdt, target_node_path);
  202. return qemu_fdt_setprop_cell(fdt, node_path, property, phandle);
  203. }
  204. uint32_t qemu_fdt_alloc_phandle(void *fdt)
  205. {
  206. static int phandle = 0x0;
  207. /*
  208. * We need to find out if the user gave us special instruction at
  209. * which phandle id to start allocting phandles.
  210. */
  211. if (!phandle) {
  212. phandle = qemu_opt_get_number(qemu_get_machine_opts(),
  213. "phandle_start", 0);
  214. }
  215. if (!phandle) {
  216. /*
  217. * None or invalid phandle given on the command line, so fall back to
  218. * default starting point.
  219. */
  220. phandle = 0x8000;
  221. }
  222. return phandle++;
  223. }
  224. int qemu_fdt_nop_node(void *fdt, const char *node_path)
  225. {
  226. int r;
  227. r = fdt_nop_node(fdt, findnode_nofail(fdt, node_path));
  228. if (r < 0) {
  229. fprintf(stderr, "%s: Couldn't nop node %s: %s\n", __func__, node_path,
  230. fdt_strerror(r));
  231. exit(1);
  232. }
  233. return r;
  234. }
  235. int qemu_fdt_add_subnode(void *fdt, const char *name)
  236. {
  237. char *dupname = g_strdup(name);
  238. char *basename = strrchr(dupname, '/');
  239. int retval;
  240. int parent = 0;
  241. if (!basename) {
  242. g_free(dupname);
  243. return -1;
  244. }
  245. basename[0] = '\0';
  246. basename++;
  247. if (dupname[0]) {
  248. parent = findnode_nofail(fdt, dupname);
  249. }
  250. retval = fdt_add_subnode(fdt, parent, basename);
  251. if (retval < 0) {
  252. fprintf(stderr, "FDT: Failed to create subnode %s: %s\n", name,
  253. fdt_strerror(retval));
  254. exit(1);
  255. }
  256. g_free(dupname);
  257. return retval;
  258. }
  259. void qemu_fdt_dumpdtb(void *fdt, int size)
  260. {
  261. const char *dumpdtb = qemu_opt_get(qemu_get_machine_opts(), "dumpdtb");
  262. if (dumpdtb) {
  263. /* Dump the dtb to a file and quit */
  264. exit(g_file_set_contents(dumpdtb, fdt, size, NULL) ? 0 : 1);
  265. }
  266. }
  267. int qemu_fdt_setprop_sized_cells_from_array(void *fdt,
  268. const char *node_path,
  269. const char *property,
  270. int numvalues,
  271. uint64_t *values)
  272. {
  273. uint32_t *propcells;
  274. uint64_t value;
  275. int cellnum, vnum, ncells;
  276. uint32_t hival;
  277. propcells = g_new0(uint32_t, numvalues * 2);
  278. cellnum = 0;
  279. for (vnum = 0; vnum < numvalues; vnum++) {
  280. ncells = values[vnum * 2];
  281. if (ncells != 1 && ncells != 2) {
  282. return -1;
  283. }
  284. value = values[vnum * 2 + 1];
  285. hival = cpu_to_be32(value >> 32);
  286. if (ncells > 1) {
  287. propcells[cellnum++] = hival;
  288. } else if (hival != 0) {
  289. return -1;
  290. }
  291. propcells[cellnum++] = cpu_to_be32(value);
  292. }
  293. return qemu_fdt_setprop(fdt, node_path, property, propcells,
  294. cellnum * sizeof(uint32_t));
  295. }