efi_device_path_to_text.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * EFI device path interface
  4. *
  5. * Copyright (c) 2017 Heinrich Schuchardt
  6. */
  7. #include <common.h>
  8. #include <blk.h>
  9. #include <efi_loader.h>
  10. #include <malloc.h>
  11. #define MAC_OUTPUT_LEN 22
  12. #define UNKNOWN_OUTPUT_LEN 23
  13. #define MAX_NODE_LEN 512
  14. #define MAX_PATH_LEN 1024
  15. const efi_guid_t efi_guid_device_path_to_text_protocol =
  16. EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID;
  17. /**
  18. * efi_str_to_u16() - convert ASCII string to UTF-16
  19. *
  20. * A u16 buffer is allocated from pool. The ASCII string is copied to the u16
  21. * buffer.
  22. *
  23. * @str: ASCII string
  24. * Return: UTF-16 string. NULL if out of memory.
  25. */
  26. static u16 *efi_str_to_u16(char *str)
  27. {
  28. efi_uintn_t len;
  29. u16 *out, *dst;
  30. len = sizeof(u16) * (utf8_utf16_strlen(str) + 1);
  31. out = efi_alloc(len);
  32. if (!out)
  33. return NULL;
  34. dst = out;
  35. utf8_utf16_strcpy(&dst, str);
  36. return out;
  37. }
  38. static char *dp_unknown(char *s, struct efi_device_path *dp)
  39. {
  40. s += sprintf(s, "UNKNOWN(%04x,%04x)", dp->type, dp->sub_type);
  41. return s;
  42. }
  43. static char *dp_hardware(char *s, struct efi_device_path *dp)
  44. {
  45. switch (dp->sub_type) {
  46. case DEVICE_PATH_SUB_TYPE_MEMORY: {
  47. struct efi_device_path_memory *mdp =
  48. (struct efi_device_path_memory *)dp;
  49. s += sprintf(s, "MemoryMapped(0x%x,0x%llx,0x%llx)",
  50. mdp->memory_type,
  51. mdp->start_address,
  52. mdp->end_address);
  53. break;
  54. }
  55. case DEVICE_PATH_SUB_TYPE_VENDOR: {
  56. int i, n;
  57. struct efi_device_path_vendor *vdp =
  58. (struct efi_device_path_vendor *)dp;
  59. s += sprintf(s, "VenHw(%pUl", &vdp->guid);
  60. n = (int)vdp->dp.length - sizeof(struct efi_device_path_vendor);
  61. /* Node must fit into MAX_NODE_LEN) */
  62. if (n > 0 && n < MAX_NODE_LEN / 2 - 22) {
  63. s += sprintf(s, ",");
  64. for (i = 0; i < n; ++i)
  65. s += sprintf(s, "%02x", vdp->vendor_data[i]);
  66. }
  67. s += sprintf(s, ")");
  68. break;
  69. }
  70. case DEVICE_PATH_SUB_TYPE_CONTROLLER: {
  71. struct efi_device_path_controller *cdp =
  72. (struct efi_device_path_controller *)dp;
  73. s += sprintf(s, "Ctrl(0x%0x)", cdp->controller_number);
  74. break;
  75. }
  76. default:
  77. s = dp_unknown(s, dp);
  78. break;
  79. }
  80. return s;
  81. }
  82. static char *dp_acpi(char *s, struct efi_device_path *dp)
  83. {
  84. switch (dp->sub_type) {
  85. case DEVICE_PATH_SUB_TYPE_ACPI_DEVICE: {
  86. struct efi_device_path_acpi_path *adp =
  87. (struct efi_device_path_acpi_path *)dp;
  88. s += sprintf(s, "Acpi(PNP%04X,%d)", EISA_PNP_NUM(adp->hid),
  89. adp->uid);
  90. break;
  91. }
  92. default:
  93. s = dp_unknown(s, dp);
  94. break;
  95. }
  96. return s;
  97. }
  98. static char *dp_msging(char *s, struct efi_device_path *dp)
  99. {
  100. switch (dp->sub_type) {
  101. case DEVICE_PATH_SUB_TYPE_MSG_ATAPI: {
  102. struct efi_device_path_atapi *ide =
  103. (struct efi_device_path_atapi *)dp;
  104. s += sprintf(s, "Ata(%d,%d,%d)", ide->primary_secondary,
  105. ide->slave_master, ide->logical_unit_number);
  106. break;
  107. }
  108. case DEVICE_PATH_SUB_TYPE_MSG_SCSI: {
  109. struct efi_device_path_scsi *ide =
  110. (struct efi_device_path_scsi *)dp;
  111. s += sprintf(s, "Scsi(%u,%u)", ide->target_id,
  112. ide->logical_unit_number);
  113. break;
  114. }
  115. case DEVICE_PATH_SUB_TYPE_MSG_UART: {
  116. struct efi_device_path_uart *uart =
  117. (struct efi_device_path_uart *)dp;
  118. const char parity_str[6] = {'D', 'N', 'E', 'O', 'M', 'S'};
  119. const char *stop_bits_str[4] = { "D", "1", "1.5", "2" };
  120. s += sprintf(s, "Uart(%lld,%d,", uart->baud_rate,
  121. uart->data_bits);
  122. /*
  123. * Parity and stop bits can either both use keywords or both use
  124. * numbers but numbers and keywords should not be mixed. Let's
  125. * go for keywords as this is what EDK II does. For illegal
  126. * values fall back to numbers.
  127. */
  128. if (uart->parity < 6)
  129. s += sprintf(s, "%c,", parity_str[uart->parity]);
  130. else
  131. s += sprintf(s, "%d,", uart->parity);
  132. if (uart->stop_bits < 4)
  133. s += sprintf(s, "%s)", stop_bits_str[uart->stop_bits]);
  134. else
  135. s += sprintf(s, "%d)", uart->stop_bits);
  136. break;
  137. }
  138. case DEVICE_PATH_SUB_TYPE_MSG_USB: {
  139. struct efi_device_path_usb *udp =
  140. (struct efi_device_path_usb *)dp;
  141. s += sprintf(s, "USB(0x%x,0x%x)", udp->parent_port_number,
  142. udp->usb_interface);
  143. break;
  144. }
  145. case DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR: {
  146. int i, n = sizeof(struct efi_mac_addr);
  147. struct efi_device_path_mac_addr *mdp =
  148. (struct efi_device_path_mac_addr *)dp;
  149. if (mdp->if_type <= 1)
  150. n = 6;
  151. s += sprintf(s, "MAC(");
  152. for (i = 0; i < n; ++i)
  153. s += sprintf(s, "%02x", mdp->mac.addr[i]);
  154. s += sprintf(s, ",%u)", mdp->if_type);
  155. break;
  156. }
  157. case DEVICE_PATH_SUB_TYPE_MSG_USB_CLASS: {
  158. struct efi_device_path_usb_class *ucdp =
  159. (struct efi_device_path_usb_class *)dp;
  160. s += sprintf(s, "UsbClass(0x%x,0x%x,0x%x,0x%x,0x%x)",
  161. ucdp->vendor_id, ucdp->product_id,
  162. ucdp->device_class, ucdp->device_subclass,
  163. ucdp->device_protocol);
  164. break;
  165. }
  166. case DEVICE_PATH_SUB_TYPE_MSG_SATA: {
  167. struct efi_device_path_sata *sdp =
  168. (struct efi_device_path_sata *) dp;
  169. s += sprintf(s, "Sata(0x%x,0x%x,0x%x)",
  170. sdp->hba_port,
  171. sdp->port_multiplier_port,
  172. sdp->logical_unit_number);
  173. break;
  174. }
  175. case DEVICE_PATH_SUB_TYPE_MSG_NVME: {
  176. struct efi_device_path_nvme *ndp =
  177. (struct efi_device_path_nvme *)dp;
  178. u32 ns_id;
  179. memcpy(&ns_id, &ndp->ns_id, sizeof(ns_id));
  180. s += sprintf(s, "NVMe(0x%x,", ns_id);
  181. /* Display byte 7 first, byte 0 last */
  182. for (int i = 0; i < 8; ++i)
  183. s += sprintf(s, "%s%02x", i ? "-" : "",
  184. ndp->eui64[i ^ 7]);
  185. s += sprintf(s, ")");
  186. break;
  187. }
  188. case DEVICE_PATH_SUB_TYPE_MSG_URI: {
  189. struct efi_device_path_uri *udp =
  190. (struct efi_device_path_uri *)dp;
  191. int n;
  192. n = (int)udp->dp.length - sizeof(struct efi_device_path_uri);
  193. s += sprintf(s, "Uri(");
  194. if (n > 0 && n < MAX_NODE_LEN - 6)
  195. s += snprintf(s, n, "%s", (char *)udp->uri);
  196. s += sprintf(s, ")");
  197. break;
  198. }
  199. case DEVICE_PATH_SUB_TYPE_MSG_SD:
  200. case DEVICE_PATH_SUB_TYPE_MSG_MMC: {
  201. const char *typename =
  202. (dp->sub_type == DEVICE_PATH_SUB_TYPE_MSG_SD) ?
  203. "SD" : "eMMC";
  204. struct efi_device_path_sd_mmc_path *sddp =
  205. (struct efi_device_path_sd_mmc_path *)dp;
  206. s += sprintf(s, "%s(%u)", typename, sddp->slot_number);
  207. break;
  208. }
  209. default:
  210. s = dp_unknown(s, dp);
  211. break;
  212. }
  213. return s;
  214. }
  215. /*
  216. * Convert a media device path node to text.
  217. *
  218. * @s output buffer
  219. * @dp device path node
  220. * Return: next unused buffer address
  221. */
  222. static char *dp_media(char *s, struct efi_device_path *dp)
  223. {
  224. switch (dp->sub_type) {
  225. case DEVICE_PATH_SUB_TYPE_HARD_DRIVE_PATH: {
  226. struct efi_device_path_hard_drive_path *hddp =
  227. (struct efi_device_path_hard_drive_path *)dp;
  228. void *sig = hddp->partition_signature;
  229. u64 start;
  230. u64 end;
  231. /* Copy from packed structure to aligned memory */
  232. memcpy(&start, &hddp->partition_start, sizeof(start));
  233. memcpy(&end, &hddp->partition_end, sizeof(end));
  234. switch (hddp->signature_type) {
  235. case SIG_TYPE_MBR: {
  236. u32 signature;
  237. memcpy(&signature, sig, sizeof(signature));
  238. s += sprintf(
  239. s, "HD(%d,MBR,0x%08x,0x%llx,0x%llx)",
  240. hddp->partition_number, signature, start, end);
  241. break;
  242. }
  243. case SIG_TYPE_GUID:
  244. s += sprintf(
  245. s, "HD(%d,GPT,%pUl,0x%llx,0x%llx)",
  246. hddp->partition_number, sig, start, end);
  247. break;
  248. default:
  249. s += sprintf(
  250. s, "HD(%d,0x%02x,0,0x%llx,0x%llx)",
  251. hddp->partition_number, hddp->partmap_type,
  252. start, end);
  253. break;
  254. }
  255. break;
  256. }
  257. case DEVICE_PATH_SUB_TYPE_CDROM_PATH: {
  258. struct efi_device_path_cdrom_path *cddp =
  259. (struct efi_device_path_cdrom_path *)dp;
  260. s += sprintf(s, "CDROM(%u,0x%llx,0x%llx)", cddp->boot_entry,
  261. cddp->partition_start, cddp->partition_size);
  262. break;
  263. }
  264. case DEVICE_PATH_SUB_TYPE_VENDOR_PATH: {
  265. int i, n;
  266. struct efi_device_path_vendor *vdp =
  267. (struct efi_device_path_vendor *)dp;
  268. s += sprintf(s, "VenMedia(%pUl", &vdp->guid);
  269. n = (int)vdp->dp.length - sizeof(struct efi_device_path_vendor);
  270. /* Node must fit into MAX_NODE_LEN) */
  271. if (n > 0 && n < MAX_NODE_LEN / 2 - 24) {
  272. s += sprintf(s, ",");
  273. for (i = 0; i < n; ++i)
  274. s += sprintf(s, "%02x", vdp->vendor_data[i]);
  275. }
  276. s += sprintf(s, ")");
  277. break;
  278. }
  279. case DEVICE_PATH_SUB_TYPE_FILE_PATH: {
  280. struct efi_device_path_file_path *fp =
  281. (struct efi_device_path_file_path *)dp;
  282. u16 *buffer;
  283. int slen = dp->length - sizeof(*dp);
  284. /* two bytes for \0, extra byte if dp->length is odd */
  285. buffer = calloc(1, slen + 3);
  286. if (!buffer) {
  287. log_err("Out of memory\n");
  288. return s;
  289. }
  290. memcpy(buffer, fp->str, dp->length - sizeof(*dp));
  291. s += snprintf(s, MAX_NODE_LEN - 1, "%ls", buffer);
  292. free(buffer);
  293. break;
  294. }
  295. default:
  296. s = dp_unknown(s, dp);
  297. break;
  298. }
  299. return s;
  300. }
  301. /*
  302. * Converts a single node to a char string.
  303. *
  304. * @buffer output buffer
  305. * @dp device path or node
  306. * Return: end of string
  307. */
  308. static char *efi_convert_single_device_node_to_text(
  309. char *buffer,
  310. struct efi_device_path *dp)
  311. {
  312. char *str = buffer;
  313. switch (dp->type) {
  314. case DEVICE_PATH_TYPE_HARDWARE_DEVICE:
  315. str = dp_hardware(str, dp);
  316. break;
  317. case DEVICE_PATH_TYPE_ACPI_DEVICE:
  318. str = dp_acpi(str, dp);
  319. break;
  320. case DEVICE_PATH_TYPE_MESSAGING_DEVICE:
  321. str = dp_msging(str, dp);
  322. break;
  323. case DEVICE_PATH_TYPE_MEDIA_DEVICE:
  324. str = dp_media(str, dp);
  325. break;
  326. case DEVICE_PATH_TYPE_END:
  327. break;
  328. default:
  329. str = dp_unknown(str, dp);
  330. }
  331. *str = '\0';
  332. return str;
  333. }
  334. /*
  335. * This function implements the ConvertDeviceNodeToText service of the
  336. * EFI_DEVICE_PATH_TO_TEXT_PROTOCOL.
  337. * See the Unified Extensible Firmware Interface (UEFI) specification
  338. * for details.
  339. *
  340. * device_node device node to be converted
  341. * display_only true if the shorter text representation shall be used
  342. * allow_shortcuts true if shortcut forms may be used
  343. * Return: text representation of the device path
  344. * NULL if out of memory of device_path is NULL
  345. */
  346. static uint16_t EFIAPI *efi_convert_device_node_to_text(
  347. struct efi_device_path *device_node,
  348. bool display_only,
  349. bool allow_shortcuts)
  350. {
  351. char str[MAX_NODE_LEN];
  352. uint16_t *text = NULL;
  353. EFI_ENTRY("%p, %d, %d", device_node, display_only, allow_shortcuts);
  354. if (!device_node)
  355. goto out;
  356. efi_convert_single_device_node_to_text(str, device_node);
  357. text = efi_str_to_u16(str);
  358. out:
  359. EFI_EXIT(EFI_SUCCESS);
  360. return text;
  361. }
  362. /*
  363. * This function implements the ConvertDevicePathToText service of the
  364. * EFI_DEVICE_PATH_TO_TEXT_PROTOCOL.
  365. * See the Unified Extensible Firmware Interface (UEFI) specification
  366. * for details.
  367. *
  368. * device_path device path to be converted
  369. * display_only true if the shorter text representation shall be used
  370. * allow_shortcuts true if shortcut forms may be used
  371. * Return: text representation of the device path
  372. * NULL if out of memory of device_path is NULL
  373. */
  374. static uint16_t EFIAPI *efi_convert_device_path_to_text(
  375. struct efi_device_path *device_path,
  376. bool display_only,
  377. bool allow_shortcuts)
  378. {
  379. uint16_t *text = NULL;
  380. char buffer[MAX_PATH_LEN];
  381. char *str = buffer;
  382. EFI_ENTRY("%p, %d, %d", device_path, display_only, allow_shortcuts);
  383. if (!device_path)
  384. goto out;
  385. while (device_path && str + MAX_NODE_LEN < buffer + MAX_PATH_LEN) {
  386. if (device_path->type == DEVICE_PATH_TYPE_END) {
  387. if (device_path->sub_type !=
  388. DEVICE_PATH_SUB_TYPE_INSTANCE_END)
  389. break;
  390. *str++ = ',';
  391. } else {
  392. *str++ = '/';
  393. str = efi_convert_single_device_node_to_text(
  394. str, device_path);
  395. }
  396. *(u8 **)&device_path += device_path->length;
  397. }
  398. *str = 0;
  399. text = efi_str_to_u16(buffer);
  400. out:
  401. EFI_EXIT(EFI_SUCCESS);
  402. return text;
  403. }
  404. /* helper for debug prints.. efi_free_pool() the result. */
  405. uint16_t *efi_dp_str(struct efi_device_path *dp)
  406. {
  407. return EFI_CALL(efi_convert_device_path_to_text(dp, true, true));
  408. }
  409. const struct efi_device_path_to_text_protocol efi_device_path_to_text = {
  410. .convert_device_node_to_text = efi_convert_device_node_to_text,
  411. .convert_device_path_to_text = efi_convert_device_path_to_text,
  412. };