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