1 /** @file
2   Device Path services. The thing to remember is device paths are built out of
3   nodes. The device path is terminated by an end node that is length
4   sizeof(EFI_DEVICE_PATH_PROTOCOL). That would be why there is sizeof(EFI_DEVICE_PATH_PROTOCOL)
5   all over this file.
6 
7   The only place where multi-instance device paths are supported is in
8   environment varibles. Multi-instance device paths should never be placed
9   on a Handle.
10 
11   Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>
12   This program and the accompanying materials
13   are licensed and made available under the terms and conditions of the BSD License
14   which accompanies this distribution.  The full text of the license may be found at
15   http://opensource.org/licenses/bsd-license.php.
16 
17   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
18   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 
20 **/
21 
22 
23 #include "UefiDevicePathLib.h"
24 
25 GLOBAL_REMOVE_IF_UNREFERENCED EFI_DEVICE_PATH_UTILITIES_PROTOCOL *mDevicePathLibDevicePathUtilities = NULL;
26 GLOBAL_REMOVE_IF_UNREFERENCED EFI_DEVICE_PATH_TO_TEXT_PROTOCOL   *mDevicePathLibDevicePathToText    = NULL;
27 GLOBAL_REMOVE_IF_UNREFERENCED EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *mDevicePathLibDevicePathFromText  = NULL;
28 
29 /**
30   The constructor function caches the pointer to DevicePathUtilites protocol,
31   DevicePathToText protocol and DevicePathFromText protocol.
32 
33   The constructor function locates these three protocols from protocol database.
34   It will caches the pointer to local protocol instance if that operation fails
35   and it will always return EFI_SUCCESS.
36 
37   @param  ImageHandle   The firmware allocated handle for the EFI image.
38   @param  SystemTable   A pointer to the EFI System Table.
39 
40   @retval EFI_SUCCESS   The constructor always returns EFI_SUCCESS.
41 
42 **/
43 EFI_STATUS
44 EFIAPI
UefiDevicePathLibOptionalDevicePathProtocolConstructor(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)45 UefiDevicePathLibOptionalDevicePathProtocolConstructor (
46   IN      EFI_HANDLE                ImageHandle,
47   IN      EFI_SYSTEM_TABLE          *SystemTable
48   )
49 {
50   EFI_STATUS                        Status;
51 
52   Status = gBS->LocateProtocol (
53                   &gEfiDevicePathUtilitiesProtocolGuid,
54                   NULL,
55                   (VOID**) &mDevicePathLibDevicePathUtilities
56                   );
57   ASSERT_EFI_ERROR (Status);
58   ASSERT (mDevicePathLibDevicePathUtilities != NULL);
59   return Status;
60 }
61 
62 /**
63   Returns the size of a device path in bytes.
64 
65   This function returns the size, in bytes, of the device path data structure
66   specified by DevicePath including the end of device path node.
67   If DevicePath is NULL or invalid, then 0 is returned.
68 
69   @param  DevicePath  A pointer to a device path data structure.
70 
71   @retval 0           If DevicePath is NULL or invalid.
72   @retval Others      The size of a device path in bytes.
73 
74 **/
75 UINTN
76 EFIAPI
GetDevicePathSize(IN CONST EFI_DEVICE_PATH_PROTOCOL * DevicePath)77 GetDevicePathSize (
78   IN CONST EFI_DEVICE_PATH_PROTOCOL  *DevicePath
79   )
80 {
81   if (mDevicePathLibDevicePathUtilities != NULL) {
82     return mDevicePathLibDevicePathUtilities->GetDevicePathSize (DevicePath);
83   } else {
84     return UefiDevicePathLibGetDevicePathSize (DevicePath);
85   }
86 }
87 
88 /**
89   Creates a new copy of an existing device path.
90 
91   This function allocates space for a new copy of the device path specified by DevicePath.
92   If DevicePath is NULL, then NULL is returned.  If the memory is successfully
93   allocated, then the contents of DevicePath are copied to the newly allocated
94   buffer, and a pointer to that buffer is returned.  Otherwise, NULL is returned.
95   The memory for the new device path is allocated from EFI boot services memory.
96   It is the responsibility of the caller to free the memory allocated.
97 
98   @param  DevicePath    A pointer to a device path data structure.
99 
100   @retval NULL          DevicePath is NULL or invalid.
101   @retval Others        A pointer to the duplicated device path.
102 
103 **/
104 EFI_DEVICE_PATH_PROTOCOL *
105 EFIAPI
DuplicateDevicePath(IN CONST EFI_DEVICE_PATH_PROTOCOL * DevicePath)106 DuplicateDevicePath (
107   IN CONST EFI_DEVICE_PATH_PROTOCOL  *DevicePath
108   )
109 {
110   if (mDevicePathLibDevicePathUtilities != NULL) {
111     return mDevicePathLibDevicePathUtilities->DuplicateDevicePath (DevicePath);
112   } else {
113     return UefiDevicePathLibDuplicateDevicePath (DevicePath);
114   }
115 }
116 
117 /**
118   Creates a new device path by appending a second device path to a first device path.
119 
120   This function creates a new device path by appending a copy of SecondDevicePath
121   to a copy of FirstDevicePath in a newly allocated buffer.  Only the end-of-device-path
122   device node from SecondDevicePath is retained. The newly created device path is
123   returned. If FirstDevicePath is NULL, then it is ignored, and a duplicate of
124   SecondDevicePath is returned.  If SecondDevicePath is NULL, then it is ignored,
125   and a duplicate of FirstDevicePath is returned. If both FirstDevicePath and
126   SecondDevicePath are NULL, then a copy of an end-of-device-path is returned.
127 
128   If there is not enough memory for the newly allocated buffer, then NULL is returned.
129   The memory for the new device path is allocated from EFI boot services memory.
130   It is the responsibility of the caller to free the memory allocated.
131 
132   @param  FirstDevicePath            A pointer to a device path data structure.
133   @param  SecondDevicePath           A pointer to a device path data structure.
134 
135   @retval NULL      If there is not enough memory for the newly allocated buffer.
136   @retval NULL      If FirstDevicePath or SecondDevicePath is invalid.
137   @retval Others    A pointer to the new device path if success.
138                     Or a copy an end-of-device-path if both FirstDevicePath and SecondDevicePath are NULL.
139 
140 **/
141 EFI_DEVICE_PATH_PROTOCOL *
142 EFIAPI
AppendDevicePath(IN CONST EFI_DEVICE_PATH_PROTOCOL * FirstDevicePath,OPTIONAL IN CONST EFI_DEVICE_PATH_PROTOCOL * SecondDevicePath OPTIONAL)143 AppendDevicePath (
144   IN CONST EFI_DEVICE_PATH_PROTOCOL  *FirstDevicePath,  OPTIONAL
145   IN CONST EFI_DEVICE_PATH_PROTOCOL  *SecondDevicePath  OPTIONAL
146   )
147 {
148   if (mDevicePathLibDevicePathUtilities != NULL) {
149     return mDevicePathLibDevicePathUtilities->AppendDevicePath (FirstDevicePath, SecondDevicePath);
150   } else {
151     return UefiDevicePathLibAppendDevicePath (FirstDevicePath, SecondDevicePath);
152   }
153 }
154 
155 /**
156   Creates a new path by appending the device node to the device path.
157 
158   This function creates a new device path by appending a copy of the device node
159   specified by DevicePathNode to a copy of the device path specified by DevicePath
160   in an allocated buffer. The end-of-device-path device node is moved after the
161   end of the appended device node.
162   If DevicePathNode is NULL then a copy of DevicePath is returned.
163   If DevicePath is NULL then a copy of DevicePathNode, followed by an end-of-device
164   path device node is returned.
165   If both DevicePathNode and DevicePath are NULL then a copy of an end-of-device-path
166   device node is returned.
167   If there is not enough memory to allocate space for the new device path, then
168   NULL is returned.
169   The memory is allocated from EFI boot services memory. It is the responsibility
170   of the caller to free the memory allocated.
171 
172   @param  DevicePath                 A pointer to a device path data structure.
173   @param  DevicePathNode             A pointer to a single device path node.
174 
175   @retval NULL      If there is not enough memory for the new device path.
176   @retval Others    A pointer to the new device path if success.
177                     A copy of DevicePathNode followed by an end-of-device-path node
178                     if both FirstDevicePath and SecondDevicePath are NULL.
179                     A copy of an end-of-device-path node if both FirstDevicePath
180                     and SecondDevicePath are NULL.
181 
182 **/
183 EFI_DEVICE_PATH_PROTOCOL *
184 EFIAPI
AppendDevicePathNode(IN CONST EFI_DEVICE_PATH_PROTOCOL * DevicePath,OPTIONAL IN CONST EFI_DEVICE_PATH_PROTOCOL * DevicePathNode OPTIONAL)185 AppendDevicePathNode (
186   IN CONST EFI_DEVICE_PATH_PROTOCOL  *DevicePath,     OPTIONAL
187   IN CONST EFI_DEVICE_PATH_PROTOCOL  *DevicePathNode  OPTIONAL
188   )
189 {
190   if (mDevicePathLibDevicePathUtilities != NULL) {
191     return mDevicePathLibDevicePathUtilities->AppendDeviceNode (DevicePath, DevicePathNode);
192   } else {
193     return UefiDevicePathLibAppendDevicePathNode (DevicePath, DevicePathNode);
194   }
195 }
196 
197 /**
198   Creates a new device path by appending the specified device path instance to the specified device
199   path.
200 
201   This function creates a new device path by appending a copy of the device path
202   instance specified by DevicePathInstance to a copy of the device path specified
203   by DevicePath in a allocated buffer.
204   The end-of-device-path device node is moved after the end of the appended device
205   path instance and a new end-of-device-path-instance node is inserted between.
206   If DevicePath is NULL, then a copy if DevicePathInstance is returned.
207   If DevicePathInstance is NULL, then NULL is returned.
208   If DevicePath or DevicePathInstance is invalid, then NULL is returned.
209   If there is not enough memory to allocate space for the new device path, then
210   NULL is returned.
211   The memory is allocated from EFI boot services memory. It is the responsibility
212   of the caller to free the memory allocated.
213 
214   @param  DevicePath                 A pointer to a device path data structure.
215   @param  DevicePathInstance         A pointer to a device path instance.
216 
217   @return A pointer to the new device path.
218 
219 **/
220 EFI_DEVICE_PATH_PROTOCOL *
221 EFIAPI
AppendDevicePathInstance(IN CONST EFI_DEVICE_PATH_PROTOCOL * DevicePath,OPTIONAL IN CONST EFI_DEVICE_PATH_PROTOCOL * DevicePathInstance OPTIONAL)222 AppendDevicePathInstance (
223   IN CONST EFI_DEVICE_PATH_PROTOCOL  *DevicePath,        OPTIONAL
224   IN CONST EFI_DEVICE_PATH_PROTOCOL  *DevicePathInstance OPTIONAL
225   )
226 {
227   if (mDevicePathLibDevicePathUtilities != NULL) {
228     return mDevicePathLibDevicePathUtilities->AppendDevicePathInstance (DevicePath, DevicePathInstance);
229   } else {
230     return UefiDevicePathLibAppendDevicePathInstance (DevicePath, DevicePathInstance);
231   }
232 }
233 
234 /**
235   Creates a copy of the current device path instance and returns a pointer to the next device path
236   instance.
237 
238   This function creates a copy of the current device path instance. It also updates
239   DevicePath to point to the next device path instance in the device path (or NULL
240   if no more) and updates Size to hold the size of the device path instance copy.
241   If DevicePath is NULL, then NULL is returned.
242   If DevicePath points to a invalid device path, then NULL is returned.
243   If there is not enough memory to allocate space for the new device path, then
244   NULL is returned.
245   The memory is allocated from EFI boot services memory. It is the responsibility
246   of the caller to free the memory allocated.
247   If Size is NULL, then ASSERT().
248 
249   @param  DevicePath                 On input, this holds the pointer to the current
250                                      device path instance. On output, this holds
251                                      the pointer to the next device path instance
252                                      or NULL if there are no more device path
253                                      instances in the device path pointer to a
254                                      device path data structure.
255   @param  Size                       On output, this holds the size of the device
256                                      path instance, in bytes or zero, if DevicePath
257                                      is NULL.
258 
259   @return A pointer to the current device path instance.
260 
261 **/
262 EFI_DEVICE_PATH_PROTOCOL *
263 EFIAPI
GetNextDevicePathInstance(IN OUT EFI_DEVICE_PATH_PROTOCOL ** DevicePath,OUT UINTN * Size)264 GetNextDevicePathInstance (
265   IN OUT EFI_DEVICE_PATH_PROTOCOL    **DevicePath,
266   OUT UINTN                          *Size
267   )
268 {
269   if (mDevicePathLibDevicePathUtilities != NULL) {
270     return mDevicePathLibDevicePathUtilities->GetNextDevicePathInstance (DevicePath, Size);
271   } else {
272     return UefiDevicePathLibGetNextDevicePathInstance (DevicePath, Size);
273   }
274 }
275 
276 /**
277   Creates a device node.
278 
279   This function creates a new device node in a newly allocated buffer of size
280   NodeLength and initializes the device path node header with NodeType and NodeSubType.
281   The new device path node is returned.
282   If NodeLength is smaller than a device path header, then NULL is returned.
283   If there is not enough memory to allocate space for the new device path, then
284   NULL is returned.
285   The memory is allocated from EFI boot services memory. It is the responsibility
286   of the caller to free the memory allocated.
287 
288   @param  NodeType                   The device node type for the new device node.
289   @param  NodeSubType                The device node sub-type for the new device node.
290   @param  NodeLength                 The length of the new device node.
291 
292   @return The new device path.
293 
294 **/
295 EFI_DEVICE_PATH_PROTOCOL *
296 EFIAPI
CreateDeviceNode(IN UINT8 NodeType,IN UINT8 NodeSubType,IN UINT16 NodeLength)297 CreateDeviceNode (
298   IN UINT8                           NodeType,
299   IN UINT8                           NodeSubType,
300   IN UINT16                          NodeLength
301   )
302 {
303   if (mDevicePathLibDevicePathUtilities != NULL) {
304     return mDevicePathLibDevicePathUtilities->CreateDeviceNode (NodeType, NodeSubType, NodeLength);
305   } else {
306     return UefiDevicePathLibCreateDeviceNode (NodeType, NodeSubType, NodeLength);
307   }
308 }
309 
310 /**
311   Determines if a device path is single or multi-instance.
312 
313   This function returns TRUE if the device path specified by DevicePath is
314   multi-instance.
315   Otherwise, FALSE is returned.
316   If DevicePath is NULL or invalid, then FALSE is returned.
317 
318   @param  DevicePath                 A pointer to a device path data structure.
319 
320   @retval  TRUE                      DevicePath is multi-instance.
321   @retval  FALSE                     DevicePath is not multi-instance, or DevicePath
322                                      is NULL or invalid.
323 
324 **/
325 BOOLEAN
326 EFIAPI
IsDevicePathMultiInstance(IN CONST EFI_DEVICE_PATH_PROTOCOL * DevicePath)327 IsDevicePathMultiInstance (
328   IN CONST EFI_DEVICE_PATH_PROTOCOL  *DevicePath
329   )
330 {
331   if (mDevicePathLibDevicePathUtilities != NULL) {
332     return mDevicePathLibDevicePathUtilities->IsDevicePathMultiInstance (DevicePath);
333   } else {
334     return UefiDevicePathLibIsDevicePathMultiInstance (DevicePath);
335   }
336 }
337 
338 /**
339   Locate and return the protocol instance identified by the ProtocolGuid.
340 
341   @param ProtocolGuid     The GUID of the protocol.
342 
343   @return A pointer to the protocol instance or NULL when absent.
344 **/
345 VOID *
UefiDevicePathLibLocateProtocol(EFI_GUID * ProtocolGuid)346 UefiDevicePathLibLocateProtocol (
347   EFI_GUID                         *ProtocolGuid
348   )
349 {
350   EFI_STATUS Status;
351   VOID       *Protocol;
352   Status = gBS->LocateProtocol (
353                   ProtocolGuid,
354                   NULL,
355                   (VOID**) &Protocol
356                   );
357   if (EFI_ERROR (Status)) {
358     return NULL;
359   } else {
360     return Protocol;
361   }
362 }
363 
364 /**
365   Converts a device node to its string representation.
366 
367   @param DeviceNode        A Pointer to the device node to be converted.
368   @param DisplayOnly       If DisplayOnly is TRUE, then the shorter text representation
369                            of the display node is used, where applicable. If DisplayOnly
370                            is FALSE, then the longer text representation of the display node
371                            is used.
372   @param AllowShortcuts    If AllowShortcuts is TRUE, then the shortcut forms of text
373                            representation for a device node can be used, where applicable.
374 
375   @return A pointer to the allocated text representation of the device node or NULL if DeviceNode
376           is NULL or there was insufficient memory.
377 
378 **/
379 CHAR16 *
380 EFIAPI
ConvertDeviceNodeToText(IN CONST EFI_DEVICE_PATH_PROTOCOL * DeviceNode,IN BOOLEAN DisplayOnly,IN BOOLEAN AllowShortcuts)381 ConvertDeviceNodeToText (
382   IN CONST EFI_DEVICE_PATH_PROTOCOL  *DeviceNode,
383   IN BOOLEAN                         DisplayOnly,
384   IN BOOLEAN                         AllowShortcuts
385   )
386 {
387   if (mDevicePathLibDevicePathToText == NULL) {
388     mDevicePathLibDevicePathToText = UefiDevicePathLibLocateProtocol (&gEfiDevicePathToTextProtocolGuid);
389   }
390   if (mDevicePathLibDevicePathToText != NULL) {
391     return mDevicePathLibDevicePathToText->ConvertDeviceNodeToText (DeviceNode, DisplayOnly, AllowShortcuts);
392   }
393 
394   return UefiDevicePathLibConvertDeviceNodeToText (DeviceNode, DisplayOnly, AllowShortcuts);
395 }
396 
397 /**
398   Converts a device path to its text representation.
399 
400   @param DevicePath      A Pointer to the device to be converted.
401   @param DisplayOnly     If DisplayOnly is TRUE, then the shorter text representation
402                          of the display node is used, where applicable. If DisplayOnly
403                          is FALSE, then the longer text representation of the display node
404                          is used.
405   @param AllowShortcuts  If AllowShortcuts is TRUE, then the shortcut forms of text
406                          representation for a device node can be used, where applicable.
407 
408   @return A pointer to the allocated text representation of the device path or
409           NULL if DeviceNode is NULL or there was insufficient memory.
410 
411 **/
412 CHAR16 *
413 EFIAPI
ConvertDevicePathToText(IN CONST EFI_DEVICE_PATH_PROTOCOL * DevicePath,IN BOOLEAN DisplayOnly,IN BOOLEAN AllowShortcuts)414 ConvertDevicePathToText (
415   IN CONST EFI_DEVICE_PATH_PROTOCOL   *DevicePath,
416   IN BOOLEAN                          DisplayOnly,
417   IN BOOLEAN                          AllowShortcuts
418   )
419 {
420   if (mDevicePathLibDevicePathToText == NULL) {
421     mDevicePathLibDevicePathToText = UefiDevicePathLibLocateProtocol (&gEfiDevicePathToTextProtocolGuid);
422   }
423   if (mDevicePathLibDevicePathToText != NULL) {
424     return mDevicePathLibDevicePathToText->ConvertDevicePathToText (DevicePath, DisplayOnly, AllowShortcuts);
425   }
426 
427   return UefiDevicePathLibConvertDevicePathToText (DevicePath, DisplayOnly, AllowShortcuts);
428 }
429 
430 /**
431   Convert text to the binary representation of a device node.
432 
433   @param TextDeviceNode  TextDeviceNode points to the text representation of a device
434                          node. Conversion starts with the first character and continues
435                          until the first non-device node character.
436 
437   @return A pointer to the EFI device node or NULL if TextDeviceNode is NULL or there was
438           insufficient memory or text unsupported.
439 
440 **/
441 EFI_DEVICE_PATH_PROTOCOL *
442 EFIAPI
ConvertTextToDeviceNode(IN CONST CHAR16 * TextDeviceNode)443 ConvertTextToDeviceNode (
444   IN CONST CHAR16 *TextDeviceNode
445   )
446 {
447   if (mDevicePathLibDevicePathFromText == NULL) {
448     mDevicePathLibDevicePathFromText = UefiDevicePathLibLocateProtocol (&gEfiDevicePathFromTextProtocolGuid);
449   }
450   if (mDevicePathLibDevicePathFromText != NULL) {
451     return mDevicePathLibDevicePathFromText->ConvertTextToDeviceNode (TextDeviceNode);
452   }
453 
454   return UefiDevicePathLibConvertTextToDeviceNode (TextDeviceNode);
455 }
456 
457 /**
458   Convert text to the binary representation of a device path.
459 
460 
461   @param TextDevicePath  TextDevicePath points to the text representation of a device
462                          path. Conversion starts with the first character and continues
463                          until the first non-device node character.
464 
465   @return A pointer to the allocated device path or NULL if TextDeviceNode is NULL or
466           there was insufficient memory.
467 
468 **/
469 EFI_DEVICE_PATH_PROTOCOL *
470 EFIAPI
ConvertTextToDevicePath(IN CONST CHAR16 * TextDevicePath)471 ConvertTextToDevicePath (
472   IN CONST CHAR16 *TextDevicePath
473   )
474 {
475   if (mDevicePathLibDevicePathFromText == NULL) {
476     mDevicePathLibDevicePathFromText = UefiDevicePathLibLocateProtocol (&gEfiDevicePathFromTextProtocolGuid);
477   }
478   if (mDevicePathLibDevicePathFromText != NULL) {
479     return mDevicePathLibDevicePathFromText->ConvertTextToDevicePath (TextDevicePath);
480   }
481 
482   return UefiDevicePathLibConvertTextToDevicePath (TextDevicePath);
483 }
484 
485