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
IsDevicePathValid(IN CONST EFI_DEVICE_PATH_PROTOCOL * DevicePath,IN UINTN MaxSize)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
DevicePathType(IN CONST VOID * Node)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
DevicePathSubType(IN CONST VOID * Node)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
DevicePathNodeLength(IN CONST VOID * Node)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
NextDevicePathNode(IN CONST VOID * Node)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
IsDevicePathEndType(IN CONST VOID * Node)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
IsDevicePathEnd(IN CONST VOID * Node)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
IsDevicePathEndInstance(IN CONST VOID * Node)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
SetDevicePathNodeLength(IN OUT VOID * Node,IN UINTN Length)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
SetDevicePathEndNode(OUT VOID * Node)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
GetDevicePathSize(IN CONST EFI_DEVICE_PATH_PROTOCOL * DevicePath)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
DuplicateDevicePath(IN CONST EFI_DEVICE_PATH_PROTOCOL * DevicePath)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
AppendDevicePath(IN CONST EFI_DEVICE_PATH_PROTOCOL * FirstDevicePath OPTIONAL,IN CONST EFI_DEVICE_PATH_PROTOCOL * SecondDevicePath OPTIONAL)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
AppendDevicePathNode(IN CONST EFI_DEVICE_PATH_PROTOCOL * DevicePath OPTIONAL,IN CONST EFI_DEVICE_PATH_PROTOCOL * DevicePathNode OPTIONAL)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
UefiDevicePathLibAppendDevicePathInstance(IN CONST EFI_DEVICE_PATH_PROTOCOL * DevicePath OPTIONAL,IN CONST EFI_DEVICE_PATH_PROTOCOL * DevicePathInstance OPTIONAL)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
UefiDevicePathLibGetNextDevicePathInstance(IN OUT EFI_DEVICE_PATH_PROTOCOL ** DevicePath,OUT UINTN * Size)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
CreateDeviceNode(IN UINT8 NodeType,IN UINT8 NodeSubType,IN UINT16 NodeLength)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
UefiDevicePathLibIsDevicePathMultiInstance(IN CONST EFI_DEVICE_PATH_PROTOCOL * DevicePath)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
FileDevicePath(IN EFI_HANDLE Device OPTIONAL,IN CONST CHAR16 * FileName)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