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