1 /*-
2 * Copyright (c) 2016 John Baldwin <[email protected]>
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 *
efi_lookup_image_devpath(EFI_HANDLE handle)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 *
efi_lookup_devpath(EFI_HANDLE handle)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
efi_close_devpath(EFI_HANDLE handle)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 *
efi_make_tail(char * suffix)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 *
efi_vendor_path(const char * type,VENDOR_DEVICE_PATH * node,char * suffix)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 *
efi_hw_dev_path(EFI_DEVICE_PATH * node,char * suffix)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 *
efi_acpi_dev_path(EFI_DEVICE_PATH * node,char * suffix)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 *
efi_messaging_dev_path(EFI_DEVICE_PATH * node,char * suffix)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 *
efi_media_dev_path(EFI_DEVICE_PATH * node,char * suffix)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 *
efi_translate_devpath(EFI_DEVICE_PATH * devpath)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 *
efi_devpath_to_name(EFI_DEVICE_PATH * devpath)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 *
efi_devpath_name(EFI_DEVICE_PATH * devpath)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
efi_free_devpath_name(CHAR16 * text)521 efi_free_devpath_name(CHAR16 *text)
522 {
523 if (text != NULL)
524 BS->FreePool(text);
525 }
526
527 EFI_DEVICE_PATH *
efi_name_to_devpath(const char * 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 *
efi_name_to_devpath16(CHAR16 * 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
efi_devpath_free(EFI_DEVICE_PATH * devpath)561 void efi_devpath_free(EFI_DEVICE_PATH *devpath)
562 {
563
564 BS->FreePool(devpath);
565 }
566
567 EFI_DEVICE_PATH *
efi_devpath_last_node(EFI_DEVICE_PATH * devpath)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 *
efi_devpath_trim(EFI_DEVICE_PATH * devpath)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
efi_devpath_handle(EFI_DEVICE_PATH * devpath)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
efi_devpath_match_node(EFI_DEVICE_PATH * devpath1,EFI_DEVICE_PATH * devpath2)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
_efi_devpath_match(EFI_DEVICE_PATH * devpath1,EFI_DEVICE_PATH * devpath2,bool ignore_media)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
efi_devpath_match(EFI_DEVICE_PATH * devpath1,EFI_DEVICE_PATH * devpath2)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
efi_devpath_same_disk(EFI_DEVICE_PATH * devpath1,EFI_DEVICE_PATH * devpath2)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
efi_devpath_is_prefix(EFI_DEVICE_PATH * prefix,EFI_DEVICE_PATH * path)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 *
efi_devpath_to_media_path(EFI_DEVICE_PATH * 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
efi_devpath_length(EFI_DEVICE_PATH * path)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
efi_devpath_to_handle(EFI_DEVICE_PATH * path,EFI_HANDLE * handles,unsigned nhandles)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 }
753