Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/lib/libefivar/uefi-dputil.c
105194 views
1
/*-
2
* Copyright (c) 2017 Netflix, Inc.
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
/*
27
* Routines to format EFI_DEVICE_PATHs from the UEFI standard. Much of
28
* this file is taken from EDK2 and rototilled.
29
*/
30
31
#include <efivar.h>
32
#include <limits.h>
33
#include <stdio.h>
34
#include <string.h>
35
#include <sys/endian.h>
36
#include "uefi-dplib.h"
37
38
/*
39
* Taken from MdePkg/Library/UefiDevicePathLib/DevicePathUtilities.c
40
* hash 2f88bd3a1296c522317f1c21377876de63de5be7 2021-Dec-07
41
*/
42
43
/** @file
44
Device Path services. The thing to remember is device paths are built out of
45
nodes. The device path is terminated by an end node that is length
46
sizeof(EFI_DEVICE_PATH_PROTOCOL). That would be why there is sizeof(EFI_DEVICE_PATH_PROTOCOL)
47
all over this file.
48
49
The only place where multi-instance device paths are supported is in
50
environment varibles. Multi-instance device paths should never be placed
51
on a Handle.
52
53
Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
54
SPDX-License-Identifier: BSD-2-Clause-Patent
55
56
**/
57
58
// #include "UefiDevicePathLib.h"
59
60
//
61
// Template for an end-of-device path node.
62
//
63
static CONST EFI_DEVICE_PATH_PROTOCOL mUefiDevicePathLibEndDevicePath = {
64
END_DEVICE_PATH_TYPE,
65
END_ENTIRE_DEVICE_PATH_SUBTYPE,
66
{
67
END_DEVICE_PATH_LENGTH,
68
0
69
}
70
};
71
72
/**
73
Determine whether a given device path is valid.
74
75
@param DevicePath A pointer to a device path data structure.
76
@param MaxSize The maximum size of the device path data structure.
77
78
@retval TRUE DevicePath is valid.
79
@retval FALSE DevicePath is NULL.
80
@retval FALSE Maxsize is less than sizeof(EFI_DEVICE_PATH_PROTOCOL).
81
@retval FALSE The length of any node Node in the DevicePath is less
82
than sizeof (EFI_DEVICE_PATH_PROTOCOL).
83
@retval FALSE If MaxSize is not zero, the size of the DevicePath
84
exceeds MaxSize.
85
@retval FALSE If PcdMaximumDevicePathNodeCount is not zero, the node
86
count of the DevicePath exceeds PcdMaximumDevicePathNodeCount.
87
**/
88
BOOLEAN
89
EFIAPI
90
IsDevicePathValid (
91
IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,
92
IN UINTN MaxSize
93
)
94
{
95
UINTN Count;
96
UINTN Size;
97
UINTN NodeLength;
98
99
//
100
// Validate the input whether exists and its size big enough to touch the first node
101
//
102
if ((DevicePath == NULL) || ((MaxSize > 0) && (MaxSize < END_DEVICE_PATH_LENGTH))) {
103
return FALSE;
104
}
105
106
if (MaxSize == 0) {
107
MaxSize = MAX_UINTN;
108
}
109
110
for (Count = 0, Size = 0; !IsDevicePathEnd (DevicePath); DevicePath = NextDevicePathNode (DevicePath)) {
111
NodeLength = DevicePathNodeLength (DevicePath);
112
if (NodeLength < sizeof (EFI_DEVICE_PATH_PROTOCOL)) {
113
return FALSE;
114
}
115
116
if (NodeLength > MAX_UINTN - Size) {
117
return FALSE;
118
}
119
120
Size += NodeLength;
121
122
//
123
// Validate next node before touch it.
124
//
125
if (Size > MaxSize - END_DEVICE_PATH_LENGTH ) {
126
return FALSE;
127
}
128
129
if (PcdGet32 (PcdMaximumDevicePathNodeCount) > 0) {
130
Count++;
131
if (Count >= PcdGet32 (PcdMaximumDevicePathNodeCount)) {
132
return FALSE;
133
}
134
}
135
136
//
137
// FilePath must be a NULL-terminated string.
138
//
139
if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) &&
140
(DevicePathSubType (DevicePath) == MEDIA_FILEPATH_DP) &&
141
(*(const CHAR16 *)((const UINT8 *) DevicePath + NodeLength - 2) != 0))
142
{
143
return FALSE;
144
}
145
}
146
147
//
148
// Only return TRUE when the End Device Path node is valid.
149
//
150
return (BOOLEAN)(DevicePathNodeLength (DevicePath) == END_DEVICE_PATH_LENGTH);
151
}
152
153
/**
154
Returns the Type field of a device path node.
155
156
Returns the Type field of the device path node specified by Node.
157
158
If Node is NULL, then ASSERT().
159
160
@param Node A pointer to a device path node data structure.
161
162
@return The Type field of the device path node specified by Node.
163
164
**/
165
UINT8
166
EFIAPI
167
DevicePathType (
168
IN CONST VOID *Node
169
)
170
{
171
ASSERT (Node != NULL);
172
return ((const EFI_DEVICE_PATH_PROTOCOL *)(Node))->Type;
173
}
174
175
/**
176
Returns the SubType field of a device path node.
177
178
Returns the SubType field of the device path node specified by Node.
179
180
If Node is NULL, then ASSERT().
181
182
@param Node A pointer to a device path node data structure.
183
184
@return The SubType field of the device path node specified by Node.
185
186
**/
187
UINT8
188
EFIAPI
189
DevicePathSubType (
190
IN CONST VOID *Node
191
)
192
{
193
ASSERT (Node != NULL);
194
return ((const EFI_DEVICE_PATH_PROTOCOL *)(Node))->SubType;
195
}
196
197
/**
198
Returns the 16-bit Length field of a device path node.
199
200
Returns the 16-bit Length field of the device path node specified by Node.
201
Node is not required to be aligned on a 16-bit boundary, so it is recommended
202
that a function such as ReadUnaligned16() be used to extract the contents of
203
the Length field.
204
205
If Node is NULL, then ASSERT().
206
207
@param Node A pointer to a device path node data structure.
208
209
@return The 16-bit Length field of the device path node specified by Node.
210
211
**/
212
UINTN
213
EFIAPI
214
DevicePathNodeLength (
215
IN CONST VOID *Node
216
)
217
{
218
ASSERT (Node != NULL);
219
// return ReadUnaligned16 ((UINT16 *)&((EFI_DEVICE_PATH_PROTOCOL *)(Node))->Length[0]);
220
return ((const EFI_DEVICE_PATH_PROTOCOL *)Node)->Length[0] |
221
(((const EFI_DEVICE_PATH_PROTOCOL *)Node)->Length[1] << 8);
222
}
223
224
/**
225
Returns a pointer to the next node in a device path.
226
227
Returns a pointer to the device path node that follows the device path node
228
specified by Node.
229
230
If Node is NULL, then ASSERT().
231
232
@param Node A pointer to a device path node data structure.
233
234
@return a pointer to the device path node that follows the device path node
235
specified by Node.
236
237
**/
238
EFI_DEVICE_PATH_PROTOCOL *
239
EFIAPI
240
NextDevicePathNode (
241
IN CONST VOID *Node
242
)
243
{
244
ASSERT (Node != NULL);
245
return (EFI_DEVICE_PATH_PROTOCOL *)(__DECONST(UINT8 *, Node) + DevicePathNodeLength (Node));
246
}
247
248
/**
249
Determines if a device path node is an end node of a device path.
250
This includes nodes that are the end of a device path instance and nodes that
251
are the end of an entire device path.
252
253
Determines if the device path node specified by Node is an end node of a device path.
254
This includes nodes that are the end of a device path instance and nodes that are the
255
end of an entire device path. If Node represents an end node of a device path,
256
then TRUE is returned. Otherwise, FALSE is returned.
257
258
If Node is NULL, then ASSERT().
259
260
@param Node A pointer to a device path node data structure.
261
262
@retval TRUE The device path node specified by Node is an end node of a
263
device path.
264
@retval FALSE The device path node specified by Node is not an end node of
265
a device path.
266
267
**/
268
BOOLEAN
269
EFIAPI
270
IsDevicePathEndType (
271
IN CONST VOID *Node
272
)
273
{
274
ASSERT (Node != NULL);
275
return (BOOLEAN)(DevicePathType (Node) == END_DEVICE_PATH_TYPE);
276
}
277
278
/**
279
Determines if a device path node is an end node of an entire device path.
280
281
Determines if a device path node specified by Node is an end node of an entire
282
device path. If Node represents the end of an entire device path, then TRUE is
283
returned. Otherwise, FALSE is returned.
284
285
If Node is NULL, then ASSERT().
286
287
@param Node A pointer to a device path node data structure.
288
289
@retval TRUE The device path node specified by Node is the end of an entire
290
device path.
291
@retval FALSE The device path node specified by Node is not the end of an
292
entire device path.
293
294
**/
295
BOOLEAN
296
EFIAPI
297
IsDevicePathEnd (
298
IN CONST VOID *Node
299
)
300
{
301
ASSERT (Node != NULL);
302
return (BOOLEAN)(IsDevicePathEndType (Node) && DevicePathSubType (Node) == END_ENTIRE_DEVICE_PATH_SUBTYPE);
303
}
304
305
#ifndef __FreeBSD__
306
/**
307
Determines if a device path node is an end node of a device path instance.
308
309
Determines if a device path node specified by Node is an end node of a device
310
path instance. If Node represents the end of a device path instance, then TRUE
311
is returned. Otherwise, FALSE is returned.
312
313
If Node is NULL, then ASSERT().
314
315
@param Node A pointer to a device path node data structure.
316
317
@retval TRUE The device path node specified by Node is the end of a device
318
path instance.
319
@retval FALSE The device path node specified by Node is not the end of a
320
device path instance.
321
322
**/
323
BOOLEAN
324
EFIAPI
325
IsDevicePathEndInstance (
326
IN CONST VOID *Node
327
)
328
{
329
ASSERT (Node != NULL);
330
return (BOOLEAN)(IsDevicePathEndType (Node) && DevicePathSubType (Node) == END_INSTANCE_DEVICE_PATH_SUBTYPE);
331
}
332
#endif
333
334
/**
335
Sets the length, in bytes, of a device path node.
336
337
Sets the length of the device path node specified by Node to the value specified
338
by NodeLength. NodeLength is returned. Node is not required to be aligned on
339
a 16-bit boundary, so it is recommended that a function such as WriteUnaligned16()
340
be used to set the contents of the Length field.
341
342
If Node is NULL, then ASSERT().
343
If NodeLength >= SIZE_64KB, then ASSERT().
344
If NodeLength < sizeof (EFI_DEVICE_PATH_PROTOCOL), then ASSERT().
345
346
@param Node A pointer to a device path node data structure.
347
@param Length The length, in bytes, of the device path node.
348
349
@return Length
350
351
**/
352
UINT16
353
EFIAPI
354
SetDevicePathNodeLength (
355
IN OUT VOID *Node,
356
IN UINTN Length
357
)
358
{
359
ASSERT (Node != NULL);
360
ASSERT ((Length >= sizeof (EFI_DEVICE_PATH_PROTOCOL)) && (Length < SIZE_64KB));
361
// return WriteUnaligned16 ((UINT16 *)&((EFI_DEVICE_PATH_PROTOCOL *)(Node))->Length[0], (UINT16)(Length));
362
le16enc(&((EFI_DEVICE_PATH_PROTOCOL *)(Node))->Length[0], (UINT16)(Length));
363
return Length;
364
}
365
366
/**
367
Fills in all the fields of a device path node that is the end of an entire device path.
368
369
Fills in all the fields of a device path node specified by Node so Node represents
370
the end of an entire device path. The Type field of Node is set to
371
END_DEVICE_PATH_TYPE, the SubType field of Node is set to
372
END_ENTIRE_DEVICE_PATH_SUBTYPE, and the Length field of Node is set to
373
END_DEVICE_PATH_LENGTH. Node is not required to be aligned on a 16-bit boundary,
374
so it is recommended that a function such as WriteUnaligned16() be used to set
375
the contents of the Length field.
376
377
If Node is NULL, then ASSERT().
378
379
@param Node A pointer to a device path node data structure.
380
381
**/
382
VOID
383
EFIAPI
384
SetDevicePathEndNode (
385
OUT VOID *Node
386
)
387
{
388
ASSERT (Node != NULL);
389
memcpy (Node, &mUefiDevicePathLibEndDevicePath, sizeof (mUefiDevicePathLibEndDevicePath));
390
}
391
392
/**
393
Returns the size of a device path in bytes.
394
395
This function returns the size, in bytes, of the device path data structure
396
specified by DevicePath including the end of device path node.
397
If DevicePath is NULL or invalid, then 0 is returned.
398
399
@param DevicePath A pointer to a device path data structure.
400
401
@retval 0 If DevicePath is NULL or invalid.
402
@retval Others The size of a device path in bytes.
403
404
**/
405
UINTN
406
EFIAPI
407
GetDevicePathSize (
408
IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath
409
)
410
{
411
CONST EFI_DEVICE_PATH_PROTOCOL *Start;
412
413
if (DevicePath == NULL) {
414
return 0;
415
}
416
417
if (!IsDevicePathValid (DevicePath, 0)) {
418
return 0;
419
}
420
421
//
422
// Search for the end of the device path structure
423
//
424
Start = DevicePath;
425
while (!IsDevicePathEnd (DevicePath)) {
426
DevicePath = NextDevicePathNode (DevicePath);
427
}
428
429
//
430
// Compute the size and add back in the size of the end device path structure
431
//
432
return ((UINTN)DevicePath - (UINTN)Start) + DevicePathNodeLength (DevicePath);
433
}
434
435
/**
436
Creates a new copy of an existing device path.
437
438
This function allocates space for a new copy of the device path specified by DevicePath.
439
If DevicePath is NULL, then NULL is returned. If the memory is successfully
440
allocated, then the contents of DevicePath are copied to the newly allocated
441
buffer, and a pointer to that buffer is returned. Otherwise, NULL is returned.
442
The memory for the new device path is allocated from EFI boot services memory.
443
It is the responsibility of the caller to free the memory allocated.
444
445
@param DevicePath A pointer to a device path data structure.
446
447
@retval NULL DevicePath is NULL or invalid.
448
@retval Others A pointer to the duplicated device path.
449
450
**/
451
EFI_DEVICE_PATH_PROTOCOL *
452
EFIAPI
453
DuplicateDevicePath (
454
IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath
455
)
456
{
457
UINTN Size;
458
459
//
460
// Compute the size
461
//
462
Size = GetDevicePathSize (DevicePath);
463
if (Size == 0) {
464
return NULL;
465
}
466
467
//
468
// Allocate space for duplicate device path
469
//
470
471
return AllocateCopyPool (Size, DevicePath);
472
}
473
474
/**
475
Creates a new device path by appending a second device path to a first device path.
476
477
This function creates a new device path by appending a copy of SecondDevicePath
478
to a copy of FirstDevicePath in a newly allocated buffer. Only the end-of-device-path
479
device node from SecondDevicePath is retained. The newly created device path is
480
returned. If FirstDevicePath is NULL, then it is ignored, and a duplicate of
481
SecondDevicePath is returned. If SecondDevicePath is NULL, then it is ignored,
482
and a duplicate of FirstDevicePath is returned. If both FirstDevicePath and
483
SecondDevicePath are NULL, then a copy of an end-of-device-path is returned.
484
485
If there is not enough memory for the newly allocated buffer, then NULL is returned.
486
The memory for the new device path is allocated from EFI boot services memory.
487
It is the responsibility of the caller to free the memory allocated.
488
489
@param FirstDevicePath A pointer to a device path data structure.
490
@param SecondDevicePath A pointer to a device path data structure.
491
492
@retval NULL If there is not enough memory for the newly allocated buffer.
493
@retval NULL If FirstDevicePath or SecondDevicePath is invalid.
494
@retval Others A pointer to the new device path if success.
495
Or a copy an end-of-device-path if both FirstDevicePath and SecondDevicePath are NULL.
496
497
**/
498
EFI_DEVICE_PATH_PROTOCOL *
499
EFIAPI
500
AppendDevicePath (
501
IN CONST EFI_DEVICE_PATH_PROTOCOL *FirstDevicePath OPTIONAL,
502
IN CONST EFI_DEVICE_PATH_PROTOCOL *SecondDevicePath OPTIONAL
503
)
504
{
505
UINTN Size;
506
UINTN Size1;
507
UINTN Size2;
508
EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
509
EFI_DEVICE_PATH_PROTOCOL *DevicePath2;
510
511
//
512
// If there's only 1 path, just duplicate it.
513
//
514
if (FirstDevicePath == NULL) {
515
return DuplicateDevicePath ((SecondDevicePath != NULL) ? SecondDevicePath : &mUefiDevicePathLibEndDevicePath);
516
}
517
518
if (SecondDevicePath == NULL) {
519
return DuplicateDevicePath (FirstDevicePath);
520
}
521
522
if (!IsDevicePathValid (FirstDevicePath, 0) || !IsDevicePathValid (SecondDevicePath, 0)) {
523
return NULL;
524
}
525
526
//
527
// Allocate space for the combined device path. It only has one end node of
528
// length EFI_DEVICE_PATH_PROTOCOL.
529
//
530
Size1 = GetDevicePathSize (FirstDevicePath);
531
Size2 = GetDevicePathSize (SecondDevicePath);
532
Size = Size1 + Size2 - END_DEVICE_PATH_LENGTH;
533
534
NewDevicePath = AllocatePool (Size);
535
536
if (NewDevicePath != NULL) {
537
NewDevicePath = CopyMem (NewDevicePath, FirstDevicePath, Size1);
538
//
539
// Over write FirstDevicePath EndNode and do the copy
540
//
541
DevicePath2 = (EFI_DEVICE_PATH_PROTOCOL *)((CHAR8 *)NewDevicePath +
542
(Size1 - END_DEVICE_PATH_LENGTH));
543
CopyMem (DevicePath2, SecondDevicePath, Size2);
544
}
545
546
return NewDevicePath;
547
}
548
549
/**
550
Creates a new path by appending the device node to the device path.
551
552
This function creates a new device path by appending a copy of the device node
553
specified by DevicePathNode to a copy of the device path specified by DevicePath
554
in an allocated buffer. The end-of-device-path device node is moved after the
555
end of the appended device node.
556
If DevicePathNode is NULL then a copy of DevicePath is returned.
557
If DevicePath is NULL then a copy of DevicePathNode, followed by an end-of-device
558
path device node is returned.
559
If both DevicePathNode and DevicePath are NULL then a copy of an end-of-device-path
560
device node is returned.
561
If there is not enough memory to allocate space for the new device path, then
562
NULL is returned.
563
The memory is allocated from EFI boot services memory. It is the responsibility
564
of the caller to free the memory allocated.
565
566
@param DevicePath A pointer to a device path data structure.
567
@param DevicePathNode A pointer to a single device path node.
568
569
@retval NULL If there is not enough memory for the new device path.
570
@retval Others A pointer to the new device path if success.
571
A copy of DevicePathNode followed by an end-of-device-path node
572
if both FirstDevicePath and SecondDevicePath are NULL.
573
A copy of an end-of-device-path node if both FirstDevicePath
574
and SecondDevicePath are NULL.
575
576
**/
577
EFI_DEVICE_PATH_PROTOCOL *
578
EFIAPI
579
AppendDevicePathNode (
580
IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath OPTIONAL,
581
IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePathNode OPTIONAL
582
)
583
{
584
EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
585
EFI_DEVICE_PATH_PROTOCOL *NextNode;
586
EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
587
UINTN NodeLength;
588
589
if (DevicePathNode == NULL) {
590
return DuplicateDevicePath ((DevicePath != NULL) ? DevicePath : &mUefiDevicePathLibEndDevicePath);
591
}
592
593
//
594
// Build a Node that has a terminator on it
595
//
596
NodeLength = DevicePathNodeLength (DevicePathNode);
597
598
TempDevicePath = AllocatePool (NodeLength + END_DEVICE_PATH_LENGTH);
599
if (TempDevicePath == NULL) {
600
return NULL;
601
}
602
603
TempDevicePath = CopyMem (TempDevicePath, DevicePathNode, NodeLength);
604
//
605
// Add and end device path node to convert Node to device path
606
//
607
NextNode = NextDevicePathNode (TempDevicePath);
608
SetDevicePathEndNode (NextNode);
609
//
610
// Append device paths
611
//
612
NewDevicePath = AppendDevicePath (DevicePath, TempDevicePath);
613
614
FreePool (TempDevicePath);
615
616
return NewDevicePath;
617
}
618
619
#ifndef __FreeBSD__
620
/**
621
Creates a new device path by appending the specified device path instance to the specified device
622
path.
623
624
This function creates a new device path by appending a copy of the device path
625
instance specified by DevicePathInstance to a copy of the device path specified
626
by DevicePath in a allocated buffer.
627
The end-of-device-path device node is moved after the end of the appended device
628
path instance and a new end-of-device-path-instance node is inserted between.
629
If DevicePath is NULL, then a copy if DevicePathInstance is returned.
630
If DevicePathInstance is NULL, then NULL is returned.
631
If DevicePath or DevicePathInstance is invalid, then NULL is returned.
632
If there is not enough memory to allocate space for the new device path, then
633
NULL is returned.
634
The memory is allocated from EFI boot services memory. It is the responsibility
635
of the caller to free the memory allocated.
636
637
@param DevicePath A pointer to a device path data structure.
638
@param DevicePathInstance A pointer to a device path instance.
639
640
@return A pointer to the new device path.
641
642
**/
643
EFI_DEVICE_PATH_PROTOCOL *
644
EFIAPI
645
UefiDevicePathLibAppendDevicePathInstance (
646
IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath OPTIONAL,
647
IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePathInstance OPTIONAL
648
)
649
{
650
EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
651
EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
652
UINTN SrcSize;
653
UINTN InstanceSize;
654
655
if (DevicePath == NULL) {
656
return DuplicateDevicePath (DevicePathInstance);
657
}
658
659
if (DevicePathInstance == NULL) {
660
return NULL;
661
}
662
663
if (!IsDevicePathValid (DevicePath, 0) || !IsDevicePathValid (DevicePathInstance, 0)) {
664
return NULL;
665
}
666
667
SrcSize = GetDevicePathSize (DevicePath);
668
InstanceSize = GetDevicePathSize (DevicePathInstance);
669
670
NewDevicePath = AllocatePool (SrcSize + InstanceSize);
671
if (NewDevicePath != NULL) {
672
TempDevicePath = CopyMem (NewDevicePath, DevicePath, SrcSize);
673
674
while (!IsDevicePathEnd (TempDevicePath)) {
675
TempDevicePath = NextDevicePathNode (TempDevicePath);
676
}
677
678
TempDevicePath->SubType = END_INSTANCE_DEVICE_PATH_SUBTYPE;
679
TempDevicePath = NextDevicePathNode (TempDevicePath);
680
CopyMem (TempDevicePath, DevicePathInstance, InstanceSize);
681
}
682
683
return NewDevicePath;
684
}
685
686
/**
687
Creates a copy of the current device path instance and returns a pointer to the next device path
688
instance.
689
690
This function creates a copy of the current device path instance. It also updates
691
DevicePath to point to the next device path instance in the device path (or NULL
692
if no more) and updates Size to hold the size of the device path instance copy.
693
If DevicePath is NULL, then NULL is returned.
694
If DevicePath points to a invalid device path, then NULL is returned.
695
If there is not enough memory to allocate space for the new device path, then
696
NULL is returned.
697
The memory is allocated from EFI boot services memory. It is the responsibility
698
of the caller to free the memory allocated.
699
If Size is NULL, then ASSERT().
700
701
@param DevicePath On input, this holds the pointer to the current
702
device path instance. On output, this holds
703
the pointer to the next device path instance
704
or NULL if there are no more device path
705
instances in the device path pointer to a
706
device path data structure.
707
@param Size On output, this holds the size of the device
708
path instance, in bytes or zero, if DevicePath
709
is NULL.
710
711
@return A pointer to the current device path instance.
712
713
**/
714
EFI_DEVICE_PATH_PROTOCOL *
715
EFIAPI
716
UefiDevicePathLibGetNextDevicePathInstance (
717
IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath,
718
OUT UINTN *Size
719
)
720
{
721
EFI_DEVICE_PATH_PROTOCOL *DevPath;
722
EFI_DEVICE_PATH_PROTOCOL *ReturnValue;
723
UINT8 Temp;
724
725
ASSERT (Size != NULL);
726
727
if ((DevicePath == NULL) || (*DevicePath == NULL)) {
728
*Size = 0;
729
return NULL;
730
}
731
732
if (!IsDevicePathValid (*DevicePath, 0)) {
733
return NULL;
734
}
735
736
//
737
// Find the end of the device path instance
738
//
739
DevPath = *DevicePath;
740
while (!IsDevicePathEndType (DevPath)) {
741
DevPath = NextDevicePathNode (DevPath);
742
}
743
744
//
745
// Compute the size of the device path instance
746
//
747
*Size = ((UINTN)DevPath - (UINTN)(*DevicePath)) + sizeof (EFI_DEVICE_PATH_PROTOCOL);
748
749
//
750
// Make a copy and return the device path instance
751
//
752
Temp = DevPath->SubType;
753
DevPath->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;
754
ReturnValue = DuplicateDevicePath (*DevicePath);
755
DevPath->SubType = Temp;
756
757
//
758
// If DevPath is the end of an entire device path, then another instance
759
// does not follow, so *DevicePath is set to NULL.
760
//
761
if (DevicePathSubType (DevPath) == END_ENTIRE_DEVICE_PATH_SUBTYPE) {
762
*DevicePath = NULL;
763
} else {
764
*DevicePath = NextDevicePathNode (DevPath);
765
}
766
767
return ReturnValue;
768
}
769
#endif
770
771
/**
772
Creates a device node.
773
774
This function creates a new device node in a newly allocated buffer of size
775
NodeLength and initializes the device path node header with NodeType and NodeSubType.
776
The new device path node is returned.
777
If NodeLength is smaller than a device path header, then NULL is returned.
778
If there is not enough memory to allocate space for the new device path, then
779
NULL is returned.
780
The memory is allocated from EFI boot services memory. It is the responsibility
781
of the caller to free the memory allocated.
782
783
@param NodeType The device node type for the new device node.
784
@param NodeSubType The device node sub-type for the new device node.
785
@param NodeLength The length of the new device node.
786
787
@return The new device path.
788
789
**/
790
EFI_DEVICE_PATH_PROTOCOL *
791
EFIAPI
792
CreateDeviceNode (
793
IN UINT8 NodeType,
794
IN UINT8 NodeSubType,
795
IN UINT16 NodeLength
796
)
797
{
798
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
799
800
if (NodeLength < sizeof (EFI_DEVICE_PATH_PROTOCOL)) {
801
//
802
// NodeLength is less than the size of the header.
803
//
804
return NULL;
805
}
806
807
DevicePath = AllocateZeroPool (NodeLength);
808
if (DevicePath != NULL) {
809
DevicePath->Type = NodeType;
810
DevicePath->SubType = NodeSubType;
811
SetDevicePathNodeLength (DevicePath, NodeLength);
812
}
813
814
return DevicePath;
815
}
816
817
#ifndef __FreeBSD__
818
/**
819
Determines if a device path is single or multi-instance.
820
821
This function returns TRUE if the device path specified by DevicePath is
822
multi-instance.
823
Otherwise, FALSE is returned.
824
If DevicePath is NULL or invalid, then FALSE is returned.
825
826
@param DevicePath A pointer to a device path data structure.
827
828
@retval TRUE DevicePath is multi-instance.
829
@retval FALSE DevicePath is not multi-instance, or DevicePath
830
is NULL or invalid.
831
832
**/
833
BOOLEAN
834
EFIAPI
835
UefiDevicePathLibIsDevicePathMultiInstance (
836
IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath
837
)
838
{
839
CONST EFI_DEVICE_PATH_PROTOCOL *Node;
840
841
if (DevicePath == NULL) {
842
return FALSE;
843
}
844
845
if (!IsDevicePathValid (DevicePath, 0)) {
846
return FALSE;
847
}
848
849
Node = DevicePath;
850
while (!IsDevicePathEnd (Node)) {
851
if (IsDevicePathEndInstance (Node)) {
852
return TRUE;
853
}
854
855
Node = NextDevicePathNode (Node);
856
}
857
858
return FALSE;
859
}
860
861
/**
862
Allocates a device path for a file and appends it to an existing device path.
863
864
If Device is a valid device handle that contains a device path protocol, then a device path for
865
the file specified by FileName is allocated and appended to the device path associated with the
866
handle Device. The allocated device path is returned. If Device is NULL or Device is a handle
867
that does not support the device path protocol, then a device path containing a single device
868
path node for the file specified by FileName is allocated and returned.
869
The memory for the new device path is allocated from EFI boot services memory. It is the responsibility
870
of the caller to free the memory allocated.
871
872
If FileName is NULL, then ASSERT().
873
If FileName is not aligned on a 16-bit boundary, then ASSERT().
874
875
@param Device A pointer to a device handle. This parameter
876
is optional and may be NULL.
877
@param FileName A pointer to a Null-terminated Unicode string.
878
879
@return The allocated device path.
880
881
**/
882
EFI_DEVICE_PATH_PROTOCOL *
883
EFIAPI
884
FileDevicePath (
885
IN EFI_HANDLE Device OPTIONAL,
886
IN CONST CHAR16 *FileName
887
)
888
{
889
UINTN Size;
890
FILEPATH_DEVICE_PATH *FilePath;
891
EFI_DEVICE_PATH_PROTOCOL *DevicePath;
892
EFI_DEVICE_PATH_PROTOCOL *FileDevicePath;
893
894
DevicePath = NULL;
895
896
Size = StrSize (FileName);
897
FileDevicePath = AllocatePool (Size + SIZE_OF_FILEPATH_DEVICE_PATH + END_DEVICE_PATH_LENGTH);
898
if (FileDevicePath != NULL) {
899
FilePath = (FILEPATH_DEVICE_PATH *)FileDevicePath;
900
FilePath->Header.Type = MEDIA_DEVICE_PATH;
901
FilePath->Header.SubType = MEDIA_FILEPATH_DP;
902
CopyMem (&FilePath->PathName, FileName, Size);
903
SetDevicePathNodeLength (&FilePath->Header, Size + SIZE_OF_FILEPATH_DEVICE_PATH);
904
SetDevicePathEndNode (NextDevicePathNode (&FilePath->Header));
905
906
if (Device != NULL) {
907
DevicePath = DevicePathFromHandle (Device);
908
}
909
910
DevicePath = AppendDevicePath (DevicePath, FileDevicePath);
911
FreePool (FileDevicePath);
912
}
913
914
return DevicePath;
915
}
916
#endif
917
918