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