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