1 /*- 2 * Copyright (c) 2017 Netflix, Inc. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 */ 25 26 /* 27 * Routines to format EFI_DEVICE_PATHs from the UEFI standard. Much of 28 * this file is taken from EDK2 and rototilled. 29 */ 30 31 #include <efivar.h> 32 #include <limits.h> 33 #include <stdio.h> 34 #include <string.h> 35 #include <sys/endian.h> 36 #include "uefi-dplib.h" 37 38 /* 39 * Taken from MdePkg/Library/UefiDevicePathLib/DevicePathUtilities.c 40 * hash 2f88bd3a1296c522317f1c21377876de63de5be7 2021-Dec-07 41 */ 42 43 /** @file 44 Device Path services. The thing to remember is device paths are built out of 45 nodes. The device path is terminated by an end node that is length 46 sizeof(EFI_DEVICE_PATH_PROTOCOL). That would be why there is sizeof(EFI_DEVICE_PATH_PROTOCOL) 47 all over this file. 48 49 The only place where multi-instance device paths are supported is in 50 environment varibles. Multi-instance device paths should never be placed 51 on a Handle. 52 53 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR> 54 SPDX-License-Identifier: BSD-2-Clause-Patent 55 56 **/ 57 58 // #include "UefiDevicePathLib.h" 59 60 // 61 // Template for an end-of-device path node. 62 // 63 static CONST EFI_DEVICE_PATH_PROTOCOL mUefiDevicePathLibEndDevicePath = { 64 END_DEVICE_PATH_TYPE, 65 END_ENTIRE_DEVICE_PATH_SUBTYPE, 66 { 67 END_DEVICE_PATH_LENGTH, 68 0 69 } 70 }; 71 72 /** 73 Determine whether a given device path is valid. 74 75 @param DevicePath A pointer to a device path data structure. 76 @param MaxSize The maximum size of the device path data structure. 77 78 @retval TRUE DevicePath is valid. 79 @retval FALSE DevicePath is NULL. 80 @retval FALSE Maxsize is less than sizeof(EFI_DEVICE_PATH_PROTOCOL). 81 @retval FALSE The length of any node Node in the DevicePath is less 82 than sizeof (EFI_DEVICE_PATH_PROTOCOL). 83 @retval FALSE If MaxSize is not zero, the size of the DevicePath 84 exceeds MaxSize. 85 @retval FALSE If PcdMaximumDevicePathNodeCount is not zero, the node 86 count of the DevicePath exceeds PcdMaximumDevicePathNodeCount. 87 **/ 88 BOOLEAN 89 EFIAPI 90 IsDevicePathValid ( 91 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath, 92 IN UINTN MaxSize 93 ) 94 { 95 UINTN Count; 96 UINTN Size; 97 UINTN NodeLength; 98 99 // 100 // Validate the input whether exists and its size big enough to touch the first node 101 // 102 if ((DevicePath == NULL) || ((MaxSize > 0) && (MaxSize < END_DEVICE_PATH_LENGTH))) { 103 return FALSE; 104 } 105 106 if (MaxSize == 0) { 107 MaxSize = MAX_UINTN; 108 } 109 110 for (Count = 0, Size = 0; !IsDevicePathEnd (DevicePath); DevicePath = NextDevicePathNode (DevicePath)) { 111 NodeLength = DevicePathNodeLength (DevicePath); 112 if (NodeLength < sizeof (EFI_DEVICE_PATH_PROTOCOL)) { 113 return FALSE; 114 } 115 116 if (NodeLength > MAX_UINTN - Size) { 117 return FALSE; 118 } 119 120 Size += NodeLength; 121 122 // 123 // Validate next node before touch it. 124 // 125 if (Size > MaxSize - END_DEVICE_PATH_LENGTH ) { 126 return FALSE; 127 } 128 129 if (PcdGet32 (PcdMaximumDevicePathNodeCount) > 0) { 130 Count++; 131 if (Count >= PcdGet32 (PcdMaximumDevicePathNodeCount)) { 132 return FALSE; 133 } 134 } 135 136 // 137 // FilePath must be a NULL-terminated string. 138 // 139 if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) && 140 (DevicePathSubType (DevicePath) == MEDIA_FILEPATH_DP) && 141 (*(const CHAR16 *)((const UINT8 *) DevicePath + NodeLength - 2) != 0)) 142 { 143 return FALSE; 144 } 145 } 146 147 // 148 // Only return TRUE when the End Device Path node is valid. 149 // 150 return (BOOLEAN)(DevicePathNodeLength (DevicePath) == END_DEVICE_PATH_LENGTH); 151 } 152 153 /** 154 Returns the Type field of a device path node. 155 156 Returns the Type field of the device path node specified by Node. 157 158 If Node is NULL, then ASSERT(). 159 160 @param Node A pointer to a device path node data structure. 161 162 @return The Type field of the device path node specified by Node. 163 164 **/ 165 UINT8 166 EFIAPI 167 DevicePathType ( 168 IN CONST VOID *Node 169 ) 170 { 171 ASSERT (Node != NULL); 172 return ((const EFI_DEVICE_PATH_PROTOCOL *)(Node))->Type; 173 } 174 175 /** 176 Returns the SubType field of a device path node. 177 178 Returns the SubType field of the device path node specified by Node. 179 180 If Node is NULL, then ASSERT(). 181 182 @param Node A pointer to a device path node data structure. 183 184 @return The SubType field of the device path node specified by Node. 185 186 **/ 187 UINT8 188 EFIAPI 189 DevicePathSubType ( 190 IN CONST VOID *Node 191 ) 192 { 193 ASSERT (Node != NULL); 194 return ((const EFI_DEVICE_PATH_PROTOCOL *)(Node))->SubType; 195 } 196 197 /** 198 Returns the 16-bit Length field of a device path node. 199 200 Returns the 16-bit Length field of the device path node specified by Node. 201 Node is not required to be aligned on a 16-bit boundary, so it is recommended 202 that a function such as ReadUnaligned16() be used to extract the contents of 203 the Length field. 204 205 If Node is NULL, then ASSERT(). 206 207 @param Node A pointer to a device path node data structure. 208 209 @return The 16-bit Length field of the device path node specified by Node. 210 211 **/ 212 UINTN 213 EFIAPI 214 DevicePathNodeLength ( 215 IN CONST VOID *Node 216 ) 217 { 218 ASSERT (Node != NULL); 219 // return ReadUnaligned16 ((UINT16 *)&((EFI_DEVICE_PATH_PROTOCOL *)(Node))->Length[0]); 220 return ((const EFI_DEVICE_PATH_PROTOCOL *)Node)->Length[0] | 221 (((const EFI_DEVICE_PATH_PROTOCOL *)Node)->Length[1] << 8); 222 } 223 224 /** 225 Returns a pointer to the next node in a device path. 226 227 Returns a pointer to the device path node that follows the device path node 228 specified by Node. 229 230 If Node is NULL, then ASSERT(). 231 232 @param Node A pointer to a device path node data structure. 233 234 @return a pointer to the device path node that follows the device path node 235 specified by Node. 236 237 **/ 238 EFI_DEVICE_PATH_PROTOCOL * 239 EFIAPI 240 NextDevicePathNode ( 241 IN CONST VOID *Node 242 ) 243 { 244 ASSERT (Node != NULL); 245 return (EFI_DEVICE_PATH_PROTOCOL *)(__DECONST(UINT8 *, Node) + DevicePathNodeLength (Node)); 246 } 247 248 /** 249 Determines if a device path node is an end node of a device path. 250 This includes nodes that are the end of a device path instance and nodes that 251 are the end of an entire device path. 252 253 Determines if the device path node specified by Node is an end node of a device path. 254 This includes nodes that are the end of a device path instance and nodes that are the 255 end of an entire device path. If Node represents an end node of a device path, 256 then TRUE is returned. Otherwise, FALSE is returned. 257 258 If Node is NULL, then ASSERT(). 259 260 @param Node A pointer to a device path node data structure. 261 262 @retval TRUE The device path node specified by Node is an end node of a 263 device path. 264 @retval FALSE The device path node specified by Node is not an end node of 265 a device path. 266 267 **/ 268 BOOLEAN 269 EFIAPI 270 IsDevicePathEndType ( 271 IN CONST VOID *Node 272 ) 273 { 274 ASSERT (Node != NULL); 275 return (BOOLEAN)(DevicePathType (Node) == END_DEVICE_PATH_TYPE); 276 } 277 278 /** 279 Determines if a device path node is an end node of an entire device path. 280 281 Determines if a device path node specified by Node is an end node of an entire 282 device path. If Node represents the end of an entire device path, then TRUE is 283 returned. Otherwise, FALSE is returned. 284 285 If Node is NULL, then ASSERT(). 286 287 @param Node A pointer to a device path node data structure. 288 289 @retval TRUE The device path node specified by Node is the end of an entire 290 device path. 291 @retval FALSE The device path node specified by Node is not the end of an 292 entire device path. 293 294 **/ 295 BOOLEAN 296 EFIAPI 297 IsDevicePathEnd ( 298 IN CONST VOID *Node 299 ) 300 { 301 ASSERT (Node != NULL); 302 return (BOOLEAN)(IsDevicePathEndType (Node) && DevicePathSubType (Node) == END_ENTIRE_DEVICE_PATH_SUBTYPE); 303 } 304 305 #ifndef __FreeBSD__ 306 /** 307 Determines if a device path node is an end node of a device path instance. 308 309 Determines if a device path node specified by Node is an end node of a device 310 path instance. If Node represents the end of a device path instance, then TRUE 311 is returned. Otherwise, FALSE is returned. 312 313 If Node is NULL, then ASSERT(). 314 315 @param Node A pointer to a device path node data structure. 316 317 @retval TRUE The device path node specified by Node is the end of a device 318 path instance. 319 @retval FALSE The device path node specified by Node is not the end of a 320 device path instance. 321 322 **/ 323 BOOLEAN 324 EFIAPI 325 IsDevicePathEndInstance ( 326 IN CONST VOID *Node 327 ) 328 { 329 ASSERT (Node != NULL); 330 return (BOOLEAN)(IsDevicePathEndType (Node) && DevicePathSubType (Node) == END_INSTANCE_DEVICE_PATH_SUBTYPE); 331 } 332 #endif 333 334 /** 335 Sets the length, in bytes, of a device path node. 336 337 Sets the length of the device path node specified by Node to the value specified 338 by NodeLength. NodeLength is returned. Node is not required to be aligned on 339 a 16-bit boundary, so it is recommended that a function such as WriteUnaligned16() 340 be used to set the contents of the Length field. 341 342 If Node is NULL, then ASSERT(). 343 If NodeLength >= SIZE_64KB, then ASSERT(). 344 If NodeLength < sizeof (EFI_DEVICE_PATH_PROTOCOL), then ASSERT(). 345 346 @param Node A pointer to a device path node data structure. 347 @param Length The length, in bytes, of the device path node. 348 349 @return Length 350 351 **/ 352 UINT16 353 EFIAPI 354 SetDevicePathNodeLength ( 355 IN OUT VOID *Node, 356 IN UINTN Length 357 ) 358 { 359 ASSERT (Node != NULL); 360 ASSERT ((Length >= sizeof (EFI_DEVICE_PATH_PROTOCOL)) && (Length < SIZE_64KB)); 361 // return WriteUnaligned16 ((UINT16 *)&((EFI_DEVICE_PATH_PROTOCOL *)(Node))->Length[0], (UINT16)(Length)); 362 le16enc(&((EFI_DEVICE_PATH_PROTOCOL *)(Node))->Length[0], (UINT16)(Length)); 363 return Length; 364 } 365 366 /** 367 Fills in all the fields of a device path node that is the end of an entire device path. 368 369 Fills in all the fields of a device path node specified by Node so Node represents 370 the end of an entire device path. The Type field of Node is set to 371 END_DEVICE_PATH_TYPE, the SubType field of Node is set to 372 END_ENTIRE_DEVICE_PATH_SUBTYPE, and the Length field of Node is set to 373 END_DEVICE_PATH_LENGTH. Node is not required to be aligned on a 16-bit boundary, 374 so it is recommended that a function such as WriteUnaligned16() be used to set 375 the contents of the Length field. 376 377 If Node is NULL, then ASSERT(). 378 379 @param Node A pointer to a device path node data structure. 380 381 **/ 382 VOID 383 EFIAPI 384 SetDevicePathEndNode ( 385 OUT VOID *Node 386 ) 387 { 388 ASSERT (Node != NULL); 389 memcpy (Node, &mUefiDevicePathLibEndDevicePath, sizeof (mUefiDevicePathLibEndDevicePath)); 390 } 391 392 /** 393 Returns the size of a device path in bytes. 394 395 This function returns the size, in bytes, of the device path data structure 396 specified by DevicePath including the end of device path node. 397 If DevicePath is NULL or invalid, then 0 is returned. 398 399 @param DevicePath A pointer to a device path data structure. 400 401 @retval 0 If DevicePath is NULL or invalid. 402 @retval Others The size of a device path in bytes. 403 404 **/ 405 UINTN 406 EFIAPI 407 GetDevicePathSize ( 408 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath 409 ) 410 { 411 CONST EFI_DEVICE_PATH_PROTOCOL *Start; 412 413 if (DevicePath == NULL) { 414 return 0; 415 } 416 417 if (!IsDevicePathValid (DevicePath, 0)) { 418 return 0; 419 } 420 421 // 422 // Search for the end of the device path structure 423 // 424 Start = DevicePath; 425 while (!IsDevicePathEnd (DevicePath)) { 426 DevicePath = NextDevicePathNode (DevicePath); 427 } 428 429 // 430 // Compute the size and add back in the size of the end device path structure 431 // 432 return ((UINTN)DevicePath - (UINTN)Start) + DevicePathNodeLength (DevicePath); 433 } 434 435 /** 436 Creates a new copy of an existing device path. 437 438 This function allocates space for a new copy of the device path specified by DevicePath. 439 If DevicePath is NULL, then NULL is returned. If the memory is successfully 440 allocated, then the contents of DevicePath are copied to the newly allocated 441 buffer, and a pointer to that buffer is returned. Otherwise, NULL is returned. 442 The memory for the new device path is allocated from EFI boot services memory. 443 It is the responsibility of the caller to free the memory allocated. 444 445 @param DevicePath A pointer to a device path data structure. 446 447 @retval NULL DevicePath is NULL or invalid. 448 @retval Others A pointer to the duplicated device path. 449 450 **/ 451 EFI_DEVICE_PATH_PROTOCOL * 452 EFIAPI 453 DuplicateDevicePath ( 454 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath 455 ) 456 { 457 UINTN Size; 458 459 // 460 // Compute the size 461 // 462 Size = GetDevicePathSize (DevicePath); 463 if (Size == 0) { 464 return NULL; 465 } 466 467 // 468 // Allocate space for duplicate device path 469 // 470 471 return AllocateCopyPool (Size, DevicePath); 472 } 473 474 /** 475 Creates a new device path by appending a second device path to a first device path. 476 477 This function creates a new device path by appending a copy of SecondDevicePath 478 to a copy of FirstDevicePath in a newly allocated buffer. Only the end-of-device-path 479 device node from SecondDevicePath is retained. The newly created device path is 480 returned. If FirstDevicePath is NULL, then it is ignored, and a duplicate of 481 SecondDevicePath is returned. If SecondDevicePath is NULL, then it is ignored, 482 and a duplicate of FirstDevicePath is returned. If both FirstDevicePath and 483 SecondDevicePath are NULL, then a copy of an end-of-device-path is returned. 484 485 If there is not enough memory for the newly allocated buffer, then NULL is returned. 486 The memory for the new device path is allocated from EFI boot services memory. 487 It is the responsibility of the caller to free the memory allocated. 488 489 @param FirstDevicePath A pointer to a device path data structure. 490 @param SecondDevicePath A pointer to a device path data structure. 491 492 @retval NULL If there is not enough memory for the newly allocated buffer. 493 @retval NULL If FirstDevicePath or SecondDevicePath is invalid. 494 @retval Others A pointer to the new device path if success. 495 Or a copy an end-of-device-path if both FirstDevicePath and SecondDevicePath are NULL. 496 497 **/ 498 EFI_DEVICE_PATH_PROTOCOL * 499 EFIAPI 500 AppendDevicePath ( 501 IN CONST EFI_DEVICE_PATH_PROTOCOL *FirstDevicePath OPTIONAL, 502 IN CONST EFI_DEVICE_PATH_PROTOCOL *SecondDevicePath OPTIONAL 503 ) 504 { 505 UINTN Size; 506 UINTN Size1; 507 UINTN Size2; 508 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath; 509 EFI_DEVICE_PATH_PROTOCOL *DevicePath2; 510 511 // 512 // If there's only 1 path, just duplicate it. 513 // 514 if (FirstDevicePath == NULL) { 515 return DuplicateDevicePath ((SecondDevicePath != NULL) ? SecondDevicePath : &mUefiDevicePathLibEndDevicePath); 516 } 517 518 if (SecondDevicePath == NULL) { 519 return DuplicateDevicePath (FirstDevicePath); 520 } 521 522 if (!IsDevicePathValid (FirstDevicePath, 0) || !IsDevicePathValid (SecondDevicePath, 0)) { 523 return NULL; 524 } 525 526 // 527 // Allocate space for the combined device path. It only has one end node of 528 // length EFI_DEVICE_PATH_PROTOCOL. 529 // 530 Size1 = GetDevicePathSize (FirstDevicePath); 531 Size2 = GetDevicePathSize (SecondDevicePath); 532 Size = Size1 + Size2 - END_DEVICE_PATH_LENGTH; 533 534 NewDevicePath = AllocatePool (Size); 535 536 if (NewDevicePath != NULL) { 537 NewDevicePath = CopyMem (NewDevicePath, FirstDevicePath, Size1); 538 // 539 // Over write FirstDevicePath EndNode and do the copy 540 // 541 DevicePath2 = (EFI_DEVICE_PATH_PROTOCOL *)((CHAR8 *)NewDevicePath + 542 (Size1 - END_DEVICE_PATH_LENGTH)); 543 CopyMem (DevicePath2, SecondDevicePath, Size2); 544 } 545 546 return NewDevicePath; 547 } 548 549 /** 550 Creates a new path by appending the device node to the device path. 551 552 This function creates a new device path by appending a copy of the device node 553 specified by DevicePathNode to a copy of the device path specified by DevicePath 554 in an allocated buffer. The end-of-device-path device node is moved after the 555 end of the appended device node. 556 If DevicePathNode is NULL then a copy of DevicePath is returned. 557 If DevicePath is NULL then a copy of DevicePathNode, followed by an end-of-device 558 path device node is returned. 559 If both DevicePathNode and DevicePath are NULL then a copy of an end-of-device-path 560 device node is returned. 561 If there is not enough memory to allocate space for the new device path, then 562 NULL is returned. 563 The memory is allocated from EFI boot services memory. It is the responsibility 564 of the caller to free the memory allocated. 565 566 @param DevicePath A pointer to a device path data structure. 567 @param DevicePathNode A pointer to a single device path node. 568 569 @retval NULL If there is not enough memory for the new device path. 570 @retval Others A pointer to the new device path if success. 571 A copy of DevicePathNode followed by an end-of-device-path node 572 if both FirstDevicePath and SecondDevicePath are NULL. 573 A copy of an end-of-device-path node if both FirstDevicePath 574 and SecondDevicePath are NULL. 575 576 **/ 577 EFI_DEVICE_PATH_PROTOCOL * 578 EFIAPI 579 AppendDevicePathNode ( 580 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath OPTIONAL, 581 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePathNode OPTIONAL 582 ) 583 { 584 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; 585 EFI_DEVICE_PATH_PROTOCOL *NextNode; 586 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath; 587 UINTN NodeLength; 588 589 if (DevicePathNode == NULL) { 590 return DuplicateDevicePath ((DevicePath != NULL) ? DevicePath : &mUefiDevicePathLibEndDevicePath); 591 } 592 593 // 594 // Build a Node that has a terminator on it 595 // 596 NodeLength = DevicePathNodeLength (DevicePathNode); 597 598 TempDevicePath = AllocatePool (NodeLength + END_DEVICE_PATH_LENGTH); 599 if (TempDevicePath == NULL) { 600 return NULL; 601 } 602 603 TempDevicePath = CopyMem (TempDevicePath, DevicePathNode, NodeLength); 604 // 605 // Add and end device path node to convert Node to device path 606 // 607 NextNode = NextDevicePathNode (TempDevicePath); 608 SetDevicePathEndNode (NextNode); 609 // 610 // Append device paths 611 // 612 NewDevicePath = AppendDevicePath (DevicePath, TempDevicePath); 613 614 FreePool (TempDevicePath); 615 616 return NewDevicePath; 617 } 618 619 #ifndef __FreeBSD__ 620 /** 621 Creates a new device path by appending the specified device path instance to the specified device 622 path. 623 624 This function creates a new device path by appending a copy of the device path 625 instance specified by DevicePathInstance to a copy of the device path specified 626 by DevicePath in a allocated buffer. 627 The end-of-device-path device node is moved after the end of the appended device 628 path instance and a new end-of-device-path-instance node is inserted between. 629 If DevicePath is NULL, then a copy if DevicePathInstance is returned. 630 If DevicePathInstance is NULL, then NULL is returned. 631 If DevicePath or DevicePathInstance is invalid, then NULL is returned. 632 If there is not enough memory to allocate space for the new device path, then 633 NULL is returned. 634 The memory is allocated from EFI boot services memory. It is the responsibility 635 of the caller to free the memory allocated. 636 637 @param DevicePath A pointer to a device path data structure. 638 @param DevicePathInstance A pointer to a device path instance. 639 640 @return A pointer to the new device path. 641 642 **/ 643 EFI_DEVICE_PATH_PROTOCOL * 644 EFIAPI 645 UefiDevicePathLibAppendDevicePathInstance ( 646 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath OPTIONAL, 647 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePathInstance OPTIONAL 648 ) 649 { 650 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath; 651 EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; 652 UINTN SrcSize; 653 UINTN InstanceSize; 654 655 if (DevicePath == NULL) { 656 return DuplicateDevicePath (DevicePathInstance); 657 } 658 659 if (DevicePathInstance == NULL) { 660 return NULL; 661 } 662 663 if (!IsDevicePathValid (DevicePath, 0) || !IsDevicePathValid (DevicePathInstance, 0)) { 664 return NULL; 665 } 666 667 SrcSize = GetDevicePathSize (DevicePath); 668 InstanceSize = GetDevicePathSize (DevicePathInstance); 669 670 NewDevicePath = AllocatePool (SrcSize + InstanceSize); 671 if (NewDevicePath != NULL) { 672 TempDevicePath = CopyMem (NewDevicePath, DevicePath, SrcSize); 673 674 while (!IsDevicePathEnd (TempDevicePath)) { 675 TempDevicePath = NextDevicePathNode (TempDevicePath); 676 } 677 678 TempDevicePath->SubType = END_INSTANCE_DEVICE_PATH_SUBTYPE; 679 TempDevicePath = NextDevicePathNode (TempDevicePath); 680 CopyMem (TempDevicePath, DevicePathInstance, InstanceSize); 681 } 682 683 return NewDevicePath; 684 } 685 686 /** 687 Creates a copy of the current device path instance and returns a pointer to the next device path 688 instance. 689 690 This function creates a copy of the current device path instance. It also updates 691 DevicePath to point to the next device path instance in the device path (or NULL 692 if no more) and updates Size to hold the size of the device path instance copy. 693 If DevicePath is NULL, then NULL is returned. 694 If DevicePath points to a invalid device path, then NULL is returned. 695 If there is not enough memory to allocate space for the new device path, then 696 NULL is returned. 697 The memory is allocated from EFI boot services memory. It is the responsibility 698 of the caller to free the memory allocated. 699 If Size is NULL, then ASSERT(). 700 701 @param DevicePath On input, this holds the pointer to the current 702 device path instance. On output, this holds 703 the pointer to the next device path instance 704 or NULL if there are no more device path 705 instances in the device path pointer to a 706 device path data structure. 707 @param Size On output, this holds the size of the device 708 path instance, in bytes or zero, if DevicePath 709 is NULL. 710 711 @return A pointer to the current device path instance. 712 713 **/ 714 EFI_DEVICE_PATH_PROTOCOL * 715 EFIAPI 716 UefiDevicePathLibGetNextDevicePathInstance ( 717 IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath, 718 OUT UINTN *Size 719 ) 720 { 721 EFI_DEVICE_PATH_PROTOCOL *DevPath; 722 EFI_DEVICE_PATH_PROTOCOL *ReturnValue; 723 UINT8 Temp; 724 725 ASSERT (Size != NULL); 726 727 if ((DevicePath == NULL) || (*DevicePath == NULL)) { 728 *Size = 0; 729 return NULL; 730 } 731 732 if (!IsDevicePathValid (*DevicePath, 0)) { 733 return NULL; 734 } 735 736 // 737 // Find the end of the device path instance 738 // 739 DevPath = *DevicePath; 740 while (!IsDevicePathEndType (DevPath)) { 741 DevPath = NextDevicePathNode (DevPath); 742 } 743 744 // 745 // Compute the size of the device path instance 746 // 747 *Size = ((UINTN)DevPath - (UINTN)(*DevicePath)) + sizeof (EFI_DEVICE_PATH_PROTOCOL); 748 749 // 750 // Make a copy and return the device path instance 751 // 752 Temp = DevPath->SubType; 753 DevPath->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE; 754 ReturnValue = DuplicateDevicePath (*DevicePath); 755 DevPath->SubType = Temp; 756 757 // 758 // If DevPath is the end of an entire device path, then another instance 759 // does not follow, so *DevicePath is set to NULL. 760 // 761 if (DevicePathSubType (DevPath) == END_ENTIRE_DEVICE_PATH_SUBTYPE) { 762 *DevicePath = NULL; 763 } else { 764 *DevicePath = NextDevicePathNode (DevPath); 765 } 766 767 return ReturnValue; 768 } 769 #endif 770 771 /** 772 Creates a device node. 773 774 This function creates a new device node in a newly allocated buffer of size 775 NodeLength and initializes the device path node header with NodeType and NodeSubType. 776 The new device path node is returned. 777 If NodeLength is smaller than a device path header, then NULL is returned. 778 If there is not enough memory to allocate space for the new device path, then 779 NULL is returned. 780 The memory is allocated from EFI boot services memory. It is the responsibility 781 of the caller to free the memory allocated. 782 783 @param NodeType The device node type for the new device node. 784 @param NodeSubType The device node sub-type for the new device node. 785 @param NodeLength The length of the new device node. 786 787 @return The new device path. 788 789 **/ 790 EFI_DEVICE_PATH_PROTOCOL * 791 EFIAPI 792 CreateDeviceNode ( 793 IN UINT8 NodeType, 794 IN UINT8 NodeSubType, 795 IN UINT16 NodeLength 796 ) 797 { 798 EFI_DEVICE_PATH_PROTOCOL *DevicePath; 799 800 if (NodeLength < sizeof (EFI_DEVICE_PATH_PROTOCOL)) { 801 // 802 // NodeLength is less than the size of the header. 803 // 804 return NULL; 805 } 806 807 DevicePath = AllocateZeroPool (NodeLength); 808 if (DevicePath != NULL) { 809 DevicePath->Type = NodeType; 810 DevicePath->SubType = NodeSubType; 811 SetDevicePathNodeLength (DevicePath, NodeLength); 812 } 813 814 return DevicePath; 815 } 816 817 #ifndef __FreeBSD__ 818 /** 819 Determines if a device path is single or multi-instance. 820 821 This function returns TRUE if the device path specified by DevicePath is 822 multi-instance. 823 Otherwise, FALSE is returned. 824 If DevicePath is NULL or invalid, then FALSE is returned. 825 826 @param DevicePath A pointer to a device path data structure. 827 828 @retval TRUE DevicePath is multi-instance. 829 @retval FALSE DevicePath is not multi-instance, or DevicePath 830 is NULL or invalid. 831 832 **/ 833 BOOLEAN 834 EFIAPI 835 UefiDevicePathLibIsDevicePathMultiInstance ( 836 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath 837 ) 838 { 839 CONST EFI_DEVICE_PATH_PROTOCOL *Node; 840 841 if (DevicePath == NULL) { 842 return FALSE; 843 } 844 845 if (!IsDevicePathValid (DevicePath, 0)) { 846 return FALSE; 847 } 848 849 Node = DevicePath; 850 while (!IsDevicePathEnd (Node)) { 851 if (IsDevicePathEndInstance (Node)) { 852 return TRUE; 853 } 854 855 Node = NextDevicePathNode (Node); 856 } 857 858 return FALSE; 859 } 860 861 /** 862 Allocates a device path for a file and appends it to an existing device path. 863 864 If Device is a valid device handle that contains a device path protocol, then a device path for 865 the file specified by FileName is allocated and appended to the device path associated with the 866 handle Device. The allocated device path is returned. If Device is NULL or Device is a handle 867 that does not support the device path protocol, then a device path containing a single device 868 path node for the file specified by FileName is allocated and returned. 869 The memory for the new device path is allocated from EFI boot services memory. It is the responsibility 870 of the caller to free the memory allocated. 871 872 If FileName is NULL, then ASSERT(). 873 If FileName is not aligned on a 16-bit boundary, then ASSERT(). 874 875 @param Device A pointer to a device handle. This parameter 876 is optional and may be NULL. 877 @param FileName A pointer to a Null-terminated Unicode string. 878 879 @return The allocated device path. 880 881 **/ 882 EFI_DEVICE_PATH_PROTOCOL * 883 EFIAPI 884 FileDevicePath ( 885 IN EFI_HANDLE Device OPTIONAL, 886 IN CONST CHAR16 *FileName 887 ) 888 { 889 UINTN Size; 890 FILEPATH_DEVICE_PATH *FilePath; 891 EFI_DEVICE_PATH_PROTOCOL *DevicePath; 892 EFI_DEVICE_PATH_PROTOCOL *FileDevicePath; 893 894 DevicePath = NULL; 895 896 Size = StrSize (FileName); 897 FileDevicePath = AllocatePool (Size + SIZE_OF_FILEPATH_DEVICE_PATH + END_DEVICE_PATH_LENGTH); 898 if (FileDevicePath != NULL) { 899 FilePath = (FILEPATH_DEVICE_PATH *)FileDevicePath; 900 FilePath->Header.Type = MEDIA_DEVICE_PATH; 901 FilePath->Header.SubType = MEDIA_FILEPATH_DP; 902 CopyMem (&FilePath->PathName, FileName, Size); 903 SetDevicePathNodeLength (&FilePath->Header, Size + SIZE_OF_FILEPATH_DEVICE_PATH); 904 SetDevicePathEndNode (NextDevicePathNode (&FilePath->Header)); 905 906 if (Device != NULL) { 907 DevicePath = DevicePathFromHandle (Device); 908 } 909 910 DevicePath = AppendDevicePath (DevicePath, FileDevicePath); 911 FreePool (FileDevicePath); 912 } 913 914 return DevicePath; 915 } 916 #endif 917