dtbdump.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Copyright 2020, Heinrich Schuchardt <xypron.glpk@gmx.de>
  4. *
  5. * dtbdump.efi saves the device tree provided as a configuration table
  6. * to a file.
  7. */
  8. #include <common.h>
  9. #include <efi_api.h>
  10. #include <efi_dt_fixup.h>
  11. #include <part.h>
  12. #include <linux/libfdt.h>
  13. #define BUFFER_SIZE 64
  14. #define ESC 0x17
  15. #define efi_size_in_pages(size) ((size + EFI_PAGE_MASK) >> EFI_PAGE_SHIFT)
  16. static struct efi_simple_text_output_protocol *cerr;
  17. static struct efi_simple_text_output_protocol *cout;
  18. static struct efi_simple_text_input_protocol *cin;
  19. static struct efi_boot_services *bs;
  20. static const efi_guid_t fdt_guid = EFI_FDT_GUID;
  21. static const efi_guid_t loaded_image_guid = EFI_LOADED_IMAGE_PROTOCOL_GUID;
  22. static const efi_guid_t guid_simple_file_system_protocol =
  23. EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID;
  24. static efi_handle_t handle;
  25. static struct efi_system_table *systable;
  26. static const efi_guid_t efi_dt_fixup_protocol_guid = EFI_DT_FIXUP_PROTOCOL_GUID;
  27. static const efi_guid_t efi_file_info_guid = EFI_FILE_INFO_GUID;
  28. static const efi_guid_t efi_system_partition_guid = PARTITION_SYSTEM_GUID;
  29. /**
  30. * print() - print string
  31. *
  32. * @string: text
  33. */
  34. static void print(u16 *string)
  35. {
  36. cout->output_string(cout, string);
  37. }
  38. /**
  39. * error() - print error string
  40. *
  41. * @string: error text
  42. */
  43. static void error(u16 *string)
  44. {
  45. cout->set_attribute(cout, EFI_LIGHTRED | EFI_BACKGROUND_BLACK);
  46. print(string);
  47. cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK);
  48. }
  49. /**
  50. * efi_input_yn() - get answer to yes/no question
  51. *
  52. * Return:
  53. * y or Y
  54. * EFI_SUCCESS
  55. * n or N
  56. * EFI_ACCESS_DENIED
  57. * ESC
  58. * EFI_ABORTED
  59. */
  60. static efi_status_t efi_input_yn(void)
  61. {
  62. struct efi_input_key key = {0};
  63. efi_uintn_t index;
  64. efi_status_t ret;
  65. /* Drain the console input */
  66. ret = cin->reset(cin, true);
  67. for (;;) {
  68. ret = bs->wait_for_event(1, &cin->wait_for_key, &index);
  69. if (ret != EFI_SUCCESS)
  70. continue;
  71. ret = cin->read_key_stroke(cin, &key);
  72. if (ret != EFI_SUCCESS)
  73. continue;
  74. switch (key.scan_code) {
  75. case 0x17: /* Escape */
  76. return EFI_ABORTED;
  77. default:
  78. break;
  79. }
  80. /* Convert to lower case */
  81. switch (key.unicode_char | 0x20) {
  82. case 'y':
  83. return EFI_SUCCESS;
  84. case 'n':
  85. return EFI_ACCESS_DENIED;
  86. default:
  87. break;
  88. }
  89. }
  90. }
  91. /**
  92. * efi_input() - read string from console
  93. *
  94. * @buffer: input buffer
  95. * @buffer_size: buffer size
  96. * Return: status code
  97. */
  98. static efi_status_t efi_input(u16 *buffer, efi_uintn_t buffer_size)
  99. {
  100. struct efi_input_key key = {0};
  101. efi_uintn_t index;
  102. efi_uintn_t pos = 0;
  103. u16 outbuf[2] = L" ";
  104. efi_status_t ret;
  105. /* Drain the console input */
  106. ret = cin->reset(cin, true);
  107. *buffer = 0;
  108. for (;;) {
  109. ret = bs->wait_for_event(1, &cin->wait_for_key, &index);
  110. if (ret != EFI_SUCCESS)
  111. continue;
  112. ret = cin->read_key_stroke(cin, &key);
  113. if (ret != EFI_SUCCESS)
  114. continue;
  115. switch (key.scan_code) {
  116. case 0x17: /* Escape */
  117. print(L"\r\nAborted\r\n");
  118. return EFI_ABORTED;
  119. default:
  120. break;
  121. }
  122. switch (key.unicode_char) {
  123. case 0x08: /* Backspace */
  124. if (pos) {
  125. buffer[pos--] = 0;
  126. print(L"\b \b");
  127. }
  128. break;
  129. case 0x0a: /* Linefeed */
  130. case 0x0d: /* Carriage return */
  131. print(L"\r\n");
  132. return EFI_SUCCESS;
  133. default:
  134. break;
  135. }
  136. /* Ignore surrogate codes */
  137. if (key.unicode_char >= 0xD800 && key.unicode_char <= 0xDBFF)
  138. continue;
  139. if (key.unicode_char >= 0x20 &&
  140. pos < buffer_size - 1) {
  141. *outbuf = key.unicode_char;
  142. buffer[pos++] = key.unicode_char;
  143. buffer[pos] = 0;
  144. print(outbuf);
  145. }
  146. }
  147. }
  148. /*
  149. * Convert FDT value to host endianness.
  150. *
  151. * @val FDT value
  152. * @return converted value
  153. */
  154. static u32 f2h(fdt32_t val)
  155. {
  156. char *buf = (char *)&val;
  157. char i;
  158. /* Swap the bytes */
  159. i = buf[0]; buf[0] = buf[3]; buf[3] = i;
  160. i = buf[1]; buf[1] = buf[2]; buf[2] = i;
  161. return *(u32 *)buf;
  162. }
  163. /**
  164. * get_dtb() - get device tree
  165. *
  166. * @systable: system table
  167. * Return: device tree or NULL
  168. */
  169. void *get_dtb(struct efi_system_table *systable)
  170. {
  171. void *dtb = NULL;
  172. efi_uintn_t i;
  173. for (i = 0; i < systable->nr_tables; ++i) {
  174. if (!memcmp(&systable->tables[i].guid, &fdt_guid,
  175. sizeof(efi_guid_t))) {
  176. dtb = systable->tables[i].table;
  177. break;
  178. }
  179. }
  180. return dtb;
  181. }
  182. /**
  183. * skip_whitespace() - skip over leading whitespace
  184. *
  185. * @pos: UTF-16 string
  186. * Return: pointer to first non-whitespace
  187. */
  188. u16 *skip_whitespace(u16 *pos)
  189. {
  190. for (; *pos && *pos <= 0x20; ++pos)
  191. ;
  192. return pos;
  193. }
  194. /**
  195. * starts_with() - check if @string starts with @keyword
  196. *
  197. * @string: string to search for keyword
  198. * @keyword: keyword to be searched
  199. * Return: true fi @string starts with the keyword
  200. */
  201. bool starts_with(u16 *string, u16 *keyword)
  202. {
  203. for (; *keyword; ++string, ++keyword) {
  204. if (*string != *keyword)
  205. return false;
  206. }
  207. return true;
  208. }
  209. /**
  210. * do_help() - print help
  211. */
  212. void do_help(void)
  213. {
  214. error(L"load <dtb> - load device-tree from file\r\n");
  215. error(L"save <dtb> - save device-tree to file\r\n");
  216. error(L"exit - exit the shell\r\n");
  217. }
  218. /**
  219. * open_file_system() - open simple file system protocol
  220. *
  221. * file_system: interface of the simple file system protocol
  222. * Return: status code
  223. */
  224. static efi_status_t
  225. open_file_system(struct efi_simple_file_system_protocol **file_system)
  226. {
  227. struct efi_loaded_image *loaded_image;
  228. efi_status_t ret;
  229. efi_handle_t *handle_buffer = NULL;
  230. efi_uintn_t count;
  231. ret = bs->open_protocol(handle, &loaded_image_guid,
  232. (void **)&loaded_image, NULL, NULL,
  233. EFI_OPEN_PROTOCOL_GET_PROTOCOL);
  234. if (ret != EFI_SUCCESS) {
  235. error(L"Loaded image protocol not found\r\n");
  236. return ret;
  237. }
  238. /* Open the simple file system protocol on the same partition */
  239. ret = bs->open_protocol(loaded_image->device_handle,
  240. &guid_simple_file_system_protocol,
  241. (void **)file_system, NULL, NULL,
  242. EFI_OPEN_PROTOCOL_GET_PROTOCOL);
  243. if (ret == EFI_SUCCESS)
  244. return ret;
  245. /* Open the simple file system protocol on the UEFI system partition */
  246. ret = bs->locate_handle_buffer(BY_PROTOCOL, &efi_system_partition_guid,
  247. NULL, &count, &handle_buffer);
  248. if (ret == EFI_SUCCESS && handle_buffer)
  249. ret = bs->open_protocol(handle_buffer[0],
  250. &guid_simple_file_system_protocol,
  251. (void **)file_system, NULL, NULL,
  252. EFI_OPEN_PROTOCOL_GET_PROTOCOL);
  253. if (ret != EFI_SUCCESS)
  254. error(L"Failed to open simple file system protocol\r\n");
  255. if (handle)
  256. bs->free_pool(handle_buffer);
  257. return ret;
  258. }
  259. /**
  260. * do_load() - load and install device-tree
  261. *
  262. * @filename: file name
  263. * Return: status code
  264. */
  265. efi_status_t do_load(u16 *filename)
  266. {
  267. struct efi_dt_fixup_protocol *dt_fixup_prot;
  268. struct efi_simple_file_system_protocol *file_system;
  269. struct efi_file_handle *root = NULL, *file = NULL;
  270. u64 addr = 0;
  271. struct efi_file_info *info;
  272. struct fdt_header *dtb;
  273. efi_uintn_t buffer_size;
  274. efi_uintn_t pages;
  275. efi_status_t ret, ret2;
  276. ret = bs->locate_protocol(&efi_dt_fixup_protocol_guid, NULL,
  277. (void **)&dt_fixup_prot);
  278. if (ret != EFI_SUCCESS) {
  279. error(L"Device-tree fix-up protocol not found\r\n");
  280. return ret;
  281. }
  282. filename = skip_whitespace(filename);
  283. ret = open_file_system(&file_system);
  284. if (ret != EFI_SUCCESS)
  285. goto out;
  286. /* Open volume */
  287. ret = file_system->open_volume(file_system, &root);
  288. if (ret != EFI_SUCCESS) {
  289. error(L"Failed to open volume\r\n");
  290. goto out;
  291. }
  292. /* Open file */
  293. ret = root->open(root, &file, filename, EFI_FILE_MODE_READ, 0);
  294. if (ret != EFI_SUCCESS) {
  295. error(L"File not found\r\n");
  296. goto out;
  297. }
  298. /* Get file size */
  299. buffer_size = 0;
  300. ret = file->getinfo(file, &efi_file_info_guid, &buffer_size, NULL);
  301. if (ret != EFI_BUFFER_TOO_SMALL) {
  302. error(L"Can't get file info size\r\n");
  303. goto out;
  304. }
  305. ret = bs->allocate_pool(EFI_LOADER_DATA, buffer_size, (void **)&info);
  306. if (ret != EFI_SUCCESS) {
  307. error(L"Out of memory\r\n");
  308. goto out;
  309. }
  310. ret = file->getinfo(file, &efi_file_info_guid, &buffer_size, info);
  311. if (ret != EFI_SUCCESS) {
  312. error(L"Can't get file info\r\n");
  313. goto out;
  314. }
  315. buffer_size = info->file_size;
  316. pages = efi_size_in_pages(buffer_size);
  317. ret = bs->free_pool(info);
  318. if (ret != EFI_SUCCESS)
  319. error(L"Can't free memory pool\r\n");
  320. /* Read file */
  321. ret = bs->allocate_pages(EFI_ALLOCATE_ANY_PAGES,
  322. EFI_ACPI_RECLAIM_MEMORY,
  323. pages, &addr);
  324. if (ret != EFI_SUCCESS) {
  325. error(L"Out of memory\r\n");
  326. goto out;
  327. }
  328. dtb = (struct fdt_header *)(uintptr_t)addr;
  329. ret = file->read(file, &buffer_size, dtb);
  330. if (ret != EFI_SUCCESS) {
  331. error(L"Can't read file\r\n");
  332. goto out;
  333. }
  334. /* Fixup file, expecting EFI_BUFFER_TOO_SMALL */
  335. ret = dt_fixup_prot->fixup(dt_fixup_prot, dtb, &buffer_size,
  336. EFI_DT_APPLY_FIXUPS | EFI_DT_RESERVE_MEMORY |
  337. EFI_DT_INSTALL_TABLE);
  338. if (ret == EFI_BUFFER_TOO_SMALL) {
  339. /* Read file into larger buffer */
  340. ret = bs->free_pages(addr, pages);
  341. if (ret != EFI_SUCCESS)
  342. error(L"Can't free memory pages\r\n");
  343. pages = efi_size_in_pages(buffer_size);
  344. ret = bs->allocate_pages(EFI_ALLOCATE_ANY_PAGES,
  345. EFI_ACPI_RECLAIM_MEMORY,
  346. pages, &addr);
  347. if (ret != EFI_SUCCESS) {
  348. error(L"Out of memory\r\n");
  349. goto out;
  350. }
  351. dtb = (struct fdt_header *)(uintptr_t)addr;
  352. ret = file->setpos(file, 0);
  353. if (ret != EFI_SUCCESS) {
  354. error(L"Can't position file\r\n");
  355. goto out;
  356. }
  357. ret = file->read(file, &buffer_size, dtb);
  358. if (ret != EFI_SUCCESS) {
  359. error(L"Can't read file\r\n");
  360. goto out;
  361. }
  362. buffer_size = pages << EFI_PAGE_SHIFT;
  363. ret = dt_fixup_prot->fixup(
  364. dt_fixup_prot, dtb, &buffer_size,
  365. EFI_DT_APPLY_FIXUPS | EFI_DT_RESERVE_MEMORY |
  366. EFI_DT_INSTALL_TABLE);
  367. }
  368. if (ret == EFI_SUCCESS)
  369. print(L"device-tree installed\r\n");
  370. else
  371. error(L"Device-tree fix-up failed\r\n");
  372. out:
  373. if (addr) {
  374. ret2 = bs->free_pages(addr, pages);
  375. if (ret2 != EFI_SUCCESS)
  376. error(L"Can't free memory pages\r\n");
  377. }
  378. if (file) {
  379. ret2 = file->close(file);
  380. if (ret2 != EFI_SUCCESS)
  381. error(L"Can't close file\r\n");
  382. }
  383. if (root) {
  384. ret2 = root->close(root);
  385. if (ret2 != EFI_SUCCESS)
  386. error(L"Can't close volume\r\n");
  387. }
  388. return ret;
  389. }
  390. /**
  391. * do_save() - save current device-tree
  392. *
  393. * @filename: file name
  394. * Return: status code
  395. */
  396. efi_status_t do_save(u16 *filename)
  397. {
  398. struct efi_simple_file_system_protocol *file_system;
  399. efi_uintn_t dtb_size;
  400. struct efi_file_handle *root, *file;
  401. struct fdt_header *dtb;
  402. efi_uintn_t ret;
  403. dtb = get_dtb(systable);
  404. if (!dtb) {
  405. error(L"DTB not found\r\n");
  406. return EFI_NOT_FOUND;
  407. }
  408. if (f2h(dtb->magic) != FDT_MAGIC) {
  409. error(L"Wrong device tree magic\r\n");
  410. return EFI_NOT_FOUND;
  411. }
  412. dtb_size = f2h(dtb->totalsize);
  413. filename = skip_whitespace(filename);
  414. ret = open_file_system(&file_system);
  415. if (ret != EFI_SUCCESS)
  416. return ret;
  417. /* Open volume */
  418. ret = file_system->open_volume(file_system, &root);
  419. if (ret != EFI_SUCCESS) {
  420. error(L"Failed to open volume\r\n");
  421. return ret;
  422. }
  423. /* Check if file already exists */
  424. ret = root->open(root, &file, filename, EFI_FILE_MODE_READ, 0);
  425. if (ret == EFI_SUCCESS) {
  426. file->close(file);
  427. print(L"Overwrite existing file (y/n)? ");
  428. ret = efi_input_yn();
  429. print(L"\r\n");
  430. if (ret != EFI_SUCCESS) {
  431. root->close(root);
  432. error(L"Aborted by user\r\n");
  433. return ret;
  434. }
  435. }
  436. /* Create file */
  437. ret = root->open(root, &file, filename,
  438. EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE |
  439. EFI_FILE_MODE_CREATE, EFI_FILE_ARCHIVE);
  440. if (ret == EFI_SUCCESS) {
  441. /* Write file */
  442. ret = file->write(file, &dtb_size, dtb);
  443. if (ret != EFI_SUCCESS)
  444. error(L"Failed to write file\r\n");
  445. file->close(file);
  446. } else {
  447. error(L"Failed to open file\r\n");
  448. }
  449. root->close(root);
  450. if (ret == EFI_SUCCESS) {
  451. print(filename);
  452. print(L" written\r\n");
  453. }
  454. return ret;
  455. }
  456. /**
  457. * efi_main() - entry point of the EFI application.
  458. *
  459. * @handle: handle of the loaded image
  460. * @systab: system table
  461. * @return: status code
  462. */
  463. efi_status_t EFIAPI efi_main(efi_handle_t image_handle,
  464. struct efi_system_table *systab)
  465. {
  466. handle = image_handle;
  467. systable = systab;
  468. cerr = systable->std_err;
  469. cout = systable->con_out;
  470. cin = systable->con_in;
  471. bs = systable->boottime;
  472. cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK);
  473. cout->clear_screen(cout);
  474. cout->set_attribute(cout, EFI_WHITE | EFI_BACKGROUND_BLACK);
  475. print(L"DTB Dump\r\n========\r\n\r\n");
  476. cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK);
  477. for (;;) {
  478. u16 command[BUFFER_SIZE];
  479. u16 *pos;
  480. efi_uintn_t ret;
  481. print(L"=> ");
  482. ret = efi_input(command, sizeof(command));
  483. if (ret == EFI_ABORTED)
  484. break;
  485. pos = skip_whitespace(command);
  486. if (starts_with(pos, L"exit"))
  487. break;
  488. else if (starts_with(pos, L"load "))
  489. do_load(pos + 5);
  490. else if (starts_with(pos, L"save "))
  491. do_save(pos + 5);
  492. else
  493. do_help();
  494. }
  495. cout->set_attribute(cout, EFI_LIGHTGRAY | EFI_BACKGROUND_BLACK);
  496. cout->clear_screen(cout);
  497. return EFI_SUCCESS;
  498. }