2
0

device_tree.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679
  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 "qemu/osdep.h"
  14. #ifdef CONFIG_LINUX
  15. #include <dirent.h>
  16. #endif
  17. #include "qapi/error.h"
  18. #include "qemu/error-report.h"
  19. #include "qemu/option.h"
  20. #include "qemu/bswap.h"
  21. #include "qemu/cutils.h"
  22. #include "qemu/guest-random.h"
  23. #include "system/device_tree.h"
  24. #include "hw/loader.h"
  25. #include "hw/boards.h"
  26. #include "qemu/config-file.h"
  27. #include "qapi/qapi-commands-machine.h"
  28. #include "qobject/qdict.h"
  29. #include "monitor/hmp.h"
  30. #include <libfdt.h>
  31. #define FDT_MAX_SIZE 0x100000
  32. void *create_device_tree(int *sizep)
  33. {
  34. void *fdt;
  35. int ret;
  36. *sizep = FDT_MAX_SIZE;
  37. fdt = g_malloc0(FDT_MAX_SIZE);
  38. ret = fdt_create(fdt, FDT_MAX_SIZE);
  39. if (ret < 0) {
  40. goto fail;
  41. }
  42. ret = fdt_finish_reservemap(fdt);
  43. if (ret < 0) {
  44. goto fail;
  45. }
  46. ret = fdt_begin_node(fdt, "");
  47. if (ret < 0) {
  48. goto fail;
  49. }
  50. ret = fdt_end_node(fdt);
  51. if (ret < 0) {
  52. goto fail;
  53. }
  54. ret = fdt_finish(fdt);
  55. if (ret < 0) {
  56. goto fail;
  57. }
  58. ret = fdt_open_into(fdt, fdt, *sizep);
  59. if (ret) {
  60. error_report("%s: Unable to copy device tree into memory: %s",
  61. __func__, fdt_strerror(ret));
  62. exit(1);
  63. }
  64. return fdt;
  65. fail:
  66. error_report("%s Couldn't create dt: %s", __func__, fdt_strerror(ret));
  67. exit(1);
  68. }
  69. void *load_device_tree(const char *filename_path, int *sizep)
  70. {
  71. int dt_size;
  72. int dt_file_load_size;
  73. int ret;
  74. void *fdt = NULL;
  75. *sizep = 0;
  76. dt_size = get_image_size(filename_path);
  77. if (dt_size < 0) {
  78. error_report("Unable to get size of device tree file '%s'",
  79. filename_path);
  80. goto fail;
  81. }
  82. if (dt_size > INT_MAX / 2 - 10000) {
  83. error_report("Device tree file '%s' is too large", filename_path);
  84. goto fail;
  85. }
  86. /* Expand to 2x size to give enough room for manipulation. */
  87. dt_size += 10000;
  88. dt_size *= 2;
  89. /* First allocate space in qemu for device tree */
  90. fdt = g_malloc0(dt_size);
  91. dt_file_load_size = load_image_size(filename_path, fdt, dt_size);
  92. if (dt_file_load_size < 0) {
  93. error_report("Unable to open device tree file '%s'",
  94. filename_path);
  95. goto fail;
  96. }
  97. ret = fdt_open_into(fdt, fdt, dt_size);
  98. if (ret) {
  99. error_report("%s: Unable to copy device tree into memory: %s",
  100. __func__, fdt_strerror(ret));
  101. goto fail;
  102. }
  103. /* Check sanity of device tree */
  104. if (fdt_check_header(fdt)) {
  105. error_report("Device tree file loaded into memory is invalid: %s",
  106. filename_path);
  107. goto fail;
  108. }
  109. *sizep = dt_size;
  110. return fdt;
  111. fail:
  112. g_free(fdt);
  113. return NULL;
  114. }
  115. #ifdef CONFIG_LINUX
  116. #define SYSFS_DT_BASEDIR "/proc/device-tree"
  117. /**
  118. * read_fstree: this function is inspired from dtc read_fstree
  119. * @fdt: preallocated fdt blob buffer, to be populated
  120. * @dirname: directory to scan under SYSFS_DT_BASEDIR
  121. * the search is recursive and the tree is searched down to the
  122. * leaves (property files).
  123. *
  124. * the function asserts in case of error
  125. */
  126. static void read_fstree(void *fdt, const char *dirname)
  127. {
  128. DIR *d;
  129. struct dirent *de;
  130. struct stat st;
  131. const char *root_dir = SYSFS_DT_BASEDIR;
  132. const char *parent_node;
  133. if (strstr(dirname, root_dir) != dirname) {
  134. error_report("%s: %s must be searched within %s",
  135. __func__, dirname, root_dir);
  136. exit(1);
  137. }
  138. parent_node = &dirname[strlen(SYSFS_DT_BASEDIR)];
  139. d = opendir(dirname);
  140. if (!d) {
  141. error_report("%s cannot open %s", __func__, dirname);
  142. exit(1);
  143. }
  144. while ((de = readdir(d)) != NULL) {
  145. char *tmpnam;
  146. if (!g_strcmp0(de->d_name, ".")
  147. || !g_strcmp0(de->d_name, "..")) {
  148. continue;
  149. }
  150. tmpnam = g_strdup_printf("%s/%s", dirname, de->d_name);
  151. if (lstat(tmpnam, &st) < 0) {
  152. error_report("%s cannot lstat %s", __func__, tmpnam);
  153. exit(1);
  154. }
  155. if (S_ISREG(st.st_mode)) {
  156. gchar *val;
  157. gsize len;
  158. if (!g_file_get_contents(tmpnam, &val, &len, NULL)) {
  159. error_report("%s not able to extract info from %s",
  160. __func__, tmpnam);
  161. exit(1);
  162. }
  163. if (strlen(parent_node) > 0) {
  164. qemu_fdt_setprop(fdt, parent_node,
  165. de->d_name, val, len);
  166. } else {
  167. qemu_fdt_setprop(fdt, "/", de->d_name, val, len);
  168. }
  169. g_free(val);
  170. } else if (S_ISDIR(st.st_mode)) {
  171. char *node_name;
  172. node_name = g_strdup_printf("%s/%s",
  173. parent_node, de->d_name);
  174. qemu_fdt_add_subnode(fdt, node_name);
  175. g_free(node_name);
  176. read_fstree(fdt, tmpnam);
  177. }
  178. g_free(tmpnam);
  179. }
  180. closedir(d);
  181. }
  182. /* load_device_tree_from_sysfs: extract the dt blob from host sysfs */
  183. void *load_device_tree_from_sysfs(void)
  184. {
  185. void *host_fdt;
  186. int host_fdt_size;
  187. host_fdt = create_device_tree(&host_fdt_size);
  188. read_fstree(host_fdt, SYSFS_DT_BASEDIR);
  189. if (fdt_check_header(host_fdt)) {
  190. error_report("%s host device tree extracted into memory is invalid",
  191. __func__);
  192. exit(1);
  193. }
  194. return host_fdt;
  195. }
  196. #endif /* CONFIG_LINUX */
  197. static int findnode_nofail(void *fdt, const char *node_path)
  198. {
  199. int offset;
  200. offset = fdt_path_offset(fdt, node_path);
  201. if (offset < 0) {
  202. error_report("%s Couldn't find node %s: %s", __func__, node_path,
  203. fdt_strerror(offset));
  204. exit(1);
  205. }
  206. return offset;
  207. }
  208. char **qemu_fdt_node_unit_path(void *fdt, const char *name, Error **errp)
  209. {
  210. char *prefix = g_strdup_printf("%s@", name);
  211. unsigned int path_len = 16, n = 0;
  212. GSList *path_list = NULL, *iter;
  213. const char *iter_name;
  214. int offset, len, ret;
  215. char **path_array;
  216. offset = fdt_next_node(fdt, -1, NULL);
  217. while (offset >= 0) {
  218. iter_name = fdt_get_name(fdt, offset, &len);
  219. if (!iter_name) {
  220. offset = len;
  221. break;
  222. }
  223. if (!strcmp(iter_name, name) || g_str_has_prefix(iter_name, prefix)) {
  224. char *path;
  225. path = g_malloc(path_len);
  226. while ((ret = fdt_get_path(fdt, offset, path, path_len))
  227. == -FDT_ERR_NOSPACE) {
  228. path_len += 16;
  229. path = g_realloc(path, path_len);
  230. }
  231. path_list = g_slist_prepend(path_list, path);
  232. n++;
  233. }
  234. offset = fdt_next_node(fdt, offset, NULL);
  235. }
  236. g_free(prefix);
  237. if (offset < 0 && offset != -FDT_ERR_NOTFOUND) {
  238. error_setg(errp, "%s: abort parsing dt for %s node units: %s",
  239. __func__, name, fdt_strerror(offset));
  240. for (iter = path_list; iter; iter = iter->next) {
  241. g_free(iter->data);
  242. }
  243. g_slist_free(path_list);
  244. return NULL;
  245. }
  246. path_array = g_new(char *, n + 1);
  247. path_array[n--] = NULL;
  248. for (iter = path_list; iter; iter = iter->next) {
  249. path_array[n--] = iter->data;
  250. }
  251. g_slist_free(path_list);
  252. return path_array;
  253. }
  254. char **qemu_fdt_node_path(void *fdt, const char *name, const char *compat,
  255. Error **errp)
  256. {
  257. int offset, len, ret;
  258. const char *iter_name;
  259. unsigned int path_len = 16, n = 0;
  260. GSList *path_list = NULL, *iter;
  261. char **path_array;
  262. offset = fdt_node_offset_by_compatible(fdt, -1, compat);
  263. while (offset >= 0) {
  264. iter_name = fdt_get_name(fdt, offset, &len);
  265. if (!iter_name) {
  266. offset = len;
  267. break;
  268. }
  269. if (!name || !strcmp(iter_name, name)) {
  270. char *path;
  271. path = g_malloc(path_len);
  272. while ((ret = fdt_get_path(fdt, offset, path, path_len))
  273. == -FDT_ERR_NOSPACE) {
  274. path_len += 16;
  275. path = g_realloc(path, path_len);
  276. }
  277. path_list = g_slist_prepend(path_list, path);
  278. n++;
  279. }
  280. offset = fdt_node_offset_by_compatible(fdt, offset, compat);
  281. }
  282. if (offset < 0 && offset != -FDT_ERR_NOTFOUND) {
  283. error_setg(errp, "%s: abort parsing dt for %s/%s: %s",
  284. __func__, name, compat, fdt_strerror(offset));
  285. for (iter = path_list; iter; iter = iter->next) {
  286. g_free(iter->data);
  287. }
  288. g_slist_free(path_list);
  289. return NULL;
  290. }
  291. path_array = g_new(char *, n + 1);
  292. path_array[n--] = NULL;
  293. for (iter = path_list; iter; iter = iter->next) {
  294. path_array[n--] = iter->data;
  295. }
  296. g_slist_free(path_list);
  297. return path_array;
  298. }
  299. int qemu_fdt_setprop(void *fdt, const char *node_path,
  300. const char *property, const void *val, int size)
  301. {
  302. int r;
  303. r = fdt_setprop(fdt, findnode_nofail(fdt, node_path), property, val, size);
  304. if (r < 0) {
  305. error_report("%s: Couldn't set %s/%s: %s", __func__, node_path,
  306. property, fdt_strerror(r));
  307. exit(1);
  308. }
  309. return r;
  310. }
  311. int qemu_fdt_setprop_cell(void *fdt, const char *node_path,
  312. const char *property, uint32_t val)
  313. {
  314. int r;
  315. r = fdt_setprop_cell(fdt, findnode_nofail(fdt, node_path), property, val);
  316. if (r < 0) {
  317. error_report("%s: Couldn't set %s/%s = %#08x: %s", __func__,
  318. node_path, property, val, fdt_strerror(r));
  319. exit(1);
  320. }
  321. return r;
  322. }
  323. int qemu_fdt_setprop_u64(void *fdt, const char *node_path,
  324. const char *property, uint64_t val)
  325. {
  326. val = cpu_to_be64(val);
  327. return qemu_fdt_setprop(fdt, node_path, property, &val, sizeof(val));
  328. }
  329. int qemu_fdt_setprop_string(void *fdt, const char *node_path,
  330. const char *property, const char *string)
  331. {
  332. int r;
  333. r = fdt_setprop_string(fdt, findnode_nofail(fdt, node_path), property, string);
  334. if (r < 0) {
  335. error_report("%s: Couldn't set %s/%s = %s: %s", __func__,
  336. node_path, property, string, fdt_strerror(r));
  337. exit(1);
  338. }
  339. return r;
  340. }
  341. /*
  342. * libfdt doesn't allow us to add string arrays directly but they are
  343. * test a series of null terminated strings with a length. We build
  344. * the string up here so we can calculate the final length.
  345. */
  346. int qemu_fdt_setprop_string_array(void *fdt, const char *node_path,
  347. const char *prop, char **array, int len)
  348. {
  349. int ret, i, total_len = 0;
  350. char *str, *p;
  351. for (i = 0; i < len; i++) {
  352. total_len += strlen(array[i]) + 1;
  353. }
  354. p = str = g_malloc0(total_len);
  355. for (i = 0; i < len; i++) {
  356. int offset = strlen(array[i]) + 1;
  357. pstrcpy(p, offset, array[i]);
  358. p += offset;
  359. }
  360. ret = qemu_fdt_setprop(fdt, node_path, prop, str, total_len);
  361. g_free(str);
  362. return ret;
  363. }
  364. const void *qemu_fdt_getprop(void *fdt, const char *node_path,
  365. const char *property, int *lenp, Error **errp)
  366. {
  367. int len;
  368. const void *r;
  369. if (!lenp) {
  370. lenp = &len;
  371. }
  372. r = fdt_getprop(fdt, findnode_nofail(fdt, node_path), property, lenp);
  373. if (!r) {
  374. error_setg(errp, "%s: Couldn't get %s/%s: %s", __func__,
  375. node_path, property, fdt_strerror(*lenp));
  376. }
  377. return r;
  378. }
  379. uint32_t qemu_fdt_getprop_cell(void *fdt, const char *node_path,
  380. const char *property, int *lenp, Error **errp)
  381. {
  382. int len;
  383. const uint32_t *p;
  384. if (!lenp) {
  385. lenp = &len;
  386. }
  387. p = qemu_fdt_getprop(fdt, node_path, property, lenp, errp);
  388. if (!p) {
  389. return 0;
  390. } else if (*lenp != 4) {
  391. error_setg(errp, "%s: %s/%s not 4 bytes long (not a cell?)",
  392. __func__, node_path, property);
  393. *lenp = -EINVAL;
  394. return 0;
  395. }
  396. return be32_to_cpu(*p);
  397. }
  398. uint32_t qemu_fdt_get_phandle(void *fdt, const char *path)
  399. {
  400. uint32_t r;
  401. r = fdt_get_phandle(fdt, findnode_nofail(fdt, path));
  402. if (r == 0) {
  403. error_report("%s: Couldn't get phandle for %s: %s", __func__,
  404. path, fdt_strerror(r));
  405. exit(1);
  406. }
  407. return r;
  408. }
  409. int qemu_fdt_setprop_phandle(void *fdt, const char *node_path,
  410. const char *property,
  411. const char *target_node_path)
  412. {
  413. uint32_t phandle = qemu_fdt_get_phandle(fdt, target_node_path);
  414. return qemu_fdt_setprop_cell(fdt, node_path, property, phandle);
  415. }
  416. uint32_t qemu_fdt_alloc_phandle(void *fdt)
  417. {
  418. static int phandle = 0x0;
  419. /*
  420. * We need to find out if the user gave us special instruction at
  421. * which phandle id to start allocating phandles.
  422. */
  423. if (!phandle) {
  424. phandle = machine_phandle_start(current_machine);
  425. }
  426. if (!phandle) {
  427. /*
  428. * None or invalid phandle given on the command line, so fall back to
  429. * default starting point.
  430. */
  431. phandle = 0x8000;
  432. }
  433. return phandle++;
  434. }
  435. int qemu_fdt_nop_node(void *fdt, const char *node_path)
  436. {
  437. int r;
  438. r = fdt_nop_node(fdt, findnode_nofail(fdt, node_path));
  439. if (r < 0) {
  440. error_report("%s: Couldn't nop node %s: %s", __func__, node_path,
  441. fdt_strerror(r));
  442. exit(1);
  443. }
  444. return r;
  445. }
  446. int qemu_fdt_add_subnode(void *fdt, const char *name)
  447. {
  448. char *dupname = g_strdup(name);
  449. char *basename = strrchr(dupname, '/');
  450. int retval;
  451. int parent = 0;
  452. if (!basename) {
  453. g_free(dupname);
  454. return -1;
  455. }
  456. basename[0] = '\0';
  457. basename++;
  458. if (dupname[0]) {
  459. parent = findnode_nofail(fdt, dupname);
  460. }
  461. retval = fdt_add_subnode(fdt, parent, basename);
  462. if (retval < 0) {
  463. error_report("%s: Failed to create subnode %s: %s",
  464. __func__, name, fdt_strerror(retval));
  465. exit(1);
  466. }
  467. g_free(dupname);
  468. return retval;
  469. }
  470. /*
  471. * qemu_fdt_add_path: Like qemu_fdt_add_subnode(), but will add
  472. * all missing subnodes from the given path.
  473. */
  474. int qemu_fdt_add_path(void *fdt, const char *path)
  475. {
  476. const char *name;
  477. int namelen, retval;
  478. int parent = 0;
  479. if (path[0] != '/') {
  480. return -1;
  481. }
  482. do {
  483. name = path + 1;
  484. path = strchr(name, '/');
  485. namelen = path != NULL ? path - name : strlen(name);
  486. retval = fdt_subnode_offset_namelen(fdt, parent, name, namelen);
  487. if (retval < 0 && retval != -FDT_ERR_NOTFOUND) {
  488. error_report("%s: Unexpected error in finding subnode %.*s: %s",
  489. __func__, namelen, name, fdt_strerror(retval));
  490. exit(1);
  491. } else if (retval == -FDT_ERR_NOTFOUND) {
  492. retval = fdt_add_subnode_namelen(fdt, parent, name, namelen);
  493. if (retval < 0) {
  494. error_report("%s: Failed to create subnode %.*s: %s",
  495. __func__, namelen, name, fdt_strerror(retval));
  496. exit(1);
  497. }
  498. }
  499. parent = retval;
  500. } while (path);
  501. return retval;
  502. }
  503. int qemu_fdt_setprop_sized_cells_from_array(void *fdt,
  504. const char *node_path,
  505. const char *property,
  506. int numvalues,
  507. uint64_t *values)
  508. {
  509. uint32_t *propcells;
  510. uint64_t value;
  511. int cellnum, vnum, ncells;
  512. uint32_t hival;
  513. int ret;
  514. propcells = g_new0(uint32_t, numvalues * 2);
  515. cellnum = 0;
  516. for (vnum = 0; vnum < numvalues; vnum++) {
  517. ncells = values[vnum * 2];
  518. if (ncells != 1 && ncells != 2) {
  519. ret = -1;
  520. goto out;
  521. }
  522. value = values[vnum * 2 + 1];
  523. hival = cpu_to_be32(value >> 32);
  524. if (ncells > 1) {
  525. propcells[cellnum++] = hival;
  526. } else if (hival != 0) {
  527. ret = -1;
  528. goto out;
  529. }
  530. propcells[cellnum++] = cpu_to_be32(value);
  531. }
  532. ret = qemu_fdt_setprop(fdt, node_path, property, propcells,
  533. cellnum * sizeof(uint32_t));
  534. out:
  535. g_free(propcells);
  536. return ret;
  537. }
  538. void qmp_dumpdtb(const char *filename, Error **errp)
  539. {
  540. ERRP_GUARD();
  541. g_autoptr(GError) err = NULL;
  542. uint32_t size;
  543. if (!current_machine->fdt) {
  544. error_setg(errp, "This machine doesn't have an FDT");
  545. error_append_hint(errp,
  546. "(Perhaps it doesn't support FDT at all, or perhaps "
  547. "you need to provide an FDT with the -fdt option?)\n");
  548. return;
  549. }
  550. size = fdt_totalsize(current_machine->fdt);
  551. g_assert(size > 0);
  552. if (!g_file_set_contents(filename, current_machine->fdt, size, &err)) {
  553. error_setg(errp, "Error saving FDT to file %s: %s",
  554. filename, err->message);
  555. }
  556. }
  557. void qemu_fdt_randomize_seeds(void *fdt)
  558. {
  559. int noffset, poffset, len;
  560. const char *name;
  561. uint8_t *data;
  562. for (noffset = fdt_next_node(fdt, 0, NULL);
  563. noffset >= 0;
  564. noffset = fdt_next_node(fdt, noffset, NULL)) {
  565. for (poffset = fdt_first_property_offset(fdt, noffset);
  566. poffset >= 0;
  567. poffset = fdt_next_property_offset(fdt, poffset)) {
  568. data = (uint8_t *)fdt_getprop_by_offset(fdt, poffset, &name, &len);
  569. if (!data || strcmp(name, "rng-seed"))
  570. continue;
  571. qemu_guest_getrandom_nofail(data, len);
  572. }
  573. }
  574. }