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 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 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 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 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 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 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 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 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 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 * 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 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 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 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 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