xref: /freebsd/lib/libefivar/uefi-dputil.c (revision 259eac0149f0d2c01e1fcbeba3be1ba6fca6f8e1)
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 
37 #include "efi-osdep.h"
38 
39 #include "uefi-dplib.h"
40 
41 /* XXX maybe I should include the entire DevicePathUtiltiies.c and ifdef out what we don't use */
42 
43 /*
44  * Taken from MdePkg/Library/UefiDevicePathLib/DevicePathUtilities.c
45  * hash a11928f3310518ab1c6fd34e8d0fdbb72de9602c 2017-Mar-01
46  */
47 
48 /** @file
49   Device Path services. The thing to remember is device paths are built out of
50   nodes. The device path is terminated by an end node that is length
51   sizeof(EFI_DEVICE_PATH_PROTOCOL). That would be why there is sizeof(EFI_DEVICE_PATH_PROTOCOL)
52   all over this file.
53 
54   The only place where multi-instance device paths are supported is in
55   environment varibles. Multi-instance device paths should never be placed
56   on a Handle.
57 
58   Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
59   This program and the accompanying materials
60   are licensed and made available under the terms and conditions of the BSD License
61   which accompanies this distribution.  The full text of the license may be found at
62   http://opensource.org/licenses/bsd-license.php.
63 
64   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
65   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
66 
67 **/
68 
69 //
70 // Template for an end-of-device path node.
71 //
72 static CONST EFI_DEVICE_PATH_PROTOCOL  mUefiDevicePathLibEndDevicePath = {
73   END_DEVICE_PATH_TYPE,
74   END_ENTIRE_DEVICE_PATH_SUBTYPE,
75   {
76     END_DEVICE_PATH_LENGTH,
77     0
78   }
79 };
80 
81 
82 /**
83   Returns the size of a device path in bytes.
84 
85   This function returns the size, in bytes, of the device path data structure
86   specified by DevicePath including the end of device path node.
87   If DevicePath is NULL or invalid, then 0 is returned.
88 
89   @param  DevicePath  A pointer to a device path data structure.
90 
91   @retval 0           If DevicePath is NULL or invalid.
92   @retval Others      The size of a device path in bytes.
93 
94 **/
95 UINTN
96 EFIAPI
GetDevicePathSize(IN CONST EFI_DEVICE_PATH_PROTOCOL * DevicePath)97 GetDevicePathSize (
98   IN CONST EFI_DEVICE_PATH_PROTOCOL  *DevicePath
99   )
100 {
101   CONST EFI_DEVICE_PATH_PROTOCOL  *Start;
102 
103   if (DevicePath == NULL) {
104     return 0;
105   }
106 
107   if (!IsDevicePathValid (DevicePath, 0)) {
108     return 0;
109   }
110 
111   //
112   // Search for the end of the device path structure
113   //
114   Start = DevicePath;
115   while (!IsDevicePathEnd (DevicePath)) {
116     DevicePath = NextDevicePathNode (DevicePath);
117   }
118 
119   //
120   // Compute the size and add back in the size of the end device path structure
121   //
122   return ((UINTN) DevicePath - (UINTN) Start) + DevicePathNodeLength (DevicePath);
123 }
124 
125 /**
126   Determine whether a given device path is valid.
127   If DevicePath is NULL, then ASSERT().
128 
129   @param  DevicePath  A pointer to a device path data structure.
130   @param  MaxSize     The maximum size of the device path data structure.
131 
132   @retval TRUE        DevicePath is valid.
133   @retval FALSE       The length of any node in the DevicePath is less
134                       than sizeof (EFI_DEVICE_PATH_PROTOCOL).
135   @retval FALSE       If MaxSize is not zero, the size of the DevicePath
136                       exceeds MaxSize.
137   @retval FALSE       If PcdMaximumDevicePathNodeCount is not zero, the node
138                       count of the DevicePath exceeds PcdMaximumDevicePathNodeCount.
139 **/
140 BOOLEAN
141 EFIAPI
IsDevicePathValid(IN CONST EFI_DEVICE_PATH_PROTOCOL * DevicePath,IN UINTN MaxSize)142 IsDevicePathValid (
143   IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,
144   IN       UINTN                    MaxSize
145   )
146 {
147   UINTN Count;
148   UINTN Size;
149   UINTN NodeLength;
150 
151   ASSERT (DevicePath != NULL);
152 
153   if (MaxSize == 0) {
154     MaxSize = MAX_UINTN;
155   }
156 
157   //
158   // Validate the input size big enough to touch the first node.
159   //
160   if (MaxSize < sizeof (EFI_DEVICE_PATH_PROTOCOL)) {
161     return FALSE;
162   }
163 
164   for (Count = 0, Size = 0; !IsDevicePathEnd (DevicePath); DevicePath = NextDevicePathNode (DevicePath)) {
165     NodeLength = DevicePathNodeLength (DevicePath);
166     if (NodeLength < sizeof (EFI_DEVICE_PATH_PROTOCOL)) {
167       return FALSE;
168     }
169 
170     if (NodeLength > MAX_UINTN - Size) {
171       return FALSE;
172     }
173     Size += NodeLength;
174 
175     //
176     // Validate next node before touch it.
177     //
178     if (Size > MaxSize - END_DEVICE_PATH_LENGTH ) {
179       return FALSE;
180     }
181 
182     if (PcdGet32 (PcdMaximumDevicePathNodeCount) > 0) {
183       Count++;
184       if (Count >= PcdGet32 (PcdMaximumDevicePathNodeCount)) {
185         return FALSE;
186       }
187     }
188   }
189 
190   //
191   // Only return TRUE when the End Device Path node is valid.
192   //
193   return (BOOLEAN) (DevicePathNodeLength (DevicePath) == END_DEVICE_PATH_LENGTH);
194 }
195 
196 /**
197   Returns the Type field of a device path node.
198 
199   Returns the Type field of the device path node specified by Node.
200 
201   If Node is NULL, then ASSERT().
202 
203   @param  Node      A pointer to a device path node data structure.
204 
205   @return The Type field of the device path node specified by Node.
206 
207 **/
208 UINT8
209 EFIAPI
DevicePathType(IN CONST VOID * Node)210 DevicePathType (
211   IN CONST VOID  *Node
212   )
213 {
214   ASSERT (Node != NULL);
215   return ((const EFI_DEVICE_PATH_PROTOCOL *)(Node))->Type;
216 }
217 
218 
219 /**
220   Returns the SubType field of a device path node.
221 
222   Returns the SubType field of the device path node specified by Node.
223 
224   If Node is NULL, then ASSERT().
225 
226   @param  Node      A pointer to a device path node data structure.
227 
228   @return The SubType field of the device path node specified by Node.
229 
230 **/
231 UINT8
232 EFIAPI
DevicePathSubType(IN CONST VOID * Node)233 DevicePathSubType (
234   IN CONST VOID  *Node
235   )
236 {
237   ASSERT (Node != NULL);
238   return ((const EFI_DEVICE_PATH_PROTOCOL *)(Node))->SubType;
239 }
240 
241 /**
242   Returns the 16-bit Length field of a device path node.
243 
244   Returns the 16-bit Length field of the device path node specified by Node.
245   Node is not required to be aligned on a 16-bit boundary, so it is recommended
246   that a function such as ReadUnaligned16() be used to extract the contents of
247   the Length field.
248 
249   If Node is NULL, then ASSERT().
250 
251   @param  Node      A pointer to a device path node data structure.
252 
253   @return The 16-bit Length field of the device path node specified by Node.
254 
255 **/
256 UINTN
257 EFIAPI
DevicePathNodeLength(IN CONST VOID * Node)258 DevicePathNodeLength (
259   IN CONST VOID  *Node
260   )
261 {
262   ASSERT (Node != NULL);
263   return ((const EFI_DEVICE_PATH_PROTOCOL *)Node)->Length[0] |
264       (((const EFI_DEVICE_PATH_PROTOCOL *)Node)->Length[1] << 8);
265 }
266 
267 /**
268   Returns a pointer to the next node in a device path.
269 
270   Returns a pointer to the device path node that follows the device path node
271   specified by Node.
272 
273   If Node is NULL, then ASSERT().
274 
275   @param  Node      A pointer to a device path node data structure.
276 
277   @return a pointer to the device path node that follows the device path node
278   specified by Node.
279 
280 **/
281 EFI_DEVICE_PATH_PROTOCOL *
282 EFIAPI
NextDevicePathNode(IN CONST VOID * Node)283 NextDevicePathNode (
284   IN CONST VOID  *Node
285   )
286 {
287   ASSERT (Node != NULL);
288   return ((EFI_DEVICE_PATH_PROTOCOL *)(__DECONST(UINT8 *, Node) + DevicePathNodeLength(Node)));
289 }
290 
291 /**
292   Determines if a device path node is an end node of a device path.
293   This includes nodes that are the end of a device path instance and nodes that
294   are the end of an entire device path.
295 
296   Determines if the device path node specified by Node is an end node of a device path.
297   This includes nodes that are the end of a device path instance and nodes that are the
298   end of an entire device path.  If Node represents an end node of a device path,
299   then TRUE is returned.  Otherwise, FALSE is returned.
300 
301   If Node is NULL, then ASSERT().
302 
303   @param  Node      A pointer to a device path node data structure.
304 
305   @retval TRUE      The device path node specified by Node is an end node of a
306                     device path.
307   @retval FALSE     The device path node specified by Node is not an end node of
308                     a device path.
309 
310 **/
311 BOOLEAN
312 EFIAPI
IsDevicePathEndType(IN CONST VOID * Node)313 IsDevicePathEndType (
314   IN CONST VOID  *Node
315   )
316 {
317   ASSERT (Node != NULL);
318   return (BOOLEAN) (DevicePathType (Node) == END_DEVICE_PATH_TYPE);
319 }
320 
321 /**
322   Determines if a device path node is an end node of an entire device path.
323 
324   Determines if a device path node specified by Node is an end node of an entire
325   device path. If Node represents the end of an entire device path, then TRUE is
326   returned.  Otherwise, FALSE is returned.
327 
328   If Node is NULL, then ASSERT().
329 
330   @param  Node      A pointer to a device path node data structure.
331 
332   @retval TRUE      The device path node specified by Node is the end of an entire
333                     device path.
334   @retval FALSE     The device path node specified by Node is not the end of an
335                     entire device path.
336 
337 **/
338 BOOLEAN
339 EFIAPI
IsDevicePathEnd(IN CONST VOID * Node)340 IsDevicePathEnd (
341   IN CONST VOID  *Node
342   )
343 {
344   ASSERT (Node != NULL);
345   return (BOOLEAN) (IsDevicePathEndType (Node) && DevicePathSubType(Node) == END_ENTIRE_DEVICE_PATH_SUBTYPE);
346 }
347 
348 /**
349   Fills in all the fields of a device path node that is the end of an entire device path.
350 
351   Fills in all the fields of a device path node specified by Node so Node represents
352   the end of an entire device path.  The Type field of Node is set to
353   END_DEVICE_PATH_TYPE, the SubType field of Node is set to
354   END_ENTIRE_DEVICE_PATH_SUBTYPE, and the Length field of Node is set to
355   END_DEVICE_PATH_LENGTH.  Node is not required to be aligned on a 16-bit boundary,
356   so it is recommended that a function such as WriteUnaligned16() be used to set
357   the contents of the Length field.
358 
359   If Node is NULL, then ASSERT().
360 
361   @param  Node      A pointer to a device path node data structure.
362 
363 **/
364 VOID
365 EFIAPI
SetDevicePathEndNode(OUT VOID * Node)366 SetDevicePathEndNode (
367   OUT VOID  *Node
368   )
369 {
370   ASSERT (Node != NULL);
371   memcpy (Node, &mUefiDevicePathLibEndDevicePath, sizeof (mUefiDevicePathLibEndDevicePath));
372 }
373 
374 /**
375   Sets the length, in bytes, of a device path node.
376 
377   Sets the length of the device path node specified by Node to the value specified
378   by NodeLength.  NodeLength is returned.  Node is not required to be aligned on
379   a 16-bit boundary, so it is recommended that a function such as WriteUnaligned16()
380   be used to set the contents of the Length field.
381 
382   If Node is NULL, then ASSERT().
383   If NodeLength >= SIZE_64KB, then ASSERT().
384   If NodeLength < sizeof (EFI_DEVICE_PATH_PROTOCOL), then ASSERT().
385 
386   @param  Node      A pointer to a device path node data structure.
387   @param  Length    The length, in bytes, of the device path node.
388 
389   @return Length
390 
391 **/
392 UINT16
393 EFIAPI
SetDevicePathNodeLength(IN OUT VOID * Node,IN UINTN Length)394 SetDevicePathNodeLength (
395   IN OUT VOID  *Node,
396   IN UINTN     Length
397   )
398 {
399   ASSERT (Node != NULL);
400   ASSERT ((Length >= sizeof (EFI_DEVICE_PATH_PROTOCOL)) && (Length < SIZE_64KB));
401 //  return WriteUnaligned16 ((UINT16 *)&((EFI_DEVICE_PATH_PROTOCOL *)(Node))->Length[0], (UINT16)(Length));
402   le16enc(&((EFI_DEVICE_PATH_PROTOCOL *)(Node))->Length[0], (UINT16)(Length));
403   return Length;
404 }
405 
406 /**
407   Creates a device node.
408 
409   This function creates a new device node in a newly allocated buffer of size
410   NodeLength and initializes the device path node header with NodeType and NodeSubType.
411   The new device path node is returned.
412   If NodeLength is smaller than a device path header, then NULL is returned.
413   If there is not enough memory to allocate space for the new device path, then
414   NULL is returned.
415   The memory is allocated from EFI boot services memory. It is the responsibility
416   of the caller to free the memory allocated.
417 
418   @param  NodeType                   The device node type for the new device node.
419   @param  NodeSubType                The device node sub-type for the new device node.
420   @param  NodeLength                 The length of the new device node.
421 
422   @return The new device path.
423 
424 **/
425 EFI_DEVICE_PATH_PROTOCOL *
426 EFIAPI
CreateDeviceNode(IN UINT8 NodeType,IN UINT8 NodeSubType,IN UINT16 NodeLength)427 CreateDeviceNode (
428   IN UINT8                           NodeType,
429   IN UINT8                           NodeSubType,
430   IN UINT16                          NodeLength
431   )
432 {
433   EFI_DEVICE_PATH_PROTOCOL      *DevicePath;
434 
435   if (NodeLength < sizeof (EFI_DEVICE_PATH_PROTOCOL)) {
436     //
437     // NodeLength is less than the size of the header.
438     //
439     return NULL;
440   }
441 
442   DevicePath = AllocateZeroPool (NodeLength);
443   if (DevicePath != NULL) {
444      DevicePath->Type    = NodeType;
445      DevicePath->SubType = NodeSubType;
446      SetDevicePathNodeLength (DevicePath, NodeLength);
447   }
448 
449   return DevicePath;
450 }
451 
452 /**
453   Creates a new copy of an existing device path.
454 
455   This function allocates space for a new copy of the device path specified by DevicePath.
456   If DevicePath is NULL, then NULL is returned.  If the memory is successfully
457   allocated, then the contents of DevicePath are copied to the newly allocated
458   buffer, and a pointer to that buffer is returned.  Otherwise, NULL is returned.
459   The memory for the new device path is allocated from EFI boot services memory.
460   It is the responsibility of the caller to free the memory allocated.
461 
462   @param  DevicePath    A pointer to a device path data structure.
463 
464   @retval NULL          DevicePath is NULL or invalid.
465   @retval Others        A pointer to the duplicated device path.
466 
467 **/
468 EFI_DEVICE_PATH_PROTOCOL *
469 EFIAPI
DuplicateDevicePath(IN CONST EFI_DEVICE_PATH_PROTOCOL * DevicePath)470 DuplicateDevicePath (
471   IN CONST EFI_DEVICE_PATH_PROTOCOL  *DevicePath
472   )
473 {
474   UINTN                     Size;
475 
476   //
477   // Compute the size
478   //
479   Size = GetDevicePathSize (DevicePath);
480   if (Size == 0) {
481     return NULL;
482   }
483 
484   //
485   // Allocate space for duplicate device path
486   //
487 
488   return AllocateCopyPool (Size, DevicePath);
489 }
490 
491 /**
492   Creates a new device path by appending a second device path to a first device path.
493 
494   This function creates a new device path by appending a copy of SecondDevicePath
495   to a copy of FirstDevicePath in a newly allocated buffer.  Only the end-of-device-path
496   device node from SecondDevicePath is retained. The newly created device path is
497   returned. If FirstDevicePath is NULL, then it is ignored, and a duplicate of
498   SecondDevicePath is returned.  If SecondDevicePath is NULL, then it is ignored,
499   and a duplicate of FirstDevicePath is returned. If both FirstDevicePath and
500   SecondDevicePath are NULL, then a copy of an end-of-device-path is returned.
501 
502   If there is not enough memory for the newly allocated buffer, then NULL is returned.
503   The memory for the new device path is allocated from EFI boot services memory.
504   It is the responsibility of the caller to free the memory allocated.
505 
506   @param  FirstDevicePath            A pointer to a device path data structure.
507   @param  SecondDevicePath           A pointer to a device path data structure.
508 
509   @retval NULL      If there is not enough memory for the newly allocated buffer.
510   @retval NULL      If FirstDevicePath or SecondDevicePath is invalid.
511   @retval Others    A pointer to the new device path if success.
512                     Or a copy an end-of-device-path if both FirstDevicePath and SecondDevicePath are NULL.
513 
514 **/
515 EFI_DEVICE_PATH_PROTOCOL *
516 EFIAPI
AppendDevicePath(IN CONST EFI_DEVICE_PATH_PROTOCOL * FirstDevicePath,OPTIONAL IN CONST EFI_DEVICE_PATH_PROTOCOL * SecondDevicePath OPTIONAL)517 AppendDevicePath (
518   IN CONST EFI_DEVICE_PATH_PROTOCOL  *FirstDevicePath,  OPTIONAL
519   IN CONST EFI_DEVICE_PATH_PROTOCOL  *SecondDevicePath  OPTIONAL
520   )
521 {
522   UINTN                     Size;
523   UINTN                     Size1;
524   UINTN                     Size2;
525   EFI_DEVICE_PATH_PROTOCOL  *NewDevicePath;
526   EFI_DEVICE_PATH_PROTOCOL  *DevicePath2;
527 
528   //
529   // If there's only 1 path, just duplicate it.
530   //
531   if (FirstDevicePath == NULL) {
532     return DuplicateDevicePath ((SecondDevicePath != NULL) ? SecondDevicePath : &mUefiDevicePathLibEndDevicePath);
533   }
534 
535   if (SecondDevicePath == NULL) {
536     return DuplicateDevicePath (FirstDevicePath);
537   }
538 
539   if (!IsDevicePathValid (FirstDevicePath, 0) || !IsDevicePathValid (SecondDevicePath, 0)) {
540     return NULL;
541   }
542 
543   //
544   // Allocate space for the combined device path. It only has one end node of
545   // length EFI_DEVICE_PATH_PROTOCOL.
546   //
547   Size1         = GetDevicePathSize (FirstDevicePath);
548   Size2         = GetDevicePathSize (SecondDevicePath);
549   Size          = Size1 + Size2 - END_DEVICE_PATH_LENGTH;
550 
551   NewDevicePath = AllocatePool (Size);
552 
553   if (NewDevicePath != NULL) {
554     NewDevicePath = CopyMem (NewDevicePath, FirstDevicePath, Size1);
555     //
556     // Over write FirstDevicePath EndNode and do the copy
557     //
558     DevicePath2 = (EFI_DEVICE_PATH_PROTOCOL *) ((CHAR8 *) NewDevicePath +
559                   (Size1 - END_DEVICE_PATH_LENGTH));
560     CopyMem (DevicePath2, SecondDevicePath, Size2);
561   }
562 
563   return NewDevicePath;
564 }
565 
566 /**
567   Creates a new path by appending the device node to the device path.
568 
569   This function creates a new device path by appending a copy of the device node
570   specified by DevicePathNode to a copy of the device path specified by DevicePath
571   in an allocated buffer. The end-of-device-path device node is moved after the
572   end of the appended device node.
573   If DevicePathNode is NULL then a copy of DevicePath is returned.
574   If DevicePath is NULL then a copy of DevicePathNode, followed by an end-of-device
575   path device node is returned.
576   If both DevicePathNode and DevicePath are NULL then a copy of an end-of-device-path
577   device node 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  DevicePathNode             A pointer to a single device path node.
585 
586   @retval NULL      If there is not enough memory for the new device path.
587   @retval Others    A pointer to the new device path if success.
588                     A copy of DevicePathNode followed by an end-of-device-path node
589                     if both FirstDevicePath and SecondDevicePath are NULL.
590                     A copy of an end-of-device-path node if both FirstDevicePath
591                     and SecondDevicePath are NULL.
592 
593 **/
594 EFI_DEVICE_PATH_PROTOCOL *
595 EFIAPI
AppendDevicePathNode(IN CONST EFI_DEVICE_PATH_PROTOCOL * DevicePath,OPTIONAL IN CONST EFI_DEVICE_PATH_PROTOCOL * DevicePathNode OPTIONAL)596 AppendDevicePathNode (
597   IN CONST EFI_DEVICE_PATH_PROTOCOL  *DevicePath,     OPTIONAL
598   IN CONST EFI_DEVICE_PATH_PROTOCOL  *DevicePathNode  OPTIONAL
599   )
600 {
601   EFI_DEVICE_PATH_PROTOCOL  *TempDevicePath;
602   EFI_DEVICE_PATH_PROTOCOL  *NextNode;
603   EFI_DEVICE_PATH_PROTOCOL  *NewDevicePath;
604   UINTN                     NodeLength;
605 
606   if (DevicePathNode == NULL) {
607     return DuplicateDevicePath ((DevicePath != NULL) ? DevicePath : &mUefiDevicePathLibEndDevicePath);
608   }
609   //
610   // Build a Node that has a terminator on it
611   //
612   NodeLength = DevicePathNodeLength (DevicePathNode);
613 
614   TempDevicePath = AllocatePool (NodeLength + END_DEVICE_PATH_LENGTH);
615   if (TempDevicePath == NULL) {
616     return NULL;
617   }
618   TempDevicePath = CopyMem (TempDevicePath, DevicePathNode, NodeLength);
619   //
620   // Add and end device path node to convert Node to device path
621   //
622   NextNode = NextDevicePathNode (TempDevicePath);
623   SetDevicePathEndNode (NextNode);
624   //
625   // Append device paths
626   //
627   NewDevicePath = AppendDevicePath (DevicePath, TempDevicePath);
628 
629   FreePool (TempDevicePath);
630 
631   return NewDevicePath;
632 }
633