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