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