17270962aSWarner Losh /*-
27270962aSWarner Losh * Copyright (c) 2017 Netflix, Inc.
37270962aSWarner Losh *
47270962aSWarner Losh * Redistribution and use in source and binary forms, with or without
57270962aSWarner Losh * modification, are permitted provided that the following conditions
67270962aSWarner Losh * are met:
77270962aSWarner Losh * 1. Redistributions of source code must retain the above copyright
86decf2ccSEd Maste * notice, this list of conditions and the following disclaimer.
97270962aSWarner Losh * 2. Redistributions in binary form must reproduce the above copyright
107270962aSWarner Losh * notice, this list of conditions and the following disclaimer in the
117270962aSWarner Losh * documentation and/or other materials provided with the distribution.
127270962aSWarner Losh *
136decf2ccSEd Maste * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
146decf2ccSEd Maste * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
156decf2ccSEd Maste * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
166decf2ccSEd Maste * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
176decf2ccSEd Maste * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
186decf2ccSEd Maste * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
196decf2ccSEd Maste * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
206decf2ccSEd Maste * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
216decf2ccSEd Maste * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
226decf2ccSEd Maste * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
236decf2ccSEd Maste * SUCH DAMAGE.
247270962aSWarner Losh */
257270962aSWarner Losh
267270962aSWarner Losh /*
277270962aSWarner Losh * Routines to format EFI_DEVICE_PATHs from the UEFI standard. Much of
287270962aSWarner Losh * this file is taken from EDK2 and rototilled.
297270962aSWarner Losh */
307270962aSWarner Losh
317270962aSWarner Losh #include <sys/cdefs.h>
327270962aSWarner Losh #include <efivar.h>
337270962aSWarner Losh #include <limits.h>
347270962aSWarner Losh #include <stdio.h>
357270962aSWarner Losh #include <string.h>
367270962aSWarner Losh #include <sys/endian.h>
377270962aSWarner Losh
387270962aSWarner Losh #include "efi-osdep.h"
397270962aSWarner Losh
407270962aSWarner Losh #include "uefi-dplib.h"
417270962aSWarner Losh
424c69a17fSWarner Losh /* XXX maybe I should include the entire DevicePathUtiltiies.c and ifdef out what we don't use */
437270962aSWarner Losh
447270962aSWarner Losh /*
457270962aSWarner Losh * Taken from MdePkg/Library/UefiDevicePathLib/DevicePathUtilities.c
467270962aSWarner Losh * hash a11928f3310518ab1c6fd34e8d0fdbb72de9602c 2017-Mar-01
477270962aSWarner Losh */
487270962aSWarner Losh
497270962aSWarner Losh /** @file
507270962aSWarner Losh Device Path services. The thing to remember is device paths are built out of
517270962aSWarner Losh nodes. The device path is terminated by an end node that is length
527270962aSWarner Losh sizeof(EFI_DEVICE_PATH_PROTOCOL). That would be why there is sizeof(EFI_DEVICE_PATH_PROTOCOL)
537270962aSWarner Losh all over this file.
547270962aSWarner Losh
557270962aSWarner Losh The only place where multi-instance device paths are supported is in
567270962aSWarner Losh environment varibles. Multi-instance device paths should never be placed
577270962aSWarner Losh on a Handle.
587270962aSWarner Losh
597270962aSWarner Losh Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
607270962aSWarner Losh This program and the accompanying materials
617270962aSWarner Losh are licensed and made available under the terms and conditions of the BSD License
627270962aSWarner Losh which accompanies this distribution. The full text of the license may be found at
637270962aSWarner Losh http://opensource.org/licenses/bsd-license.php.
647270962aSWarner Losh
657270962aSWarner Losh THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
667270962aSWarner Losh WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
677270962aSWarner Losh
687270962aSWarner Losh **/
697270962aSWarner Losh
707270962aSWarner Losh //
717270962aSWarner Losh // Template for an end-of-device path node.
727270962aSWarner Losh //
737270962aSWarner Losh static CONST EFI_DEVICE_PATH_PROTOCOL mUefiDevicePathLibEndDevicePath = {
747270962aSWarner Losh END_DEVICE_PATH_TYPE,
757270962aSWarner Losh END_ENTIRE_DEVICE_PATH_SUBTYPE,
767270962aSWarner Losh {
777270962aSWarner Losh END_DEVICE_PATH_LENGTH,
787270962aSWarner Losh 0
797270962aSWarner Losh }
807270962aSWarner Losh };
817270962aSWarner Losh
827270962aSWarner Losh
837270962aSWarner Losh /**
847270962aSWarner Losh Returns the size of a device path in bytes.
857270962aSWarner Losh
867270962aSWarner Losh This function returns the size, in bytes, of the device path data structure
877270962aSWarner Losh specified by DevicePath including the end of device path node.
887270962aSWarner Losh If DevicePath is NULL or invalid, then 0 is returned.
897270962aSWarner Losh
907270962aSWarner Losh @param DevicePath A pointer to a device path data structure.
917270962aSWarner Losh
927270962aSWarner Losh @retval 0 If DevicePath is NULL or invalid.
937270962aSWarner Losh @retval Others The size of a device path in bytes.
947270962aSWarner Losh
957270962aSWarner Losh **/
967270962aSWarner Losh UINTN
977270962aSWarner Losh EFIAPI
GetDevicePathSize(IN CONST EFI_DEVICE_PATH_PROTOCOL * DevicePath)987270962aSWarner Losh GetDevicePathSize (
997270962aSWarner Losh IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath
1007270962aSWarner Losh )
1017270962aSWarner Losh {
1027270962aSWarner Losh CONST EFI_DEVICE_PATH_PROTOCOL *Start;
1037270962aSWarner Losh
1047270962aSWarner Losh if (DevicePath == NULL) {
1057270962aSWarner Losh return 0;
1067270962aSWarner Losh }
1077270962aSWarner Losh
1087270962aSWarner Losh if (!IsDevicePathValid (DevicePath, 0)) {
1097270962aSWarner Losh return 0;
1107270962aSWarner Losh }
1117270962aSWarner Losh
1127270962aSWarner Losh //
1137270962aSWarner Losh // Search for the end of the device path structure
1147270962aSWarner Losh //
1157270962aSWarner Losh Start = DevicePath;
1167270962aSWarner Losh while (!IsDevicePathEnd (DevicePath)) {
1177270962aSWarner Losh DevicePath = NextDevicePathNode (DevicePath);
1187270962aSWarner Losh }
1197270962aSWarner Losh
1207270962aSWarner Losh //
1217270962aSWarner Losh // Compute the size and add back in the size of the end device path structure
1227270962aSWarner Losh //
1237270962aSWarner Losh return ((UINTN) DevicePath - (UINTN) Start) + DevicePathNodeLength (DevicePath);
1247270962aSWarner Losh }
1257270962aSWarner Losh
1267270962aSWarner Losh /**
1277270962aSWarner Losh Determine whether a given device path is valid.
1287270962aSWarner Losh If DevicePath is NULL, then ASSERT().
1297270962aSWarner Losh
1307270962aSWarner Losh @param DevicePath A pointer to a device path data structure.
1317270962aSWarner Losh @param MaxSize The maximum size of the device path data structure.
1327270962aSWarner Losh
1337270962aSWarner Losh @retval TRUE DevicePath is valid.
134d52a982eSEitan Adler @retval FALSE The length of any node in the DevicePath is less
1357270962aSWarner Losh than sizeof (EFI_DEVICE_PATH_PROTOCOL).
1367270962aSWarner Losh @retval FALSE If MaxSize is not zero, the size of the DevicePath
1377270962aSWarner Losh exceeds MaxSize.
1387270962aSWarner Losh @retval FALSE If PcdMaximumDevicePathNodeCount is not zero, the node
1397270962aSWarner Losh count of the DevicePath exceeds PcdMaximumDevicePathNodeCount.
1407270962aSWarner Losh **/
1417270962aSWarner Losh BOOLEAN
1427270962aSWarner Losh EFIAPI
IsDevicePathValid(IN CONST EFI_DEVICE_PATH_PROTOCOL * DevicePath,IN UINTN MaxSize)1437270962aSWarner Losh IsDevicePathValid (
1447270962aSWarner Losh IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,
1457270962aSWarner Losh IN UINTN MaxSize
1467270962aSWarner Losh )
1477270962aSWarner Losh {
1487270962aSWarner Losh UINTN Count;
1497270962aSWarner Losh UINTN Size;
1507270962aSWarner Losh UINTN NodeLength;
1517270962aSWarner Losh
1527270962aSWarner Losh ASSERT (DevicePath != NULL);
1537270962aSWarner Losh
1547270962aSWarner Losh if (MaxSize == 0) {
1557270962aSWarner Losh MaxSize = MAX_UINTN;
1567270962aSWarner Losh }
1577270962aSWarner Losh
1587270962aSWarner Losh //
1597270962aSWarner Losh // Validate the input size big enough to touch the first node.
1607270962aSWarner Losh //
1617270962aSWarner Losh if (MaxSize < sizeof (EFI_DEVICE_PATH_PROTOCOL)) {
1627270962aSWarner Losh return FALSE;
1637270962aSWarner Losh }
1647270962aSWarner Losh
1657270962aSWarner Losh for (Count = 0, Size = 0; !IsDevicePathEnd (DevicePath); DevicePath = NextDevicePathNode (DevicePath)) {
1667270962aSWarner Losh NodeLength = DevicePathNodeLength (DevicePath);
1677270962aSWarner Losh if (NodeLength < sizeof (EFI_DEVICE_PATH_PROTOCOL)) {
1687270962aSWarner Losh return FALSE;
1697270962aSWarner Losh }
1707270962aSWarner Losh
1717270962aSWarner Losh if (NodeLength > MAX_UINTN - Size) {
1727270962aSWarner Losh return FALSE;
1737270962aSWarner Losh }
1747270962aSWarner Losh Size += NodeLength;
1757270962aSWarner Losh
1767270962aSWarner Losh //
1777270962aSWarner Losh // Validate next node before touch it.
1787270962aSWarner Losh //
1797270962aSWarner Losh if (Size > MaxSize - END_DEVICE_PATH_LENGTH ) {
1807270962aSWarner Losh return FALSE;
1817270962aSWarner Losh }
1827270962aSWarner Losh
1837270962aSWarner Losh if (PcdGet32 (PcdMaximumDevicePathNodeCount) > 0) {
1847270962aSWarner Losh Count++;
1857270962aSWarner Losh if (Count >= PcdGet32 (PcdMaximumDevicePathNodeCount)) {
1867270962aSWarner Losh return FALSE;
1877270962aSWarner Losh }
1887270962aSWarner Losh }
1897270962aSWarner Losh }
1907270962aSWarner Losh
1917270962aSWarner Losh //
1927270962aSWarner Losh // Only return TRUE when the End Device Path node is valid.
1937270962aSWarner Losh //
1947270962aSWarner Losh return (BOOLEAN) (DevicePathNodeLength (DevicePath) == END_DEVICE_PATH_LENGTH);
1957270962aSWarner Losh }
1967270962aSWarner Losh
1977270962aSWarner Losh /**
1987270962aSWarner Losh Returns the Type field of a device path node.
1997270962aSWarner Losh
2007270962aSWarner Losh Returns the Type field of the device path node specified by Node.
2017270962aSWarner Losh
2027270962aSWarner Losh If Node is NULL, then ASSERT().
2037270962aSWarner Losh
2047270962aSWarner Losh @param Node A pointer to a device path node data structure.
2057270962aSWarner Losh
2067270962aSWarner Losh @return The Type field of the device path node specified by Node.
2077270962aSWarner Losh
2087270962aSWarner Losh **/
2097270962aSWarner Losh UINT8
2107270962aSWarner Losh EFIAPI
DevicePathType(IN CONST VOID * Node)2117270962aSWarner Losh DevicePathType (
2127270962aSWarner Losh IN CONST VOID *Node
2137270962aSWarner Losh )
2147270962aSWarner Losh {
2157270962aSWarner Losh ASSERT (Node != NULL);
2167270962aSWarner Losh return ((const EFI_DEVICE_PATH_PROTOCOL *)(Node))->Type;
2177270962aSWarner Losh }
2187270962aSWarner Losh
2197270962aSWarner Losh
2207270962aSWarner Losh /**
2217270962aSWarner Losh Returns the SubType field of a device path node.
2227270962aSWarner Losh
2237270962aSWarner Losh Returns the SubType field of the device path node specified by Node.
2247270962aSWarner Losh
2257270962aSWarner Losh If Node is NULL, then ASSERT().
2267270962aSWarner Losh
2277270962aSWarner Losh @param Node A pointer to a device path node data structure.
2287270962aSWarner Losh
2297270962aSWarner Losh @return The SubType field of the device path node specified by Node.
2307270962aSWarner Losh
2317270962aSWarner Losh **/
2327270962aSWarner Losh UINT8
2337270962aSWarner Losh EFIAPI
DevicePathSubType(IN CONST VOID * Node)2347270962aSWarner Losh DevicePathSubType (
2357270962aSWarner Losh IN CONST VOID *Node
2367270962aSWarner Losh )
2377270962aSWarner Losh {
2387270962aSWarner Losh ASSERT (Node != NULL);
2397270962aSWarner Losh return ((const EFI_DEVICE_PATH_PROTOCOL *)(Node))->SubType;
2407270962aSWarner Losh }
2417270962aSWarner Losh
2427270962aSWarner Losh /**
2437270962aSWarner Losh Returns the 16-bit Length field of a device path node.
2447270962aSWarner Losh
2457270962aSWarner Losh Returns the 16-bit Length field of the device path node specified by Node.
2467270962aSWarner Losh Node is not required to be aligned on a 16-bit boundary, so it is recommended
2477270962aSWarner Losh that a function such as ReadUnaligned16() be used to extract the contents of
2487270962aSWarner Losh the Length field.
2497270962aSWarner Losh
2507270962aSWarner Losh If Node is NULL, then ASSERT().
2517270962aSWarner Losh
2527270962aSWarner Losh @param Node A pointer to a device path node data structure.
2537270962aSWarner Losh
2547270962aSWarner Losh @return The 16-bit Length field of the device path node specified by Node.
2557270962aSWarner Losh
2567270962aSWarner Losh **/
2577270962aSWarner Losh UINTN
2587270962aSWarner Losh EFIAPI
DevicePathNodeLength(IN CONST VOID * Node)2597270962aSWarner Losh DevicePathNodeLength (
2607270962aSWarner Losh IN CONST VOID *Node
2617270962aSWarner Losh )
2627270962aSWarner Losh {
2637270962aSWarner Losh ASSERT (Node != NULL);
2647270962aSWarner Losh return ((const EFI_DEVICE_PATH_PROTOCOL *)Node)->Length[0] |
2657270962aSWarner Losh (((const EFI_DEVICE_PATH_PROTOCOL *)Node)->Length[1] << 8);
2667270962aSWarner Losh }
2677270962aSWarner Losh
2687270962aSWarner Losh /**
2697270962aSWarner Losh Returns a pointer to the next node in a device path.
2707270962aSWarner Losh
2717270962aSWarner Losh Returns a pointer to the device path node that follows the device path node
2727270962aSWarner Losh specified by Node.
2737270962aSWarner Losh
2747270962aSWarner Losh If Node is NULL, then ASSERT().
2757270962aSWarner Losh
2767270962aSWarner Losh @param Node A pointer to a device path node data structure.
2777270962aSWarner Losh
2787270962aSWarner Losh @return a pointer to the device path node that follows the device path node
2797270962aSWarner Losh specified by Node.
2807270962aSWarner Losh
2817270962aSWarner Losh **/
2827270962aSWarner Losh EFI_DEVICE_PATH_PROTOCOL *
2837270962aSWarner Losh EFIAPI
NextDevicePathNode(IN CONST VOID * Node)2847270962aSWarner Losh NextDevicePathNode (
2857270962aSWarner Losh IN CONST VOID *Node
2867270962aSWarner Losh )
2877270962aSWarner Losh {
2887270962aSWarner Losh ASSERT (Node != NULL);
2897270962aSWarner Losh return ((EFI_DEVICE_PATH_PROTOCOL *)(__DECONST(UINT8 *, Node) + DevicePathNodeLength(Node)));
2907270962aSWarner Losh }
2917270962aSWarner Losh
2927270962aSWarner Losh /**
2937270962aSWarner Losh Determines if a device path node is an end node of a device path.
2947270962aSWarner Losh This includes nodes that are the end of a device path instance and nodes that
2957270962aSWarner Losh are the end of an entire device path.
2967270962aSWarner Losh
2977270962aSWarner Losh Determines if the device path node specified by Node is an end node of a device path.
2987270962aSWarner Losh This includes nodes that are the end of a device path instance and nodes that are the
2997270962aSWarner Losh end of an entire device path. If Node represents an end node of a device path,
3007270962aSWarner Losh then TRUE is returned. Otherwise, FALSE is returned.
3017270962aSWarner Losh
3027270962aSWarner Losh If Node is NULL, then ASSERT().
3037270962aSWarner Losh
3047270962aSWarner Losh @param Node A pointer to a device path node data structure.
3057270962aSWarner Losh
3067270962aSWarner Losh @retval TRUE The device path node specified by Node is an end node of a
3077270962aSWarner Losh device path.
3087270962aSWarner Losh @retval FALSE The device path node specified by Node is not an end node of
3097270962aSWarner Losh a device path.
3107270962aSWarner Losh
3117270962aSWarner Losh **/
3127270962aSWarner Losh BOOLEAN
3137270962aSWarner Losh EFIAPI
IsDevicePathEndType(IN CONST VOID * Node)3147270962aSWarner Losh IsDevicePathEndType (
3157270962aSWarner Losh IN CONST VOID *Node
3167270962aSWarner Losh )
3177270962aSWarner Losh {
3187270962aSWarner Losh ASSERT (Node != NULL);
3197270962aSWarner Losh return (BOOLEAN) (DevicePathType (Node) == END_DEVICE_PATH_TYPE);
3207270962aSWarner Losh }
3217270962aSWarner Losh
3227270962aSWarner Losh /**
3237270962aSWarner Losh Determines if a device path node is an end node of an entire device path.
3247270962aSWarner Losh
3257270962aSWarner Losh Determines if a device path node specified by Node is an end node of an entire
3267270962aSWarner Losh device path. If Node represents the end of an entire device path, then TRUE is
3277270962aSWarner Losh returned. Otherwise, FALSE is returned.
3287270962aSWarner Losh
3297270962aSWarner Losh If Node is NULL, then ASSERT().
3307270962aSWarner Losh
3317270962aSWarner Losh @param Node A pointer to a device path node data structure.
3327270962aSWarner Losh
3337270962aSWarner Losh @retval TRUE The device path node specified by Node is the end of an entire
3347270962aSWarner Losh device path.
3357270962aSWarner Losh @retval FALSE The device path node specified by Node is not the end of an
3367270962aSWarner Losh entire device path.
3377270962aSWarner Losh
3387270962aSWarner Losh **/
3397270962aSWarner Losh BOOLEAN
3407270962aSWarner Losh EFIAPI
IsDevicePathEnd(IN CONST VOID * Node)3417270962aSWarner Losh IsDevicePathEnd (
3427270962aSWarner Losh IN CONST VOID *Node
3437270962aSWarner Losh )
3447270962aSWarner Losh {
3457270962aSWarner Losh ASSERT (Node != NULL);
3467270962aSWarner Losh return (BOOLEAN) (IsDevicePathEndType (Node) && DevicePathSubType(Node) == END_ENTIRE_DEVICE_PATH_SUBTYPE);
3477270962aSWarner Losh }
3487270962aSWarner Losh
3497270962aSWarner Losh /**
3507270962aSWarner Losh Fills in all the fields of a device path node that is the end of an entire device path.
3517270962aSWarner Losh
3527270962aSWarner Losh Fills in all the fields of a device path node specified by Node so Node represents
3537270962aSWarner Losh the end of an entire device path. The Type field of Node is set to
3547270962aSWarner Losh END_DEVICE_PATH_TYPE, the SubType field of Node is set to
3557270962aSWarner Losh END_ENTIRE_DEVICE_PATH_SUBTYPE, and the Length field of Node is set to
3567270962aSWarner Losh END_DEVICE_PATH_LENGTH. Node is not required to be aligned on a 16-bit boundary,
3577270962aSWarner Losh so it is recommended that a function such as WriteUnaligned16() be used to set
3587270962aSWarner Losh the contents of the Length field.
3597270962aSWarner Losh
3607270962aSWarner Losh If Node is NULL, then ASSERT().
3617270962aSWarner Losh
3627270962aSWarner Losh @param Node A pointer to a device path node data structure.
3637270962aSWarner Losh
3647270962aSWarner Losh **/
3657270962aSWarner Losh VOID
3667270962aSWarner Losh EFIAPI
SetDevicePathEndNode(OUT VOID * Node)3677270962aSWarner Losh SetDevicePathEndNode (
3687270962aSWarner Losh OUT VOID *Node
3697270962aSWarner Losh )
3707270962aSWarner Losh {
3717270962aSWarner Losh ASSERT (Node != NULL);
3727270962aSWarner Losh memcpy (Node, &mUefiDevicePathLibEndDevicePath, sizeof (mUefiDevicePathLibEndDevicePath));
3737270962aSWarner Losh }
3747270962aSWarner Losh
3757270962aSWarner Losh /**
3767270962aSWarner Losh Sets the length, in bytes, of a device path node.
3777270962aSWarner Losh
3787270962aSWarner Losh Sets the length of the device path node specified by Node to the value specified
3797270962aSWarner Losh by NodeLength. NodeLength is returned. Node is not required to be aligned on
3807270962aSWarner Losh a 16-bit boundary, so it is recommended that a function such as WriteUnaligned16()
3817270962aSWarner Losh be used to set the contents of the Length field.
3827270962aSWarner Losh
3837270962aSWarner Losh If Node is NULL, then ASSERT().
3847270962aSWarner Losh If NodeLength >= SIZE_64KB, then ASSERT().
3857270962aSWarner Losh If NodeLength < sizeof (EFI_DEVICE_PATH_PROTOCOL), then ASSERT().
3867270962aSWarner Losh
3877270962aSWarner Losh @param Node A pointer to a device path node data structure.
3887270962aSWarner Losh @param Length The length, in bytes, of the device path node.
3897270962aSWarner Losh
3907270962aSWarner Losh @return Length
3917270962aSWarner Losh
3927270962aSWarner Losh **/
3937270962aSWarner Losh UINT16
3947270962aSWarner Losh EFIAPI
SetDevicePathNodeLength(IN OUT VOID * Node,IN UINTN Length)3957270962aSWarner Losh SetDevicePathNodeLength (
3967270962aSWarner Losh IN OUT VOID *Node,
3977270962aSWarner Losh IN UINTN Length
3987270962aSWarner Losh )
3997270962aSWarner Losh {
4007270962aSWarner Losh ASSERT (Node != NULL);
4017270962aSWarner Losh ASSERT ((Length >= sizeof (EFI_DEVICE_PATH_PROTOCOL)) && (Length < SIZE_64KB));
4027270962aSWarner Losh // return WriteUnaligned16 ((UINT16 *)&((EFI_DEVICE_PATH_PROTOCOL *)(Node))->Length[0], (UINT16)(Length));
4037270962aSWarner Losh le16enc(&((EFI_DEVICE_PATH_PROTOCOL *)(Node))->Length[0], (UINT16)(Length));
4047270962aSWarner Losh return Length;
4057270962aSWarner Losh }
4067270962aSWarner Losh
4077270962aSWarner Losh /**
4087270962aSWarner Losh Creates a device node.
4097270962aSWarner Losh
4107270962aSWarner Losh This function creates a new device node in a newly allocated buffer of size
4117270962aSWarner Losh NodeLength and initializes the device path node header with NodeType and NodeSubType.
4127270962aSWarner Losh The new device path node is returned.
4137270962aSWarner Losh If NodeLength is smaller than a device path header, then NULL is returned.
4147270962aSWarner Losh If there is not enough memory to allocate space for the new device path, then
4157270962aSWarner Losh NULL is returned.
4167270962aSWarner Losh The memory is allocated from EFI boot services memory. It is the responsibility
4177270962aSWarner Losh of the caller to free the memory allocated.
4187270962aSWarner Losh
4197270962aSWarner Losh @param NodeType The device node type for the new device node.
4207270962aSWarner Losh @param NodeSubType The device node sub-type for the new device node.
4217270962aSWarner Losh @param NodeLength The length of the new device node.
4227270962aSWarner Losh
4237270962aSWarner Losh @return The new device path.
4247270962aSWarner Losh
4257270962aSWarner Losh **/
4267270962aSWarner Losh EFI_DEVICE_PATH_PROTOCOL *
4277270962aSWarner Losh EFIAPI
CreateDeviceNode(IN UINT8 NodeType,IN UINT8 NodeSubType,IN UINT16 NodeLength)4287270962aSWarner Losh CreateDeviceNode (
4297270962aSWarner Losh IN UINT8 NodeType,
4307270962aSWarner Losh IN UINT8 NodeSubType,
4317270962aSWarner Losh IN UINT16 NodeLength
4327270962aSWarner Losh )
4337270962aSWarner Losh {
4347270962aSWarner Losh EFI_DEVICE_PATH_PROTOCOL *DevicePath;
4357270962aSWarner Losh
4367270962aSWarner Losh if (NodeLength < sizeof (EFI_DEVICE_PATH_PROTOCOL)) {
4377270962aSWarner Losh //
4387270962aSWarner Losh // NodeLength is less than the size of the header.
4397270962aSWarner Losh //
4407270962aSWarner Losh return NULL;
4417270962aSWarner Losh }
4427270962aSWarner Losh
4437270962aSWarner Losh DevicePath = AllocateZeroPool (NodeLength);
4447270962aSWarner Losh if (DevicePath != NULL) {
4457270962aSWarner Losh DevicePath->Type = NodeType;
4467270962aSWarner Losh DevicePath->SubType = NodeSubType;
4477270962aSWarner Losh SetDevicePathNodeLength (DevicePath, NodeLength);
4487270962aSWarner Losh }
4497270962aSWarner Losh
4507270962aSWarner Losh return DevicePath;
4517270962aSWarner Losh }
4527270962aSWarner Losh
4537270962aSWarner Losh /**
4547270962aSWarner Losh Creates a new copy of an existing device path.
4557270962aSWarner Losh
4567270962aSWarner Losh This function allocates space for a new copy of the device path specified by DevicePath.
4577270962aSWarner Losh If DevicePath is NULL, then NULL is returned. If the memory is successfully
4587270962aSWarner Losh allocated, then the contents of DevicePath are copied to the newly allocated
4597270962aSWarner Losh buffer, and a pointer to that buffer is returned. Otherwise, NULL is returned.
4607270962aSWarner Losh The memory for the new device path is allocated from EFI boot services memory.
4617270962aSWarner Losh It is the responsibility of the caller to free the memory allocated.
4627270962aSWarner Losh
4637270962aSWarner Losh @param DevicePath A pointer to a device path data structure.
4647270962aSWarner Losh
4657270962aSWarner Losh @retval NULL DevicePath is NULL or invalid.
4667270962aSWarner Losh @retval Others A pointer to the duplicated device path.
4677270962aSWarner Losh
4687270962aSWarner Losh **/
4697270962aSWarner Losh EFI_DEVICE_PATH_PROTOCOL *
4707270962aSWarner Losh EFIAPI
DuplicateDevicePath(IN CONST EFI_DEVICE_PATH_PROTOCOL * DevicePath)4717270962aSWarner Losh DuplicateDevicePath (
4727270962aSWarner Losh IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath
4737270962aSWarner Losh )
4747270962aSWarner Losh {
4757270962aSWarner Losh UINTN Size;
4767270962aSWarner Losh
4777270962aSWarner Losh //
4787270962aSWarner Losh // Compute the size
4797270962aSWarner Losh //
4807270962aSWarner Losh Size = GetDevicePathSize (DevicePath);
4817270962aSWarner Losh if (Size == 0) {
4827270962aSWarner Losh return NULL;
4837270962aSWarner Losh }
4847270962aSWarner Losh
4857270962aSWarner Losh //
4867270962aSWarner Losh // Allocate space for duplicate device path
4877270962aSWarner Losh //
4887270962aSWarner Losh
4897270962aSWarner Losh return AllocateCopyPool (Size, DevicePath);
4907270962aSWarner Losh }
4917270962aSWarner Losh
4927270962aSWarner Losh /**
4937270962aSWarner Losh Creates a new device path by appending a second device path to a first device path.
4947270962aSWarner Losh
4957270962aSWarner Losh This function creates a new device path by appending a copy of SecondDevicePath
4967270962aSWarner Losh to a copy of FirstDevicePath in a newly allocated buffer. Only the end-of-device-path
4977270962aSWarner Losh device node from SecondDevicePath is retained. The newly created device path is
4987270962aSWarner Losh returned. If FirstDevicePath is NULL, then it is ignored, and a duplicate of
4997270962aSWarner Losh SecondDevicePath is returned. If SecondDevicePath is NULL, then it is ignored,
5007270962aSWarner Losh and a duplicate of FirstDevicePath is returned. If both FirstDevicePath and
5017270962aSWarner Losh SecondDevicePath are NULL, then a copy of an end-of-device-path is returned.
5027270962aSWarner Losh
5037270962aSWarner Losh If there is not enough memory for the newly allocated buffer, then NULL is returned.
5047270962aSWarner Losh The memory for the new device path is allocated from EFI boot services memory.
5057270962aSWarner Losh It is the responsibility of the caller to free the memory allocated.
5067270962aSWarner Losh
5077270962aSWarner Losh @param FirstDevicePath A pointer to a device path data structure.
5087270962aSWarner Losh @param SecondDevicePath A pointer to a device path data structure.
5097270962aSWarner Losh
5107270962aSWarner Losh @retval NULL If there is not enough memory for the newly allocated buffer.
5117270962aSWarner Losh @retval NULL If FirstDevicePath or SecondDevicePath is invalid.
5127270962aSWarner Losh @retval Others A pointer to the new device path if success.
5137270962aSWarner Losh Or a copy an end-of-device-path if both FirstDevicePath and SecondDevicePath are NULL.
5147270962aSWarner Losh
5157270962aSWarner Losh **/
5167270962aSWarner Losh EFI_DEVICE_PATH_PROTOCOL *
5177270962aSWarner Losh EFIAPI
AppendDevicePath(IN CONST EFI_DEVICE_PATH_PROTOCOL * FirstDevicePath,OPTIONAL IN CONST EFI_DEVICE_PATH_PROTOCOL * SecondDevicePath OPTIONAL)5187270962aSWarner Losh AppendDevicePath (
5197270962aSWarner Losh IN CONST EFI_DEVICE_PATH_PROTOCOL *FirstDevicePath, OPTIONAL
5207270962aSWarner Losh IN CONST EFI_DEVICE_PATH_PROTOCOL *SecondDevicePath OPTIONAL
5217270962aSWarner Losh )
5227270962aSWarner Losh {
5237270962aSWarner Losh UINTN Size;
5247270962aSWarner Losh UINTN Size1;
5257270962aSWarner Losh UINTN Size2;
5267270962aSWarner Losh EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
5277270962aSWarner Losh EFI_DEVICE_PATH_PROTOCOL *DevicePath2;
5287270962aSWarner Losh
5297270962aSWarner Losh //
5307270962aSWarner Losh // If there's only 1 path, just duplicate it.
5317270962aSWarner Losh //
5327270962aSWarner Losh if (FirstDevicePath == NULL) {
5337270962aSWarner Losh return DuplicateDevicePath ((SecondDevicePath != NULL) ? SecondDevicePath : &mUefiDevicePathLibEndDevicePath);
5347270962aSWarner Losh }
5357270962aSWarner Losh
5367270962aSWarner Losh if (SecondDevicePath == NULL) {
5377270962aSWarner Losh return DuplicateDevicePath (FirstDevicePath);
5387270962aSWarner Losh }
5397270962aSWarner Losh
5407270962aSWarner Losh if (!IsDevicePathValid (FirstDevicePath, 0) || !IsDevicePathValid (SecondDevicePath, 0)) {
5417270962aSWarner Losh return NULL;
5427270962aSWarner Losh }
5437270962aSWarner Losh
5447270962aSWarner Losh //
5457270962aSWarner Losh // Allocate space for the combined device path. It only has one end node of
5467270962aSWarner Losh // length EFI_DEVICE_PATH_PROTOCOL.
5477270962aSWarner Losh //
5487270962aSWarner Losh Size1 = GetDevicePathSize (FirstDevicePath);
5497270962aSWarner Losh Size2 = GetDevicePathSize (SecondDevicePath);
5507270962aSWarner Losh Size = Size1 + Size2 - END_DEVICE_PATH_LENGTH;
5517270962aSWarner Losh
5527270962aSWarner Losh NewDevicePath = AllocatePool (Size);
5537270962aSWarner Losh
5547270962aSWarner Losh if (NewDevicePath != NULL) {
5557270962aSWarner Losh NewDevicePath = CopyMem (NewDevicePath, FirstDevicePath, Size1);
5567270962aSWarner Losh //
5577270962aSWarner Losh // Over write FirstDevicePath EndNode and do the copy
5587270962aSWarner Losh //
5597270962aSWarner Losh DevicePath2 = (EFI_DEVICE_PATH_PROTOCOL *) ((CHAR8 *) NewDevicePath +
5607270962aSWarner Losh (Size1 - END_DEVICE_PATH_LENGTH));
5617270962aSWarner Losh CopyMem (DevicePath2, SecondDevicePath, Size2);
5627270962aSWarner Losh }
5637270962aSWarner Losh
5647270962aSWarner Losh return NewDevicePath;
5657270962aSWarner Losh }
5667270962aSWarner Losh
5677270962aSWarner Losh /**
5687270962aSWarner Losh Creates a new path by appending the device node to the device path.
5697270962aSWarner Losh
5707270962aSWarner Losh This function creates a new device path by appending a copy of the device node
5717270962aSWarner Losh specified by DevicePathNode to a copy of the device path specified by DevicePath
5727270962aSWarner Losh in an allocated buffer. The end-of-device-path device node is moved after the
5737270962aSWarner Losh end of the appended device node.
5747270962aSWarner Losh If DevicePathNode is NULL then a copy of DevicePath is returned.
5757270962aSWarner Losh If DevicePath is NULL then a copy of DevicePathNode, followed by an end-of-device
5767270962aSWarner Losh path device node is returned.
5777270962aSWarner Losh If both DevicePathNode and DevicePath are NULL then a copy of an end-of-device-path
5787270962aSWarner Losh device node is returned.
5797270962aSWarner Losh If there is not enough memory to allocate space for the new device path, then
5807270962aSWarner Losh NULL is returned.
5817270962aSWarner Losh The memory is allocated from EFI boot services memory. It is the responsibility
5827270962aSWarner Losh of the caller to free the memory allocated.
5837270962aSWarner Losh
5847270962aSWarner Losh @param DevicePath A pointer to a device path data structure.
5857270962aSWarner Losh @param DevicePathNode A pointer to a single device path node.
5867270962aSWarner Losh
5877270962aSWarner Losh @retval NULL If there is not enough memory for the new device path.
5887270962aSWarner Losh @retval Others A pointer to the new device path if success.
5897270962aSWarner Losh A copy of DevicePathNode followed by an end-of-device-path node
5907270962aSWarner Losh if both FirstDevicePath and SecondDevicePath are NULL.
5917270962aSWarner Losh A copy of an end-of-device-path node if both FirstDevicePath
5927270962aSWarner Losh and SecondDevicePath are NULL.
5937270962aSWarner Losh
5947270962aSWarner Losh **/
5957270962aSWarner Losh EFI_DEVICE_PATH_PROTOCOL *
5967270962aSWarner Losh EFIAPI
AppendDevicePathNode(IN CONST EFI_DEVICE_PATH_PROTOCOL * DevicePath,OPTIONAL IN CONST EFI_DEVICE_PATH_PROTOCOL * DevicePathNode OPTIONAL)5977270962aSWarner Losh AppendDevicePathNode (
5987270962aSWarner Losh IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath, OPTIONAL
5997270962aSWarner Losh IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePathNode OPTIONAL
6007270962aSWarner Losh )
6017270962aSWarner Losh {
6027270962aSWarner Losh EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
6037270962aSWarner Losh EFI_DEVICE_PATH_PROTOCOL *NextNode;
6047270962aSWarner Losh EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
6057270962aSWarner Losh UINTN NodeLength;
6067270962aSWarner Losh
6077270962aSWarner Losh if (DevicePathNode == NULL) {
6087270962aSWarner Losh return DuplicateDevicePath ((DevicePath != NULL) ? DevicePath : &mUefiDevicePathLibEndDevicePath);
6097270962aSWarner Losh }
6107270962aSWarner Losh //
6117270962aSWarner Losh // Build a Node that has a terminator on it
6127270962aSWarner Losh //
6137270962aSWarner Losh NodeLength = DevicePathNodeLength (DevicePathNode);
6147270962aSWarner Losh
6157270962aSWarner Losh TempDevicePath = AllocatePool (NodeLength + END_DEVICE_PATH_LENGTH);
6167270962aSWarner Losh if (TempDevicePath == NULL) {
6177270962aSWarner Losh return NULL;
6187270962aSWarner Losh }
6197270962aSWarner Losh TempDevicePath = CopyMem (TempDevicePath, DevicePathNode, NodeLength);
6207270962aSWarner Losh //
6217270962aSWarner Losh // Add and end device path node to convert Node to device path
6227270962aSWarner Losh //
6237270962aSWarner Losh NextNode = NextDevicePathNode (TempDevicePath);
6247270962aSWarner Losh SetDevicePathEndNode (NextNode);
6257270962aSWarner Losh //
6267270962aSWarner Losh // Append device paths
6277270962aSWarner Losh //
6287270962aSWarner Losh NewDevicePath = AppendDevicePath (DevicePath, TempDevicePath);
6297270962aSWarner Losh
6307270962aSWarner Losh FreePool (TempDevicePath);
6317270962aSWarner Losh
6327270962aSWarner Losh return NewDevicePath;
6337270962aSWarner Losh }
634