1 /*++ 2 3 Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR> 4 This program and the accompanying materials 5 are licensed and made available under the terms and conditions of the BSD License 6 which accompanies this distribution. The full text of the license may be found at 7 http://opensource.org/licenses/bsd-license.php 8 9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 11 12 Module Name: 13 14 RtDevicePath.c 15 16 Abstract: 17 18 Device Path services. The thing to remember is device paths are built out of 19 nodes. The device path is terminated by an end node that is length 20 sizeof(EFI_DEVICE_PATH_PROTOCOL). That would be why there is sizeof(EFI_DEVICE_PATH_PROTOCOL) 21 all over this file. 22 23 The only place where multi-instance device paths are supported is in 24 environment varibles. Multi-instance device paths should never be placed 25 on a Handle. 26 27 --*/ 28 29 #include "Tiano.h" 30 #include "EfiRuntimeLib.h" 31 #include "RtDevicePath.h" 32 #include EFI_GUID_DEFINITION (FrameworkDevicePath) 33 #include EFI_PROTOCOL_DEFINITION (DevicePath) 34 35 STATIC 36 VOID * 37 InternalAllocatePool ( 38 IN UINTN AllocationSize 39 ) 40 /*++ 41 42 Routine Description: 43 44 Allocate BootServicesData pool. 45 46 Arguments: 47 48 AllocationSize - The size to allocate 49 50 Returns: 51 52 Pointer of the buffer allocated. 53 54 --*/ 55 { 56 VOID *Memory; 57 58 Memory = NULL; 59 gBS->AllocatePool (EfiBootServicesData, AllocationSize, &Memory); 60 return Memory; 61 } 62 63 STATIC 64 VOID * 65 InternalAllocateCopyPool ( 66 IN UINTN AllocationSize, 67 IN VOID *Buffer 68 ) 69 /*++ 70 71 Routine Description: 72 73 Allocate BootServicesData pool and use a buffer provided by 74 caller to fill it. 75 76 Arguments: 77 78 AllocationSize - The size to allocate 79 80 Buffer - Buffer that will be filled into the buffer allocated 81 82 Returns: 83 84 Pointer of the buffer allocated. 85 86 --*/ 87 { 88 VOID *Memory; 89 90 Memory = NULL; 91 gBS->AllocatePool (EfiBootServicesData, AllocationSize, &Memory); 92 if (Memory != NULL) { 93 gBS->CopyMem (Memory, Buffer, AllocationSize); 94 } 95 96 return Memory; 97 } 98 99 STATIC 100 VOID * 101 InternalAllocateZeroPool ( 102 IN UINTN AllocationSize 103 ) 104 /*++ 105 106 Routine Description: 107 108 Allocate BootServicesData pool and zero it. 109 110 Arguments: 111 112 AllocationSize - The size to allocate 113 114 Returns: 115 116 Pointer of the buffer allocated. 117 118 --*/ 119 { 120 VOID *Memory; 121 122 Memory = InternalAllocatePool (AllocationSize); 123 if (Memory != NULL) { 124 gBS->SetMem (Memory, AllocationSize, 0); 125 } 126 127 return Memory; 128 } 129 130 EFI_DEVICE_PATH_PROTOCOL * 131 RtEfiDevicePathInstance ( 132 IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath, 133 OUT UINTN *Size 134 ) 135 /*++ 136 137 Routine Description: 138 Function retrieves the next device path instance from a device path data structure. 139 140 Arguments: 141 DevicePath - A pointer to a device path data structure. 142 143 Size - A pointer to the size of a device path instance in bytes. 144 145 Returns: 146 147 This function returns a pointer to the current device path instance. 148 In addition, it returns the size in bytes of the current device path instance in Size, 149 and a pointer to the next device path instance in DevicePath. 150 If there are no more device path instances in DevicePath, then DevicePath will be set to NULL. 151 152 --*/ 153 { 154 EFI_DEVICE_PATH_PROTOCOL *DevPath; 155 EFI_DEVICE_PATH_PROTOCOL *ReturnValue; 156 UINT8 Temp; 157 158 if (*DevicePath == NULL) { 159 if (Size != NULL) { 160 *Size = 0; 161 } 162 163 return NULL; 164 } 165 166 // 167 // Find the end of the device path instance 168 // 169 DevPath = *DevicePath; 170 while (!IsDevicePathEndType (DevPath)) { 171 DevPath = NextDevicePathNode (DevPath); 172 } 173 174 // 175 // Compute the size of the device path instance 176 // 177 if (Size != NULL) { 178 *Size = ((UINTN) DevPath - (UINTN) (*DevicePath)) + sizeof (EFI_DEVICE_PATH_PROTOCOL); 179 } 180 181 // 182 // Make a copy and return the device path instance 183 // 184 Temp = DevPath->SubType; 185 DevPath->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE; 186 ReturnValue = RtEfiDuplicateDevicePath (*DevicePath); 187 DevPath->SubType = Temp; 188 189 // 190 // If DevPath is the end of an entire device path, then another instance 191 // does not follow, so *DevicePath is set to NULL. 192 // 193 if (DevicePathSubType (DevPath) == END_ENTIRE_DEVICE_PATH_SUBTYPE) { 194 *DevicePath = NULL; 195 } else { 196 *DevicePath = NextDevicePathNode (DevPath); 197 } 198 199 return ReturnValue; 200 } 201 202 BOOLEAN 203 RtEfiIsDevicePathMultiInstance ( 204 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath 205 ) 206 /*++ 207 208 Routine Description: 209 Return TRUE is this is a multi instance device path. 210 211 Arguments: 212 DevicePath - A pointer to a device path data structure. 213 214 215 Returns: 216 TRUE - If DevicePath is multi instance. FALSE - If DevicePath is not multi 217 instance. 218 219 --*/ 220 { 221 EFI_DEVICE_PATH_PROTOCOL *Node; 222 223 if (DevicePath == NULL) { 224 return FALSE; 225 } 226 227 Node = DevicePath; 228 while (!EfiIsDevicePathEnd (Node)) { 229 if (EfiIsDevicePathEndInstance (Node)) { 230 return TRUE; 231 } 232 233 Node = EfiNextDevicePathNode (Node); 234 } 235 236 return FALSE; 237 } 238 239 UINTN 240 RtEfiDevicePathSize ( 241 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath 242 ) 243 /*++ 244 245 Routine Description: 246 247 Calculate the space size of a device path. 248 249 Arguments: 250 251 DevicePath - A specified device path 252 253 Returns: 254 255 The size. 256 257 --*/ 258 { 259 EFI_DEVICE_PATH_PROTOCOL *Start; 260 261 if (DevicePath == NULL) { 262 return 0; 263 } 264 265 // 266 // Search for the end of the device path structure 267 // 268 Start = DevicePath; 269 while (!EfiIsDevicePathEnd (DevicePath)) { 270 DevicePath = EfiNextDevicePathNode (DevicePath); 271 } 272 273 // 274 // Compute the size and add back in the size of the end device path structure 275 // 276 return ((UINTN) DevicePath - (UINTN) Start) + sizeof (EFI_DEVICE_PATH_PROTOCOL); 277 } 278 279 EFI_DEVICE_PATH_PROTOCOL * 280 RtEfiDevicePathFromHandle ( 281 IN EFI_HANDLE Handle 282 ) 283 /*++ 284 285 Routine Description: 286 287 Get the device path protocol interface installed on a specified handle. 288 289 Arguments: 290 291 Handle - a specified handle 292 293 Returns: 294 295 The device path protocol interface installed on that handle. 296 297 --*/ 298 { 299 EFI_DEVICE_PATH_PROTOCOL *DevicePath; 300 301 DevicePath = NULL; 302 gBS->HandleProtocol ( 303 Handle, 304 &gEfiDevicePathProtocolGuid, 305 (VOID *) &DevicePath 306 ); 307 return DevicePath; 308 } 309 310 EFI_DEVICE_PATH_PROTOCOL * 311 RtEfiDuplicateDevicePath ( 312 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath 313 ) 314 /*++ 315 316 Routine Description: 317 318 Duplicate a device path structure. 319 320 Arguments: 321 322 DevicePath - The device path to duplicated. 323 324 Returns: 325 326 The duplicated device path. 327 328 --*/ 329 { 330 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath; 331 UINTN Size; 332 333 if (DevicePath == NULL) { 334 return NULL; 335 } 336 337 // 338 // Compute the size 339 // 340 Size = RtEfiDevicePathSize (DevicePath); 341 if (Size == 0) { 342 return NULL; 343 } 344 345 // 346 // Allocate space for duplicate device path 347 // 348 NewDevicePath = InternalAllocateCopyPool (Size, DevicePath); 349 350 return NewDevicePath; 351 } 352 353 EFI_DEVICE_PATH_PROTOCOL * 354 RtEfiAppendDevicePath ( 355 IN EFI_DEVICE_PATH_PROTOCOL *Src1, 356 IN EFI_DEVICE_PATH_PROTOCOL *Src2 357 ) 358 /*++ 359 360 Routine Description: 361 Function is used to append a Src1 and Src2 together. 362 363 Arguments: 364 Src1 - A pointer to a device path data structure. 365 366 Src2 - A pointer to a device path data structure. 367 368 Returns: 369 370 A pointer to the new device path is returned. 371 NULL is returned if space for the new device path could not be allocated from pool. 372 It is up to the caller to free the memory used by Src1 and Src2 if they are no longer needed. 373 374 --*/ 375 { 376 UINTN Size; 377 UINTN Size1; 378 UINTN Size2; 379 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath; 380 EFI_DEVICE_PATH_PROTOCOL *SecondDevicePath; 381 382 // 383 // If there's only 1 path, just duplicate it 384 // 385 if (!Src1) { 386 ASSERT (!IsDevicePathUnpacked (Src2)); 387 return RtEfiDuplicateDevicePath (Src2); 388 } 389 390 if (!Src2) { 391 ASSERT (!IsDevicePathUnpacked (Src1)); 392 return RtEfiDuplicateDevicePath (Src1); 393 } 394 395 // 396 // Allocate space for the combined device path. It only has one end node of 397 // length EFI_DEVICE_PATH_PROTOCOL 398 // 399 Size1 = RtEfiDevicePathSize (Src1); 400 Size2 = RtEfiDevicePathSize (Src2); 401 Size = Size1 + Size2 - sizeof (EFI_DEVICE_PATH_PROTOCOL); 402 403 NewDevicePath = InternalAllocateCopyPool (Size, Src1); 404 405 if (NewDevicePath != NULL) { 406 407 // 408 // Over write Src1 EndNode and do the copy 409 // 410 SecondDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) ((CHAR8 *) NewDevicePath + (Size1 - sizeof (EFI_DEVICE_PATH_PROTOCOL))); 411 EfiCopyMem (SecondDevicePath, Src2, Size2); 412 } 413 414 return NewDevicePath; 415 } 416 417 EFI_DEVICE_PATH_PROTOCOL * 418 RtEfiAppendDevicePathNode ( 419 IN EFI_DEVICE_PATH_PROTOCOL *Src1, 420 IN EFI_DEVICE_PATH_PROTOCOL *Node 421 ) 422 /*++ 423 424 Routine Description: 425 Function is used to append a device path node to the end of another device path. 426 427 Arguments: 428 Src1 - A pointer to a device path data structure. 429 430 Node - A pointer to a device path data structure. 431 432 Returns: 433 This function returns a pointer to the new device path. 434 If there is not enough temporary pool memory available to complete this function, 435 then NULL is returned. 436 437 438 --*/ 439 { 440 EFI_DEVICE_PATH_PROTOCOL *Temp; 441 EFI_DEVICE_PATH_PROTOCOL *NextNode; 442 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath; 443 UINTN NodeLength; 444 445 // 446 // Build a Node that has a terminator on it 447 // 448 NodeLength = DevicePathNodeLength (Node); 449 450 Temp = InternalAllocateCopyPool (NodeLength + sizeof (EFI_DEVICE_PATH_PROTOCOL), Node); 451 if (Temp == NULL) { 452 return NULL; 453 } 454 455 // 456 // Add and end device path node to convert Node to device path 457 // 458 NextNode = NextDevicePathNode (Temp); 459 SetDevicePathEndNode (NextNode); 460 461 // 462 // Append device paths 463 // 464 NewDevicePath = RtEfiAppendDevicePath (Src1, Temp); 465 gBS->FreePool (Temp); 466 return NewDevicePath; 467 } 468 469 EFI_DEVICE_PATH_PROTOCOL * 470 RtEfiFileDevicePath ( 471 IN EFI_HANDLE Device OPTIONAL, 472 IN CHAR16 *FileName 473 ) 474 /*++ 475 476 Routine Description: 477 478 This function allocates a device path for a file and appends it to an existiong 479 device path. 480 481 Arguments: 482 Device - A pointer to a device handle. 483 484 FileName - A pointer to a Null-terminated Unicodestring. 485 486 Returns: 487 A device path contain the file name. 488 489 --*/ 490 { 491 UINTN Size; 492 FILEPATH_DEVICE_PATH *FilePath; 493 EFI_DEVICE_PATH_PROTOCOL *Eop; 494 EFI_DEVICE_PATH_PROTOCOL *DevicePath; 495 496 for (Size = 0; FileName[Size] != 0; Size++) 497 ; 498 Size = (Size + 1) * 2; 499 500 FilePath = InternalAllocateZeroPool (Size + SIZE_OF_FILEPATH_DEVICE_PATH + sizeof (EFI_DEVICE_PATH_PROTOCOL)); 501 502 DevicePath = NULL; 503 504 if (FilePath != NULL) { 505 506 // 507 // Build a file path 508 // 509 FilePath->Header.Type = MEDIA_DEVICE_PATH; 510 FilePath->Header.SubType = MEDIA_FILEPATH_DP; 511 SetDevicePathNodeLength (&FilePath->Header, Size + SIZE_OF_FILEPATH_DEVICE_PATH); 512 EfiCopyMem (FilePath->PathName, FileName, Size); 513 Eop = NextDevicePathNode (&FilePath->Header); 514 SetDevicePathEndNode (Eop); 515 516 // 517 // Append file path to device's device path 518 // 519 520 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) FilePath; 521 if (Device != NULL) { 522 DevicePath = RtEfiAppendDevicePath ( 523 RtEfiDevicePathFromHandle (Device), 524 DevicePath 525 ); 526 527 gBS->FreePool (FilePath); 528 } 529 } 530 531 return DevicePath; 532 } 533 534 EFI_DEVICE_PATH_PROTOCOL * 535 RtEfiAppendDevicePathInstance ( 536 IN EFI_DEVICE_PATH_PROTOCOL *Src, 537 IN EFI_DEVICE_PATH_PROTOCOL *Instance 538 ) 539 /*++ 540 541 Routine Description: 542 543 Append a device path instance to another. 544 545 Arguments: 546 547 Src - The device path instance to be appended with. 548 Instance - The device path instance appending the other. 549 550 Returns: 551 552 The contaction of these two. 553 554 --*/ 555 { 556 UINT8 *Ptr; 557 EFI_DEVICE_PATH_PROTOCOL *DevPath; 558 UINTN SrcSize; 559 UINTN InstanceSize; 560 561 if (Src == NULL) { 562 return RtEfiDuplicateDevicePath (Instance); 563 } 564 565 SrcSize = RtEfiDevicePathSize (Src); 566 InstanceSize = RtEfiDevicePathSize (Instance); 567 568 Ptr = InternalAllocateCopyPool (SrcSize + InstanceSize, Src); 569 if (Ptr != NULL) { 570 571 DevPath = (EFI_DEVICE_PATH_PROTOCOL *) Ptr; 572 573 while (!IsDevicePathEnd (DevPath)) { 574 DevPath = NextDevicePathNode (DevPath); 575 } 576 // 577 // Convert the End to an End Instance, since we are 578 // appending another instacne after this one its a good 579 // idea. 580 // 581 DevPath->SubType = END_INSTANCE_DEVICE_PATH_SUBTYPE; 582 583 DevPath = NextDevicePathNode (DevPath); 584 EfiCopyMem (DevPath, Instance, InstanceSize); 585 } 586 587 return (EFI_DEVICE_PATH_PROTOCOL *) Ptr; 588 } 589 590 VOID 591 EFIAPI 592 RtEfiInitializeFwVolDevicepathNode ( 593 IN MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvDevicePathNode, 594 IN EFI_GUID *NameGuid 595 ) 596 /*++ 597 598 Routine Description: 599 600 Initialize a Firmware Volume (FV) Media Device Path node. 601 602 Arguments: 603 604 FvDevicePathNode - Pointer to a FV device path node to initialize 605 NameGuid - FV file name to use in FvDevicePathNode 606 607 Returns: 608 609 None 610 611 --*/ 612 { 613 FvDevicePathNode->Header.Type = MEDIA_DEVICE_PATH; 614 FvDevicePathNode->Header.SubType = MEDIA_FV_FILEPATH_DP; 615 SetDevicePathNodeLength (&FvDevicePathNode->Header, sizeof (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH)); 616 617 EfiCopyMem (&FvDevicePathNode->NameGuid, NameGuid, sizeof(EFI_GUID)); 618 } 619 620 EFI_GUID * 621 EFIAPI 622 RtEfiGetNameGuidFromFwVolDevicePathNode ( 623 IN MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvDevicePathNode 624 ) 625 /*++ 626 627 Routine Description: 628 629 Check to see if the Firmware Volume (FV) Media Device Path is valid. 630 631 Arguments: 632 633 FvDevicePathNode - Pointer to FV device path to check 634 635 Returns: 636 637 NULL - FvDevicePathNode is not valid. 638 Other - FvDevicePathNode is valid and pointer to NameGuid was returned. 639 640 --*/ 641 { 642 if (DevicePathType (&FvDevicePathNode->Header) == MEDIA_DEVICE_PATH && 643 DevicePathSubType (&FvDevicePathNode->Header) == MEDIA_FV_FILEPATH_DP) { 644 return &FvDevicePathNode->NameGuid; 645 } 646 647 return NULL; 648 } 649 650