Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/stand/efi/libefi/devpath.c
103829 views
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 <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 *
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 *
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
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 *
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 *
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 *
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 *
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 *
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 *
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 *
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 *
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 *
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
520
efi_free_devpath_name(CHAR16 *text)
521
{
522
if (text != NULL)
523
BS->FreePool(text);
524
}
525
526
EFI_DEVICE_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 *
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
560
void efi_devpath_free(EFI_DEVICE_PATH *devpath)
561
{
562
563
BS->FreePool(devpath);
564
}
565
566
EFI_DEVICE_PATH *
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 *
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 *
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
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
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
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
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
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
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 *
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
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
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
770