1 /** @file 2 Last PEIM. 3 Responsibility of this module is to load the DXE Core from a Firmware Volume. 4 5 Copyright (c) 2016 HP Development Company, L.P. 6 Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR> 7 This program and the accompanying materials 8 are licensed and made available under the terms and conditions of the BSD License 9 which accompanies this distribution. The full text of the license may be found at 10 http://opensource.org/licenses/bsd-license.php 11 12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 14 15 **/ 16 17 #include "DxeIpl.h" 18 19 20 // 21 // Module Globals used in the DXE to PEI hand off 22 // These must be module globals, so the stack can be switched 23 // 24 CONST EFI_DXE_IPL_PPI mDxeIplPpi = { 25 DxeLoadCore 26 }; 27 28 CONST EFI_PEI_PPI_DESCRIPTOR mDxeIplPpiList = { 29 EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST, 30 &gEfiDxeIplPpiGuid, 31 (VOID *) &mDxeIplPpi 32 }; 33 34 CONST EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI mCustomGuidedSectionExtractionPpi = { 35 CustomGuidedSectionExtract 36 }; 37 38 CONST EFI_PEI_DECOMPRESS_PPI mDecompressPpi = { 39 Decompress 40 }; 41 42 CONST EFI_PEI_PPI_DESCRIPTOR mDecompressPpiList = { 43 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), 44 &gEfiPeiDecompressPpiGuid, 45 (VOID *) &mDecompressPpi 46 }; 47 48 CONST EFI_PEI_PPI_DESCRIPTOR gEndOfPeiSignalPpi = { 49 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), 50 &gEfiEndOfPeiSignalPpiGuid, 51 NULL 52 }; 53 54 CONST EFI_PEI_NOTIFY_DESCRIPTOR mMemoryDiscoveredNotifyList = { 55 (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_DISPATCH | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), 56 &gEfiPeiMemoryDiscoveredPpiGuid, 57 InstallIplPermanentMemoryPpis 58 }; 59 60 /** 61 Entry point of DXE IPL PEIM. 62 63 This function installs DXE IPL PPI. It also reloads 64 itself to memory on non-S3 resume boot path. 65 66 @param FileHandle Handle of the file being invoked. 67 @param PeiServices Describes the list of possible PEI Services. 68 69 @retval EFI_SUCESS The entry point of DXE IPL PEIM executes successfully. 70 @retval Others Some error occurs during the execution of this function. 71 72 **/ 73 EFI_STATUS 74 EFIAPI 75 PeimInitializeDxeIpl ( 76 IN EFI_PEI_FILE_HANDLE FileHandle, 77 IN CONST EFI_PEI_SERVICES **PeiServices 78 ) 79 { 80 EFI_STATUS Status; 81 EFI_BOOT_MODE BootMode; 82 VOID *Dummy; 83 84 BootMode = GetBootModeHob (); 85 86 if (BootMode != BOOT_ON_S3_RESUME) { 87 Status = PeiServicesRegisterForShadow (FileHandle); 88 if (Status == EFI_SUCCESS) { 89 // 90 // EFI_SUCESS means it is the first time to call register for shadow. 91 // 92 return Status; 93 } 94 95 // 96 // Ensure that DXE IPL is shadowed to permanent memory. 97 // 98 ASSERT (Status == EFI_ALREADY_STARTED); 99 100 // 101 // DXE core load requires permanent memory. 102 // 103 Status = PeiServicesLocatePpi ( 104 &gEfiPeiMemoryDiscoveredPpiGuid, 105 0, 106 NULL, 107 (VOID **) &Dummy 108 ); 109 ASSERT_EFI_ERROR (Status); 110 if (EFI_ERROR (Status)) { 111 return Status; 112 } 113 114 // 115 // Now the permanent memory exists, install the PPIs for decompression 116 // and section extraction. 117 // 118 Status = InstallIplPermanentMemoryPpis (NULL, NULL, NULL); 119 ASSERT_EFI_ERROR (Status); 120 } else { 121 // 122 // Install memory discovered PPI notification to install PPIs for 123 // decompression and section extraction. 124 // 125 Status = PeiServicesNotifyPpi (&mMemoryDiscoveredNotifyList); 126 ASSERT_EFI_ERROR (Status); 127 } 128 129 // 130 // Install DxeIpl PPI. 131 // 132 Status = PeiServicesInstallPpi (&mDxeIplPpiList); 133 ASSERT_EFI_ERROR(Status); 134 135 return Status; 136 } 137 138 /** 139 This function installs the PPIs that require permanent memory. 140 141 @param PeiServices Indirect reference to the PEI Services Table. 142 @param NotifyDescriptor Address of the notification descriptor data structure. 143 @param Ppi Address of the PPI that was installed. 144 145 @return EFI_SUCCESS The PPIs were installed successfully. 146 @return Others Some error occurs during the execution of this function. 147 148 **/ 149 EFI_STATUS 150 EFIAPI 151 InstallIplPermanentMemoryPpis ( 152 IN EFI_PEI_SERVICES **PeiServices, 153 IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, 154 IN VOID *Ppi 155 ) 156 { 157 EFI_STATUS Status; 158 EFI_GUID *ExtractHandlerGuidTable; 159 UINTN ExtractHandlerNumber; 160 EFI_PEI_PPI_DESCRIPTOR *GuidPpi; 161 162 // 163 // Get custom extract guided section method guid list 164 // 165 ExtractHandlerNumber = ExtractGuidedSectionGetGuidList (&ExtractHandlerGuidTable); 166 167 // 168 // Install custom guided section extraction PPI 169 // 170 if (ExtractHandlerNumber > 0) { 171 GuidPpi = (EFI_PEI_PPI_DESCRIPTOR *) AllocatePool (ExtractHandlerNumber * sizeof (EFI_PEI_PPI_DESCRIPTOR)); 172 ASSERT (GuidPpi != NULL); 173 while (ExtractHandlerNumber-- > 0) { 174 GuidPpi->Flags = EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST; 175 GuidPpi->Ppi = (VOID *) &mCustomGuidedSectionExtractionPpi; 176 GuidPpi->Guid = &ExtractHandlerGuidTable[ExtractHandlerNumber]; 177 Status = PeiServicesInstallPpi (GuidPpi++); 178 ASSERT_EFI_ERROR(Status); 179 } 180 } 181 182 // 183 // Install Decompress PPI. 184 // 185 Status = PeiServicesInstallPpi (&mDecompressPpiList); 186 ASSERT_EFI_ERROR(Status); 187 188 return Status; 189 } 190 191 /** 192 Validate variable data for the MemoryTypeInformation. 193 194 @param MemoryData Variable data. 195 @param MemoryDataSize Variable data length. 196 197 @return TRUE The variable data is valid. 198 @return FALSE The variable data is invalid. 199 200 **/ 201 BOOLEAN 202 ValidateMemoryTypeInfoVariable ( 203 IN EFI_MEMORY_TYPE_INFORMATION *MemoryData, 204 IN UINTN MemoryDataSize 205 ) 206 { 207 UINTN Count; 208 UINTN Index; 209 210 // Check the input parameter. 211 if (MemoryData == NULL) { 212 return FALSE; 213 } 214 215 // Get Count 216 Count = MemoryDataSize / sizeof (*MemoryData); 217 218 // Check Size 219 if (Count * sizeof(*MemoryData) != MemoryDataSize) { 220 return FALSE; 221 } 222 223 // Check last entry type filed. 224 if (MemoryData[Count - 1].Type != EfiMaxMemoryType) { 225 return FALSE; 226 } 227 228 // Check the type filed. 229 for (Index = 0; Index < Count - 1; Index++) { 230 if (MemoryData[Index].Type >= EfiMaxMemoryType) { 231 return FALSE; 232 } 233 } 234 235 return TRUE; 236 } 237 238 /** 239 Main entry point to last PEIM. 240 241 This function finds DXE Core in the firmware volume and transfer the control to 242 DXE core. 243 244 @param This Entry point for DXE IPL PPI. 245 @param PeiServices General purpose services available to every PEIM. 246 @param HobList Address to the Pei HOB list. 247 248 @return EFI_SUCCESS DXE core was successfully loaded. 249 @return EFI_OUT_OF_RESOURCES There are not enough resources to load DXE core. 250 251 **/ 252 EFI_STATUS 253 EFIAPI 254 DxeLoadCore ( 255 IN CONST EFI_DXE_IPL_PPI *This, 256 IN EFI_PEI_SERVICES **PeiServices, 257 IN EFI_PEI_HOB_POINTERS HobList 258 ) 259 { 260 EFI_STATUS Status; 261 EFI_FV_FILE_INFO DxeCoreFileInfo; 262 EFI_PHYSICAL_ADDRESS DxeCoreAddress; 263 UINT64 DxeCoreSize; 264 EFI_PHYSICAL_ADDRESS DxeCoreEntryPoint; 265 EFI_BOOT_MODE BootMode; 266 EFI_PEI_FILE_HANDLE FileHandle; 267 EFI_PEI_READ_ONLY_VARIABLE2_PPI *Variable; 268 EFI_PEI_LOAD_FILE_PPI *LoadFile; 269 UINTN Instance; 270 UINT32 AuthenticationState; 271 UINTN DataSize; 272 EFI_PEI_S3_RESUME2_PPI *S3Resume; 273 EFI_PEI_RECOVERY_MODULE_PPI *PeiRecovery; 274 EFI_MEMORY_TYPE_INFORMATION MemoryData[EfiMaxMemoryType + 1]; 275 276 // 277 // if in S3 Resume, restore configure 278 // 279 BootMode = GetBootModeHob (); 280 281 if (BootMode == BOOT_ON_S3_RESUME) { 282 Status = PeiServicesLocatePpi ( 283 &gEfiPeiS3Resume2PpiGuid, 284 0, 285 NULL, 286 (VOID **) &S3Resume 287 ); 288 if (EFI_ERROR (Status)) { 289 // 290 // Report Status code that S3Resume PPI can not be found 291 // 292 REPORT_STATUS_CODE ( 293 EFI_ERROR_CODE | EFI_ERROR_MAJOR, 294 (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_EC_S3_RESUME_PPI_NOT_FOUND) 295 ); 296 } 297 ASSERT_EFI_ERROR (Status); 298 299 Status = S3Resume->S3RestoreConfig2 (S3Resume); 300 ASSERT_EFI_ERROR (Status); 301 } else if (BootMode == BOOT_IN_RECOVERY_MODE) { 302 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_PC_RECOVERY_BEGIN)); 303 Status = PeiServicesLocatePpi ( 304 &gEfiPeiRecoveryModulePpiGuid, 305 0, 306 NULL, 307 (VOID **) &PeiRecovery 308 ); 309 310 if (EFI_ERROR (Status)) { 311 DEBUG ((DEBUG_ERROR, "Locate Recovery PPI Failed.(Status = %r)\n", Status)); 312 // 313 // Report Status code the failure of locating Recovery PPI 314 // 315 REPORT_STATUS_CODE ( 316 EFI_ERROR_CODE | EFI_ERROR_MAJOR, 317 (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_EC_RECOVERY_PPI_NOT_FOUND) 318 ); 319 CpuDeadLoop (); 320 } 321 322 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_PC_CAPSULE_LOAD)); 323 Status = PeiRecovery->LoadRecoveryCapsule (PeiServices, PeiRecovery); 324 if (EFI_ERROR (Status)) { 325 DEBUG ((DEBUG_ERROR, "Load Recovery Capsule Failed.(Status = %r)\n", Status)); 326 // 327 // Report Status code that recovery image can not be found 328 // 329 REPORT_STATUS_CODE ( 330 EFI_ERROR_CODE | EFI_ERROR_MAJOR, 331 (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_EC_NO_RECOVERY_CAPSULE) 332 ); 333 CpuDeadLoop (); 334 } 335 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_PC_CAPSULE_START)); 336 // 337 // Now should have a HOB with the DXE core 338 // 339 } 340 341 if (GetFirstGuidHob ((CONST EFI_GUID *)&gEfiMemoryTypeInformationGuid) == NULL) { 342 // 343 // Don't build GuidHob if GuidHob has been installed. 344 // 345 Status = PeiServicesLocatePpi ( 346 &gEfiPeiReadOnlyVariable2PpiGuid, 347 0, 348 NULL, 349 (VOID **)&Variable 350 ); 351 if (!EFI_ERROR (Status)) { 352 DataSize = sizeof (MemoryData); 353 Status = Variable->GetVariable ( 354 Variable, 355 EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME, 356 &gEfiMemoryTypeInformationGuid, 357 NULL, 358 &DataSize, 359 &MemoryData 360 ); 361 if (!EFI_ERROR (Status) && ValidateMemoryTypeInfoVariable(MemoryData, DataSize)) { 362 // 363 // Build the GUID'd HOB for DXE 364 // 365 BuildGuidDataHob ( 366 &gEfiMemoryTypeInformationGuid, 367 MemoryData, 368 DataSize 369 ); 370 } 371 } 372 } 373 374 // 375 // Look in all the FVs present in PEI and find the DXE Core FileHandle 376 // 377 FileHandle = DxeIplFindDxeCore (); 378 379 // 380 // Load the DXE Core from a Firmware Volume. 381 // 382 Instance = 0; 383 do { 384 Status = PeiServicesLocatePpi (&gEfiPeiLoadFilePpiGuid, Instance++, NULL, (VOID **) &LoadFile); 385 // 386 // These must exist an instance of EFI_PEI_LOAD_FILE_PPI to support to load DxeCore file handle successfully. 387 // 388 ASSERT_EFI_ERROR (Status); 389 390 Status = LoadFile->LoadFile ( 391 LoadFile, 392 FileHandle, 393 &DxeCoreAddress, 394 &DxeCoreSize, 395 &DxeCoreEntryPoint, 396 &AuthenticationState 397 ); 398 } while (EFI_ERROR (Status)); 399 400 // 401 // Get the DxeCore File Info from the FileHandle for the DxeCore GUID file name. 402 // 403 Status = PeiServicesFfsGetFileInfo (FileHandle, &DxeCoreFileInfo); 404 ASSERT_EFI_ERROR (Status); 405 406 // 407 // Add HOB for the DXE Core 408 // 409 BuildModuleHob ( 410 &DxeCoreFileInfo.FileName, 411 DxeCoreAddress, 412 ALIGN_VALUE (DxeCoreSize, EFI_PAGE_SIZE), 413 DxeCoreEntryPoint 414 ); 415 416 // 417 // Report Status Code EFI_SW_PEI_PC_HANDOFF_TO_NEXT 418 // 419 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_PEI_CORE | EFI_SW_PEI_CORE_PC_HANDOFF_TO_NEXT)); 420 421 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Loading DXE CORE at 0x%11p EntryPoint=0x%11p\n", (VOID *)(UINTN)DxeCoreAddress, FUNCTION_ENTRY_POINT (DxeCoreEntryPoint))); 422 423 // 424 // Transfer control to the DXE Core 425 // The hand off state is simply a pointer to the HOB list 426 // 427 HandOffToDxeCore (DxeCoreEntryPoint, HobList); 428 // 429 // If we get here, then the DXE Core returned. This is an error 430 // DxeCore should not return. 431 // 432 ASSERT (FALSE); 433 CpuDeadLoop (); 434 435 return EFI_OUT_OF_RESOURCES; 436 } 437 438 439 /** 440 Searches DxeCore in all firmware Volumes and loads the first 441 instance that contains DxeCore. 442 443 @return FileHandle of DxeCore to load DxeCore. 444 445 **/ 446 EFI_PEI_FILE_HANDLE 447 DxeIplFindDxeCore ( 448 VOID 449 ) 450 { 451 EFI_STATUS Status; 452 UINTN Instance; 453 EFI_PEI_FV_HANDLE VolumeHandle; 454 EFI_PEI_FILE_HANDLE FileHandle; 455 456 Instance = 0; 457 while (TRUE) { 458 // 459 // Traverse all firmware volume instances 460 // 461 Status = PeiServicesFfsFindNextVolume (Instance, &VolumeHandle); 462 // 463 // If some error occurs here, then we cannot find any firmware 464 // volume that may contain DxeCore. 465 // 466 if (EFI_ERROR (Status)) { 467 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_CORE_EC_DXE_CORRUPT)); 468 } 469 ASSERT_EFI_ERROR (Status); 470 471 // 472 // Find the DxeCore file type from the beginning in this firmware volume. 473 // 474 FileHandle = NULL; 475 Status = PeiServicesFfsFindNextFile (EFI_FV_FILETYPE_DXE_CORE, VolumeHandle, &FileHandle); 476 if (!EFI_ERROR (Status)) { 477 // 478 // Find DxeCore FileHandle in this volume, then we skip other firmware volume and 479 // return the FileHandle. 480 // 481 return FileHandle; 482 } 483 // 484 // We cannot find DxeCore in this firmware volume, then search the next volume. 485 // 486 Instance++; 487 } 488 } 489 490 491 492 /** 493 The ExtractSection() function processes the input section and 494 returns a pointer to the section contents. If the section being 495 extracted does not require processing (if the section 496 GuidedSectionHeader.Attributes has the 497 EFI_GUIDED_SECTION_PROCESSING_REQUIRED field cleared), then 498 OutputBuffer is just updated to point to the start of the 499 section's contents. Otherwise, *Buffer must be allocated 500 from PEI permanent memory. 501 502 @param This Indicates the 503 EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI instance. 504 Buffer containing the input GUIDed section to be 505 processed. OutputBuffer OutputBuffer is 506 allocated from PEI permanent memory and contains 507 the new section stream. 508 @param InputSection A pointer to the input buffer, which contains 509 the input section to be processed. 510 @param OutputBuffer A pointer to a caller-allocated buffer, whose 511 size is specified by the contents of OutputSize. 512 @param OutputSize A pointer to a caller-allocated 513 UINTN in which the size of *OutputBuffer 514 allocation is stored. If the function 515 returns anything other than EFI_SUCCESS, 516 the value of OutputSize is undefined. 517 @param AuthenticationStatus A pointer to a caller-allocated 518 UINT32 that indicates the 519 authentication status of the 520 output buffer. If the input 521 section's GuidedSectionHeader. 522 Attributes field has the 523 EFI_GUIDED_SECTION_AUTH_STATUS_VALID 524 bit as clear, 525 AuthenticationStatus must return 526 zero. These bits reflect the 527 status of the extraction 528 operation. If the function 529 returns anything other than 530 EFI_SUCCESS, the value of 531 AuthenticationStatus is 532 undefined. 533 534 @retval EFI_SUCCESS The InputSection was 535 successfully processed and the 536 section contents were returned. 537 538 @retval EFI_OUT_OF_RESOURCES The system has insufficient 539 resources to process the request. 540 541 @retval EFI_INVALID_PARAMETER The GUID in InputSection does 542 not match this instance of the 543 GUIDed Section Extraction PPI. 544 545 **/ 546 EFI_STATUS 547 EFIAPI 548 CustomGuidedSectionExtract ( 549 IN CONST EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI *This, 550 IN CONST VOID *InputSection, 551 OUT VOID **OutputBuffer, 552 OUT UINTN *OutputSize, 553 OUT UINT32 *AuthenticationStatus 554 ) 555 { 556 EFI_STATUS Status; 557 UINT8 *ScratchBuffer; 558 UINT32 ScratchBufferSize; 559 UINT32 OutputBufferSize; 560 UINT16 SectionAttribute; 561 562 // 563 // Init local variable 564 // 565 ScratchBuffer = NULL; 566 567 // 568 // Call GetInfo to get the size and attribute of input guided section data. 569 // 570 Status = ExtractGuidedSectionGetInfo ( 571 InputSection, 572 &OutputBufferSize, 573 &ScratchBufferSize, 574 &SectionAttribute 575 ); 576 577 if (EFI_ERROR (Status)) { 578 DEBUG ((DEBUG_ERROR, "GetInfo from guided section Failed - %r\n", Status)); 579 return Status; 580 } 581 582 if (ScratchBufferSize != 0) { 583 // 584 // Allocate scratch buffer 585 // 586 ScratchBuffer = AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize)); 587 if (ScratchBuffer == NULL) { 588 return EFI_OUT_OF_RESOURCES; 589 } 590 } 591 592 if (((SectionAttribute & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) != 0) && OutputBufferSize > 0) { 593 // 594 // Allocate output buffer 595 // 596 *OutputBuffer = AllocatePages (EFI_SIZE_TO_PAGES (OutputBufferSize) + 1); 597 if (*OutputBuffer == NULL) { 598 return EFI_OUT_OF_RESOURCES; 599 } 600 DEBUG ((DEBUG_INFO, "Customized Guided section Memory Size required is 0x%x and address is 0x%p\n", OutputBufferSize, *OutputBuffer)); 601 // 602 // *OutputBuffer still is one section. Adjust *OutputBuffer offset, 603 // skip EFI section header to make section data at page alignment. 604 // 605 *OutputBuffer = (VOID *)((UINT8 *) *OutputBuffer + EFI_PAGE_SIZE - sizeof (EFI_COMMON_SECTION_HEADER)); 606 } 607 608 Status = ExtractGuidedSectionDecode ( 609 InputSection, 610 OutputBuffer, 611 ScratchBuffer, 612 AuthenticationStatus 613 ); 614 if (EFI_ERROR (Status)) { 615 // 616 // Decode failed 617 // 618 DEBUG ((DEBUG_ERROR, "Extract guided section Failed - %r\n", Status)); 619 return Status; 620 } 621 622 *OutputSize = (UINTN) OutputBufferSize; 623 624 return EFI_SUCCESS; 625 } 626 627 628 629 /** 630 Decompresses a section to the output buffer. 631 632 This function looks up the compression type field in the input section and 633 applies the appropriate compression algorithm to compress the section to a 634 callee allocated buffer. 635 636 @param This Points to this instance of the 637 EFI_PEI_DECOMPRESS_PEI PPI. 638 @param CompressionSection Points to the compressed section. 639 @param OutputBuffer Holds the returned pointer to the decompressed 640 sections. 641 @param OutputSize Holds the returned size of the decompress 642 section streams. 643 644 @retval EFI_SUCCESS The section was decompressed successfully. 645 OutputBuffer contains the resulting data and 646 OutputSize contains the resulting size. 647 648 **/ 649 EFI_STATUS 650 EFIAPI 651 Decompress ( 652 IN CONST EFI_PEI_DECOMPRESS_PPI *This, 653 IN CONST EFI_COMPRESSION_SECTION *CompressionSection, 654 OUT VOID **OutputBuffer, 655 OUT UINTN *OutputSize 656 ) 657 { 658 EFI_STATUS Status; 659 UINT8 *DstBuffer; 660 UINT8 *ScratchBuffer; 661 UINT32 DstBufferSize; 662 UINT32 ScratchBufferSize; 663 VOID *CompressionSource; 664 UINT32 CompressionSourceSize; 665 UINT32 UncompressedLength; 666 UINT8 CompressionType; 667 668 if (CompressionSection->CommonHeader.Type != EFI_SECTION_COMPRESSION) { 669 ASSERT (FALSE); 670 return EFI_INVALID_PARAMETER; 671 } 672 673 if (IS_SECTION2 (CompressionSection)) { 674 CompressionSource = (VOID *) ((UINT8 *) CompressionSection + sizeof (EFI_COMPRESSION_SECTION2)); 675 CompressionSourceSize = (UINT32) (SECTION2_SIZE (CompressionSection) - sizeof (EFI_COMPRESSION_SECTION2)); 676 UncompressedLength = ((EFI_COMPRESSION_SECTION2 *) CompressionSection)->UncompressedLength; 677 CompressionType = ((EFI_COMPRESSION_SECTION2 *) CompressionSection)->CompressionType; 678 } else { 679 CompressionSource = (VOID *) ((UINT8 *) CompressionSection + sizeof (EFI_COMPRESSION_SECTION)); 680 CompressionSourceSize = (UINT32) (SECTION_SIZE (CompressionSection) - sizeof (EFI_COMPRESSION_SECTION)); 681 UncompressedLength = CompressionSection->UncompressedLength; 682 CompressionType = CompressionSection->CompressionType; 683 } 684 685 // 686 // This is a compression set, expand it 687 // 688 switch (CompressionType) { 689 case EFI_STANDARD_COMPRESSION: 690 if (FeaturePcdGet(PcdDxeIplSupportUefiDecompress)) { 691 // 692 // Load EFI standard compression. 693 // For compressed data, decompress them to destination buffer. 694 // 695 Status = UefiDecompressGetInfo ( 696 CompressionSource, 697 CompressionSourceSize, 698 &DstBufferSize, 699 &ScratchBufferSize 700 ); 701 if (EFI_ERROR (Status)) { 702 // 703 // GetInfo failed 704 // 705 DEBUG ((DEBUG_ERROR, "Decompress GetInfo Failed - %r\n", Status)); 706 return EFI_NOT_FOUND; 707 } 708 // 709 // Allocate scratch buffer 710 // 711 ScratchBuffer = AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize)); 712 if (ScratchBuffer == NULL) { 713 return EFI_OUT_OF_RESOURCES; 714 } 715 // 716 // Allocate destination buffer, extra one page for adjustment 717 // 718 DstBuffer = AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize) + 1); 719 if (DstBuffer == NULL) { 720 return EFI_OUT_OF_RESOURCES; 721 } 722 // 723 // DstBuffer still is one section. Adjust DstBuffer offset, skip EFI section header 724 // to make section data at page alignment. 725 // 726 DstBuffer = DstBuffer + EFI_PAGE_SIZE - sizeof (EFI_COMMON_SECTION_HEADER); 727 // 728 // Call decompress function 729 // 730 Status = UefiDecompress ( 731 CompressionSource, 732 DstBuffer, 733 ScratchBuffer 734 ); 735 if (EFI_ERROR (Status)) { 736 // 737 // Decompress failed 738 // 739 DEBUG ((DEBUG_ERROR, "Decompress Failed - %r\n", Status)); 740 return EFI_NOT_FOUND; 741 } 742 break; 743 } else { 744 // 745 // PcdDxeIplSupportUefiDecompress is FALSE 746 // Don't support UEFI decompression algorithm. 747 // 748 ASSERT (FALSE); 749 return EFI_NOT_FOUND; 750 } 751 752 case EFI_NOT_COMPRESSED: 753 // 754 // Allocate destination buffer 755 // 756 DstBufferSize = UncompressedLength; 757 DstBuffer = AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize) + 1); 758 if (DstBuffer == NULL) { 759 return EFI_OUT_OF_RESOURCES; 760 } 761 // 762 // Adjust DstBuffer offset, skip EFI section header 763 // to make section data at page alignment. 764 // 765 DstBuffer = DstBuffer + EFI_PAGE_SIZE - sizeof (EFI_COMMON_SECTION_HEADER); 766 // 767 // stream is not actually compressed, just encapsulated. So just copy it. 768 // 769 CopyMem (DstBuffer, CompressionSource, DstBufferSize); 770 break; 771 772 default: 773 // 774 // Don't support other unknown compression type. 775 // 776 ASSERT (FALSE); 777 return EFI_NOT_FOUND; 778 } 779 780 *OutputSize = DstBufferSize; 781 *OutputBuffer = DstBuffer; 782 783 return EFI_SUCCESS; 784 } 785 786 787 /** 788 Updates the Stack HOB passed to DXE phase. 789 790 This function traverses the whole HOB list and update the stack HOB to 791 reflect the real stack that is used by DXE core. 792 793 @param BaseAddress The lower address of stack used by DxeCore. 794 @param Length The length of stack used by DxeCore. 795 796 **/ 797 VOID 798 UpdateStackHob ( 799 IN EFI_PHYSICAL_ADDRESS BaseAddress, 800 IN UINT64 Length 801 ) 802 { 803 EFI_PEI_HOB_POINTERS Hob; 804 805 Hob.Raw = GetHobList (); 806 while ((Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw)) != NULL) { 807 if (CompareGuid (&gEfiHobMemoryAllocStackGuid, &(Hob.MemoryAllocationStack->AllocDescriptor.Name))) { 808 // 809 // Build a new memory allocation HOB with old stack info with EfiBootServicesData type. Need to 810 // avoid this region be reclaimed by DXE core as the IDT built in SEC might be on stack, and some 811 // PEIMs may also keep key information on stack 812 // 813 BuildMemoryAllocationHob ( 814 Hob.MemoryAllocationStack->AllocDescriptor.MemoryBaseAddress, 815 Hob.MemoryAllocationStack->AllocDescriptor.MemoryLength, 816 EfiBootServicesData 817 ); 818 // 819 // Update the BSP Stack Hob to reflect the new stack info. 820 // 821 Hob.MemoryAllocationStack->AllocDescriptor.MemoryBaseAddress = BaseAddress; 822 Hob.MemoryAllocationStack->AllocDescriptor.MemoryLength = Length; 823 break; 824 } 825 Hob.Raw = GET_NEXT_HOB (Hob); 826 } 827 } 828