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