xref: /freebsd/stand/efi/libefi/devpath.c (revision e6bfd18d21b225af6a0ed67ceeaf1293b7b9eba5)
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)->Device,
150 		    ((PCI_DEVICE_PATH *)node)->Function, 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 /*
579  * Walk device path nodes, return next instance or end node.
580  */
581 EFI_DEVICE_PATH *
582 efi_devpath_next_instance(EFI_DEVICE_PATH *devpath)
583 {
584 	while (!IsDevicePathEnd(devpath)) {
585 		devpath = NextDevicePathNode(devpath);
586 		if (IsDevicePathEndType(devpath) &&
587 		    devpath->SubType == END_INSTANCE_DEVICE_PATH_SUBTYPE) {
588 			devpath = NextDevicePathNode(devpath);
589 			break;
590 		}
591 	}
592 	return (devpath);
593 }
594 
595 EFI_DEVICE_PATH *
596 efi_devpath_trim(EFI_DEVICE_PATH *devpath)
597 {
598 	EFI_DEVICE_PATH *node, *copy;
599 	size_t prefix, len;
600 
601 	if ((node = efi_devpath_last_node(devpath)) == NULL)
602 		return (NULL);
603 	prefix = (UINT8 *)node - (UINT8 *)devpath;
604 	if (prefix == 0)
605 		return (NULL);
606 	len = prefix + DevicePathNodeLength(NextDevicePathNode(node));
607 	copy = malloc(len);
608 	if (copy != NULL) {
609 		memcpy(copy, devpath, prefix);
610 		node = (EFI_DEVICE_PATH *)((UINT8 *)copy + prefix);
611 		SetDevicePathEndNode(node);
612 	}
613 	return (copy);
614 }
615 
616 EFI_HANDLE
617 efi_devpath_handle(EFI_DEVICE_PATH *devpath)
618 {
619 	EFI_STATUS status;
620 	EFI_HANDLE h;
621 
622 	/*
623 	 * There isn't a standard way to locate a handle for a given
624 	 * device path.  However, querying the EFI_DEVICE_PATH protocol
625 	 * for a given device path should give us a handle for the
626 	 * closest node in the path to the end that is valid.
627 	 */
628 	status = BS->LocateDevicePath(&DevicePathGUID, &devpath, &h);
629 	if (EFI_ERROR(status))
630 		return (NULL);
631 	return (h);
632 }
633 
634 bool
635 efi_devpath_match_node(EFI_DEVICE_PATH *devpath1, EFI_DEVICE_PATH *devpath2)
636 {
637 	size_t len;
638 
639 	if (devpath1 == NULL || devpath2 == NULL)
640 		return (false);
641 	if (DevicePathType(devpath1) != DevicePathType(devpath2) ||
642 	    DevicePathSubType(devpath1) != DevicePathSubType(devpath2))
643 		return (false);
644 	len = DevicePathNodeLength(devpath1);
645 	if (len != DevicePathNodeLength(devpath2))
646 		return (false);
647 	if (memcmp(devpath1, devpath2, len) != 0)
648 		return (false);
649 	return (true);
650 }
651 
652 static bool
653 _efi_devpath_match(EFI_DEVICE_PATH *devpath1, EFI_DEVICE_PATH *devpath2,
654     bool ignore_media)
655 {
656 
657 	if (devpath1 == NULL || devpath2 == NULL)
658 		return (false);
659 
660 	while (true) {
661 		if (ignore_media &&
662 		    IsDevicePathType(devpath1, MEDIA_DEVICE_PATH) &&
663 		    IsDevicePathType(devpath2, MEDIA_DEVICE_PATH))
664 			return (true);
665 		if (!efi_devpath_match_node(devpath1, devpath2))
666 			return false;
667 		if (IsDevicePathEnd(devpath1))
668 			break;
669 		devpath1 = NextDevicePathNode(devpath1);
670 		devpath2 = NextDevicePathNode(devpath2);
671 	}
672 	return (true);
673 }
674 /*
675  * Are two devpaths identical?
676  */
677 bool
678 efi_devpath_match(EFI_DEVICE_PATH *devpath1, EFI_DEVICE_PATH *devpath2)
679 {
680 	return _efi_devpath_match(devpath1, devpath2, false);
681 }
682 
683 /*
684  * Like efi_devpath_match, but stops at when we hit the media device
685  * path node that specifies the partition information. If we match
686  * up to that point, then we're on the same disk.
687  */
688 bool
689 efi_devpath_same_disk(EFI_DEVICE_PATH *devpath1, EFI_DEVICE_PATH *devpath2)
690 {
691 	return _efi_devpath_match(devpath1, devpath2, true);
692 }
693 
694 bool
695 efi_devpath_is_prefix(EFI_DEVICE_PATH *prefix, EFI_DEVICE_PATH *path)
696 {
697 	size_t len;
698 
699 	if (prefix == NULL || path == NULL)
700 		return (false);
701 
702 	while (1) {
703 		if (IsDevicePathEnd(prefix))
704 			break;
705 
706 		if (DevicePathType(prefix) != DevicePathType(path) ||
707 		    DevicePathSubType(prefix) != DevicePathSubType(path))
708 			return (false);
709 
710 		len = DevicePathNodeLength(prefix);
711 		if (len != DevicePathNodeLength(path))
712 			return (false);
713 
714 		if (memcmp(prefix, path, len) != 0)
715 			return (false);
716 
717 		prefix = NextDevicePathNode(prefix);
718 		path = NextDevicePathNode(path);
719 	}
720 	return (true);
721 }
722 
723 /*
724  * Skip over the 'prefix' part of path and return the part of the path
725  * that starts with the first node that's a MEDIA_DEVICE_PATH.
726  */
727 EFI_DEVICE_PATH *
728 efi_devpath_to_media_path(EFI_DEVICE_PATH *path)
729 {
730 
731 	while (!IsDevicePathEnd(path)) {
732 		if (DevicePathType(path) == MEDIA_DEVICE_PATH)
733 			return (path);
734 		path = NextDevicePathNode(path);
735 	}
736 	return (NULL);
737 }
738 
739 UINTN
740 efi_devpath_length(EFI_DEVICE_PATH  *path)
741 {
742 	EFI_DEVICE_PATH *start = path;
743 
744 	while (!IsDevicePathEnd(path))
745 		path = NextDevicePathNode(path);
746 	return ((UINTN)path - (UINTN)start) + DevicePathNodeLength(path);
747 }
748 
749 EFI_HANDLE
750 efi_devpath_to_handle(EFI_DEVICE_PATH *path, EFI_HANDLE *handles, unsigned nhandles)
751 {
752 	unsigned i;
753 	EFI_DEVICE_PATH *media, *devpath;
754 	EFI_HANDLE h;
755 
756 	media = efi_devpath_to_media_path(path);
757 	if (media == NULL)
758 		return (NULL);
759 	for (i = 0; i < nhandles; i++) {
760 		h = handles[i];
761 		devpath = efi_lookup_devpath(h);
762 		if (devpath == NULL)
763 			continue;
764 		if (!efi_devpath_match_node(media, efi_devpath_to_media_path(devpath)))
765 			continue;
766 		return (h);
767 	}
768 	return (NULL);
769 }
770