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