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