1 /** @file 2 Implementation of the 6 PEI Ffs (FV) APIs in library form. 3 4 This code only knows about a FV if it has a EFI_HOB_TYPE_FV entry in the HOB list 5 6 Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR> 7 8 This program and the accompanying materials 9 are licensed and made available under the terms and conditions of the BSD License 10 which accompanies this distribution. The full text of the license may be found at 11 http://opensource.org/licenses/bsd-license.php 12 13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 15 16 **/ 17 18 #include <PrePi.h> 19 #include <Library/ExtractGuidedSectionLib.h> 20 21 22 #define GET_OCCUPIED_SIZE(ActualSize, Alignment) \ 23 (ActualSize) + (((Alignment) - ((ActualSize) & ((Alignment) - 1))) & ((Alignment) - 1)) 24 25 26 /** 27 Returns the highest bit set of the State field 28 29 @param ErasePolarity Erase Polarity as defined by EFI_FVB2_ERASE_POLARITY 30 in the Attributes field. 31 @param FfsHeader Pointer to FFS File Header 32 33 34 @retval the highest bit in the State field 35 36 **/ 37 STATIC 38 EFI_FFS_FILE_STATE 39 GetFileState( 40 IN UINT8 ErasePolarity, 41 IN EFI_FFS_FILE_HEADER *FfsHeader 42 ) 43 { 44 EFI_FFS_FILE_STATE FileState; 45 EFI_FFS_FILE_STATE HighestBit; 46 47 FileState = FfsHeader->State; 48 49 if (ErasePolarity != 0) { 50 FileState = (EFI_FFS_FILE_STATE)~FileState; 51 } 52 53 HighestBit = 0x80; 54 while (HighestBit != 0 && (HighestBit & FileState) == 0) { 55 HighestBit >>= 1; 56 } 57 58 return HighestBit; 59 } 60 61 62 /** 63 Calculates the checksum of the header of a file. 64 The header is a zero byte checksum, so zero means header is good 65 66 @param FfsHeader Pointer to FFS File Header 67 68 @retval Checksum of the header 69 70 **/ 71 STATIC 72 UINT8 73 CalculateHeaderChecksum ( 74 IN EFI_FFS_FILE_HEADER *FileHeader 75 ) 76 { 77 UINT8 *Ptr; 78 UINTN Index; 79 UINT8 Sum; 80 81 Sum = 0; 82 Ptr = (UINT8 *)FileHeader; 83 84 for (Index = 0; Index < sizeof(EFI_FFS_FILE_HEADER) - 3; Index += 4) { 85 Sum = (UINT8)(Sum + Ptr[Index]); 86 Sum = (UINT8)(Sum + Ptr[Index+1]); 87 Sum = (UINT8)(Sum + Ptr[Index+2]); 88 Sum = (UINT8)(Sum + Ptr[Index+3]); 89 } 90 91 for (; Index < sizeof(EFI_FFS_FILE_HEADER); Index++) { 92 Sum = (UINT8)(Sum + Ptr[Index]); 93 } 94 95 // 96 // State field (since this indicates the different state of file). 97 // 98 Sum = (UINT8)(Sum - FileHeader->State); 99 // 100 // Checksum field of the file is not part of the header checksum. 101 // 102 Sum = (UINT8)(Sum - FileHeader->IntegrityCheck.Checksum.File); 103 104 return Sum; 105 } 106 107 108 /** 109 Given a FileHandle return the VolumeHandle 110 111 @param FileHandle File handle to look up 112 @param VolumeHandle Match for FileHandle 113 114 @retval TRUE VolumeHandle is valid 115 116 **/ 117 STATIC 118 BOOLEAN 119 EFIAPI 120 FileHandleToVolume ( 121 IN EFI_PEI_FILE_HANDLE FileHandle, 122 OUT EFI_PEI_FV_HANDLE *VolumeHandle 123 ) 124 { 125 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; 126 EFI_PEI_HOB_POINTERS Hob; 127 128 Hob.Raw = GetHobList (); 129 if (Hob.Raw == NULL) { 130 return FALSE; 131 } 132 133 do { 134 Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, Hob.Raw); 135 if (Hob.Raw != NULL) { 136 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(Hob.FirmwareVolume->BaseAddress); 137 if (((UINT64) (UINTN) FileHandle > (UINT64) (UINTN) FwVolHeader ) && \ 138 ((UINT64) (UINTN) FileHandle <= ((UINT64) (UINTN) FwVolHeader + FwVolHeader->FvLength - 1))) { 139 *VolumeHandle = (EFI_PEI_FV_HANDLE)FwVolHeader; 140 return TRUE; 141 } 142 143 Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, GET_NEXT_HOB (Hob)); 144 } 145 } while (Hob.Raw != NULL); 146 147 return FALSE; 148 } 149 150 151 152 /** 153 Given the input file pointer, search for the next matching file in the 154 FFS volume as defined by SearchType. The search starts from FileHeader inside 155 the Firmware Volume defined by FwVolHeader. 156 157 @param FileHandle File handle to look up 158 @param VolumeHandle Match for FileHandle 159 160 161 **/ 162 EFI_STATUS 163 FindFileEx ( 164 IN CONST EFI_PEI_FV_HANDLE FvHandle, 165 IN CONST EFI_GUID *FileName, OPTIONAL 166 IN EFI_FV_FILETYPE SearchType, 167 IN OUT EFI_PEI_FILE_HANDLE *FileHandle 168 ) 169 { 170 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; 171 EFI_FFS_FILE_HEADER **FileHeader; 172 EFI_FFS_FILE_HEADER *FfsFileHeader; 173 EFI_FIRMWARE_VOLUME_EXT_HEADER *FwVolExHeaderInfo; 174 UINT32 FileLength; 175 UINT32 FileOccupiedSize; 176 UINT32 FileOffset; 177 UINT64 FvLength; 178 UINT8 ErasePolarity; 179 UINT8 FileState; 180 181 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)FvHandle; 182 FileHeader = (EFI_FFS_FILE_HEADER **)FileHandle; 183 184 FvLength = FwVolHeader->FvLength; 185 if (FwVolHeader->Attributes & EFI_FVB2_ERASE_POLARITY) { 186 ErasePolarity = 1; 187 } else { 188 ErasePolarity = 0; 189 } 190 191 // 192 // If FileHeader is not specified (NULL) or FileName is not NULL, 193 // start with the first file in the firmware volume. Otherwise, 194 // start from the FileHeader. 195 // 196 if ((*FileHeader == NULL) || (FileName != NULL)) { 197 FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FwVolHeader + FwVolHeader->HeaderLength); 198 if (FwVolHeader->ExtHeaderOffset != 0) { 199 FwVolExHeaderInfo = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)(((UINT8 *)FwVolHeader) + FwVolHeader->ExtHeaderOffset); 200 FfsFileHeader = (EFI_FFS_FILE_HEADER *)(((UINT8 *)FwVolExHeaderInfo) + FwVolExHeaderInfo->ExtHeaderSize); 201 } 202 } else { 203 // 204 // Length is 24 bits wide so mask upper 8 bits 205 // FileLength is adjusted to FileOccupiedSize as it is 8 byte aligned. 206 // 207 FileLength = *(UINT32 *)(*FileHeader)->Size & 0x00FFFFFF; 208 FileOccupiedSize = GET_OCCUPIED_SIZE (FileLength, 8); 209 FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)*FileHeader + FileOccupiedSize); 210 } 211 212 // FFS files begin with a header that is aligned on an 8-byte boundary 213 FfsFileHeader = ALIGN_POINTER (FfsFileHeader, 8); 214 215 FileOffset = (UINT32) ((UINT8 *)FfsFileHeader - (UINT8 *)FwVolHeader); 216 ASSERT (FileOffset <= 0xFFFFFFFF); 217 218 while (FileOffset < (FvLength - sizeof (EFI_FFS_FILE_HEADER))) { 219 // 220 // Get FileState which is the highest bit of the State 221 // 222 FileState = GetFileState (ErasePolarity, FfsFileHeader); 223 224 switch (FileState) { 225 226 case EFI_FILE_HEADER_INVALID: 227 FileOffset += sizeof(EFI_FFS_FILE_HEADER); 228 FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + sizeof(EFI_FFS_FILE_HEADER)); 229 break; 230 231 case EFI_FILE_DATA_VALID: 232 case EFI_FILE_MARKED_FOR_UPDATE: 233 if (CalculateHeaderChecksum (FfsFileHeader) != 0) { 234 ASSERT (FALSE); 235 *FileHeader = NULL; 236 return EFI_NOT_FOUND; 237 } 238 239 FileLength = *(UINT32 *)(FfsFileHeader->Size) & 0x00FFFFFF; 240 FileOccupiedSize = GET_OCCUPIED_SIZE(FileLength, 8); 241 242 if (FileName != NULL) { 243 if (CompareGuid (&FfsFileHeader->Name, (EFI_GUID*)FileName)) { 244 *FileHeader = FfsFileHeader; 245 return EFI_SUCCESS; 246 } 247 } else if (((SearchType == FfsFileHeader->Type) || (SearchType == EFI_FV_FILETYPE_ALL)) && 248 (FfsFileHeader->Type != EFI_FV_FILETYPE_FFS_PAD)) { 249 *FileHeader = FfsFileHeader; 250 return EFI_SUCCESS; 251 } 252 253 FileOffset += FileOccupiedSize; 254 FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + FileOccupiedSize); 255 break; 256 257 case EFI_FILE_DELETED: 258 FileLength = *(UINT32 *)(FfsFileHeader->Size) & 0x00FFFFFF; 259 FileOccupiedSize = GET_OCCUPIED_SIZE(FileLength, 8); 260 FileOffset += FileOccupiedSize; 261 FfsFileHeader = (EFI_FFS_FILE_HEADER *)((UINT8 *)FfsFileHeader + FileOccupiedSize); 262 break; 263 264 default: 265 *FileHeader = NULL; 266 return EFI_NOT_FOUND; 267 } 268 } 269 270 271 *FileHeader = NULL; 272 return EFI_NOT_FOUND; 273 } 274 275 276 /** 277 Go through the file to search SectionType section, 278 when meeting an encapsuled section. 279 280 @param SectionType - Filter to find only section of this type. 281 @param Section - From where to search. 282 @param SectionSize - The file size to search. 283 @param OutputBuffer - Pointer to the section to search. 284 285 @retval EFI_SUCCESS 286 **/ 287 EFI_STATUS 288 FfsProcessSection ( 289 IN EFI_SECTION_TYPE SectionType, 290 IN EFI_COMMON_SECTION_HEADER *Section, 291 IN UINTN SectionSize, 292 OUT VOID **OutputBuffer 293 ) 294 { 295 EFI_STATUS Status; 296 UINT32 SectionLength; 297 UINT32 ParsedLength; 298 EFI_COMPRESSION_SECTION *CompressionSection; 299 UINT32 DstBufferSize; 300 VOID *ScratchBuffer; 301 UINT32 ScratchBufferSize; 302 VOID *DstBuffer; 303 UINT16 SectionAttribute; 304 UINT32 AuthenticationStatus; 305 306 307 *OutputBuffer = NULL; 308 ParsedLength = 0; 309 Status = EFI_NOT_FOUND; 310 while (ParsedLength < SectionSize) { 311 if (Section->Type == SectionType) { 312 *OutputBuffer = (VOID *)(Section + 1); 313 314 return EFI_SUCCESS; 315 } else if ((Section->Type == EFI_SECTION_COMPRESSION) || (Section->Type == EFI_SECTION_GUID_DEFINED)) { 316 317 if (Section->Type == EFI_SECTION_COMPRESSION) { 318 CompressionSection = (EFI_COMPRESSION_SECTION *) Section; 319 SectionLength = *(UINT32 *)Section->Size & 0x00FFFFFF; 320 321 if (CompressionSection->CompressionType != EFI_STANDARD_COMPRESSION) { 322 return EFI_UNSUPPORTED; 323 } 324 325 Status = UefiDecompressGetInfo ( 326 (UINT8 *) ((EFI_COMPRESSION_SECTION *) Section + 1), 327 (UINT32) SectionLength - sizeof (EFI_COMPRESSION_SECTION), 328 &DstBufferSize, 329 &ScratchBufferSize 330 ); 331 } else if (Section->Type == EFI_SECTION_GUID_DEFINED) { 332 Status = ExtractGuidedSectionGetInfo ( 333 Section, 334 &DstBufferSize, 335 &ScratchBufferSize, 336 &SectionAttribute 337 ); 338 } 339 340 if (EFI_ERROR (Status)) { 341 // 342 // GetInfo failed 343 // 344 DEBUG ((EFI_D_ERROR, "Decompress GetInfo Failed - %r\n", Status)); 345 return EFI_NOT_FOUND; 346 } 347 // 348 // Allocate scratch buffer 349 // 350 ScratchBuffer = (VOID *)(UINTN)AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize)); 351 if (ScratchBuffer == NULL) { 352 return EFI_OUT_OF_RESOURCES; 353 } 354 // 355 // Allocate destination buffer, extra one page for adjustment 356 // 357 DstBuffer = (VOID *)(UINTN)AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize) + 1); 358 if (DstBuffer == NULL) { 359 return EFI_OUT_OF_RESOURCES; 360 } 361 // 362 // DstBuffer still is one section. Adjust DstBuffer offset, skip EFI section header 363 // to make section data at page alignment. 364 // 365 DstBuffer = (UINT8 *)DstBuffer + EFI_PAGE_SIZE - sizeof (EFI_COMMON_SECTION_HEADER); 366 // 367 // Call decompress function 368 // 369 if (Section->Type == EFI_SECTION_COMPRESSION) { 370 Status = UefiDecompress ( 371 (CHAR8 *) ((EFI_COMPRESSION_SECTION *) Section + 1), 372 DstBuffer, 373 ScratchBuffer 374 ); 375 } else if (Section->Type == EFI_SECTION_GUID_DEFINED) { 376 Status = ExtractGuidedSectionDecode ( 377 Section, 378 &DstBuffer, 379 ScratchBuffer, 380 &AuthenticationStatus 381 ); 382 } 383 384 if (EFI_ERROR (Status)) { 385 // 386 // Decompress failed 387 // 388 DEBUG ((EFI_D_ERROR, "Decompress Failed - %r\n", Status)); 389 return EFI_NOT_FOUND; 390 } else { 391 return FfsProcessSection ( 392 SectionType, 393 DstBuffer, 394 DstBufferSize, 395 OutputBuffer 396 ); 397 } 398 } 399 400 // 401 // Size is 24 bits wide so mask upper 8 bits. 402 // SectionLength is adjusted it is 4 byte aligned. 403 // Go to the next section 404 // 405 SectionLength = *(UINT32 *)Section->Size & 0x00FFFFFF; 406 SectionLength = GET_OCCUPIED_SIZE (SectionLength, 4); 407 ASSERT (SectionLength != 0); 408 ParsedLength += SectionLength; 409 Section = (EFI_COMMON_SECTION_HEADER *)((UINT8 *)Section + SectionLength); 410 } 411 412 return EFI_NOT_FOUND; 413 } 414 415 416 417 /** 418 This service enables discovery sections of a given type within a valid FFS file. 419 420 @param SearchType The value of the section type to find. 421 @param FfsFileHeader A pointer to the file header that contains the set of sections to 422 be searched. 423 @param SectionData A pointer to the discovered section, if successful. 424 425 @retval EFI_SUCCESS The section was found. 426 @retval EFI_NOT_FOUND The section was not found. 427 428 **/ 429 EFI_STATUS 430 EFIAPI 431 FfsFindSectionData ( 432 IN EFI_SECTION_TYPE SectionType, 433 IN EFI_PEI_FILE_HANDLE FileHandle, 434 OUT VOID **SectionData 435 ) 436 { 437 EFI_FFS_FILE_HEADER *FfsFileHeader; 438 UINT32 FileSize; 439 EFI_COMMON_SECTION_HEADER *Section; 440 441 FfsFileHeader = (EFI_FFS_FILE_HEADER *)(FileHandle); 442 443 // 444 // Size is 24 bits wide so mask upper 8 bits. 445 // Does not include FfsFileHeader header size 446 // FileSize is adjusted to FileOccupiedSize as it is 8 byte aligned. 447 // 448 Section = (EFI_COMMON_SECTION_HEADER *)(FfsFileHeader + 1); 449 FileSize = *(UINT32 *)(FfsFileHeader->Size) & 0x00FFFFFF; 450 FileSize -= sizeof (EFI_FFS_FILE_HEADER); 451 452 return FfsProcessSection ( 453 SectionType, 454 Section, 455 FileSize, 456 SectionData 457 ); 458 } 459 460 461 462 463 464 465 /** 466 This service enables discovery of additional firmware files. 467 468 @param SearchType A filter to find files only of this type. 469 @param FwVolHeader Pointer to the firmware volume header of the volume to search. 470 This parameter must point to a valid FFS volume. 471 @param FileHeader Pointer to the current file from which to begin searching. 472 473 @retval EFI_SUCCESS The file was found. 474 @retval EFI_NOT_FOUND The file was not found. 475 @retval EFI_NOT_FOUND The header checksum was not zero. 476 477 **/ 478 EFI_STATUS 479 EFIAPI 480 FfsFindNextFile ( 481 IN UINT8 SearchType, 482 IN EFI_PEI_FV_HANDLE VolumeHandle, 483 IN OUT EFI_PEI_FILE_HANDLE *FileHandle 484 ) 485 { 486 return FindFileEx (VolumeHandle, NULL, SearchType, FileHandle); 487 } 488 489 490 /** 491 This service enables discovery of additional firmware volumes. 492 493 @param Instance This instance of the firmware volume to find. The value 0 is the 494 Boot Firmware Volume (BFV). 495 @param FwVolHeader Pointer to the firmware volume header of the volume to return. 496 497 @retval EFI_SUCCESS The volume was found. 498 @retval EFI_NOT_FOUND The volume was not found. 499 500 **/ 501 EFI_STATUS 502 EFIAPI 503 FfsFindNextVolume ( 504 IN UINTN Instance, 505 IN OUT EFI_PEI_FV_HANDLE *VolumeHandle 506 ) 507 { 508 EFI_PEI_HOB_POINTERS Hob; 509 510 511 Hob.Raw = GetHobList (); 512 if (Hob.Raw == NULL) { 513 return EFI_NOT_FOUND; 514 } 515 516 do { 517 Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, Hob.Raw); 518 if (Hob.Raw != NULL) { 519 if (Instance-- == 0) { 520 *VolumeHandle = (EFI_PEI_FV_HANDLE)(UINTN)(Hob.FirmwareVolume->BaseAddress); 521 return EFI_SUCCESS; 522 } 523 524 Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, GET_NEXT_HOB (Hob)); 525 } 526 } while (Hob.Raw != NULL); 527 528 return EFI_NOT_FOUND; 529 530 } 531 532 533 /** 534 Find a file in the volume by name 535 536 @param FileName A pointer to the name of the file to 537 find within the firmware volume. 538 539 @param VolumeHandle The firmware volume to search FileHandle 540 Upon exit, points to the found file's 541 handle or NULL if it could not be found. 542 543 @retval EFI_SUCCESS File was found. 544 545 @retval EFI_NOT_FOUND File was not found. 546 547 @retval EFI_INVALID_PARAMETER VolumeHandle or FileHandle or 548 FileName was NULL. 549 550 **/ 551 EFI_STATUS 552 EFIAPI 553 FfsFindFileByName ( 554 IN CONST EFI_GUID *FileName, 555 IN EFI_PEI_FV_HANDLE VolumeHandle, 556 OUT EFI_PEI_FILE_HANDLE *FileHandle 557 ) 558 { 559 EFI_STATUS Status; 560 if ((VolumeHandle == NULL) || (FileName == NULL) || (FileHandle == NULL)) { 561 return EFI_INVALID_PARAMETER; 562 } 563 Status = FindFileEx (VolumeHandle, FileName, 0, FileHandle); 564 if (Status == EFI_NOT_FOUND) { 565 *FileHandle = NULL; 566 } 567 return Status; 568 } 569 570 571 572 573 /** 574 Get information about the file by name. 575 576 @param FileHandle Handle of the file. 577 578 @param FileInfo Upon exit, points to the file's 579 information. 580 581 @retval EFI_SUCCESS File information returned. 582 583 @retval EFI_INVALID_PARAMETER If FileHandle does not 584 represent a valid file. 585 586 @retval EFI_INVALID_PARAMETER If FileInfo is NULL. 587 588 **/ 589 EFI_STATUS 590 EFIAPI 591 FfsGetFileInfo ( 592 IN EFI_PEI_FILE_HANDLE FileHandle, 593 OUT EFI_FV_FILE_INFO *FileInfo 594 ) 595 { 596 UINT8 FileState; 597 UINT8 ErasePolarity; 598 EFI_FFS_FILE_HEADER *FileHeader; 599 EFI_PEI_FV_HANDLE VolumeHandle; 600 601 if ((FileHandle == NULL) || (FileInfo == NULL)) { 602 return EFI_INVALID_PARAMETER; 603 } 604 605 VolumeHandle = 0; 606 // 607 // Retrieve the FirmwareVolume which the file resides in. 608 // 609 if (!FileHandleToVolume(FileHandle, &VolumeHandle)) { 610 return EFI_INVALID_PARAMETER; 611 } 612 613 if (((EFI_FIRMWARE_VOLUME_HEADER*)VolumeHandle)->Attributes & EFI_FVB2_ERASE_POLARITY) { 614 ErasePolarity = 1; 615 } else { 616 ErasePolarity = 0; 617 } 618 619 // 620 // Get FileState which is the highest bit of the State 621 // 622 FileState = GetFileState (ErasePolarity, (EFI_FFS_FILE_HEADER*)FileHandle); 623 624 switch (FileState) { 625 case EFI_FILE_DATA_VALID: 626 case EFI_FILE_MARKED_FOR_UPDATE: 627 break; 628 default: 629 return EFI_INVALID_PARAMETER; 630 } 631 632 FileHeader = (EFI_FFS_FILE_HEADER *)FileHandle; 633 CopyMem (&FileInfo->FileName, &FileHeader->Name, sizeof(EFI_GUID)); 634 FileInfo->FileType = FileHeader->Type; 635 FileInfo->FileAttributes = FileHeader->Attributes; 636 FileInfo->BufferSize = ((*(UINT32 *)FileHeader->Size) & 0x00FFFFFF) - sizeof (EFI_FFS_FILE_HEADER); 637 FileInfo->Buffer = (FileHeader + 1); 638 return EFI_SUCCESS; 639 } 640 641 642 /** 643 Get Information about the volume by name 644 645 @param VolumeHandle Handle of the volume. 646 647 @param VolumeInfo Upon exit, points to the volume's 648 information. 649 650 @retval EFI_SUCCESS File information returned. 651 652 @retval EFI_INVALID_PARAMETER If FileHandle does not 653 represent a valid file. 654 655 @retval EFI_INVALID_PARAMETER If FileInfo is NULL. 656 657 **/ 658 EFI_STATUS 659 EFIAPI 660 FfsGetVolumeInfo ( 661 IN EFI_PEI_FV_HANDLE VolumeHandle, 662 OUT EFI_FV_INFO *VolumeInfo 663 ) 664 { 665 EFI_FIRMWARE_VOLUME_HEADER FwVolHeader; 666 EFI_FIRMWARE_VOLUME_EXT_HEADER *FwVolExHeaderInfo; 667 668 if (VolumeInfo == NULL) { 669 return EFI_INVALID_PARAMETER; 670 } 671 672 // 673 // VolumeHandle may not align at 8 byte, 674 // but FvLength is UINT64 type, which requires FvHeader align at least 8 byte. 675 // So, Copy FvHeader into the local FvHeader structure. 676 // 677 CopyMem (&FwVolHeader, VolumeHandle, sizeof (EFI_FIRMWARE_VOLUME_HEADER)); 678 // 679 // Check Fv Image Signature 680 // 681 if (FwVolHeader.Signature != EFI_FVH_SIGNATURE) { 682 return EFI_INVALID_PARAMETER; 683 } 684 VolumeInfo->FvAttributes = FwVolHeader.Attributes; 685 VolumeInfo->FvStart = (VOID *) VolumeHandle; 686 VolumeInfo->FvSize = FwVolHeader.FvLength; 687 CopyMem (&VolumeInfo->FvFormat, &FwVolHeader.FileSystemGuid, sizeof(EFI_GUID)); 688 689 if (FwVolHeader.ExtHeaderOffset != 0) { 690 FwVolExHeaderInfo = (EFI_FIRMWARE_VOLUME_EXT_HEADER*)(((UINT8 *)VolumeHandle) + FwVolHeader.ExtHeaderOffset); 691 CopyMem (&VolumeInfo->FvName, &FwVolExHeaderInfo->FvName, sizeof(EFI_GUID)); 692 } 693 return EFI_SUCCESS; 694 } 695 696 697 698 /** 699 Search through every FV until you find a file of type FileType 700 701 @param FileType File handle of a Fv type file. 702 @param Volumehandle On succes Volume Handle of the match 703 @param FileHandle On success File Handle of the match 704 705 @retval EFI_NOT_FOUND FV image can't be found. 706 @retval EFI_SUCCESS Successfully found FileType 707 708 **/ 709 EFI_STATUS 710 EFIAPI 711 FfsAnyFvFindFirstFile ( 712 IN EFI_FV_FILETYPE FileType, 713 OUT EFI_PEI_FV_HANDLE *VolumeHandle, 714 OUT EFI_PEI_FILE_HANDLE *FileHandle 715 ) 716 { 717 EFI_STATUS Status; 718 UINTN Instance; 719 720 // 721 // Search every FV for the DXE Core 722 // 723 Instance = 0; 724 *FileHandle = NULL; 725 726 while (1) 727 { 728 Status = FfsFindNextVolume (Instance++, VolumeHandle); 729 if (EFI_ERROR (Status)) 730 { 731 break; 732 } 733 734 Status = FfsFindNextFile (FileType, *VolumeHandle, FileHandle); 735 if (!EFI_ERROR (Status)) 736 { 737 break; 738 } 739 } 740 741 return Status; 742 } 743 744 745 746 /** 747 Get Fv image from the FV type file, then add FV & FV2 Hob. 748 749 @param FileHandle File handle of a Fv type file. 750 751 752 @retval EFI_NOT_FOUND FV image can't be found. 753 @retval EFI_SUCCESS Successfully to process it. 754 755 **/ 756 EFI_STATUS 757 EFIAPI 758 FfsProcessFvFile ( 759 IN EFI_PEI_FILE_HANDLE FvFileHandle 760 ) 761 { 762 EFI_STATUS Status; 763 EFI_PEI_FV_HANDLE FvImageHandle; 764 EFI_FV_INFO FvImageInfo; 765 UINT32 FvAlignment; 766 VOID *FvBuffer; 767 EFI_PEI_HOB_POINTERS HobFv2; 768 769 FvBuffer = NULL; 770 771 772 // 773 // Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has already 774 // been extracted. 775 // 776 HobFv2.Raw = GetHobList (); 777 while ((HobFv2.Raw = GetNextHob (EFI_HOB_TYPE_FV2, HobFv2.Raw)) != NULL) { 778 if (CompareGuid (&(((EFI_FFS_FILE_HEADER *)FvFileHandle)->Name), &HobFv2.FirmwareVolume2->FileName)) { 779 // 780 // this FILE has been dispatched, it will not be dispatched again. 781 // 782 return EFI_SUCCESS; 783 } 784 HobFv2.Raw = GET_NEXT_HOB (HobFv2); 785 } 786 787 // 788 // Find FvImage in FvFile 789 // 790 Status = FfsFindSectionData (EFI_SECTION_FIRMWARE_VOLUME_IMAGE, FvFileHandle, (VOID **)&FvImageHandle); 791 if (EFI_ERROR (Status)) { 792 return Status; 793 } 794 795 // 796 // Collect FvImage Info. 797 // 798 ZeroMem (&FvImageInfo, sizeof (FvImageInfo)); 799 Status = FfsGetVolumeInfo (FvImageHandle, &FvImageInfo); 800 ASSERT_EFI_ERROR (Status); 801 802 // 803 // FvAlignment must be more than 8 bytes required by FvHeader structure. 804 // 805 FvAlignment = 1 << ((FvImageInfo.FvAttributes & EFI_FVB2_ALIGNMENT) >> 16); 806 if (FvAlignment < 8) { 807 FvAlignment = 8; 808 } 809 810 // 811 // Check FvImage 812 // 813 if ((UINTN) FvImageInfo.FvStart % FvAlignment != 0) { 814 FvBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES ((UINT32) FvImageInfo.FvSize), FvAlignment); 815 if (FvBuffer == NULL) { 816 return EFI_OUT_OF_RESOURCES; 817 } 818 CopyMem (FvBuffer, FvImageInfo.FvStart, (UINTN) FvImageInfo.FvSize); 819 // 820 // Update FvImageInfo after reload FvImage to new aligned memory 821 // 822 FfsGetVolumeInfo ((EFI_PEI_FV_HANDLE) FvBuffer, &FvImageInfo); 823 } 824 825 826 // 827 // Inform HOB consumer phase, i.e. DXE core, the existance of this FV 828 // 829 BuildFvHob ((EFI_PHYSICAL_ADDRESS) (UINTN) FvImageInfo.FvStart, FvImageInfo.FvSize); 830 831 // 832 // Makes the encapsulated volume show up in DXE phase to skip processing of 833 // encapsulated file again. 834 // 835 BuildFv2Hob ( 836 (EFI_PHYSICAL_ADDRESS) (UINTN) FvImageInfo.FvStart, 837 FvImageInfo.FvSize, 838 &FvImageInfo.FvName, 839 &(((EFI_FFS_FILE_HEADER *)FvFileHandle)->Name) 840 ); 841 842 return EFI_SUCCESS; 843 } 844 845 846