2. Add three PeCoff library instances for NT32 PeImage load. 3. Update PeCoffGetEntryPointLib to support TeImage. git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@3965 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			750 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			750 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /**@file
 | |
|   Last PEIM.
 | |
|   Responsibility of this module is to load the DXE Core from a Firmware Volume.
 | |
| 
 | |
| Copyright (c) 2006 - 2007 Intel Corporation
 | |
| All rights reserved. This program and the accompanying materials
 | |
| are licensed and made available under the terms and conditions of the BSD License
 | |
| which accompanies this distribution.  The full text of the license may be found at
 | |
| http://opensource.org/licenses/bsd-license.php
 | |
| 
 | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include "DxeIpl.h"
 | |
| #include <Ppi/GuidedSectionExtraction.h>
 | |
| #include <FrameworkPei.h>
 | |
| 
 | |
| EFI_STATUS
 | |
| CustomDecompressExtractSection (
 | |
|   IN CONST  EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI *This,
 | |
|   IN CONST  VOID                                  *InputSection,
 | |
|   OUT       VOID                                  **OutputBuffer,
 | |
|   OUT       UINTN                                 *OutputSize,
 | |
|   OUT       UINT32                                *AuthenticationStatus
 | |
| );
 | |
| 
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| EFIAPI 
 | |
| Decompress (
 | |
|   IN CONST  EFI_PEI_DECOMPRESS_PPI  *This,
 | |
|   IN CONST  EFI_COMPRESSION_SECTION *InputSection,
 | |
|   OUT       VOID                    **OutputBuffer,
 | |
|   OUT       UINTN                   *OutputSize
 | |
| );
 | |
| 
 | |
| 
 | |
| BOOLEAN gInMemory = FALSE;
 | |
| 
 | |
| //
 | |
| // Module Globals used in the DXE to PEI handoff
 | |
| // These must be module globals, so the stack can be switched
 | |
| //
 | |
| static EFI_DXE_IPL_PPI mDxeIplPpi = {
 | |
|   DxeLoadCore
 | |
| };
 | |
| 
 | |
| STATIC EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI mCustomDecompressExtractiongPpi = {
 | |
|   CustomDecompressExtractSection
 | |
| };
 | |
| 
 | |
| STATIC EFI_PEI_DECOMPRESS_PPI mDecompressPpi = {
 | |
|   Decompress
 | |
| };
 | |
| 
 | |
| static EFI_PEI_PPI_DESCRIPTOR     mPpiList[] = {
 | |
|   {
 | |
|     EFI_PEI_PPI_DESCRIPTOR_PPI,
 | |
|     &gEfiDxeIplPpiGuid,
 | |
|     &mDxeIplPpi
 | |
|   },
 | |
|   {
 | |
|     (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
 | |
|     &gEfiPeiDecompressPpiGuid,
 | |
|     &mDecompressPpi
 | |
|   }
 | |
| };
 | |
| 
 | |
| static EFI_PEI_PPI_DESCRIPTOR     mPpiSignal = {
 | |
|   (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
 | |
|   &gEfiEndOfPeiSignalPpiGuid,
 | |
|   NULL
 | |
| };
 | |
| 
 | |
| /**
 | |
|   Initializes the Dxe Ipl PPI
 | |
| 
 | |
|   @param  FfsHandle   The handle of FFS file.
 | |
|   @param  PeiServices General purpose services available to
 | |
|                       every PEIM.
 | |
|   @return EFI_SUCESS 
 | |
| */ 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| PeimInitializeDxeIpl (
 | |
|   IN EFI_PEI_FILE_HANDLE       FfsHandle,
 | |
|   IN EFI_PEI_SERVICES          **PeiServices
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                                Status;
 | |
|   EFI_BOOT_MODE                             BootMode;
 | |
|   EFI_GUID                                  **DecompressGuidList;
 | |
|   UINT32                                    DecompressMethodNumber;
 | |
|   EFI_PEI_PPI_DESCRIPTOR                    *GuidPpi;
 | |
|   
 | |
|   Status = PeiServicesGetBootMode (&BootMode);
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   if (BootMode != BOOT_ON_S3_RESUME) {
 | |
|     Status = PeiServicesRegisterForShadow (FfsHandle);
 | |
|     if (Status == EFI_SUCCESS) {
 | |
|       //
 | |
|       // EFI_SUCESS means the first time call register for shadow 
 | |
|       // 
 | |
|       return Status;
 | |
|     } else if (Status == EFI_ALREADY_STARTED) {
 | |
|       
 | |
|       gInMemory = TRUE;
 | |
|       
 | |
|       //
 | |
|       // Get custom decompress method guid list 
 | |
|       //
 | |
|       DecompressGuidList     = NULL;
 | |
|       DecompressMethodNumber = 0;
 | |
|       Status = CustomDecompressGetAlgorithms (DecompressGuidList, &DecompressMethodNumber);
 | |
|       if (Status == EFI_OUT_OF_RESOURCES) {
 | |
|       DecompressGuidList = (EFI_GUID **) AllocatePages (EFI_SIZE_TO_PAGES (DecompressMethodNumber * sizeof (EFI_GUID *)));
 | |
|       ASSERT (DecompressGuidList != NULL);
 | |
|       Status = CustomDecompressGetAlgorithms (DecompressGuidList, &DecompressMethodNumber);
 | |
|       }
 | |
|       ASSERT_EFI_ERROR(Status);
 | |
|       
 | |
|       //
 | |
|       // Install custom decompress extraction guid ppi
 | |
|       //
 | |
|       if (DecompressMethodNumber > 0) {
 | |
|       	GuidPpi = NULL;
 | |
|       	GuidPpi = (EFI_PEI_PPI_DESCRIPTOR *) AllocatePages (EFI_SIZE_TO_PAGES (DecompressMethodNumber * sizeof (EFI_PEI_PPI_DESCRIPTOR)));
 | |
|       	ASSERT (GuidPpi != NULL);
 | |
|       	while (DecompressMethodNumber-- > 0) {
 | |
|       	  GuidPpi->Flags = EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST;
 | |
|       	  GuidPpi->Ppi   = &mCustomDecompressExtractiongPpi;
 | |
|       	  GuidPpi->Guid  = DecompressGuidList [DecompressMethodNumber];
 | |
|       	  Status = PeiServicesInstallPpi (GuidPpi++);
 | |
|       	  ASSERT_EFI_ERROR(Status);
 | |
|       	}
 | |
|       }
 | |
|     } else {
 | |
|       ASSERT_EFI_ERROR (FALSE);
 | |
|     }
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // Install FvFileLoader and DxeIpl PPIs.
 | |
|   //
 | |
|   Status = PeiServicesInstallPpi (mPpiList);
 | |
|   ASSERT_EFI_ERROR(Status);  
 | |
| 	
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|    Main entry point to last PEIM 
 | |
|     
 | |
|    @param This          Entry point for DXE IPL PPI
 | |
|    @param PeiServices   General purpose services available to every PEIM.
 | |
|    @param HobList       Address to the Pei HOB list
 | |
|    
 | |
|    @return EFI_SUCCESS              DXE core was successfully loaded. 
 | |
|    @return EFI_OUT_OF_RESOURCES     There are not enough resources to load DXE core.
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| DxeLoadCore (
 | |
|   IN EFI_DXE_IPL_PPI       *This,
 | |
|   IN EFI_PEI_SERVICES      **PeiServices,
 | |
|   IN EFI_PEI_HOB_POINTERS  HobList
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                                Status;
 | |
|   EFI_GUID                                  DxeCoreFileName;
 | |
|   EFI_PHYSICAL_ADDRESS                      DxeCoreAddress;
 | |
|   UINT64                                    DxeCoreSize;
 | |
|   EFI_PHYSICAL_ADDRESS                      DxeCoreEntryPoint;
 | |
|   EFI_BOOT_MODE                             BootMode;
 | |
|   EFI_PEI_FV_HANDLE                         VolumeHandle;
 | |
|   EFI_PEI_FILE_HANDLE                       FileHandle;
 | |
|   UINTN                                     Instance;
 | |
| 
 | |
|   //
 | |
|   // if in S3 Resume, restore configure
 | |
|   //
 | |
|   Status = PeiServicesGetBootMode (&BootMode);
 | |
|   ASSERT_EFI_ERROR(Status);
 | |
| 
 | |
|   if (BootMode == BOOT_ON_S3_RESUME) {
 | |
|     Status = AcpiS3ResumeOs();
 | |
|     ASSERT_EFI_ERROR (Status);
 | |
|   } else if (BootMode == BOOT_IN_RECOVERY_MODE) {
 | |
|     Status = PeiRecoverFirmware ();
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       DEBUG ((EFI_D_ERROR, "Load Recovery Capsule Failed.(Status = %r)\n", Status));
 | |
|       CpuDeadLoop ();
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Now should have a HOB with the DXE core w/ the old HOB destroyed
 | |
|     //
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // If any FV contains an encapsulated FV extract that FV
 | |
|   //
 | |
|   DxeIplAddEncapsulatedFirmwareVolumes ();
 | |
|   
 | |
|   //
 | |
|   // Look in all the FVs present in PEI and find the DXE Core
 | |
|   //
 | |
|   Instance = 0;
 | |
|   Status = DxeIplFindFirmwareVolumeInstance (&Instance, EFI_FV_FILETYPE_DXE_CORE, &VolumeHandle, &FileHandle);
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   CopyMem(&DxeCoreFileName, &(((EFI_FFS_FILE_HEADER*)FileHandle)->Name), sizeof (EFI_GUID));
 | |
| 
 | |
|   //
 | |
|   // Load the DXE Core from a Firmware Volume
 | |
|   //
 | |
|   Status = PeiLoadFile (
 | |
|             FileHandle,
 | |
|             &DxeCoreAddress,
 | |
|             &DxeCoreSize,
 | |
|             &DxeCoreEntryPoint
 | |
|             );
 | |
| 
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   //
 | |
|   // Add HOB for the DXE Core
 | |
|   //
 | |
|   BuildModuleHob (
 | |
|     &DxeCoreFileName,
 | |
|     DxeCoreAddress,
 | |
|     DxeCoreSize,
 | |
|     DxeCoreEntryPoint
 | |
|     );
 | |
| 
 | |
|   //
 | |
|   // Report Status Code EFI_SW_PEI_PC_HANDOFF_TO_NEXT
 | |
|   //
 | |
|   REPORT_STATUS_CODE (
 | |
|     EFI_PROGRESS_CODE,
 | |
|     EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_CORE_PC_HANDOFF_TO_NEXT
 | |
|     );
 | |
| 
 | |
|   //
 | |
|   // Transfer control to the DXE Core
 | |
|   // The handoff state is simply a pointer to the HOB list
 | |
|   //
 | |
|   DEBUG ((EFI_D_INFO, "DXE Core Entry Point 0x%08x\n", (UINTN) DxeCoreEntryPoint));
 | |
|   HandOffToDxeCore (DxeCoreEntryPoint, HobList, &mPpiSignal);
 | |
|   //
 | |
|   // If we get here, then the DXE Core returned.  This is an error
 | |
|   // Dxe Core should not return.
 | |
|   //
 | |
|   ASSERT (FALSE);
 | |
|   CpuDeadLoop ();
 | |
| 
 | |
|   return EFI_OUT_OF_RESOURCES;
 | |
| }
 | |
| 
 | |
| 
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| GetFvAlignment (
 | |
|   IN    EFI_FIRMWARE_VOLUME_HEADER   *FvHeader,
 | |
|   OUT   UINT32                      *FvAlignment
 | |
|   )
 | |
| {
 | |
|   //
 | |
|   // Because FvLength in FvHeader is UINT64 type, 
 | |
|   // so FvHeader must meed at least 8 bytes alignment.
 | |
|   // Get the appropriate alignment requirement.
 | |
|   // 
 | |
|   if ((FvHeader->Attributes & EFI_FVB2_ALIGNMENT) < EFI_FVB2_ALIGNMENT_8) {
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
|   
 | |
|    *FvAlignment = 1 << ((FvHeader->Attributes & EFI_FVB2_ALIGNMENT) >> 16);
 | |
|    return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|    Search EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE image and expand 
 | |
|    as memory FV 
 | |
|     
 | |
|    @return EFI_OUT_OF_RESOURCES There are no memory space to exstract FV
 | |
|    @return EFI_SUCESS           Sucess to find the FV 
 | |
| **/
 | |
| EFI_STATUS
 | |
| DxeIplAddEncapsulatedFirmwareVolumes (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                  Status;
 | |
|   EFI_STATUS                  VolumeStatus;
 | |
|   UINTN                       Index;
 | |
|   EFI_FV_INFO                 VolumeInfo; 
 | |
|   EFI_PEI_FV_HANDLE           VolumeHandle;
 | |
|   EFI_PEI_FILE_HANDLE         FileHandle;
 | |
|   UINT32                      SectionLength;
 | |
|   EFI_FIRMWARE_VOLUME_HEADER  *FvHeader;
 | |
|   EFI_FIRMWARE_VOLUME_IMAGE_SECTION *SectionHeader;
 | |
|   VOID                        *DstBuffer;
 | |
|   UINT32                       FvAlignment;
 | |
| 
 | |
|   Status = EFI_NOT_FOUND;
 | |
|   Index  = 0;
 | |
| 
 | |
|   do {
 | |
|     VolumeStatus = DxeIplFindFirmwareVolumeInstance (
 | |
|                     &Index, 
 | |
|                     EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE, 
 | |
|                     &VolumeHandle, 
 | |
|                     &FileHandle
 | |
|                     );
 | |
|                     
 | |
|     if (!EFI_ERROR (VolumeStatus)) {
 | |
|          Status = PeiServicesFfsFindSectionData (
 | |
|                     EFI_SECTION_FIRMWARE_VOLUME_IMAGE, 
 | |
|                     (EFI_FFS_FILE_HEADER *)FileHandle, 
 | |
|                     (VOID **)&FvHeader
 | |
|                     );
 | |
|                     
 | |
|       if (!EFI_ERROR (Status)) {
 | |
|         if (FvHeader->Signature == EFI_FVH_SIGNATURE) {
 | |
|           //
 | |
|           // Because FvLength in FvHeader is UINT64 type, 
 | |
|           // so FvHeader must meed at least 8 bytes alignment.
 | |
|           // If current FvImage base address doesn't meet its alignment,
 | |
|           // we need to reload this FvImage to another correct memory address.
 | |
|           //
 | |
|           Status = GetFvAlignment(FvHeader, &FvAlignment); 
 | |
|           if (EFI_ERROR(Status)) {
 | |
|             return Status;
 | |
|           }
 | |
|           if (((UINTN) FvHeader % FvAlignment) != 0) {
 | |
|             SectionHeader = (EFI_FIRMWARE_VOLUME_IMAGE_SECTION*)((UINTN)FvHeader - sizeof(EFI_FIRMWARE_VOLUME_IMAGE_SECTION));
 | |
|             SectionLength =  *(UINT32 *)SectionHeader->Size & 0x00FFFFFF;
 | |
|             
 | |
|             DstBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES ((UINTN) SectionLength - sizeof (EFI_COMMON_SECTION_HEADER)), FvAlignment);
 | |
|             if (DstBuffer == NULL) {
 | |
|               return EFI_OUT_OF_RESOURCES;
 | |
|             }
 | |
|             CopyMem (DstBuffer, FvHeader, (UINTN) SectionLength - sizeof (EFI_COMMON_SECTION_HEADER));
 | |
|             FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) DstBuffer;  
 | |
|           }
 | |
| 
 | |
|           //
 | |
|           // This new Firmware Volume comes from a firmware file within a firmware volume.
 | |
|           // Record the original Firmware Volume Name.
 | |
|           //
 | |
|           PeiServicesFfsGetVolumeInfo (&VolumeHandle, &VolumeInfo);
 | |
| 
 | |
|           PeiPiLibBuildPiFvInfoPpi (
 | |
|             (EFI_PHYSICAL_ADDRESS) FvHeader,
 | |
|             FvHeader->FvLength,
 | |
|             &(VolumeInfo.FvName),
 | |
|             &(((EFI_FFS_FILE_HEADER*)FileHandle)->Name)
 | |
|             );
 | |
|             
 | |
|           ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|           //
 | |
|           // Makes the encapsulated volume show up in DXE phase to skip processing of
 | |
|           // encapsulated file again.
 | |
|           //
 | |
|           BuildFv2Hob (
 | |
|             (EFI_PHYSICAL_ADDRESS)(UINTN)FvHeader,
 | |
|             FvHeader->FvLength, 
 | |
|             &VolumeInfo.FvName,
 | |
|             &(((EFI_FFS_FILE_HEADER *)FileHandle)->Name)
 | |
|             );
 | |
|           return Status;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   } while (!EFI_ERROR (VolumeStatus));
 | |
|   
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|    Find the First Volume that contains the first FileType.
 | |
| 
 | |
|    @param Instance      The Fv instance.
 | |
|    @param SeachType     The type of file to search.
 | |
|    @param VolumeHandle  Pointer to Fv which contains the file to search. 
 | |
|    @param FileHandle    Pointer to FFS file to search.
 | |
|    
 | |
|    @return EFI_SUCESS   Success to find the FFS in specificed FV
 | |
|    @return others       Fail to find the FFS in specificed FV
 | |
|  */
 | |
| EFI_STATUS
 | |
| DxeIplFindFirmwareVolumeInstance (
 | |
|   IN OUT UINTN              *Instance,
 | |
|   IN  EFI_FV_FILETYPE       SeachType,
 | |
|   OUT EFI_PEI_FV_HANDLE     *VolumeHandle,
 | |
|   OUT EFI_PEI_FILE_HANDLE   *FileHandle
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
|   EFI_STATUS  VolumeStatus;
 | |
| 
 | |
|   do {
 | |
|     VolumeStatus = PeiServicesFfsFindNextVolume (*Instance, VolumeHandle);
 | |
|     if (!EFI_ERROR (VolumeStatus)) {
 | |
|       *FileHandle = NULL;
 | |
|       Status = PeiServicesFfsFindNextFile (SeachType, *VolumeHandle, FileHandle);
 | |
|       if (!EFI_ERROR (Status)) {
 | |
|         return Status;
 | |
|       }
 | |
|     }
 | |
|     *Instance += 1;
 | |
|   } while (!EFI_ERROR (VolumeStatus));
 | |
| 
 | |
|   return VolumeStatus;
 | |
| }
 | |
| 
 | |
| /**
 | |
|    Loads and relocates a PE/COFF image into memory.
 | |
| 
 | |
|    @param FileHandle        The image file handle
 | |
|    @param ImageAddress      The base address of the relocated PE/COFF image
 | |
|    @param ImageSize         The size of the relocated PE/COFF image
 | |
|    @param EntryPoint        The entry point of the relocated PE/COFF image
 | |
|    
 | |
|    @return EFI_SUCCESS           The file was loaded and relocated
 | |
|    @return EFI_OUT_OF_RESOURCES  There was not enough memory to load and relocate the PE/COFF file
 | |
| **/
 | |
| EFI_STATUS
 | |
| PeiLoadFile (
 | |
|   IN  EFI_PEI_FILE_HANDLE                       FileHandle,
 | |
|   OUT EFI_PHYSICAL_ADDRESS                      *ImageAddress,
 | |
|   OUT UINT64                                    *ImageSize,
 | |
|   OUT EFI_PHYSICAL_ADDRESS                      *EntryPoint
 | |
|   )
 | |
| {
 | |
| 
 | |
|   EFI_STATUS                        Status;
 | |
|   PE_COFF_LOADER_IMAGE_CONTEXT      ImageContext;
 | |
|   VOID                              *Pe32Data;
 | |
|   //
 | |
|   // First try to find the required section in this ffs file.
 | |
|   //
 | |
|   Status = PeiServicesFfsFindSectionData (
 | |
|              EFI_SECTION_PE32,
 | |
|              FileHandle,
 | |
|              &Pe32Data
 | |
|              );
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status = PeiServicesFfsFindSectionData (
 | |
|                EFI_SECTION_TE,
 | |
|                FileHandle,
 | |
|                &Pe32Data
 | |
|                );
 | |
|   }
 | |
|   
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     //
 | |
|     // NO image types we support so exit.
 | |
|     //
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   ZeroMem (&ImageContext, sizeof (ImageContext));
 | |
|   ImageContext.Handle = Pe32Data;
 | |
|   Status              = GetImageReadFunction (&ImageContext);
 | |
| 
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
|   Status = PeCoffLoaderGetImageInfo (&ImageContext);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
|   //
 | |
|   // Allocate Memory for the image
 | |
|   //
 | |
|   ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) AllocatePages (EFI_SIZE_TO_PAGES ((UINT32) ImageContext.ImageSize));
 | |
|   ASSERT (ImageContext.ImageAddress != 0);
 | |
| 
 | |
|   //
 | |
|   // Load the image to our new buffer
 | |
|   //
 | |
|   Status = PeCoffLoaderLoadImage (&ImageContext);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
|   //
 | |
|   // Relocate the image in our new buffer
 | |
|   //
 | |
|   Status = PeCoffLoaderRelocateImage (&ImageContext);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Flush the instruction cache so the image data is written before we execute it
 | |
|   //
 | |
|   InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);
 | |
| 
 | |
|   *ImageAddress = ImageContext.ImageAddress;
 | |
|   *ImageSize    = ImageContext.ImageSize;
 | |
|   *EntryPoint   = ImageContext.EntryPoint;
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   The ExtractSection() function processes the input section and
 | |
|   returns a pointer to the section contents. If the section being
 | |
|   extracted does not require processing (if the section
 | |
|   GuidedSectionHeader.Attributes has the
 | |
|   EFI_GUIDED_SECTION_PROCESSING_REQUIRED field cleared), then
 | |
|   OutputBuffer is just updated to point to the start of the
 | |
|   section's contents. Otherwise, *Buffer must be allocated
 | |
|   from PEI permanent memory.
 | |
| 
 | |
|   @param This                   Indicates the
 | |
|                                 EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI instance.
 | |
|                                 Buffer containing the input GUIDed section to be
 | |
|                                 processed. OutputBuffer OutputBuffer is
 | |
|                                 allocated from PEI permanent memory and contains
 | |
|                                 the new section stream.
 | |
|   
 | |
|   @param OutputSize             A pointer to a caller-allocated
 | |
|                                 UINTN in which the size of *OutputBuffer
 | |
|                                 allocation is stored. If the function
 | |
|                                 returns anything other than EFI_SUCCESS,
 | |
|                                 the value of OutputSize is undefined.
 | |
|   
 | |
|   @param AuthenticationStatus   A pointer to a caller-allocated
 | |
|                                 UINT32 that indicates the
 | |
|                                 authentication status of the
 | |
|                                 output buffer. If the input
 | |
|                                 section's GuidedSectionHeader.
 | |
|                                 Attributes field has the
 | |
|                                 EFI_GUIDED_SECTION_AUTH_STATUS_VALID 
 | |
|                                 bit as clear,
 | |
|                                 AuthenticationStatus must return
 | |
|                                 zero. These bits reflect the
 | |
|                                 status of the extraction
 | |
|                                 operation. If the function
 | |
|                                 returns anything other than
 | |
|                                 EFI_SUCCESS, the value of
 | |
|                                 AuthenticationStatus is
 | |
|                                 undefined.
 | |
|   
 | |
|   @retval EFI_SUCCESS           The InputSection was
 | |
|                                 successfully processed and the
 | |
|                                 section contents were returned.
 | |
|   
 | |
|   @retval EFI_OUT_OF_RESOURCES  The system has insufficient
 | |
|                                 resources to process the request.
 | |
|   
 | |
|   @reteval EFI_INVALID_PARAMETER The GUID in InputSection does
 | |
|                                 not match this instance of the
 | |
|                                 GUIDed Section Extraction PPI.
 | |
| **/
 | |
| EFI_STATUS
 | |
| CustomDecompressExtractSection (
 | |
|   IN CONST  EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI *This,
 | |
|   IN CONST  VOID                                  *InputSection,
 | |
|   OUT       VOID                                  **OutputBuffer,
 | |
|   OUT       UINTN                                 *OutputSize,
 | |
|   OUT       UINT32                                *AuthenticationStatus
 | |
| )
 | |
| {
 | |
|   EFI_STATUS      Status;
 | |
|   UINT8           *ScratchBuffer;
 | |
|   UINT32          ScratchSize;
 | |
|   UINT32          SectionLength;
 | |
|   UINT32          DestinationSize;  
 | |
|   
 | |
|   //
 | |
|   // Set authentic value to zero.
 | |
|   //
 | |
|   *AuthenticationStatus = 0;
 | |
|   //
 | |
|   // Calculate Section data Size
 | |
|   //
 | |
|   SectionLength   = *(UINT32 *) (((EFI_COMMON_SECTION_HEADER *) InputSection)->Size) & 0x00ffffff;
 | |
|   //
 | |
|   // Get compressed data information
 | |
|   //
 | |
|   Status = CustomDecompressGetInfo (
 | |
|              (GUID *) ((UINT8 *) InputSection + sizeof (EFI_COMMON_SECTION_HEADER)),
 | |
|              (UINT8 *) InputSection + sizeof (EFI_GUID_DEFINED_SECTION),
 | |
|              SectionLength - sizeof (EFI_GUID_DEFINED_SECTION),
 | |
|              &DestinationSize,
 | |
|              &ScratchSize
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     //
 | |
|     // GetInfo failed
 | |
|     //
 | |
|     DEBUG ((EFI_D_ERROR, "Extract guided section Failed - %r\n", Status));
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Allocate scratch buffer
 | |
|   //
 | |
|   ScratchBuffer = AllocatePages (EFI_SIZE_TO_PAGES (ScratchSize));
 | |
|   if (ScratchBuffer == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
|   //
 | |
|   // Allocate destination buffer
 | |
|   //
 | |
|   *OutputSize   = (UINTN) DestinationSize;
 | |
|   *OutputBuffer = AllocatePages (EFI_SIZE_TO_PAGES (*OutputSize));
 | |
|   if (*OutputBuffer == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Call decompress function
 | |
|   //
 | |
|   Status = CustomDecompress (
 | |
|              (GUID *) ((UINT8 *) InputSection + sizeof (EFI_COMMON_SECTION_HEADER)),
 | |
|              (UINT8 *) InputSection + sizeof (EFI_GUID_DEFINED_SECTION),
 | |
|              *OutputBuffer,
 | |
|              ScratchBuffer
 | |
|              );
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     //
 | |
|     // Decompress failed
 | |
|     //
 | |
|     DEBUG ((EFI_D_ERROR, "Extract guided section Failed - %r\n", Status));
 | |
|     return Status;
 | |
|   }
 | |
|   
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| EFIAPI 
 | |
| Decompress (
 | |
|   IN CONST  EFI_PEI_DECOMPRESS_PPI  *This,
 | |
|   IN CONST  EFI_COMPRESSION_SECTION *CompressionSection,
 | |
|   OUT       VOID                    **OutputBuffer,
 | |
|   OUT       UINTN                   *OutputSize
 | |
|  )
 | |
| {
 | |
|   EFI_STATUS                      Status;
 | |
|   UINT8                           *DstBuffer;
 | |
|   UINT8                           *ScratchBuffer;
 | |
|   UINTN                           DstBufferSize;
 | |
|   UINT32                          ScratchBufferSize;
 | |
|   EFI_COMMON_SECTION_HEADER       *Section;
 | |
|   UINTN                           SectionLength;
 | |
| 
 | |
|   if (CompressionSection->CommonHeader.Type != EFI_SECTION_COMPRESSION) {
 | |
|     ASSERT (FALSE);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   Section = (EFI_COMMON_SECTION_HEADER *) CompressionSection;
 | |
|   SectionLength         = *(UINT32 *) (Section->Size) & 0x00ffffff;
 | |
|   
 | |
|   //
 | |
|   // This is a compression set, expand it
 | |
|   //
 | |
|   switch (CompressionSection->CompressionType) {
 | |
|   case EFI_STANDARD_COMPRESSION:
 | |
|     //
 | |
|     // Load EFI standard compression.
 | |
|     // For compressed data, decompress them to dstbuffer.
 | |
|     //
 | |
|     Status = UefiDecompressGetInfo (
 | |
|                (UINT8 *) ((EFI_COMPRESSION_SECTION *) Section + 1),
 | |
|                (UINT32) SectionLength - sizeof (EFI_COMPRESSION_SECTION),
 | |
|                (UINT32 *) &DstBufferSize,
 | |
|                &ScratchBufferSize
 | |
|                );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       //
 | |
|       // GetInfo failed
 | |
|       //
 | |
|       DEBUG ((EFI_D_ERROR, "Decompress GetInfo Failed - %r\n", Status));
 | |
|       return EFI_NOT_FOUND;
 | |
|     }
 | |
|     //
 | |
|     // Allocate scratch buffer
 | |
|     //
 | |
|     ScratchBuffer = AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize));
 | |
|     if (ScratchBuffer == NULL) {
 | |
|       return EFI_OUT_OF_RESOURCES;
 | |
|     }
 | |
|     //
 | |
|     // Allocate destination buffer
 | |
|     //
 | |
|     DstBuffer = AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize));
 | |
|     if (DstBuffer == NULL) {
 | |
|       return EFI_OUT_OF_RESOURCES;
 | |
|     }
 | |
|     //
 | |
|     // Call decompress function
 | |
|     //
 | |
|     Status = UefiDecompress (
 | |
|                 (CHAR8 *) ((EFI_COMPRESSION_SECTION *) Section + 1),
 | |
|                 DstBuffer,
 | |
|                 ScratchBuffer
 | |
|                 );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       //
 | |
|       // Decompress failed
 | |
|       //
 | |
|       DEBUG ((EFI_D_ERROR, "Decompress Failed - %r\n", Status));
 | |
|       return EFI_NOT_FOUND;
 | |
|     }
 | |
|     break;
 | |
| 
 | |
|   // porting note the original branch for customized compress is removed, it should be change to use GUID compress
 | |
| 
 | |
|   case EFI_NOT_COMPRESSED:
 | |
|     //
 | |
|     // Allocate destination buffer
 | |
|     //
 | |
|     DstBufferSize = CompressionSection->UncompressedLength;
 | |
|     DstBuffer     = AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize));
 | |
|     if (DstBuffer == NULL) {
 | |
|       return EFI_OUT_OF_RESOURCES;
 | |
|     }
 | |
|     //
 | |
|     // stream is not actually compressed, just encapsulated.  So just copy it.
 | |
|     //
 | |
|     CopyMem (DstBuffer, CompressionSection + 1, DstBufferSize);
 | |
|     break;
 | |
| 
 | |
|   default:
 | |
|     //
 | |
|     // Don't support other unknown compression type.
 | |
|     //
 | |
|     ASSERT (FALSE);
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| 
 | |
|   *OutputSize = DstBufferSize;
 | |
|   *OutputBuffer = DstBuffer;
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 |