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