Merge tag 'u-boot-imx-20190415' of git://git.denx.de/u-boot-imx
[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         ret = dp_alloc(length);
339         if (!ret)
340                 return ret;
341         ret->type = type;
342         ret->sub_type = sub_type;
343         ret->length = length;
344         return ret;
345 }
346
347 struct efi_device_path *efi_dp_append_instance(
348                 const struct efi_device_path *dp,
349                 const struct efi_device_path *dpi)
350 {
351         size_t sz, szi;
352         struct efi_device_path *p, *ret;
353
354         if (!dpi)
355                 return NULL;
356         if (!dp)
357                 return efi_dp_dup(dpi);
358         sz = efi_dp_size(dp);
359         szi = efi_dp_instance_size(dpi);
360         p = dp_alloc(sz + szi + 2 * sizeof(END));
361         if (!p)
362                 return NULL;
363         ret = p;
364         memcpy(p, dp, sz + sizeof(END));
365         p = (void *)p + sz;
366         p->sub_type = DEVICE_PATH_SUB_TYPE_INSTANCE_END;
367         p = (void *)p + sizeof(END);
368         memcpy(p, dpi, szi);
369         p = (void *)p + szi;
370         memcpy(p, &END, sizeof(END));
371         return ret;
372 }
373
374 struct efi_device_path *efi_dp_get_next_instance(struct efi_device_path **dp,
375                                                  efi_uintn_t *size)
376 {
377         size_t sz;
378         struct efi_device_path *p;
379
380         if (size)
381                 *size = 0;
382         if (!dp || !*dp)
383                 return NULL;
384         sz = efi_dp_instance_size(*dp);
385         p = dp_alloc(sz + sizeof(END));
386         if (!p)
387                 return NULL;
388         memcpy(p, *dp, sz + sizeof(END));
389         *dp = (void *)*dp + sz;
390         if ((*dp)->sub_type == DEVICE_PATH_SUB_TYPE_INSTANCE_END)
391                 *dp = (void *)*dp + sizeof(END);
392         else
393                 *dp = NULL;
394         if (size)
395                 *size = sz + sizeof(END);
396         return p;
397 }
398
399 bool efi_dp_is_multi_instance(const struct efi_device_path *dp)
400 {
401         const struct efi_device_path *p = dp;
402
403         if (!p)
404                 return false;
405         while (p->type != DEVICE_PATH_TYPE_END)
406                 p = (void *)p + p->length;
407         return p->sub_type == DEVICE_PATH_SUB_TYPE_INSTANCE_END;
408 }
409
410 #ifdef CONFIG_DM
411 /* size of device-path not including END node for device and all parents
412  * up to the root device.
413  */
414 static unsigned dp_size(struct udevice *dev)
415 {
416         if (!dev || !dev->driver)
417                 return sizeof(ROOT);
418
419         switch (dev->driver->id) {
420         case UCLASS_ROOT:
421         case UCLASS_SIMPLE_BUS:
422                 /* stop traversing parents at this point: */
423                 return sizeof(ROOT);
424         case UCLASS_ETH:
425                 return dp_size(dev->parent) +
426                         sizeof(struct efi_device_path_mac_addr);
427 #ifdef CONFIG_BLK
428         case UCLASS_BLK:
429                 switch (dev->parent->uclass->uc_drv->id) {
430 #ifdef CONFIG_IDE
431                 case UCLASS_IDE:
432                         return dp_size(dev->parent) +
433                                 sizeof(struct efi_device_path_atapi);
434 #endif
435 #if defined(CONFIG_SCSI) && defined(CONFIG_DM_SCSI)
436                 case UCLASS_SCSI:
437                         return dp_size(dev->parent) +
438                                 sizeof(struct efi_device_path_scsi);
439 #endif
440 #if defined(CONFIG_DM_MMC) && defined(CONFIG_MMC)
441                 case UCLASS_MMC:
442                         return dp_size(dev->parent) +
443                                 sizeof(struct efi_device_path_sd_mmc_path);
444 #endif
445                 default:
446                         return dp_size(dev->parent);
447                 }
448 #endif
449 #if defined(CONFIG_DM_MMC) && defined(CONFIG_MMC)
450         case UCLASS_MMC:
451                 return dp_size(dev->parent) +
452                         sizeof(struct efi_device_path_sd_mmc_path);
453 #endif
454         case UCLASS_MASS_STORAGE:
455         case UCLASS_USB_HUB:
456                 return dp_size(dev->parent) +
457                         sizeof(struct efi_device_path_usb_class);
458         default:
459                 /* just skip over unknown classes: */
460                 return dp_size(dev->parent);
461         }
462 }
463
464 /*
465  * Recursively build a device path.
466  *
467  * @buf         pointer to the end of the device path
468  * @dev         device
469  * @return      pointer to the end of the device path
470  */
471 static void *dp_fill(void *buf, struct udevice *dev)
472 {
473         if (!dev || !dev->driver)
474                 return buf;
475
476         switch (dev->driver->id) {
477         case UCLASS_ROOT:
478         case UCLASS_SIMPLE_BUS: {
479                 /* stop traversing parents at this point: */
480                 struct efi_device_path_vendor *vdp = buf;
481                 *vdp = ROOT;
482                 return &vdp[1];
483         }
484 #ifdef CONFIG_DM_ETH
485         case UCLASS_ETH: {
486                 struct efi_device_path_mac_addr *dp =
487                         dp_fill(buf, dev->parent);
488                 struct eth_pdata *pdata = dev->platdata;
489
490                 dp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
491                 dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR;
492                 dp->dp.length = sizeof(*dp);
493                 memset(&dp->mac, 0, sizeof(dp->mac));
494                 /* We only support IPv4 */
495                 memcpy(&dp->mac, &pdata->enetaddr, ARP_HLEN);
496                 /* Ethernet */
497                 dp->if_type = 1;
498                 return &dp[1];
499         }
500 #endif
501 #ifdef CONFIG_BLK
502         case UCLASS_BLK:
503                 switch (dev->parent->uclass->uc_drv->id) {
504 #ifdef CONFIG_IDE
505                 case UCLASS_IDE: {
506                         struct efi_device_path_atapi *dp =
507                         dp_fill(buf, dev->parent);
508                         struct blk_desc *desc = dev_get_uclass_platdata(dev);
509
510                         dp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
511                         dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_ATAPI;
512                         dp->dp.length = sizeof(*dp);
513                         dp->logical_unit_number = desc->devnum;
514                         dp->primary_secondary = IDE_BUS(desc->devnum);
515                         dp->slave_master = desc->devnum %
516                                 (CONFIG_SYS_IDE_MAXDEVICE /
517                                  CONFIG_SYS_IDE_MAXBUS);
518                         return &dp[1];
519                         }
520 #endif
521 #if defined(CONFIG_SCSI) && defined(CONFIG_DM_SCSI)
522                 case UCLASS_SCSI: {
523                         struct efi_device_path_scsi *dp =
524                                 dp_fill(buf, dev->parent);
525                         struct blk_desc *desc = dev_get_uclass_platdata(dev);
526
527                         dp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
528                         dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_SCSI;
529                         dp->dp.length = sizeof(*dp);
530                         dp->logical_unit_number = desc->lun;
531                         dp->target_id = desc->target;
532                         return &dp[1];
533                         }
534 #endif
535 #if defined(CONFIG_DM_MMC) && defined(CONFIG_MMC)
536                 case UCLASS_MMC: {
537                         struct efi_device_path_sd_mmc_path *sddp =
538                                 dp_fill(buf, dev->parent);
539                         struct blk_desc *desc = dev_get_uclass_platdata(dev);
540
541                         sddp->dp.type     = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
542                         sddp->dp.sub_type = is_sd(desc) ?
543                                 DEVICE_PATH_SUB_TYPE_MSG_SD :
544                                 DEVICE_PATH_SUB_TYPE_MSG_MMC;
545                         sddp->dp.length   = sizeof(*sddp);
546                         sddp->slot_number = dev->seq;
547                         return &sddp[1];
548                         }
549 #endif
550                 default:
551                         debug("%s(%u) %s: unhandled parent class: %s (%u)\n",
552                               __FILE__, __LINE__, __func__,
553                               dev->name, dev->parent->uclass->uc_drv->id);
554                         return dp_fill(buf, dev->parent);
555                 }
556 #endif
557 #if defined(CONFIG_DM_MMC) && defined(CONFIG_MMC)
558         case UCLASS_MMC: {
559                 struct efi_device_path_sd_mmc_path *sddp =
560                         dp_fill(buf, dev->parent);
561                 struct mmc *mmc = mmc_get_mmc_dev(dev);
562                 struct blk_desc *desc = mmc_get_blk_desc(mmc);
563
564                 sddp->dp.type     = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
565                 sddp->dp.sub_type = is_sd(desc) ?
566                         DEVICE_PATH_SUB_TYPE_MSG_SD :
567                         DEVICE_PATH_SUB_TYPE_MSG_MMC;
568                 sddp->dp.length   = sizeof(*sddp);
569                 sddp->slot_number = dev->seq;
570
571                 return &sddp[1];
572         }
573 #endif
574         case UCLASS_MASS_STORAGE:
575         case UCLASS_USB_HUB: {
576                 struct efi_device_path_usb_class *udp =
577                         dp_fill(buf, dev->parent);
578                 struct usb_device *udev = dev_get_parent_priv(dev);
579                 struct usb_device_descriptor *desc = &udev->descriptor;
580
581                 udp->dp.type     = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
582                 udp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_USB_CLASS;
583                 udp->dp.length   = sizeof(*udp);
584                 udp->vendor_id   = desc->idVendor;
585                 udp->product_id  = desc->idProduct;
586                 udp->device_class    = desc->bDeviceClass;
587                 udp->device_subclass = desc->bDeviceSubClass;
588                 udp->device_protocol = desc->bDeviceProtocol;
589
590                 return &udp[1];
591         }
592         default:
593                 debug("%s(%u) %s: unhandled device class: %s (%u)\n",
594                       __FILE__, __LINE__, __func__,
595                       dev->name, dev->driver->id);
596                 return dp_fill(buf, dev->parent);
597         }
598 }
599
600 /* Construct a device-path from a device: */
601 struct efi_device_path *efi_dp_from_dev(struct udevice *dev)
602 {
603         void *buf, *start;
604
605         start = buf = dp_alloc(dp_size(dev) + sizeof(END));
606         if (!buf)
607                 return NULL;
608         buf = dp_fill(buf, dev);
609         *((struct efi_device_path *)buf) = END;
610
611         return start;
612 }
613 #endif
614
615 static unsigned dp_part_size(struct blk_desc *desc, int part)
616 {
617         unsigned dpsize;
618
619 #ifdef CONFIG_BLK
620         {
621                 struct udevice *dev;
622                 int ret = blk_find_device(desc->if_type, desc->devnum, &dev);
623
624                 if (ret)
625                         dev = desc->bdev->parent;
626                 dpsize = dp_size(dev);
627         }
628 #else
629         dpsize = sizeof(ROOT) + sizeof(struct efi_device_path_usb);
630 #endif
631
632         if (part == 0) /* the actual disk, not a partition */
633                 return dpsize;
634
635         if (desc->part_type == PART_TYPE_ISO)
636                 dpsize += sizeof(struct efi_device_path_cdrom_path);
637         else
638                 dpsize += sizeof(struct efi_device_path_hard_drive_path);
639
640         return dpsize;
641 }
642
643 /*
644  * Create a device node for a block device partition.
645  *
646  * @buf         buffer to which the device path is written
647  * @desc        block device descriptor
648  * @part        partition number, 0 identifies a block device
649  */
650 static void *dp_part_node(void *buf, struct blk_desc *desc, int part)
651 {
652         disk_partition_t info;
653
654         part_get_info(desc, part, &info);
655
656         if (desc->part_type == PART_TYPE_ISO) {
657                 struct efi_device_path_cdrom_path *cddp = buf;
658
659                 cddp->boot_entry = part;
660                 cddp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE;
661                 cddp->dp.sub_type = DEVICE_PATH_SUB_TYPE_CDROM_PATH;
662                 cddp->dp.length = sizeof(*cddp);
663                 cddp->partition_start = info.start;
664                 cddp->partition_end = info.size;
665
666                 buf = &cddp[1];
667         } else {
668                 struct efi_device_path_hard_drive_path *hddp = buf;
669
670                 hddp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE;
671                 hddp->dp.sub_type = DEVICE_PATH_SUB_TYPE_HARD_DRIVE_PATH;
672                 hddp->dp.length = sizeof(*hddp);
673                 hddp->partition_number = part;
674                 hddp->partition_start = info.start;
675                 hddp->partition_end = info.size;
676                 if (desc->part_type == PART_TYPE_EFI)
677                         hddp->partmap_type = 2;
678                 else
679                         hddp->partmap_type = 1;
680
681                 switch (desc->sig_type) {
682                 case SIG_TYPE_NONE:
683                 default:
684                         hddp->signature_type = 0;
685                         memset(hddp->partition_signature, 0,
686                                sizeof(hddp->partition_signature));
687                         break;
688                 case SIG_TYPE_MBR:
689                         hddp->signature_type = 1;
690                         memset(hddp->partition_signature, 0,
691                                sizeof(hddp->partition_signature));
692                         memcpy(hddp->partition_signature, &desc->mbr_sig,
693                                sizeof(desc->mbr_sig));
694                         break;
695                 case SIG_TYPE_GUID:
696                         hddp->signature_type = 2;
697                         memcpy(hddp->partition_signature, &desc->guid_sig,
698                                sizeof(hddp->partition_signature));
699                         break;
700                 }
701
702                 buf = &hddp[1];
703         }
704
705         return buf;
706 }
707
708 /*
709  * Create a device path for a block device or one of its partitions.
710  *
711  * @buf         buffer to which the device path is written
712  * @desc        block device descriptor
713  * @part        partition number, 0 identifies a block device
714  */
715 static void *dp_part_fill(void *buf, struct blk_desc *desc, int part)
716 {
717 #ifdef CONFIG_BLK
718         {
719                 struct udevice *dev;
720                 int ret = blk_find_device(desc->if_type, desc->devnum, &dev);
721
722                 if (ret)
723                         dev = desc->bdev->parent;
724                 buf = dp_fill(buf, dev);
725         }
726 #else
727         /*
728          * We *could* make a more accurate path, by looking at if_type
729          * and handling all the different cases like we do for non-
730          * legacy (i.e. CONFIG_BLK=y) case. But most important thing
731          * is just to have a unique device-path for if_type+devnum.
732          * So map things to a fictitious USB device.
733          */
734         struct efi_device_path_usb *udp;
735
736         memcpy(buf, &ROOT, sizeof(ROOT));
737         buf += sizeof(ROOT);
738
739         udp = buf;
740         udp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
741         udp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_USB;
742         udp->dp.length = sizeof(*udp);
743         udp->parent_port_number = desc->if_type;
744         udp->usb_interface = desc->devnum;
745         buf = &udp[1];
746 #endif
747
748         if (part == 0) /* the actual disk, not a partition */
749                 return buf;
750
751         return dp_part_node(buf, desc, part);
752 }
753
754 /* Construct a device-path from a partition on a block device: */
755 struct efi_device_path *efi_dp_from_part(struct blk_desc *desc, int part)
756 {
757         void *buf, *start;
758
759         start = buf = dp_alloc(dp_part_size(desc, part) + sizeof(END));
760         if (!buf)
761                 return NULL;
762
763         buf = dp_part_fill(buf, desc, part);
764
765         *((struct efi_device_path *)buf) = END;
766
767         return start;
768 }
769
770 /*
771  * Create a device node for a block device partition.
772  *
773  * @buf         buffer to which the device path is written
774  * @desc        block device descriptor
775  * @part        partition number, 0 identifies a block device
776  */
777 struct efi_device_path *efi_dp_part_node(struct blk_desc *desc, int part)
778 {
779         efi_uintn_t dpsize;
780         void *buf;
781
782         if (desc->part_type == PART_TYPE_ISO)
783                 dpsize = sizeof(struct efi_device_path_cdrom_path);
784         else
785                 dpsize = sizeof(struct efi_device_path_hard_drive_path);
786         buf = dp_alloc(dpsize);
787
788         dp_part_node(buf, desc, part);
789
790         return buf;
791 }
792
793 /* convert path to an UEFI style path (i.e. DOS style backslashes and UTF-16) */
794 static void path_to_uefi(u16 *uefi, const char *path)
795 {
796         while (*path) {
797                 char c = *(path++);
798                 if (c == '/')
799                         c = '\\';
800                 *(uefi++) = c;
801         }
802         *uefi = '\0';
803 }
804
805 /*
806  * If desc is NULL, this creates a path with only the file component,
807  * otherwise it creates a full path with both device and file components
808  */
809 struct efi_device_path *efi_dp_from_file(struct blk_desc *desc, int part,
810                 const char *path)
811 {
812         struct efi_device_path_file_path *fp;
813         void *buf, *start;
814         unsigned dpsize = 0, fpsize;
815
816         if (desc)
817                 dpsize = dp_part_size(desc, part);
818
819         fpsize = sizeof(struct efi_device_path) + 2 * (strlen(path) + 1);
820         dpsize += fpsize;
821
822         start = buf = dp_alloc(dpsize + sizeof(END));
823         if (!buf)
824                 return NULL;
825
826         if (desc)
827                 buf = dp_part_fill(buf, desc, part);
828
829         /* add file-path: */
830         fp = buf;
831         fp->dp.type = DEVICE_PATH_TYPE_MEDIA_DEVICE;
832         fp->dp.sub_type = DEVICE_PATH_SUB_TYPE_FILE_PATH;
833         fp->dp.length = fpsize;
834         path_to_uefi(fp->str, path);
835         buf += fpsize;
836
837         *((struct efi_device_path *)buf) = END;
838
839         return start;
840 }
841
842 #ifdef CONFIG_NET
843 struct efi_device_path *efi_dp_from_eth(void)
844 {
845 #ifndef CONFIG_DM_ETH
846         struct efi_device_path_mac_addr *ndp;
847 #endif
848         void *buf, *start;
849         unsigned dpsize = 0;
850
851         assert(eth_get_dev());
852
853 #ifdef CONFIG_DM_ETH
854         dpsize += dp_size(eth_get_dev());
855 #else
856         dpsize += sizeof(ROOT);
857         dpsize += sizeof(*ndp);
858 #endif
859
860         start = buf = dp_alloc(dpsize + sizeof(END));
861         if (!buf)
862                 return NULL;
863
864 #ifdef CONFIG_DM_ETH
865         buf = dp_fill(buf, eth_get_dev());
866 #else
867         memcpy(buf, &ROOT, sizeof(ROOT));
868         buf += sizeof(ROOT);
869
870         ndp = buf;
871         ndp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
872         ndp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR;
873         ndp->dp.length = sizeof(*ndp);
874         ndp->if_type = 1; /* Ethernet */
875         memcpy(ndp->mac.addr, eth_get_ethaddr(), ARP_HLEN);
876         buf = &ndp[1];
877 #endif
878
879         *((struct efi_device_path *)buf) = END;
880
881         return start;
882 }
883 #endif
884
885 /* Construct a device-path for memory-mapped image */
886 struct efi_device_path *efi_dp_from_mem(uint32_t memory_type,
887                                         uint64_t start_address,
888                                         uint64_t end_address)
889 {
890         struct efi_device_path_memory *mdp;
891         void *buf, *start;
892
893         start = buf = dp_alloc(sizeof(*mdp) + sizeof(END));
894         if (!buf)
895                 return NULL;
896
897         mdp = buf;
898         mdp->dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE;
899         mdp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MEMORY;
900         mdp->dp.length = sizeof(*mdp);
901         mdp->memory_type = memory_type;
902         mdp->start_address = start_address;
903         mdp->end_address = end_address;
904         buf = &mdp[1];
905
906         *((struct efi_device_path *)buf) = END;
907
908         return start;
909 }
910
911 /**
912  * efi_dp_split_file_path() - split of relative file path from device path
913  *
914  * Given a device path indicating a file on a device, separate the device
915  * path in two: the device path of the actual device and the file path
916  * relative to this device.
917  *
918  * @full_path:          device path including device and file path
919  * @device_path:        path of the device
920  * @file_path:          relative path of the file
921  * Return:              status code
922  */
923 efi_status_t efi_dp_split_file_path(struct efi_device_path *full_path,
924                                     struct efi_device_path **device_path,
925                                     struct efi_device_path **file_path)
926 {
927         struct efi_device_path *p, *dp, *fp;
928
929         *device_path = NULL;
930         *file_path = NULL;
931         dp = efi_dp_dup(full_path);
932         if (!dp)
933                 return EFI_OUT_OF_RESOURCES;
934         p = dp;
935         while (!EFI_DP_TYPE(p, MEDIA_DEVICE, FILE_PATH)) {
936                 p = efi_dp_next(p);
937                 if (!p)
938                         return EFI_INVALID_PARAMETER;
939         }
940         fp = efi_dp_dup(p);
941         if (!fp)
942                 return EFI_OUT_OF_RESOURCES;
943         p->type = DEVICE_PATH_TYPE_END;
944         p->sub_type = DEVICE_PATH_SUB_TYPE_END;
945         p->length = sizeof(*p);
946
947         *device_path = dp;
948         *file_path = fp;
949         return EFI_SUCCESS;
950 }
951
952 efi_status_t efi_dp_from_name(const char *dev, const char *devnr,
953                               const char *path,
954                               struct efi_device_path **device,
955                               struct efi_device_path **file)
956 {
957         int is_net;
958         struct blk_desc *desc = NULL;
959         disk_partition_t fs_partition;
960         int part = 0;
961         char filename[32] = { 0 }; /* dp->str is u16[32] long */
962         char *s;
963
964         if (path && !file)
965                 return EFI_INVALID_PARAMETER;
966
967         is_net = !strcmp(dev, "Net");
968         if (!is_net) {
969                 part = blk_get_device_part_str(dev, devnr, &desc, &fs_partition,
970                                                1);
971                 if (part < 0 || !desc)
972                         return EFI_INVALID_PARAMETER;
973
974                 if (device)
975                         *device = efi_dp_from_part(desc, part);
976         } else {
977 #ifdef CONFIG_NET
978                 if (device)
979                         *device = efi_dp_from_eth();
980 #endif
981         }
982
983         if (!path)
984                 return EFI_SUCCESS;
985
986         snprintf(filename, sizeof(filename), "%s", path);
987         /* DOS style file path: */
988         s = filename;
989         while ((s = strchr(s, '/')))
990                 *s++ = '\\';
991         *file = efi_dp_from_file(((!is_net && device) ? desc : NULL),
992                                  part, filename);
993
994         return EFI_SUCCESS;
995 }