]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - stand/efi/libefi/devpath.c
MFV r354377: 10554 Implemented zpool sync command
[FreeBSD/FreeBSD.git] / stand / efi / libefi / devpath.c
1 /*-
2  * Copyright (c) 2016 John Baldwin <jhb@FreeBSD.org>
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  */
25
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
28
29 #include <efi.h>
30 #include <efilib.h>
31 #include <efichar.h>
32 #include <uuid.h>
33 #include <machine/_inttypes.h>
34
35 static EFI_GUID ImageDevicePathGUID =
36     EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL_GUID;
37 static EFI_GUID DevicePathGUID = DEVICE_PATH_PROTOCOL;
38 static EFI_GUID DevicePathToTextGUID = EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID;
39 static EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *toTextProtocol;
40 static EFI_GUID DevicePathFromTextGUID =
41     EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL_GUID;
42 static EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *fromTextProtocol;
43
44 EFI_DEVICE_PATH *
45 efi_lookup_image_devpath(EFI_HANDLE handle)
46 {
47         EFI_DEVICE_PATH *devpath;
48         EFI_STATUS status;
49
50         status = OpenProtocolByHandle(handle, &ImageDevicePathGUID,
51             (void **)&devpath);
52         if (EFI_ERROR(status))
53                 devpath = NULL;
54         return (devpath);
55 }
56
57 EFI_DEVICE_PATH *
58 efi_lookup_devpath(EFI_HANDLE handle)
59 {
60         EFI_DEVICE_PATH *devpath;
61         EFI_STATUS status;
62
63         status = OpenProtocolByHandle(handle, &DevicePathGUID,
64             (void **)&devpath);
65         if (EFI_ERROR(status))
66                 devpath = NULL;
67         return (devpath);
68 }
69
70 static char *
71 efi_make_tail(char *suffix)
72 {
73         char *tail;
74
75         tail = NULL;
76         if (suffix != NULL)
77                 (void)asprintf(&tail, "/%s", suffix);
78         else
79                 tail = strdup("");
80         return (tail);
81 }
82
83 typedef struct {
84         EFI_DEVICE_PATH Header;
85         EFI_GUID        Guid;
86         UINT8           VendorDefinedData[1];
87 } __packed VENDOR_DEVICE_PATH_WITH_DATA;
88
89 static char *
90 efi_vendor_path(const char *type, VENDOR_DEVICE_PATH *node, char *suffix)
91 {
92         uint32_t size = DevicePathNodeLength(&node->Header) - sizeof(*node);
93         VENDOR_DEVICE_PATH_WITH_DATA *dp = (VENDOR_DEVICE_PATH_WITH_DATA *)node;
94         char *name, *tail, *head;
95         char *uuid;
96         int rv;
97
98         uuid_to_string((const uuid_t *)(void *)&node->Guid, &uuid, &rv);
99         if (rv != uuid_s_ok)
100                 return (NULL);
101
102         tail = efi_make_tail(suffix);
103         rv = asprintf(&head, "%sVendor(%s)[%x:", type, uuid, size);
104         free(uuid);
105         if (rv < 0)
106                 return (NULL);
107
108         if (DevicePathNodeLength(&node->Header) > sizeof(*node)) {
109                 for (uint32_t i = 0; i < size; i++) {
110                         rv = asprintf(&name, "%s%02x", head,
111                             dp->VendorDefinedData[i]);
112                         if (rv < 0) {
113                                 free(tail);
114                                 free(head);
115                                 return (NULL);
116                         }
117                         free(head);
118                         head = name;
119                 }
120         }
121
122         if (asprintf(&name, "%s]%s", head, tail) < 0)
123                 name = NULL;
124         free(head);
125         free(tail);
126         return (name);
127 }
128
129 static char *
130 efi_hw_dev_path(EFI_DEVICE_PATH *node, char *suffix)
131 {
132         uint8_t subtype = DevicePathSubType(node);
133         char *name, *tail;
134
135         tail = efi_make_tail(suffix);
136         switch (subtype) {
137         case HW_PCI_DP:
138                 if (asprintf(&name, "Pci(%x,%x)%s",
139                     ((PCI_DEVICE_PATH *)node)->Function,
140                     ((PCI_DEVICE_PATH *)node)->Device, tail) < 0)
141                         name = NULL;
142                 break;
143         case HW_PCCARD_DP:
144                 if (asprintf(&name, "PCCARD(%x)%s",
145                     ((PCCARD_DEVICE_PATH *)node)->FunctionNumber, tail) < 0)
146                         name = NULL;
147                 break;
148         case HW_MEMMAP_DP:
149                 if (asprintf(&name, "MMap(%x,%" PRIx64 ",%" PRIx64 ")%s",
150                     ((MEMMAP_DEVICE_PATH *)node)->MemoryType,
151                     ((MEMMAP_DEVICE_PATH *)node)->StartingAddress,
152                     ((MEMMAP_DEVICE_PATH *)node)->EndingAddress, tail) < 0)
153                         name = NULL;
154                 break;
155         case HW_VENDOR_DP:
156                 name = efi_vendor_path("Hardware",
157                     (VENDOR_DEVICE_PATH *)node, tail);
158                 break;
159         case HW_CONTROLLER_DP:
160                 if (asprintf(&name, "Ctrl(%x)%s",
161                     ((CONTROLLER_DEVICE_PATH *)node)->Controller, tail) < 0)
162                         name = NULL;
163                 break;
164         default:
165                 if (asprintf(&name, "UnknownHW(%x)%s", subtype, tail) < 0)
166                         name = NULL;
167                 break;
168         }
169         free(tail);
170         return (name);
171 }
172
173 static char *
174 efi_acpi_dev_path(EFI_DEVICE_PATH *node, char *suffix)
175 {
176         uint8_t subtype = DevicePathSubType(node);
177         ACPI_HID_DEVICE_PATH *acpi = (ACPI_HID_DEVICE_PATH *)node;
178         char *name, *tail;
179
180         tail = efi_make_tail(suffix);
181         switch (subtype) {
182         case ACPI_DP:
183                 if ((acpi->HID & PNP_EISA_ID_MASK) == PNP_EISA_ID_CONST) {
184                         switch (EISA_ID_TO_NUM (acpi->HID)) {
185                         case 0x0a03:
186                                 if (asprintf(&name, "PciRoot(%x)%s",
187                                     acpi->UID, tail) < 0)
188                                         name = NULL;
189                                 break;
190                         case 0x0a08:
191                                 if (asprintf(&name, "PcieRoot(%x)%s",
192                                     acpi->UID, tail) < 0)
193                                         name = NULL;
194                                 break;
195                         case 0x0604:
196                                 if (asprintf(&name, "Floppy(%x)%s",
197                                     acpi->UID, tail) < 0)
198                                         name = NULL;
199                                 break;
200                         case 0x0301:
201                                 if (asprintf(&name, "Keyboard(%x)%s",
202                                     acpi->UID, tail) < 0)
203                                         name = NULL;
204                                 break;
205                         case 0x0501:
206                                 if (asprintf(&name, "Serial(%x)%s",
207                                     acpi->UID, tail) < 0)
208                                         name = NULL;
209                                 break;
210                         case 0x0401:
211                                 if (asprintf(&name, "ParallelPort(%x)%s",
212                                     acpi->UID, tail) < 0)
213                                         name = NULL;
214                                 break;
215                         default:
216                                 if (asprintf(&name, "Acpi(PNP%04x,%x)%s",
217                                     EISA_ID_TO_NUM(acpi->HID),
218                                     acpi->UID, tail) < 0)
219                                         name = NULL;
220                                 break;
221                         }
222                 } else {
223                         if (asprintf(&name, "Acpi(%08x,%x)%s",
224                             acpi->HID, acpi->UID, tail) < 0)
225                                 name = NULL;
226                 }
227                 break;
228         case ACPI_EXTENDED_DP:
229         default:
230                 if (asprintf(&name, "UnknownACPI(%x)%s", subtype, tail) < 0)
231                         name = NULL;
232                 break;
233         }
234         free(tail);
235         return (name);
236 }
237
238 static char *
239 efi_messaging_dev_path(EFI_DEVICE_PATH *node, char *suffix)
240 {
241         uint8_t subtype = DevicePathSubType(node);
242         char *name;
243         char *tail;
244
245         tail = efi_make_tail(suffix);
246         switch (subtype) {
247         case MSG_ATAPI_DP:
248                 if (asprintf(&name, "ATA(%s,%s,%x)%s",
249                     ((ATAPI_DEVICE_PATH *)node)->PrimarySecondary == 1 ?
250                     "Secondary" : "Primary",
251                     ((ATAPI_DEVICE_PATH *)node)->SlaveMaster == 1 ?
252                     "Slave" : "Master",
253                     ((ATAPI_DEVICE_PATH *)node)->Lun, tail) < 0)
254                         name = NULL;
255                 break;
256         case MSG_SCSI_DP:
257                 if (asprintf(&name, "SCSI(%x,%x)%s",
258                     ((SCSI_DEVICE_PATH *)node)->Pun,
259                     ((SCSI_DEVICE_PATH *)node)->Lun, tail) < 0)
260                         name = NULL;
261                 break;
262         case MSG_FIBRECHANNEL_DP:
263                 if (asprintf(&name, "Fibre(%" PRIx64 ",%" PRIx64 ")%s",
264                     ((FIBRECHANNEL_DEVICE_PATH *)node)->WWN,
265                     ((FIBRECHANNEL_DEVICE_PATH *)node)->Lun, tail) < 0)
266                         name = NULL;
267                 break;
268         case MSG_1394_DP:
269                 if (asprintf(&name, "I1394(%016" PRIx64 ")%s",
270                     ((F1394_DEVICE_PATH *)node)->Guid, tail) < 0)
271                         name = NULL;
272                 break;
273         case MSG_USB_DP:
274                 if (asprintf(&name, "USB(%x,%x)%s",
275                     ((USB_DEVICE_PATH *)node)->ParentPortNumber,
276                     ((USB_DEVICE_PATH *)node)->InterfaceNumber, tail) < 0)
277                         name = NULL;
278                 break;
279         case MSG_USB_CLASS_DP:
280                 if (asprintf(&name, "UsbClass(%x,%x,%x,%x,%x)%s",
281                     ((USB_CLASS_DEVICE_PATH *)node)->VendorId,
282                     ((USB_CLASS_DEVICE_PATH *)node)->ProductId,
283                     ((USB_CLASS_DEVICE_PATH *)node)->DeviceClass,
284                     ((USB_CLASS_DEVICE_PATH *)node)->DeviceSubClass,
285                     ((USB_CLASS_DEVICE_PATH *)node)->DeviceProtocol, tail) < 0)
286                         name = NULL;
287                 break;
288         case MSG_MAC_ADDR_DP:
289                 if (asprintf(&name, "MAC(%02x:%02x:%02x:%02x:%02x:%02x,%x)%s",
290                     ((MAC_ADDR_DEVICE_PATH *)node)->MacAddress.Addr[0],
291                     ((MAC_ADDR_DEVICE_PATH *)node)->MacAddress.Addr[1],
292                     ((MAC_ADDR_DEVICE_PATH *)node)->MacAddress.Addr[2],
293                     ((MAC_ADDR_DEVICE_PATH *)node)->MacAddress.Addr[3],
294                     ((MAC_ADDR_DEVICE_PATH *)node)->MacAddress.Addr[4],
295                     ((MAC_ADDR_DEVICE_PATH *)node)->MacAddress.Addr[5],
296                     ((MAC_ADDR_DEVICE_PATH *)node)->IfType, tail) < 0)
297                         name = NULL;
298                 break;
299         case MSG_VENDOR_DP:
300                 name = efi_vendor_path("Messaging",
301                     (VENDOR_DEVICE_PATH *)node, tail);
302                 break;
303         case MSG_UART_DP:
304                 if (asprintf(&name, "UART(%" PRIu64 ",%u,%x,%x)%s",
305                     ((UART_DEVICE_PATH *)node)->BaudRate,
306                     ((UART_DEVICE_PATH *)node)->DataBits,
307                     ((UART_DEVICE_PATH *)node)->Parity,
308                     ((UART_DEVICE_PATH *)node)->StopBits, tail) < 0)
309                         name = NULL;
310                 break;
311         case MSG_SATA_DP:
312                 if (asprintf(&name, "Sata(%x,%x,%x)%s",
313                     ((SATA_DEVICE_PATH *)node)->HBAPortNumber,
314                     ((SATA_DEVICE_PATH *)node)->PortMultiplierPortNumber,
315                     ((SATA_DEVICE_PATH *)node)->Lun, tail) < 0)
316                         name = NULL;
317                 break;
318         default:
319                 if (asprintf(&name, "UnknownMessaging(%x)%s",
320                     subtype, tail) < 0)
321                         name = NULL;
322                 break;
323         }
324         free(tail);
325         return (name);
326 }
327
328 static char *
329 efi_media_dev_path(EFI_DEVICE_PATH *node, char *suffix)
330 {
331         uint8_t subtype = DevicePathSubType(node);
332         HARDDRIVE_DEVICE_PATH *hd;
333         char *name;
334         char *str;
335         char *tail;
336         int rv;
337
338         tail = efi_make_tail(suffix);
339         name = NULL;
340         switch (subtype) {
341         case MEDIA_HARDDRIVE_DP:
342                 hd = (HARDDRIVE_DEVICE_PATH *)node;
343                 switch (hd->SignatureType) {
344                 case SIGNATURE_TYPE_MBR:
345                         if (asprintf(&name, "HD(%d,MBR,%08x,%" PRIx64
346                             ",%" PRIx64 ")%s",
347                             hd->PartitionNumber,
348                             *((uint32_t *)(uintptr_t)&hd->Signature[0]),
349                             hd->PartitionStart,
350                             hd->PartitionSize, tail) < 0)
351                                 name = NULL;
352                         break;
353                 case SIGNATURE_TYPE_GUID:
354                         name = NULL;
355                         uuid_to_string((const uuid_t *)(void *)
356                             &hd->Signature[0], &str, &rv);
357                         if (rv != uuid_s_ok)
358                                 break;
359                         rv = asprintf(&name, "HD(%d,GPT,%s,%" PRIx64 ",%"
360                             PRIx64 ")%s",
361                             hd->PartitionNumber, str,
362                             hd->PartitionStart, hd->PartitionSize, tail);
363                         free(str);
364                         break;
365                 default:
366                         if (asprintf(&name, "HD(%d,%d,0)%s",
367                             hd->PartitionNumber,
368                             hd->SignatureType, tail) < 0) {
369                                 name = NULL;
370                         }
371                         break;
372                 }
373                 break;
374         case MEDIA_CDROM_DP:
375                 if (asprintf(&name, "CD(%x,%" PRIx64 ",%" PRIx64 ")%s",
376                     ((CDROM_DEVICE_PATH *)node)->BootEntry,
377                     ((CDROM_DEVICE_PATH *)node)->PartitionStart,
378                     ((CDROM_DEVICE_PATH *)node)->PartitionSize, tail) < 0) {
379                         name = NULL;
380                 }
381                 break;
382         case MEDIA_VENDOR_DP:
383                 name = efi_vendor_path("Media",
384                     (VENDOR_DEVICE_PATH *)node, tail);
385                 break;
386         case MEDIA_FILEPATH_DP:
387                 name = NULL;
388                 str = NULL;
389                 if (ucs2_to_utf8(((FILEPATH_DEVICE_PATH *)node)->PathName,
390                     &str) == 0) {
391                         (void)asprintf(&name, "%s%s", str, tail);
392                         free(str);
393                 }
394                 break;
395         case MEDIA_PROTOCOL_DP:
396                 name = NULL;
397                 uuid_to_string((const uuid_t *)(void *)
398                     &((MEDIA_PROTOCOL_DEVICE_PATH *)node)->Protocol,
399                     &str, &rv);
400                 if (rv != uuid_s_ok)
401                         break;
402                 rv = asprintf(&name, "Protocol(%s)%s", str, tail);
403                 free(str);
404                 break;
405         default:
406                 if (asprintf(&name, "UnknownMedia(%x)%s",
407                     subtype, tail) < 0)
408                         name = NULL;
409         }
410         free(tail);
411         return (name);
412 }
413
414 static char *
415 efi_translate_devpath(EFI_DEVICE_PATH *devpath)
416 {
417         EFI_DEVICE_PATH *dp = NextDevicePathNode(devpath);
418         char *name, *ptr;
419         uint8_t type;
420
421         if (!IsDevicePathEnd(devpath))
422                 name = efi_translate_devpath(dp);
423         else
424                 return (NULL);
425
426         ptr = NULL;
427         type = DevicePathType(devpath);
428         switch (type) {
429         case HARDWARE_DEVICE_PATH:
430                 ptr = efi_hw_dev_path(devpath, name);
431                 break;
432         case ACPI_DEVICE_PATH:
433                 ptr = efi_acpi_dev_path(devpath, name);
434                 break;
435         case MESSAGING_DEVICE_PATH:
436                 ptr = efi_messaging_dev_path(devpath, name);
437                 break;
438         case MEDIA_DEVICE_PATH:
439                 ptr = efi_media_dev_path(devpath, name);
440                 break;
441         case BBS_DEVICE_PATH:
442         default:
443                 if (asprintf(&ptr, "UnknownPath(%x)%s", type,
444                     name? name : "") < 0)
445                         ptr = NULL;
446                 break;
447         }
448
449         if (ptr != NULL) {
450                 free(name);
451                 name = ptr;
452         }
453         return (name);
454 }
455
456 static CHAR16 *
457 efi_devpath_to_name(EFI_DEVICE_PATH *devpath)
458 {
459         char *name = NULL;
460         CHAR16 *ptr = NULL;
461         size_t len;
462         int rv;
463
464         name = efi_translate_devpath(devpath);
465         if (name == NULL)
466                 return (NULL);
467
468         /*
469          * We need to return memory from AllocatePool, so it can be freed
470          * with FreePool() in efi_free_devpath_name().
471          */
472         rv = utf8_to_ucs2(name, &ptr, &len);
473         free(name);
474         if (rv == 0) {
475                 CHAR16 *out = NULL;
476                 EFI_STATUS status;
477
478                 status = BS->AllocatePool(EfiLoaderData, len, (void **)&out);
479                 if (EFI_ERROR(status)) {
480                         free(ptr);
481                         return (out);
482                 }
483                 memcpy(out, ptr, len);
484                 free(ptr);
485                 ptr = out;
486         }
487         
488         return (ptr);
489 }
490
491 CHAR16 *
492 efi_devpath_name(EFI_DEVICE_PATH *devpath)
493 {
494         EFI_STATUS status;
495
496         if (devpath == NULL)
497                 return (NULL);
498         if (toTextProtocol == NULL) {
499                 status = BS->LocateProtocol(&DevicePathToTextGUID, NULL,
500                     (VOID **)&toTextProtocol);
501                 if (EFI_ERROR(status))
502                         toTextProtocol = NULL;
503         }
504         if (toTextProtocol == NULL)
505                 return (efi_devpath_to_name(devpath));
506
507         return (toTextProtocol->ConvertDevicePathToText(devpath, TRUE, TRUE));
508 }
509
510 void
511 efi_free_devpath_name(CHAR16 *text)
512 {
513         if (text != NULL)
514                 BS->FreePool(text);
515 }
516
517 EFI_DEVICE_PATH *
518 efi_name_to_devpath(const char *path)
519 {
520         EFI_DEVICE_PATH *devpath;
521         CHAR16 *uv;
522         size_t ul;
523
524         uv = NULL;
525         if (utf8_to_ucs2(path, &uv, &ul) != 0)
526                 return (NULL);
527         devpath = efi_name_to_devpath16(uv);
528         free(uv);
529         return (devpath);
530 }
531
532 EFI_DEVICE_PATH *
533 efi_name_to_devpath16(CHAR16 *path)
534 {
535         EFI_STATUS status;
536
537         if (path == NULL)
538                 return (NULL);
539         if (fromTextProtocol == NULL) {
540                 status = BS->LocateProtocol(&DevicePathFromTextGUID, NULL,
541                     (VOID **)&fromTextProtocol);
542                 if (EFI_ERROR(status))
543                         fromTextProtocol = NULL;
544         }
545         if (fromTextProtocol == NULL)
546                 return (NULL);
547
548         return (fromTextProtocol->ConvertTextToDevicePath(path));
549 }
550
551 void efi_devpath_free(EFI_DEVICE_PATH *devpath)
552 {
553
554         BS->FreePool(devpath);
555 }
556
557 EFI_DEVICE_PATH *
558 efi_devpath_last_node(EFI_DEVICE_PATH *devpath)
559 {
560
561         if (IsDevicePathEnd(devpath))
562                 return (NULL);
563         while (!IsDevicePathEnd(NextDevicePathNode(devpath)))
564                 devpath = NextDevicePathNode(devpath);
565         return (devpath);
566 }
567
568 EFI_DEVICE_PATH *
569 efi_devpath_trim(EFI_DEVICE_PATH *devpath)
570 {
571         EFI_DEVICE_PATH *node, *copy;
572         size_t prefix, len;
573
574         if ((node = efi_devpath_last_node(devpath)) == NULL)
575                 return (NULL);
576         prefix = (UINT8 *)node - (UINT8 *)devpath;
577         if (prefix == 0)
578                 return (NULL);
579         len = prefix + DevicePathNodeLength(NextDevicePathNode(node));
580         copy = malloc(len);
581         if (copy != NULL) {
582                 memcpy(copy, devpath, prefix);
583                 node = (EFI_DEVICE_PATH *)((UINT8 *)copy + prefix);
584                 SetDevicePathEndNode(node);
585         }
586         return (copy);
587 }
588
589 EFI_HANDLE
590 efi_devpath_handle(EFI_DEVICE_PATH *devpath)
591 {
592         EFI_STATUS status;
593         EFI_HANDLE h;
594
595         /*
596          * There isn't a standard way to locate a handle for a given
597          * device path.  However, querying the EFI_DEVICE_PATH protocol
598          * for a given device path should give us a handle for the
599          * closest node in the path to the end that is valid.
600          */
601         status = BS->LocateDevicePath(&DevicePathGUID, &devpath, &h);
602         if (EFI_ERROR(status))
603                 return (NULL);
604         return (h);
605 }
606
607 bool
608 efi_devpath_match_node(EFI_DEVICE_PATH *devpath1, EFI_DEVICE_PATH *devpath2)
609 {
610         size_t len;
611
612         if (devpath1 == NULL || devpath2 == NULL)
613                 return (false);
614         if (DevicePathType(devpath1) != DevicePathType(devpath2) ||
615             DevicePathSubType(devpath1) != DevicePathSubType(devpath2))
616                 return (false);
617         len = DevicePathNodeLength(devpath1);
618         if (len != DevicePathNodeLength(devpath2))
619                 return (false);
620         if (memcmp(devpath1, devpath2, len) != 0)
621                 return (false);
622         return (true);
623 }
624
625 static bool
626 _efi_devpath_match(EFI_DEVICE_PATH *devpath1, EFI_DEVICE_PATH *devpath2,
627     bool ignore_media)
628 {
629
630         if (devpath1 == NULL || devpath2 == NULL)
631                 return (false);
632
633         while (true) {
634                 if (ignore_media &&
635                     IsDevicePathType(devpath1, MEDIA_DEVICE_PATH) &&
636                     IsDevicePathType(devpath2, MEDIA_DEVICE_PATH))
637                         return (true);
638                 if (!efi_devpath_match_node(devpath1, devpath2))
639                         return false;
640                 if (IsDevicePathEnd(devpath1))
641                         break;
642                 devpath1 = NextDevicePathNode(devpath1);
643                 devpath2 = NextDevicePathNode(devpath2);
644         }
645         return (true);
646 }
647 /*
648  * Are two devpaths identical?
649  */
650 bool
651 efi_devpath_match(EFI_DEVICE_PATH *devpath1, EFI_DEVICE_PATH *devpath2)
652 {
653         return _efi_devpath_match(devpath1, devpath2, false);
654 }
655
656 /*
657  * Like efi_devpath_match, but stops at when we hit the media device
658  * path node that specifies the partition information. If we match
659  * up to that point, then we're on the same disk.
660  */
661 bool
662 efi_devpath_same_disk(EFI_DEVICE_PATH *devpath1, EFI_DEVICE_PATH *devpath2)
663 {
664         return _efi_devpath_match(devpath1, devpath2, true);
665 }
666
667 bool
668 efi_devpath_is_prefix(EFI_DEVICE_PATH *prefix, EFI_DEVICE_PATH *path)
669 {
670         size_t len;
671
672         if (prefix == NULL || path == NULL)
673                 return (false);
674
675         while (1) {
676                 if (IsDevicePathEnd(prefix))
677                         break;
678
679                 if (DevicePathType(prefix) != DevicePathType(path) ||
680                     DevicePathSubType(prefix) != DevicePathSubType(path))
681                         return (false);
682
683                 len = DevicePathNodeLength(prefix);
684                 if (len != DevicePathNodeLength(path))
685                         return (false);
686
687                 if (memcmp(prefix, path, len) != 0)
688                         return (false);
689
690                 prefix = NextDevicePathNode(prefix);
691                 path = NextDevicePathNode(path);
692         }
693         return (true);
694 }
695
696 /*
697  * Skip over the 'prefix' part of path and return the part of the path
698  * that starts with the first node that's a MEDIA_DEVICE_PATH.
699  */
700 EFI_DEVICE_PATH *
701 efi_devpath_to_media_path(EFI_DEVICE_PATH *path)
702 {
703
704         while (!IsDevicePathEnd(path)) {
705                 if (DevicePathType(path) == MEDIA_DEVICE_PATH)
706                         return (path);
707                 path = NextDevicePathNode(path);
708         }
709         return (NULL);
710 }
711
712 UINTN
713 efi_devpath_length(EFI_DEVICE_PATH  *path)
714 {
715         EFI_DEVICE_PATH *start = path;
716
717         while (!IsDevicePathEnd(path))
718                 path = NextDevicePathNode(path);
719         return ((UINTN)path - (UINTN)start) + DevicePathNodeLength(path);
720 }
721
722 EFI_HANDLE
723 efi_devpath_to_handle(EFI_DEVICE_PATH *path, EFI_HANDLE *handles, unsigned nhandles)
724 {
725         unsigned i;
726         EFI_DEVICE_PATH *media, *devpath;
727         EFI_HANDLE h;
728
729         media = efi_devpath_to_media_path(path);
730         if (media == NULL)
731                 return (NULL);
732         for (i = 0; i < nhandles; i++) {
733                 h = handles[i];
734                 devpath = efi_lookup_devpath(h);
735                 if (devpath == NULL)
736                         continue;
737                 if (!efi_devpath_match_node(media, efi_devpath_to_media_path(devpath)))
738                         continue;
739                 return (h);
740         }
741         return (NULL);
742 }