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