efi_device_path.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748
  1. /*
  2. * EFI device path from u-boot device-model mapping
  3. *
  4. * (C) Copyright 2017 Rob Clark
  5. *
  6. * SPDX-License-Identifier: GPL-2.0+
  7. */
  8. #include <common.h>
  9. #include <blk.h>
  10. #include <dm.h>
  11. #include <usb.h>
  12. #include <mmc.h>
  13. #include <efi_loader.h>
  14. #include <inttypes.h>
  15. #include <part.h>
  16. /* template END node: */
  17. static const struct efi_device_path END = {
  18. .type = DEVICE_PATH_TYPE_END,
  19. .sub_type = DEVICE_PATH_SUB_TYPE_END,
  20. .length = sizeof(END),
  21. };
  22. #define U_BOOT_GUID \
  23. EFI_GUID(0xe61d73b9, 0xa384, 0x4acc, \
  24. 0xae, 0xab, 0x82, 0xe8, 0x28, 0xf3, 0x62, 0x8b)
  25. /* template ROOT node: */
  26. static const struct efi_device_path_vendor ROOT = {
  27. .dp = {
  28. .type = DEVICE_PATH_TYPE_HARDWARE_DEVICE,
  29. .sub_type = DEVICE_PATH_SUB_TYPE_VENDOR,
  30. .length = sizeof(ROOT),
  31. },
  32. .guid = U_BOOT_GUID,
  33. };
  34. #if defined(CONFIG_DM_MMC) && defined(CONFIG_MMC)
  35. /*
  36. * Determine if an MMC device is an SD card.
  37. *
  38. * @desc block device descriptor
  39. * @return true if the device is an SD card
  40. */
  41. static bool is_sd(struct blk_desc *desc)
  42. {
  43. struct mmc *mmc = find_mmc_device(desc->devnum);
  44. if (!mmc)
  45. return false;
  46. return IS_SD(mmc) != 0U;
  47. }
  48. #endif
  49. static void *dp_alloc(size_t sz)
  50. {
  51. void *buf;
  52. if (efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES, sz, &buf) !=
  53. EFI_SUCCESS) {
  54. debug("EFI: ERROR: out of memory in %s\n", __func__);
  55. return NULL;
  56. }
  57. return buf;
  58. }
  59. /*
  60. * Iterate to next block in device-path, terminating (returning NULL)
  61. * at /End* node.
  62. */
  63. struct efi_device_path *efi_dp_next(const struct efi_device_path *dp)
  64. {
  65. if (dp == NULL)
  66. return NULL;
  67. if (dp->type == DEVICE_PATH_TYPE_END)
  68. return NULL;
  69. dp = ((void *)dp) + dp->length;
  70. if (dp->type == DEVICE_PATH_TYPE_END)
  71. return NULL;
  72. return (struct efi_device_path *)dp;
  73. }
  74. /*
  75. * Compare two device-paths, stopping when the shorter of the two hits
  76. * an End* node. This is useful to, for example, compare a device-path
  77. * representing a device with one representing a file on the device, or
  78. * a device with a parent device.
  79. */
  80. int efi_dp_match(const struct efi_device_path *a,
  81. const struct efi_device_path *b)
  82. {
  83. while (1) {
  84. int ret;
  85. ret = memcmp(&a->length, &b->length, sizeof(a->length));
  86. if (ret)
  87. return ret;
  88. ret = memcmp(a, b, a->length);
  89. if (ret)
  90. return ret;
  91. a = efi_dp_next(a);
  92. b = efi_dp_next(b);
  93. if (!a || !b)
  94. return 0;
  95. }
  96. }
  97. /*
  98. * See UEFI spec (section 3.1.2, about short-form device-paths..
  99. * tl;dr: we can have a device-path that starts with a USB WWID
  100. * or USB Class node, and a few other cases which don't encode
  101. * the full device path with bus hierarchy:
  102. *
  103. * - MESSAGING:USB_WWID
  104. * - MESSAGING:USB_CLASS
  105. * - MEDIA:FILE_PATH
  106. * - MEDIA:HARD_DRIVE
  107. * - MESSAGING:URI
  108. */
  109. static struct efi_device_path *shorten_path(struct efi_device_path *dp)
  110. {
  111. while (dp) {
  112. /*
  113. * TODO: Add MESSAGING:USB_WWID and MESSAGING:URI..
  114. * in practice fallback.efi just uses MEDIA:HARD_DRIVE
  115. * so not sure when we would see these other cases.
  116. */
  117. if (EFI_DP_TYPE(dp, MESSAGING_DEVICE, MSG_USB_CLASS) ||
  118. EFI_DP_TYPE(dp, MEDIA_DEVICE, HARD_DRIVE_PATH) ||
  119. EFI_DP_TYPE(dp, MEDIA_DEVICE, FILE_PATH))
  120. return dp;
  121. dp = efi_dp_next(dp);
  122. }
  123. return dp;
  124. }
  125. static struct efi_object *find_obj(struct efi_device_path *dp, bool short_path,
  126. struct efi_device_path **rem)
  127. {
  128. struct efi_object *efiobj;
  129. unsigned int dp_size = efi_dp_size(dp);
  130. list_for_each_entry(efiobj, &efi_obj_list, link) {
  131. struct efi_handler *handler;
  132. struct efi_device_path *obj_dp;
  133. efi_status_t ret;
  134. ret = efi_search_protocol(efiobj->handle,
  135. &efi_guid_device_path, &handler);
  136. if (ret != EFI_SUCCESS)
  137. continue;
  138. obj_dp = handler->protocol_interface;
  139. do {
  140. if (efi_dp_match(dp, obj_dp) == 0) {
  141. if (rem) {
  142. /*
  143. * Allow partial matches, but inform
  144. * the caller.
  145. */
  146. *rem = ((void *)dp) +
  147. efi_dp_size(obj_dp);
  148. return efiobj;
  149. } else {
  150. /* Only return on exact matches */
  151. if (efi_dp_size(obj_dp) == dp_size)
  152. return efiobj;
  153. }
  154. }
  155. obj_dp = shorten_path(efi_dp_next(obj_dp));
  156. } while (short_path && obj_dp);
  157. }
  158. return NULL;
  159. }
  160. /*
  161. * Find an efiobj from device-path, if 'rem' is not NULL, returns the
  162. * remaining part of the device path after the matched object.
  163. */
  164. struct efi_object *efi_dp_find_obj(struct efi_device_path *dp,
  165. struct efi_device_path **rem)
  166. {
  167. struct efi_object *efiobj;
  168. /* Search for an exact match first */
  169. efiobj = find_obj(dp, false, NULL);
  170. /* Then for a fuzzy match */
  171. if (!efiobj)
  172. efiobj = find_obj(dp, false, rem);
  173. /* And now for a fuzzy short match */
  174. if (!efiobj)
  175. efiobj = find_obj(dp, true, rem);
  176. return efiobj;
  177. }
  178. /* return size not including End node: */
  179. unsigned efi_dp_size(const struct efi_device_path *dp)
  180. {
  181. unsigned sz = 0;
  182. while (dp) {
  183. sz += dp->length;
  184. dp = efi_dp_next(dp);
  185. }
  186. return sz;
  187. }
  188. struct efi_device_path *efi_dp_dup(const struct efi_device_path *dp)
  189. {
  190. struct efi_device_path *ndp;
  191. unsigned sz = efi_dp_size(dp) + sizeof(END);
  192. if (!dp)
  193. return NULL;
  194. ndp = dp_alloc(sz);
  195. if (!ndp)
  196. return NULL;
  197. memcpy(ndp, dp, sz);
  198. return ndp;
  199. }
  200. struct efi_device_path *efi_dp_append(const struct efi_device_path *dp1,
  201. const struct efi_device_path *dp2)
  202. {
  203. struct efi_device_path *ret;
  204. if (!dp1) {
  205. ret = efi_dp_dup(dp2);
  206. } else if (!dp2) {
  207. ret = efi_dp_dup(dp1);
  208. } else {
  209. /* both dp1 and dp2 are non-null */
  210. unsigned sz1 = efi_dp_size(dp1);
  211. unsigned sz2 = efi_dp_size(dp2);
  212. void *p = dp_alloc(sz1 + sz2 + sizeof(END));
  213. if (!p)
  214. return NULL;
  215. memcpy(p, dp1, sz1);
  216. memcpy(p + sz1, dp2, sz2);
  217. memcpy(p + sz1 + sz2, &END, sizeof(END));
  218. ret = p;
  219. }
  220. return ret;
  221. }
  222. struct efi_device_path *efi_dp_append_node(const struct efi_device_path *dp,
  223. const struct efi_device_path *node)
  224. {
  225. struct efi_device_path *ret;
  226. if (!node && !dp) {
  227. ret = efi_dp_dup(&END);
  228. } else if (!node) {
  229. ret = efi_dp_dup(dp);
  230. } else if (!dp) {
  231. unsigned sz = node->length;
  232. void *p = dp_alloc(sz + sizeof(END));
  233. if (!p)
  234. return NULL;
  235. memcpy(p, node, sz);
  236. memcpy(p + sz, &END, sizeof(END));
  237. ret = p;
  238. } else {
  239. /* both dp and node are non-null */
  240. unsigned sz = efi_dp_size(dp);
  241. void *p = dp_alloc(sz + node->length + sizeof(END));
  242. if (!p)
  243. return NULL;
  244. memcpy(p, dp, sz);
  245. memcpy(p + sz, node, node->length);
  246. memcpy(p + sz + node->length, &END, sizeof(END));
  247. ret = p;
  248. }
  249. return ret;
  250. }
  251. #ifdef CONFIG_DM
  252. /* size of device-path not including END node for device and all parents
  253. * up to the root device.
  254. */
  255. static unsigned dp_size(struct udevice *dev)
  256. {
  257. if (!dev || !dev->driver)
  258. return sizeof(ROOT);
  259. switch (dev->driver->id) {
  260. case UCLASS_ROOT:
  261. case UCLASS_SIMPLE_BUS:
  262. /* stop traversing parents at this point: */
  263. return sizeof(ROOT);
  264. #ifdef CONFIG_BLK
  265. case UCLASS_BLK:
  266. switch (dev->parent->uclass->uc_drv->id) {
  267. #ifdef CONFIG_IDE
  268. case UCLASS_IDE:
  269. return dp_size(dev->parent) +
  270. sizeof(struct efi_device_path_atapi);
  271. #endif
  272. #if defined(CONFIG_SCSI) && defined(CONFIG_DM_SCSI)
  273. case UCLASS_SCSI:
  274. return dp_size(dev->parent) +
  275. sizeof(struct efi_device_path_scsi);
  276. #endif
  277. default:
  278. return dp_size(dev->parent);
  279. }
  280. #endif
  281. case UCLASS_MMC:
  282. return dp_size(dev->parent) +
  283. sizeof(struct efi_device_path_sd_mmc_path);
  284. case UCLASS_MASS_STORAGE:
  285. case UCLASS_USB_HUB:
  286. return dp_size(dev->parent) +
  287. sizeof(struct efi_device_path_usb_class);
  288. default:
  289. /* just skip over unknown classes: */
  290. return dp_size(dev->parent);
  291. }
  292. }
  293. /*
  294. * Recursively build a device path.
  295. *
  296. * @buf pointer to the end of the device path
  297. * @dev device
  298. * @return pointer to the end of the device path
  299. */
  300. static void *dp_fill(void *buf, struct udevice *dev)
  301. {
  302. if (!dev || !dev->driver)
  303. return buf;
  304. switch (dev->driver->id) {
  305. case UCLASS_ROOT:
  306. case UCLASS_SIMPLE_BUS: {
  307. /* stop traversing parents at this point: */
  308. struct efi_device_path_vendor *vdp = buf;
  309. *vdp = ROOT;
  310. return &vdp[1];
  311. }
  312. #ifdef CONFIG_BLK
  313. case UCLASS_BLK:
  314. switch (dev->parent->uclass->uc_drv->id) {
  315. #ifdef CONFIG_IDE
  316. case UCLASS_IDE: {
  317. struct efi_device_path_atapi *dp =
  318. dp_fill(buf, dev->parent);
  319. struct blk_desc *desc = dev_get_uclass_platdata(dev);
  320. dp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
  321. dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_ATAPI;
  322. dp->dp.length = sizeof(*dp);
  323. dp->logical_unit_number = desc->devnum;
  324. dp->primary_secondary = IDE_BUS(desc->devnum);
  325. dp->slave_master = desc->devnum %
  326. (CONFIG_SYS_IDE_MAXDEVICE /
  327. CONFIG_SYS_IDE_MAXBUS);
  328. return &dp[1];
  329. }
  330. #endif
  331. #if defined(CONFIG_SCSI) && defined(CONFIG_DM_SCSI)
  332. case UCLASS_SCSI: {
  333. struct efi_device_path_scsi *dp =
  334. dp_fill(buf, dev->parent);
  335. struct blk_desc *desc = dev_get_uclass_platdata(dev);
  336. dp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
  337. dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_SCSI;
  338. dp->dp.length = sizeof(*dp);
  339. dp->logical_unit_number = desc->lun;
  340. dp->target_id = desc->target;
  341. return &dp[1];
  342. }
  343. #endif
  344. default:
  345. printf("unhandled parent class: %s (%u)\n",
  346. dev->name, dev->driver->id);
  347. return dp_fill(buf, dev->parent);
  348. }
  349. #endif
  350. #if defined(CONFIG_DM_MMC) && defined(CONFIG_MMC)
  351. case UCLASS_MMC: {
  352. struct efi_device_path_sd_mmc_path *sddp =
  353. dp_fill(buf, dev->parent);
  354. struct mmc *mmc = mmc_get_mmc_dev(dev);
  355. struct blk_desc *desc = mmc_get_blk_desc(mmc);
  356. sddp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
  357. sddp->dp.sub_type = is_sd(desc) ?
  358. DEVICE_PATH_SUB_TYPE_MSG_SD :
  359. DEVICE_PATH_SUB_TYPE_MSG_MMC;
  360. sddp->dp.length = sizeof(*sddp);
  361. sddp->slot_number = dev->seq;
  362. return &sddp[1];
  363. }
  364. #endif
  365. case UCLASS_MASS_STORAGE:
  366. case UCLASS_USB_HUB: {
  367. struct efi_device_path_usb_class *udp =
  368. dp_fill(buf, dev->parent);
  369. struct usb_device *udev = dev_get_parent_priv(dev);
  370. struct usb_device_descriptor *desc = &udev->descriptor;
  371. udp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
  372. udp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_USB_CLASS;
  373. udp->dp.length = sizeof(*udp);
  374. udp->vendor_id = desc->idVendor;
  375. udp->product_id = desc->idProduct;
  376. udp->device_class = desc->bDeviceClass;
  377. udp->device_subclass = desc->bDeviceSubClass;
  378. udp->device_protocol = desc->bDeviceProtocol;
  379. return &udp[1];
  380. }
  381. default:
  382. debug("unhandled device class: %s (%u)\n",
  383. dev->name, dev->driver->id);
  384. return dp_fill(buf, dev->parent);
  385. }
  386. }
  387. /* Construct a device-path from a device: */
  388. struct efi_device_path *efi_dp_from_dev(struct udevice *dev)
  389. {
  390. void *buf, *start;
  391. start = buf = dp_alloc(dp_size(dev) + sizeof(END));
  392. if (!buf)
  393. return NULL;
  394. buf = dp_fill(buf, dev);
  395. *((struct efi_device_path *)buf) = END;
  396. return start;
  397. }
  398. #endif
  399. static unsigned dp_part_size(struct blk_desc *desc, int part)
  400. {
  401. unsigned dpsize;
  402. #ifdef CONFIG_BLK
  403. {
  404. struct udevice *dev;
  405. int ret = blk_find_device(desc->if_type, desc->devnum, &dev);
  406. if (ret)
  407. dev = desc->bdev->parent;
  408. dpsize = dp_size(dev);
  409. }
  410. #else
  411. dpsize = sizeof(ROOT) + sizeof(struct efi_device_path_usb);
  412. #endif
  413. if (part == 0) /* the actual disk, not a partition */
  414. return dpsize;
  415. if (desc->part_type == PART_TYPE_ISO)
  416. dpsize += sizeof(struct efi_device_path_cdrom_path);
  417. else
  418. dpsize += sizeof(struct efi_device_path_hard_drive_path);
  419. return dpsize;
  420. }
  421. /*
  422. * Create a device path for a block device or one of its partitions.
  423. *
  424. * @buf buffer to which the device path is wirtten
  425. * @desc block device descriptor
  426. * @part partition number, 0 identifies a block device
  427. */
  428. static void *dp_part_fill(void *buf, struct blk_desc *desc, int part)
  429. {
  430. disk_partition_t info;
  431. #ifdef CONFIG_BLK
  432. {
  433. struct udevice *dev;
  434. int ret = blk_find_device(desc->if_type, desc->devnum, &dev);
  435. if (ret)
  436. dev = desc->bdev->parent;
  437. buf = dp_fill(buf, dev);
  438. }
  439. #else
  440. /*
  441. * We *could* make a more accurate path, by looking at if_type
  442. * and handling all the different cases like we do for non-
  443. * legacy (ie CONFIG_BLK=y) case. But most important thing
  444. * is just to have a unique device-path for if_type+devnum.
  445. * So map things to a fictitious USB device.
  446. */
  447. struct efi_device_path_usb *udp;
  448. memcpy(buf, &ROOT, sizeof(ROOT));
  449. buf += sizeof(ROOT);
  450. udp = buf;
  451. udp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
  452. udp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_USB;
  453. udp->dp.length = sizeof(*udp);
  454. udp->parent_port_number = desc->if_type;
  455. udp->usb_interface = desc->devnum;
  456. buf = &udp[1];
  457. #endif
  458. if (part == 0) /* the actual disk, not a partition */
  459. return buf;
  460. part_get_info(desc, part, &info);
  461. if (desc->part_type == PART_TYPE_ISO) {
  462. struct efi_device_path_cdrom_path *cddp = buf;
  463. cddp->boot_entry = part;
  464. cddp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE;
  465. cddp->dp.sub_type = DEVICE_PATH_SUB_TYPE_CDROM_PATH;
  466. cddp->dp.length = sizeof(*cddp);
  467. cddp->partition_start = info.start;
  468. cddp->partition_end = info.size;
  469. buf = &cddp[1];
  470. } else {
  471. struct efi_device_path_hard_drive_path *hddp = buf;
  472. hddp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE;
  473. hddp->dp.sub_type = DEVICE_PATH_SUB_TYPE_HARD_DRIVE_PATH;
  474. hddp->dp.length = sizeof(*hddp);
  475. hddp->partition_number = part;
  476. hddp->partition_start = info.start;
  477. hddp->partition_end = info.size;
  478. if (desc->part_type == PART_TYPE_EFI)
  479. hddp->partmap_type = 2;
  480. else
  481. hddp->partmap_type = 1;
  482. switch (desc->sig_type) {
  483. case SIG_TYPE_NONE:
  484. default:
  485. hddp->signature_type = 0;
  486. memset(hddp->partition_signature, 0,
  487. sizeof(hddp->partition_signature));
  488. break;
  489. case SIG_TYPE_MBR:
  490. hddp->signature_type = 1;
  491. memset(hddp->partition_signature, 0,
  492. sizeof(hddp->partition_signature));
  493. memcpy(hddp->partition_signature, &desc->mbr_sig,
  494. sizeof(desc->mbr_sig));
  495. break;
  496. case SIG_TYPE_GUID:
  497. hddp->signature_type = 2;
  498. memcpy(hddp->partition_signature, &desc->guid_sig,
  499. sizeof(hddp->partition_signature));
  500. break;
  501. }
  502. buf = &hddp[1];
  503. }
  504. return buf;
  505. }
  506. /* Construct a device-path from a partition on a blk device: */
  507. struct efi_device_path *efi_dp_from_part(struct blk_desc *desc, int part)
  508. {
  509. void *buf, *start;
  510. start = buf = dp_alloc(dp_part_size(desc, part) + sizeof(END));
  511. if (!buf)
  512. return NULL;
  513. buf = dp_part_fill(buf, desc, part);
  514. *((struct efi_device_path *)buf) = END;
  515. return start;
  516. }
  517. /* convert path to an UEFI style path (ie. DOS style backslashes and utf16) */
  518. static void path_to_uefi(u16 *uefi, const char *path)
  519. {
  520. while (*path) {
  521. char c = *(path++);
  522. if (c == '/')
  523. c = '\\';
  524. *(uefi++) = c;
  525. }
  526. *uefi = '\0';
  527. }
  528. /*
  529. * If desc is NULL, this creates a path with only the file component,
  530. * otherwise it creates a full path with both device and file components
  531. */
  532. struct efi_device_path *efi_dp_from_file(struct blk_desc *desc, int part,
  533. const char *path)
  534. {
  535. struct efi_device_path_file_path *fp;
  536. void *buf, *start;
  537. unsigned dpsize = 0, fpsize;
  538. if (desc)
  539. dpsize = dp_part_size(desc, part);
  540. fpsize = sizeof(struct efi_device_path) + 2 * (strlen(path) + 1);
  541. dpsize += fpsize;
  542. start = buf = dp_alloc(dpsize + sizeof(END));
  543. if (!buf)
  544. return NULL;
  545. if (desc)
  546. buf = dp_part_fill(buf, desc, part);
  547. /* add file-path: */
  548. fp = buf;
  549. fp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE;
  550. fp->dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH;
  551. fp->dp.length = fpsize;
  552. path_to_uefi(fp->str, path);
  553. buf += fpsize;
  554. *((struct efi_device_path *)buf) = END;
  555. return start;
  556. }
  557. #ifdef CONFIG_NET
  558. struct efi_device_path *efi_dp_from_eth(void)
  559. {
  560. struct efi_device_path_mac_addr *ndp;
  561. void *buf, *start;
  562. unsigned dpsize = 0;
  563. assert(eth_get_dev());
  564. #ifdef CONFIG_DM_ETH
  565. dpsize += dp_size(eth_get_dev());
  566. #else
  567. dpsize += sizeof(ROOT);
  568. #endif
  569. dpsize += sizeof(*ndp);
  570. start = buf = dp_alloc(dpsize + sizeof(END));
  571. if (!buf)
  572. return NULL;
  573. #ifdef CONFIG_DM_ETH
  574. buf = dp_fill(buf, eth_get_dev());
  575. #else
  576. memcpy(buf, &ROOT, sizeof(ROOT));
  577. buf += sizeof(ROOT);
  578. #endif
  579. ndp = buf;
  580. ndp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
  581. ndp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR;
  582. ndp->dp.length = sizeof(*ndp);
  583. memcpy(ndp->mac.addr, eth_get_ethaddr(), ARP_HLEN);
  584. buf = &ndp[1];
  585. *((struct efi_device_path *)buf) = END;
  586. return start;
  587. }
  588. #endif
  589. /* Construct a device-path for memory-mapped image */
  590. struct efi_device_path *efi_dp_from_mem(uint32_t memory_type,
  591. uint64_t start_address,
  592. uint64_t end_address)
  593. {
  594. struct efi_device_path_memory *mdp;
  595. void *buf, *start;
  596. start = buf = dp_alloc(sizeof(*mdp) + sizeof(END));
  597. if (!buf)
  598. return NULL;
  599. mdp = buf;
  600. mdp->dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE;
  601. mdp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MEMORY;
  602. mdp->dp.length = sizeof(*mdp);
  603. mdp->memory_type = memory_type;
  604. mdp->start_address = start_address;
  605. mdp->end_address = end_address;
  606. buf = &mdp[1];
  607. *((struct efi_device_path *)buf) = END;
  608. return start;
  609. }
  610. /*
  611. * Helper to split a full device path (containing both device and file
  612. * parts) into it's constituent parts.
  613. */
  614. efi_status_t efi_dp_split_file_path(struct efi_device_path *full_path,
  615. struct efi_device_path **device_path,
  616. struct efi_device_path **file_path)
  617. {
  618. struct efi_device_path *p, *dp, *fp;
  619. *device_path = NULL;
  620. *file_path = NULL;
  621. dp = efi_dp_dup(full_path);
  622. if (!dp)
  623. return EFI_OUT_OF_RESOURCES;
  624. p = dp;
  625. while (!EFI_DP_TYPE(p, MEDIA_DEVICE, FILE_PATH)) {
  626. p = efi_dp_next(p);
  627. if (!p)
  628. return EFI_OUT_OF_RESOURCES;
  629. }
  630. fp = efi_dp_dup(p);
  631. if (!fp)
  632. return EFI_OUT_OF_RESOURCES;
  633. p->type = DEVICE_PATH_TYPE_END;
  634. p->sub_type = DEVICE_PATH_SUB_TYPE_END;
  635. p->length = sizeof(*p);
  636. *device_path = dp;
  637. *file_path = fp;
  638. return EFI_SUCCESS;
  639. }