]> git.ipfire.org Git - thirdparty/u-boot.git/blob - lib/efi_loader/efi_device_path.c
5b2ff813191cb2e27e9920433b93cfb363b3e103
[thirdparty/u-boot.git] / lib / efi_loader / efi_device_path.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * EFI device path from u-boot device-model mapping
4 *
5 * (C) Copyright 2017 Rob Clark
6 */
7
8 #include <common.h>
9 #include <blk.h>
10 #include <dm.h>
11 #include <net.h>
12 #include <usb.h>
13 #include <mmc.h>
14 #include <nvme.h>
15 #include <efi_loader.h>
16 #include <part.h>
17 #include <sandboxblockdev.h>
18 #include <asm-generic/unaligned.h>
19 #include <linux/compat.h> /* U16_MAX */
20
21 #ifdef CONFIG_SANDBOX
22 const efi_guid_t efi_guid_host_dev = U_BOOT_HOST_DEV_GUID;
23 #endif
24
25 /* template END node: */
26 static const struct efi_device_path END = {
27 .type = DEVICE_PATH_TYPE_END,
28 .sub_type = DEVICE_PATH_SUB_TYPE_END,
29 .length = sizeof(END),
30 };
31
32 /* template ROOT node: */
33 static const struct efi_device_path_vendor ROOT = {
34 .dp = {
35 .type = DEVICE_PATH_TYPE_HARDWARE_DEVICE,
36 .sub_type = DEVICE_PATH_SUB_TYPE_VENDOR,
37 .length = sizeof(ROOT),
38 },
39 .guid = U_BOOT_GUID,
40 };
41
42 #if defined(CONFIG_DM_MMC) && defined(CONFIG_MMC)
43 /*
44 * Determine if an MMC device is an SD card.
45 *
46 * @desc block device descriptor
47 * @return true if the device is an SD card
48 */
49 static bool is_sd(struct blk_desc *desc)
50 {
51 struct mmc *mmc = find_mmc_device(desc->devnum);
52
53 if (!mmc)
54 return false;
55
56 return IS_SD(mmc) != 0U;
57 }
58 #endif
59
60 static void *dp_alloc(size_t sz)
61 {
62 void *buf;
63
64 if (efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES, sz, &buf) !=
65 EFI_SUCCESS) {
66 debug("EFI: ERROR: out of memory in %s\n", __func__);
67 return NULL;
68 }
69
70 memset(buf, 0, sz);
71 return buf;
72 }
73
74 /*
75 * Iterate to next block in device-path, terminating (returning NULL)
76 * at /End* node.
77 */
78 struct efi_device_path *efi_dp_next(const struct efi_device_path *dp)
79 {
80 if (dp == NULL)
81 return NULL;
82 if (dp->type == DEVICE_PATH_TYPE_END)
83 return NULL;
84 dp = ((void *)dp) + dp->length;
85 if (dp->type == DEVICE_PATH_TYPE_END)
86 return NULL;
87 return (struct efi_device_path *)dp;
88 }
89
90 /*
91 * Compare two device-paths, stopping when the shorter of the two hits
92 * an End* node. This is useful to, for example, compare a device-path
93 * representing a device with one representing a file on the device, or
94 * a device with a parent device.
95 */
96 int efi_dp_match(const struct efi_device_path *a,
97 const struct efi_device_path *b)
98 {
99 while (1) {
100 int ret;
101
102 ret = memcmp(&a->length, &b->length, sizeof(a->length));
103 if (ret)
104 return ret;
105
106 ret = memcmp(a, b, a->length);
107 if (ret)
108 return ret;
109
110 a = efi_dp_next(a);
111 b = efi_dp_next(b);
112
113 if (!a || !b)
114 return 0;
115 }
116 }
117
118 /*
119 * We can have device paths that start with a USB WWID or a USB Class node,
120 * and a few other cases which don't encode the full device path with bus
121 * hierarchy:
122 *
123 * - MESSAGING:USB_WWID
124 * - MESSAGING:USB_CLASS
125 * - MEDIA:FILE_PATH
126 * - MEDIA:HARD_DRIVE
127 * - MESSAGING:URI
128 *
129 * See UEFI spec (section 3.1.2, about short-form device-paths)
130 */
131 static struct efi_device_path *shorten_path(struct efi_device_path *dp)
132 {
133 while (dp) {
134 /*
135 * TODO: Add MESSAGING:USB_WWID and MESSAGING:URI..
136 * in practice fallback.efi just uses MEDIA:HARD_DRIVE
137 * so not sure when we would see these other cases.
138 */
139 if (EFI_DP_TYPE(dp, MESSAGING_DEVICE, MSG_USB_CLASS) ||
140 EFI_DP_TYPE(dp, MEDIA_DEVICE, HARD_DRIVE_PATH) ||
141 EFI_DP_TYPE(dp, MEDIA_DEVICE, FILE_PATH))
142 return dp;
143
144 dp = efi_dp_next(dp);
145 }
146
147 return dp;
148 }
149
150 static struct efi_object *find_obj(struct efi_device_path *dp, bool short_path,
151 struct efi_device_path **rem)
152 {
153 struct efi_object *efiobj;
154 efi_uintn_t dp_size = efi_dp_instance_size(dp);
155
156 list_for_each_entry(efiobj, &efi_obj_list, link) {
157 struct efi_handler *handler;
158 struct efi_device_path *obj_dp;
159 efi_status_t ret;
160
161 ret = efi_search_protocol(efiobj,
162 &efi_guid_device_path, &handler);
163 if (ret != EFI_SUCCESS)
164 continue;
165 obj_dp = handler->protocol_interface;
166
167 do {
168 if (efi_dp_match(dp, obj_dp) == 0) {
169 if (rem) {
170 /*
171 * Allow partial matches, but inform
172 * the caller.
173 */
174 *rem = ((void *)dp) +
175 efi_dp_instance_size(obj_dp);
176 return efiobj;
177 } else {
178 /* Only return on exact matches */
179 if (efi_dp_instance_size(obj_dp) ==
180 dp_size)
181 return efiobj;
182 }
183 }
184
185 obj_dp = shorten_path(efi_dp_next(obj_dp));
186 } while (short_path && obj_dp);
187 }
188
189 return NULL;
190 }
191
192 /*
193 * Find an efiobj from device-path, if 'rem' is not NULL, returns the
194 * remaining part of the device path after the matched object.
195 */
196 struct efi_object *efi_dp_find_obj(struct efi_device_path *dp,
197 struct efi_device_path **rem)
198 {
199 struct efi_object *efiobj;
200
201 /* Search for an exact match first */
202 efiobj = find_obj(dp, false, NULL);
203
204 /* Then for a fuzzy match */
205 if (!efiobj)
206 efiobj = find_obj(dp, false, rem);
207
208 /* And now for a fuzzy short match */
209 if (!efiobj)
210 efiobj = find_obj(dp, true, rem);
211
212 return efiobj;
213 }
214
215 /*
216 * Determine the last device path node that is not the end node.
217 *
218 * @dp device path
219 * @return last node before the end node if it exists
220 * otherwise NULL
221 */
222 const struct efi_device_path *efi_dp_last_node(const struct efi_device_path *dp)
223 {
224 struct efi_device_path *ret;
225
226 if (!dp || dp->type == DEVICE_PATH_TYPE_END)
227 return NULL;
228 while (dp) {
229 ret = (struct efi_device_path *)dp;
230 dp = efi_dp_next(dp);
231 }
232 return ret;
233 }
234
235 /* get size of the first device path instance excluding end node */
236 efi_uintn_t efi_dp_instance_size(const struct efi_device_path *dp)
237 {
238 efi_uintn_t sz = 0;
239
240 if (!dp || dp->type == DEVICE_PATH_TYPE_END)
241 return 0;
242 while (dp) {
243 sz += dp->length;
244 dp = efi_dp_next(dp);
245 }
246
247 return sz;
248 }
249
250 /* get size of multi-instance device path excluding end node */
251 efi_uintn_t efi_dp_size(const struct efi_device_path *dp)
252 {
253 const struct efi_device_path *p = dp;
254
255 if (!p)
256 return 0;
257 while (p->type != DEVICE_PATH_TYPE_END ||
258 p->sub_type != DEVICE_PATH_SUB_TYPE_END)
259 p = (void *)p + p->length;
260
261 return (void *)p - (void *)dp;
262 }
263
264 /* copy multi-instance device path */
265 struct efi_device_path *efi_dp_dup(const struct efi_device_path *dp)
266 {
267 struct efi_device_path *ndp;
268 size_t sz = efi_dp_size(dp) + sizeof(END);
269
270 if (!dp)
271 return NULL;
272
273 ndp = dp_alloc(sz);
274 if (!ndp)
275 return NULL;
276 memcpy(ndp, dp, sz);
277
278 return ndp;
279 }
280
281 struct efi_device_path *efi_dp_append(const struct efi_device_path *dp1,
282 const struct efi_device_path *dp2)
283 {
284 struct efi_device_path *ret;
285
286 if (!dp1 && !dp2) {
287 /* return an end node */
288 ret = efi_dp_dup(&END);
289 } else if (!dp1) {
290 ret = efi_dp_dup(dp2);
291 } else if (!dp2) {
292 ret = efi_dp_dup(dp1);
293 } else {
294 /* both dp1 and dp2 are non-null */
295 unsigned sz1 = efi_dp_size(dp1);
296 unsigned sz2 = efi_dp_size(dp2);
297 void *p = dp_alloc(sz1 + sz2 + sizeof(END));
298 if (!p)
299 return NULL;
300 memcpy(p, dp1, sz1);
301 /* the end node of the second device path has to be retained */
302 memcpy(p + sz1, dp2, sz2 + sizeof(END));
303 ret = p;
304 }
305
306 return ret;
307 }
308
309 struct efi_device_path *efi_dp_append_node(const struct efi_device_path *dp,
310 const struct efi_device_path *node)
311 {
312 struct efi_device_path *ret;
313
314 if (!node && !dp) {
315 ret = efi_dp_dup(&END);
316 } else if (!node) {
317 ret = efi_dp_dup(dp);
318 } else if (!dp) {
319 size_t sz = node->length;
320 void *p = dp_alloc(sz + sizeof(END));
321 if (!p)
322 return NULL;
323 memcpy(p, node, sz);
324 memcpy(p + sz, &END, sizeof(END));
325 ret = p;
326 } else {
327 /* both dp and node are non-null */
328 size_t sz = efi_dp_size(dp);
329 void *p = dp_alloc(sz + node->length + sizeof(END));
330 if (!p)
331 return NULL;
332 memcpy(p, dp, sz);
333 memcpy(p + sz, node, node->length);
334 memcpy(p + sz + node->length, &END, sizeof(END));
335 ret = p;
336 }
337
338 return ret;
339 }
340
341 struct efi_device_path *efi_dp_create_device_node(const u8 type,
342 const u8 sub_type,
343 const u16 length)
344 {
345 struct efi_device_path *ret;
346
347 if (length < sizeof(struct efi_device_path))
348 return NULL;
349
350 ret = dp_alloc(length);
351 if (!ret)
352 return ret;
353 ret->type = type;
354 ret->sub_type = sub_type;
355 ret->length = length;
356 return ret;
357 }
358
359 struct efi_device_path *efi_dp_append_instance(
360 const struct efi_device_path *dp,
361 const struct efi_device_path *dpi)
362 {
363 size_t sz, szi;
364 struct efi_device_path *p, *ret;
365
366 if (!dpi)
367 return NULL;
368 if (!dp)
369 return efi_dp_dup(dpi);
370 sz = efi_dp_size(dp);
371 szi = efi_dp_instance_size(dpi);
372 p = dp_alloc(sz + szi + 2 * sizeof(END));
373 if (!p)
374 return NULL;
375 ret = p;
376 memcpy(p, dp, sz + sizeof(END));
377 p = (void *)p + sz;
378 p->sub_type = DEVICE_PATH_SUB_TYPE_INSTANCE_END;
379 p = (void *)p + sizeof(END);
380 memcpy(p, dpi, szi);
381 p = (void *)p + szi;
382 memcpy(p, &END, sizeof(END));
383 return ret;
384 }
385
386 struct efi_device_path *efi_dp_get_next_instance(struct efi_device_path **dp,
387 efi_uintn_t *size)
388 {
389 size_t sz;
390 struct efi_device_path *p;
391
392 if (size)
393 *size = 0;
394 if (!dp || !*dp)
395 return NULL;
396 sz = efi_dp_instance_size(*dp);
397 p = dp_alloc(sz + sizeof(END));
398 if (!p)
399 return NULL;
400 memcpy(p, *dp, sz + sizeof(END));
401 *dp = (void *)*dp + sz;
402 if ((*dp)->sub_type == DEVICE_PATH_SUB_TYPE_INSTANCE_END)
403 *dp = (void *)*dp + sizeof(END);
404 else
405 *dp = NULL;
406 if (size)
407 *size = sz + sizeof(END);
408 return p;
409 }
410
411 bool efi_dp_is_multi_instance(const struct efi_device_path *dp)
412 {
413 const struct efi_device_path *p = dp;
414
415 if (!p)
416 return false;
417 while (p->type != DEVICE_PATH_TYPE_END)
418 p = (void *)p + p->length;
419 return p->sub_type == DEVICE_PATH_SUB_TYPE_INSTANCE_END;
420 }
421
422 #ifdef CONFIG_DM
423 /* size of device-path not including END node for device and all parents
424 * up to the root device.
425 */
426 __maybe_unused static unsigned int dp_size(struct udevice *dev)
427 {
428 if (!dev || !dev->driver)
429 return sizeof(ROOT);
430
431 switch (dev->driver->id) {
432 case UCLASS_ROOT:
433 case UCLASS_SIMPLE_BUS:
434 /* stop traversing parents at this point: */
435 return sizeof(ROOT);
436 case UCLASS_ETH:
437 return dp_size(dev->parent) +
438 sizeof(struct efi_device_path_mac_addr);
439 #ifdef CONFIG_BLK
440 case UCLASS_BLK:
441 switch (dev->parent->uclass->uc_drv->id) {
442 #ifdef CONFIG_IDE
443 case UCLASS_IDE:
444 return dp_size(dev->parent) +
445 sizeof(struct efi_device_path_atapi);
446 #endif
447 #if defined(CONFIG_SCSI) && defined(CONFIG_DM_SCSI)
448 case UCLASS_SCSI:
449 return dp_size(dev->parent) +
450 sizeof(struct efi_device_path_scsi);
451 #endif
452 #if defined(CONFIG_DM_MMC) && defined(CONFIG_MMC)
453 case UCLASS_MMC:
454 return dp_size(dev->parent) +
455 sizeof(struct efi_device_path_sd_mmc_path);
456 #endif
457 #if defined(CONFIG_NVME)
458 case UCLASS_NVME:
459 return dp_size(dev->parent) +
460 sizeof(struct efi_device_path_nvme);
461 #endif
462 #ifdef CONFIG_SANDBOX
463 case UCLASS_ROOT:
464 /*
465 * Sandbox's host device will be represented
466 * as vendor device with extra one byte for
467 * device number
468 */
469 return dp_size(dev->parent)
470 + sizeof(struct efi_device_path_vendor) + 1;
471 #endif
472 default:
473 return dp_size(dev->parent);
474 }
475 #endif
476 #if defined(CONFIG_DM_MMC) && defined(CONFIG_MMC)
477 case UCLASS_MMC:
478 return dp_size(dev->parent) +
479 sizeof(struct efi_device_path_sd_mmc_path);
480 #endif
481 case UCLASS_MASS_STORAGE:
482 case UCLASS_USB_HUB:
483 return dp_size(dev->parent) +
484 sizeof(struct efi_device_path_usb_class);
485 default:
486 /* just skip over unknown classes: */
487 return dp_size(dev->parent);
488 }
489 }
490
491 /*
492 * Recursively build a device path.
493 *
494 * @buf pointer to the end of the device path
495 * @dev device
496 * @return pointer to the end of the device path
497 */
498 __maybe_unused static void *dp_fill(void *buf, struct udevice *dev)
499 {
500 if (!dev || !dev->driver)
501 return buf;
502
503 switch (dev->driver->id) {
504 case UCLASS_ROOT:
505 case UCLASS_SIMPLE_BUS: {
506 /* stop traversing parents at this point: */
507 struct efi_device_path_vendor *vdp = buf;
508 *vdp = ROOT;
509 return &vdp[1];
510 }
511 #ifdef CONFIG_DM_ETH
512 case UCLASS_ETH: {
513 struct efi_device_path_mac_addr *dp =
514 dp_fill(buf, dev->parent);
515 struct eth_pdata *pdata = dev->platdata;
516
517 dp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
518 dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR;
519 dp->dp.length = sizeof(*dp);
520 memset(&dp->mac, 0, sizeof(dp->mac));
521 /* We only support IPv4 */
522 memcpy(&dp->mac, &pdata->enetaddr, ARP_HLEN);
523 /* Ethernet */
524 dp->if_type = 1;
525 return &dp[1];
526 }
527 #endif
528 #ifdef CONFIG_BLK
529 case UCLASS_BLK:
530 switch (dev->parent->uclass->uc_drv->id) {
531 #ifdef CONFIG_SANDBOX
532 case UCLASS_ROOT: {
533 /* stop traversing parents at this point: */
534 struct efi_device_path_vendor *dp;
535 struct blk_desc *desc = dev_get_uclass_platdata(dev);
536
537 dp_fill(buf, dev->parent);
538 dp = buf;
539 ++dp;
540 dp->dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE;
541 dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_VENDOR;
542 dp->dp.length = sizeof(*dp) + 1;
543 memcpy(&dp->guid, &efi_guid_host_dev,
544 sizeof(efi_guid_t));
545 dp->vendor_data[0] = desc->devnum;
546 return &dp->vendor_data[1];
547 }
548 #endif
549 #ifdef CONFIG_IDE
550 case UCLASS_IDE: {
551 struct efi_device_path_atapi *dp =
552 dp_fill(buf, dev->parent);
553 struct blk_desc *desc = dev_get_uclass_platdata(dev);
554
555 dp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
556 dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_ATAPI;
557 dp->dp.length = sizeof(*dp);
558 dp->logical_unit_number = desc->devnum;
559 dp->primary_secondary = IDE_BUS(desc->devnum);
560 dp->slave_master = desc->devnum %
561 (CONFIG_SYS_IDE_MAXDEVICE /
562 CONFIG_SYS_IDE_MAXBUS);
563 return &dp[1];
564 }
565 #endif
566 #if defined(CONFIG_SCSI) && defined(CONFIG_DM_SCSI)
567 case UCLASS_SCSI: {
568 struct efi_device_path_scsi *dp =
569 dp_fill(buf, dev->parent);
570 struct blk_desc *desc = dev_get_uclass_platdata(dev);
571
572 dp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
573 dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_SCSI;
574 dp->dp.length = sizeof(*dp);
575 dp->logical_unit_number = desc->lun;
576 dp->target_id = desc->target;
577 return &dp[1];
578 }
579 #endif
580 #if defined(CONFIG_DM_MMC) && defined(CONFIG_MMC)
581 case UCLASS_MMC: {
582 struct efi_device_path_sd_mmc_path *sddp =
583 dp_fill(buf, dev->parent);
584 struct blk_desc *desc = dev_get_uclass_platdata(dev);
585
586 sddp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
587 sddp->dp.sub_type = is_sd(desc) ?
588 DEVICE_PATH_SUB_TYPE_MSG_SD :
589 DEVICE_PATH_SUB_TYPE_MSG_MMC;
590 sddp->dp.length = sizeof(*sddp);
591 sddp->slot_number = dev->seq;
592 return &sddp[1];
593 }
594 #endif
595 #if defined(CONFIG_NVME)
596 case UCLASS_NVME: {
597 struct efi_device_path_nvme *dp =
598 dp_fill(buf, dev->parent);
599 u32 ns_id;
600
601 dp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
602 dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_NVME;
603 dp->dp.length = sizeof(*dp);
604 nvme_get_namespace_id(dev, &ns_id, dp->eui64);
605 memcpy(&dp->ns_id, &ns_id, sizeof(ns_id));
606 return &dp[1];
607 }
608 #endif
609 default:
610 debug("%s(%u) %s: unhandled parent class: %s (%u)\n",
611 __FILE__, __LINE__, __func__,
612 dev->name, dev->parent->uclass->uc_drv->id);
613 return dp_fill(buf, dev->parent);
614 }
615 #endif
616 #if defined(CONFIG_DM_MMC) && defined(CONFIG_MMC)
617 case UCLASS_MMC: {
618 struct efi_device_path_sd_mmc_path *sddp =
619 dp_fill(buf, dev->parent);
620 struct mmc *mmc = mmc_get_mmc_dev(dev);
621 struct blk_desc *desc = mmc_get_blk_desc(mmc);
622
623 sddp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
624 sddp->dp.sub_type = is_sd(desc) ?
625 DEVICE_PATH_SUB_TYPE_MSG_SD :
626 DEVICE_PATH_SUB_TYPE_MSG_MMC;
627 sddp->dp.length = sizeof(*sddp);
628 sddp->slot_number = dev->seq;
629
630 return &sddp[1];
631 }
632 #endif
633 case UCLASS_MASS_STORAGE:
634 case UCLASS_USB_HUB: {
635 struct efi_device_path_usb_class *udp =
636 dp_fill(buf, dev->parent);
637 struct usb_device *udev = dev_get_parent_priv(dev);
638 struct usb_device_descriptor *desc = &udev->descriptor;
639
640 udp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
641 udp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_USB_CLASS;
642 udp->dp.length = sizeof(*udp);
643 udp->vendor_id = desc->idVendor;
644 udp->product_id = desc->idProduct;
645 udp->device_class = desc->bDeviceClass;
646 udp->device_subclass = desc->bDeviceSubClass;
647 udp->device_protocol = desc->bDeviceProtocol;
648
649 return &udp[1];
650 }
651 default:
652 debug("%s(%u) %s: unhandled device class: %s (%u)\n",
653 __FILE__, __LINE__, __func__,
654 dev->name, dev->driver->id);
655 return dp_fill(buf, dev->parent);
656 }
657 }
658 #endif
659
660 static unsigned dp_part_size(struct blk_desc *desc, int part)
661 {
662 unsigned dpsize;
663
664 #ifdef CONFIG_BLK
665 {
666 struct udevice *dev;
667 int ret = blk_find_device(desc->if_type, desc->devnum, &dev);
668
669 if (ret)
670 dev = desc->bdev->parent;
671 dpsize = dp_size(dev);
672 }
673 #else
674 dpsize = sizeof(ROOT) + sizeof(struct efi_device_path_usb);
675 #endif
676
677 if (part == 0) /* the actual disk, not a partition */
678 return dpsize;
679
680 if (desc->part_type == PART_TYPE_ISO)
681 dpsize += sizeof(struct efi_device_path_cdrom_path);
682 else
683 dpsize += sizeof(struct efi_device_path_hard_drive_path);
684
685 return dpsize;
686 }
687
688 /*
689 * Create a device node for a block device partition.
690 *
691 * @buf buffer to which the device path is written
692 * @desc block device descriptor
693 * @part partition number, 0 identifies a block device
694 */
695 static void *dp_part_node(void *buf, struct blk_desc *desc, int part)
696 {
697 disk_partition_t info;
698
699 part_get_info(desc, part, &info);
700
701 if (desc->part_type == PART_TYPE_ISO) {
702 struct efi_device_path_cdrom_path *cddp = buf;
703
704 cddp->boot_entry = part;
705 cddp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE;
706 cddp->dp.sub_type = DEVICE_PATH_SUB_TYPE_CDROM_PATH;
707 cddp->dp.length = sizeof(*cddp);
708 cddp->partition_start = info.start;
709 cddp->partition_size = info.size;
710
711 buf = &cddp[1];
712 } else {
713 struct efi_device_path_hard_drive_path *hddp = buf;
714
715 hddp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE;
716 hddp->dp.sub_type = DEVICE_PATH_SUB_TYPE_HARD_DRIVE_PATH;
717 hddp->dp.length = sizeof(*hddp);
718 hddp->partition_number = part;
719 hddp->partition_start = info.start;
720 hddp->partition_end = info.size;
721 if (desc->part_type == PART_TYPE_EFI)
722 hddp->partmap_type = 2;
723 else
724 hddp->partmap_type = 1;
725
726 switch (desc->sig_type) {
727 case SIG_TYPE_NONE:
728 default:
729 hddp->signature_type = 0;
730 memset(hddp->partition_signature, 0,
731 sizeof(hddp->partition_signature));
732 break;
733 case SIG_TYPE_MBR:
734 hddp->signature_type = 1;
735 memset(hddp->partition_signature, 0,
736 sizeof(hddp->partition_signature));
737 memcpy(hddp->partition_signature, &desc->mbr_sig,
738 sizeof(desc->mbr_sig));
739 break;
740 case SIG_TYPE_GUID:
741 hddp->signature_type = 2;
742 memcpy(hddp->partition_signature, &desc->guid_sig,
743 sizeof(hddp->partition_signature));
744 break;
745 }
746
747 buf = &hddp[1];
748 }
749
750 return buf;
751 }
752
753 /*
754 * Create a device path for a block device or one of its partitions.
755 *
756 * @buf buffer to which the device path is written
757 * @desc block device descriptor
758 * @part partition number, 0 identifies a block device
759 */
760 static void *dp_part_fill(void *buf, struct blk_desc *desc, int part)
761 {
762 #ifdef CONFIG_BLK
763 {
764 struct udevice *dev;
765 int ret = blk_find_device(desc->if_type, desc->devnum, &dev);
766
767 if (ret)
768 dev = desc->bdev->parent;
769 buf = dp_fill(buf, dev);
770 }
771 #else
772 /*
773 * We *could* make a more accurate path, by looking at if_type
774 * and handling all the different cases like we do for non-
775 * legacy (i.e. CONFIG_BLK=y) case. But most important thing
776 * is just to have a unique device-path for if_type+devnum.
777 * So map things to a fictitious USB device.
778 */
779 struct efi_device_path_usb *udp;
780
781 memcpy(buf, &ROOT, sizeof(ROOT));
782 buf += sizeof(ROOT);
783
784 udp = buf;
785 udp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
786 udp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_USB;
787 udp->dp.length = sizeof(*udp);
788 udp->parent_port_number = desc->if_type;
789 udp->usb_interface = desc->devnum;
790 buf = &udp[1];
791 #endif
792
793 if (part == 0) /* the actual disk, not a partition */
794 return buf;
795
796 return dp_part_node(buf, desc, part);
797 }
798
799 /* Construct a device-path from a partition on a block device: */
800 struct efi_device_path *efi_dp_from_part(struct blk_desc *desc, int part)
801 {
802 void *buf, *start;
803
804 start = buf = dp_alloc(dp_part_size(desc, part) + sizeof(END));
805 if (!buf)
806 return NULL;
807
808 buf = dp_part_fill(buf, desc, part);
809
810 *((struct efi_device_path *)buf) = END;
811
812 return start;
813 }
814
815 /*
816 * Create a device node for a block device partition.
817 *
818 * @buf buffer to which the device path is written
819 * @desc block device descriptor
820 * @part partition number, 0 identifies a block device
821 */
822 struct efi_device_path *efi_dp_part_node(struct blk_desc *desc, int part)
823 {
824 efi_uintn_t dpsize;
825 void *buf;
826
827 if (desc->part_type == PART_TYPE_ISO)
828 dpsize = sizeof(struct efi_device_path_cdrom_path);
829 else
830 dpsize = sizeof(struct efi_device_path_hard_drive_path);
831 buf = dp_alloc(dpsize);
832
833 dp_part_node(buf, desc, part);
834
835 return buf;
836 }
837
838 /**
839 * path_to_uefi() - convert UTF-8 path to an UEFI style path
840 *
841 * Convert UTF-8 path to a UEFI style path (i.e. with backslashes as path
842 * separators and UTF-16).
843 *
844 * @src: source buffer
845 * @uefi: target buffer, possibly unaligned
846 */
847 static void path_to_uefi(void *uefi, const char *src)
848 {
849 u16 *pos = uefi;
850
851 /*
852 * efi_set_bootdev() calls this routine indirectly before the UEFI
853 * subsystem is initialized. So we cannot assume unaligned access to be
854 * enabled.
855 */
856 allow_unaligned();
857
858 while (*src) {
859 s32 code = utf8_get(&src);
860
861 if (code < 0)
862 code = '?';
863 else if (code == '/')
864 code = '\\';
865 utf16_put(code, &pos);
866 }
867 *pos = 0;
868 }
869
870 /*
871 * If desc is NULL, this creates a path with only the file component,
872 * otherwise it creates a full path with both device and file components
873 */
874 struct efi_device_path *efi_dp_from_file(struct blk_desc *desc, int part,
875 const char *path)
876 {
877 struct efi_device_path_file_path *fp;
878 void *buf, *start;
879 size_t dpsize = 0, fpsize;
880
881 if (desc)
882 dpsize = dp_part_size(desc, part);
883
884 fpsize = sizeof(struct efi_device_path) +
885 2 * (utf8_utf16_strlen(path) + 1);
886 if (fpsize > U16_MAX)
887 return NULL;
888
889 dpsize += fpsize;
890
891 start = buf = dp_alloc(dpsize + sizeof(END));
892 if (!buf)
893 return NULL;
894
895 if (desc)
896 buf = dp_part_fill(buf, desc, part);
897
898 /* add file-path: */
899 fp = buf;
900 fp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE;
901 fp->dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH;
902 fp->dp.length = (u16)fpsize;
903 path_to_uefi(fp->str, path);
904 buf += fpsize;
905
906 *((struct efi_device_path *)buf) = END;
907
908 return start;
909 }
910
911 #ifdef CONFIG_NET
912 struct efi_device_path *efi_dp_from_eth(void)
913 {
914 #ifndef CONFIG_DM_ETH
915 struct efi_device_path_mac_addr *ndp;
916 #endif
917 void *buf, *start;
918 unsigned dpsize = 0;
919
920 assert(eth_get_dev());
921
922 #ifdef CONFIG_DM_ETH
923 dpsize += dp_size(eth_get_dev());
924 #else
925 dpsize += sizeof(ROOT);
926 dpsize += sizeof(*ndp);
927 #endif
928
929 start = buf = dp_alloc(dpsize + sizeof(END));
930 if (!buf)
931 return NULL;
932
933 #ifdef CONFIG_DM_ETH
934 buf = dp_fill(buf, eth_get_dev());
935 #else
936 memcpy(buf, &ROOT, sizeof(ROOT));
937 buf += sizeof(ROOT);
938
939 ndp = buf;
940 ndp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
941 ndp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR;
942 ndp->dp.length = sizeof(*ndp);
943 ndp->if_type = 1; /* Ethernet */
944 memcpy(ndp->mac.addr, eth_get_ethaddr(), ARP_HLEN);
945 buf = &ndp[1];
946 #endif
947
948 *((struct efi_device_path *)buf) = END;
949
950 return start;
951 }
952 #endif
953
954 /* Construct a device-path for memory-mapped image */
955 struct efi_device_path *efi_dp_from_mem(uint32_t memory_type,
956 uint64_t start_address,
957 uint64_t end_address)
958 {
959 struct efi_device_path_memory *mdp;
960 void *buf, *start;
961
962 start = buf = dp_alloc(sizeof(*mdp) + sizeof(END));
963 if (!buf)
964 return NULL;
965
966 mdp = buf;
967 mdp->dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE;
968 mdp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MEMORY;
969 mdp->dp.length = sizeof(*mdp);
970 mdp->memory_type = memory_type;
971 mdp->start_address = start_address;
972 mdp->end_address = end_address;
973 buf = &mdp[1];
974
975 *((struct efi_device_path *)buf) = END;
976
977 return start;
978 }
979
980 /**
981 * efi_dp_split_file_path() - split of relative file path from device path
982 *
983 * Given a device path indicating a file on a device, separate the device
984 * path in two: the device path of the actual device and the file path
985 * relative to this device.
986 *
987 * @full_path: device path including device and file path
988 * @device_path: path of the device
989 * @file_path: relative path of the file or NULL if there is none
990 * Return: status code
991 */
992 efi_status_t efi_dp_split_file_path(struct efi_device_path *full_path,
993 struct efi_device_path **device_path,
994 struct efi_device_path **file_path)
995 {
996 struct efi_device_path *p, *dp, *fp = NULL;
997
998 *device_path = NULL;
999 *file_path = NULL;
1000 dp = efi_dp_dup(full_path);
1001 if (!dp)
1002 return EFI_OUT_OF_RESOURCES;
1003 p = dp;
1004 while (!EFI_DP_TYPE(p, MEDIA_DEVICE, FILE_PATH)) {
1005 p = efi_dp_next(p);
1006 if (!p)
1007 goto out;
1008 }
1009 fp = efi_dp_dup(p);
1010 if (!fp)
1011 return EFI_OUT_OF_RESOURCES;
1012 p->type = DEVICE_PATH_TYPE_END;
1013 p->sub_type = DEVICE_PATH_SUB_TYPE_END;
1014 p->length = sizeof(*p);
1015
1016 out:
1017 *device_path = dp;
1018 *file_path = fp;
1019 return EFI_SUCCESS;
1020 }
1021
1022 /**
1023 * efi_dp_from_name() - convert U-Boot device and file path to device path
1024 *
1025 * @dev: U-Boot device, e.g. 'mmc'
1026 * @devnr: U-Boot device number, e.g. 1 for 'mmc:1'
1027 * @path: file path relative to U-Boot device, may be NULL
1028 * @device: pointer to receive device path of the device
1029 * @file: pointer to receive device path for the file
1030 * Return: status code
1031 */
1032 efi_status_t efi_dp_from_name(const char *dev, const char *devnr,
1033 const char *path,
1034 struct efi_device_path **device,
1035 struct efi_device_path **file)
1036 {
1037 int is_net;
1038 struct blk_desc *desc = NULL;
1039 disk_partition_t fs_partition;
1040 int part = 0;
1041 char filename[32] = { 0 }; /* dp->str is u16[32] long */
1042 char *s;
1043
1044 if (path && !file)
1045 return EFI_INVALID_PARAMETER;
1046
1047 is_net = !strcmp(dev, "Net");
1048 if (!is_net) {
1049 part = blk_get_device_part_str(dev, devnr, &desc, &fs_partition,
1050 1);
1051 if (part < 0 || !desc)
1052 return EFI_INVALID_PARAMETER;
1053
1054 if (device)
1055 *device = efi_dp_from_part(desc, part);
1056 } else {
1057 #ifdef CONFIG_NET
1058 if (device)
1059 *device = efi_dp_from_eth();
1060 #endif
1061 }
1062
1063 if (!path)
1064 return EFI_SUCCESS;
1065
1066 snprintf(filename, sizeof(filename), "%s", path);
1067 /* DOS style file path: */
1068 s = filename;
1069 while ((s = strchr(s, '/')))
1070 *s++ = '\\';
1071 *file = efi_dp_from_file(is_net ? NULL : desc, part, filename);
1072
1073 if (!*file)
1074 return EFI_INVALID_PARAMETER;
1075
1076 return EFI_SUCCESS;
1077 }