/*---------------------------------------------------------------------------------------*/ EFI_STATUS LoadExeFileInMemory ( IN EFI_GUID *File, IN EFI_SECTION_TYPE SectionType, IN EFI_PHYSICAL_ADDRESS Memory, OUT UINTN *ImageSize, OUT EFI_IMAGE_ENTRY_POINT *ExeEntryPoint ) { EFI_STATUS Status; VOID *SourceBuffer; PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; *ExeEntryPoint = NULL; SourceBuffer = NULL; *ImageSize = 0; // Look for SMM foundation FFS FV Status = GetSectionFromAnyFv (File, SectionType, 0, (VOID **) &SourceBuffer, ImageSize); if (EFI_ERROR (Status)) { return (Status); } ImageContext.Handle = SourceBuffer; ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory; // Gather SMM foundation Coff image information Status = PeCoffLoaderGetImageInfo (&ImageContext); if (EFI_ERROR (Status)) { FreePool (SourceBuffer); return Status; } ImageContext.ImageAddress = Memory; ImageContext.ImageAddress += ImageContext.SectionAlignment - 1; ImageContext.ImageAddress &= ~(ImageContext.SectionAlignment - 1); // Load SMM foundation FFS in SMM space Status = PeCoffLoaderLoadImage (&ImageContext); if (!EFI_ERROR (Status)) { // // Relocate the image in our new buffer // Status = PeCoffLoaderRelocateImage (&ImageContext); if (!EFI_ERROR (Status)) { *ExeEntryPoint = (EFI_IMAGE_ENTRY_POINT)(UINTN)ImageContext.EntryPoint; //Status = (*ExeEntryPoint) (NULL, gST); } } FreePool (SourceBuffer); return Status; }
RETURN_STATUS EFIAPI SecPeCoffGetEntryPoint ( IN VOID *Pe32Data, IN OUT VOID **EntryPoint ) { EFI_STATUS Status; PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; ZeroMem (&ImageContext, sizeof (ImageContext)); ImageContext.Handle = Pe32Data; ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) SecImageRead; Status = PeCoffLoaderGetImageInfo (&ImageContext); if (EFI_ERROR (Status)) { return Status; } if (ImageContext.ImageAddress != (UINTN)Pe32Data) { // // Relocate image to match the address where it resides // ImageContext.ImageAddress = (UINTN)Pe32Data; Status = PeCoffLoaderLoadImage (&ImageContext); if (EFI_ERROR (Status)) { return Status; } Status = PeCoffLoaderRelocateImage (&ImageContext); if (EFI_ERROR (Status)) { return Status; } } else { // // Or just return image entry point // ImageContext.PdbPointer = PeCoffLoaderGetPdbPointer (Pe32Data); Status = PeCoffLoaderGetEntryPoint (Pe32Data, EntryPoint); if (EFI_ERROR (Status)) { return Status; } ImageContext.EntryPoint = (UINTN)*EntryPoint; } // On Unix a dlopen is done that will change the entry point SecPeCoffRelocateImageExtraAction (&ImageContext); *EntryPoint = (VOID *)(UINTN)ImageContext.EntryPoint; return Status; }
RETURN_STATUS EFIAPI SecPeCoffGetEntryPoint ( IN VOID *Pe32Data, IN OUT VOID **EntryPoint ) { EFI_STATUS Status; PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; ZeroMem (&ImageContext, sizeof (ImageContext)); ImageContext.Handle = Pe32Data; ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) SecImageRead; Status = PeCoffLoaderGetImageInfo (&ImageContext); if (EFI_ERROR (Status)) { return Status; } // // Allocate space in NT (not emulator) memory with ReadWrite and Execute attribute. // Extra space is for alignment // ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) VirtualAlloc (NULL, (SIZE_T) (ImageContext.ImageSize + (ImageContext.SectionAlignment * 2)), MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (ImageContext.ImageAddress == 0) { return EFI_OUT_OF_RESOURCES; } // // Align buffer on section boundary // ImageContext.ImageAddress += ImageContext.SectionAlignment - 1; ImageContext.ImageAddress &= ~((EFI_PHYSICAL_ADDRESS)ImageContext.SectionAlignment - 1); Status = PeCoffLoaderLoadImage (&ImageContext); if (EFI_ERROR (Status)) { return Status; } Status = PeCoffLoaderRelocateImage (&ImageContext); if (EFI_ERROR (Status)) { return Status; } *EntryPoint = (VOID *)(UINTN)ImageContext.EntryPoint; return EFI_SUCCESS; }
/** This is the Event notification function to reload BootScriptExecutor image to RESERVED mem and save it to LockBox. @param Event Pointer to this event @param Context Event handler private data **/ VOID EFIAPI ReadyToLockEventNotify ( IN EFI_EVENT Event, IN VOID *Context ) { EFI_STATUS Status; VOID *Interface; UINT8 *Buffer; UINTN BufferSize; EFI_HANDLE NewImageHandle; UINTN Pages; EFI_PHYSICAL_ADDRESS FfsBuffer; PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; Status = gBS->LocateProtocol (&gEfiDxeSmmReadyToLockProtocolGuid, NULL, &Interface); if (EFI_ERROR (Status)) { return; } // // A workaround: Here we install a dummy handle // NewImageHandle = NULL; Status = gBS->InstallProtocolInterface ( &NewImageHandle, &gEfiCallerIdGuid, EFI_NATIVE_INTERFACE, NULL ); ASSERT_EFI_ERROR (Status); // // Reload BootScriptExecutor image itself to RESERVED mem // Status = GetSectionFromAnyFv ( &gEfiCallerIdGuid, EFI_SECTION_PE32, 0, (VOID **) &Buffer, &BufferSize ); ASSERT_EFI_ERROR (Status); ImageContext.Handle = Buffer; ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory; // // Get information about the image being loaded // Status = PeCoffLoaderGetImageInfo (&ImageContext); ASSERT_EFI_ERROR (Status); if (ImageContext.SectionAlignment > EFI_PAGE_SIZE) { Pages = EFI_SIZE_TO_PAGES ((UINTN) (ImageContext.ImageSize + ImageContext.SectionAlignment)); } else { Pages = EFI_SIZE_TO_PAGES ((UINTN) ImageContext.ImageSize); } FfsBuffer = 0xFFFFFFFF; Status = gBS->AllocatePages ( AllocateMaxAddress, EfiReservedMemoryType, Pages, &FfsBuffer ); ASSERT_EFI_ERROR (Status); ImageContext.ImageAddress = (PHYSICAL_ADDRESS)(UINTN)FfsBuffer; // // Align buffer on section boundry // ImageContext.ImageAddress += ImageContext.SectionAlignment - 1; ImageContext.ImageAddress &= ~((EFI_PHYSICAL_ADDRESS)(ImageContext.SectionAlignment - 1)); // // Load the image to our new buffer // Status = PeCoffLoaderLoadImage (&ImageContext); ASSERT_EFI_ERROR (Status); // // Relocate the image in our new buffer // Status = PeCoffLoaderRelocateImage (&ImageContext); ASSERT_EFI_ERROR (Status); // // Free the buffer allocated by ReadSection since the image has been relocated in the new buffer // gBS->FreePool (Buffer); // // Flush the instruction cache so the image data is written before we execute it // InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize); RegisterMemoryProfileImage ( &gEfiCallerIdGuid, ImageContext.ImageAddress, ImageContext.ImageSize, EFI_FV_FILETYPE_DRIVER ); Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)(ImageContext.EntryPoint)) (NewImageHandle, gST); ASSERT_EFI_ERROR (Status); // // Additional step for BootScript integrity // Save BootScriptExecutor image // Status = SaveLockBox ( &mBootScriptExecutorImageGuid, (VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize ); ASSERT_EFI_ERROR (Status); Status = SetLockBoxAttributes (&mBootScriptExecutorImageGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE); ASSERT_EFI_ERROR (Status); gBS->CloseEvent (Event); }
/** Loads an EFI image into SMRAM. @param DriverEntry EFI_SMM_DRIVER_ENTRY instance @return EFI_STATUS **/ EFI_STATUS EFIAPI SmmLoadImage ( IN OUT EFI_SMM_DRIVER_ENTRY *DriverEntry ) { UINT32 AuthenticationStatus; UINTN FilePathSize; VOID *Buffer; UINTN Size; UINTN PageCount; EFI_GUID *NameGuid; EFI_STATUS Status; EFI_STATUS SecurityStatus; EFI_HANDLE DeviceHandle; EFI_PHYSICAL_ADDRESS DstBuffer; EFI_DEVICE_PATH_PROTOCOL *FilePath; EFI_DEVICE_PATH_PROTOCOL *OriginalFilePath; EFI_DEVICE_PATH_PROTOCOL *HandleFilePath; EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv; PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; Buffer = NULL; Size = 0; Fv = DriverEntry->Fv; NameGuid = &DriverEntry->FileName; FilePath = DriverEntry->FvFileDevicePath; OriginalFilePath = FilePath; HandleFilePath = FilePath; DeviceHandle = NULL; SecurityStatus = EFI_SUCCESS; Status = EFI_SUCCESS; AuthenticationStatus = 0; // // Try to get the image device handle by checking the match protocol. // Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &HandleFilePath, &DeviceHandle); if (EFI_ERROR(Status)) { return Status; } // // If the Security Architectural Protocol has not been located yet, then attempt to locate it // if (mSecurity == NULL) { gBS->LocateProtocol (&gEfiSecurityArchProtocolGuid, NULL, (VOID**)&mSecurity); } // // Verify the Authentication Status through the Security Architectural Protocol // if ((mSecurity != NULL) && (OriginalFilePath != NULL)) { SecurityStatus = mSecurity->FileAuthenticationState ( mSecurity, AuthenticationStatus, OriginalFilePath ); if (EFI_ERROR (SecurityStatus) && SecurityStatus != EFI_SECURITY_VIOLATION) { Status = SecurityStatus; return Status; } } // // Pull out just the file portion of the DevicePath for the LoadedImage FilePath // FilePath = OriginalFilePath; Status = gBS->HandleProtocol (DeviceHandle, &gEfiDevicePathProtocolGuid, (VOID **)&HandleFilePath); if (!EFI_ERROR (Status)) { FilePathSize = GetDevicePathSize (HandleFilePath) - sizeof(EFI_DEVICE_PATH_PROTOCOL); FilePath = (EFI_DEVICE_PATH_PROTOCOL *) (((UINT8 *)FilePath) + FilePathSize ); } // // Try reading PE32 section firstly // Status = Fv->ReadSection ( Fv, NameGuid, EFI_SECTION_PE32, 0, &Buffer, &Size, &AuthenticationStatus ); if (EFI_ERROR (Status)) { // // Try reading TE section secondly // Buffer = NULL; Size = 0; Status = Fv->ReadSection ( Fv, NameGuid, EFI_SECTION_TE, 0, &Buffer, &Size, &AuthenticationStatus ); } if (EFI_ERROR (Status)) { if (Buffer != NULL) { Status = gBS->FreePool (Buffer); } return Status; } // // Initialize ImageContext // ImageContext.Handle = Buffer; ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory; // // Get information about the image being loaded // Status = PeCoffLoaderGetImageInfo (&ImageContext); if (EFI_ERROR (Status)) { if (Buffer != NULL) { Status = gBS->FreePool (Buffer); } return Status; } // // if Loading module at Fixed Address feature is enabled, then cut out a memory range started from TESG BASE // to hold the Smm driver code // if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) { // // Get the fixed loading address assigned by Build tool // Status = GetPeCoffImageFixLoadingAssignedAddress (&ImageContext); if (!EFI_ERROR (Status)) { // // Since the memory range to load Smm core alreay been cut out, so no need to allocate and free this range // following statements is to bypass SmmFreePages // PageCount = 0; DstBuffer = (UINTN)gLoadModuleAtFixAddressSmramBase; } else { DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED ERROR: Failed to load module at fixed address. \n")); // // allocate the memory to load the SMM driver // PageCount = (UINTN)EFI_SIZE_TO_PAGES((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment); DstBuffer = (UINTN)(-1); Status = SmmAllocatePages ( AllocateMaxAddress, EfiRuntimeServicesCode, PageCount, &DstBuffer ); if (EFI_ERROR (Status)) { if (Buffer != NULL) { Status = gBS->FreePool (Buffer); } return Status; } ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)DstBuffer; } } else { PageCount = (UINTN)EFI_SIZE_TO_PAGES((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment); DstBuffer = (UINTN)(-1); Status = SmmAllocatePages ( AllocateMaxAddress, EfiRuntimeServicesCode, PageCount, &DstBuffer ); if (EFI_ERROR (Status)) { if (Buffer != NULL) { Status = gBS->FreePool (Buffer); } return Status; } ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)DstBuffer; } // // Align buffer on section boundry // ImageContext.ImageAddress += ImageContext.SectionAlignment - 1; ImageContext.ImageAddress &= ~(ImageContext.SectionAlignment - 1); // // Load the image to our new buffer // Status = PeCoffLoaderLoadImage (&ImageContext); if (EFI_ERROR (Status)) { if (Buffer != NULL) { Status = gBS->FreePool (Buffer); } SmmFreePages (DstBuffer, PageCount); return Status; } // // Relocate the image in our new buffer // Status = PeCoffLoaderRelocateImage (&ImageContext); if (EFI_ERROR (Status)) { if (Buffer != NULL) { Status = gBS->FreePool (Buffer); } SmmFreePages (DstBuffer, PageCount); return Status; } // // Flush the instruction cache so the image data are written before we execute it // InvalidateInstructionCacheRange ((VOID *)(UINTN) ImageContext.ImageAddress, (UINTN) ImageContext.ImageSize); // // Save Image EntryPoint in DriverEntry // DriverEntry->ImageEntryPoint = ImageContext.EntryPoint; DriverEntry->ImageBuffer = DstBuffer; DriverEntry->NumberOfPage = PageCount; // // Allocate a Loaded Image Protocol in EfiBootServicesData // Status = gBS->AllocatePool (EfiBootServicesData, sizeof (EFI_LOADED_IMAGE_PROTOCOL), (VOID **)&DriverEntry->LoadedImage); if (EFI_ERROR (Status)) { if (Buffer != NULL) { Status = gBS->FreePool (Buffer); } SmmFreePages (DstBuffer, PageCount); return Status; } // // Fill in the remaining fields of the Loaded Image Protocol instance. // Note: ImageBase is an SMRAM address that can not be accessed outside of SMRAM if SMRAM window is closed. // DriverEntry->LoadedImage->Revision = EFI_LOADED_IMAGE_PROTOCOL_REVISION; DriverEntry->LoadedImage->ParentHandle = gSmmCorePrivate->SmmIplImageHandle; DriverEntry->LoadedImage->SystemTable = gST; DriverEntry->LoadedImage->DeviceHandle = DeviceHandle; // // Make an EfiBootServicesData buffer copy of FilePath // Status = gBS->AllocatePool (EfiBootServicesData, GetDevicePathSize (FilePath), (VOID **)&DriverEntry->LoadedImage->FilePath); if (EFI_ERROR (Status)) { if (Buffer != NULL) { Status = gBS->FreePool (Buffer); } SmmFreePages (DstBuffer, PageCount); return Status; } CopyMem (DriverEntry->LoadedImage->FilePath, FilePath, GetDevicePathSize (FilePath)); DriverEntry->LoadedImage->ImageBase = (VOID *)(UINTN)DriverEntry->ImageBuffer; DriverEntry->LoadedImage->ImageSize = ImageContext.ImageSize; DriverEntry->LoadedImage->ImageCodeType = EfiRuntimeServicesCode; DriverEntry->LoadedImage->ImageDataType = EfiRuntimeServicesData; // // Create a new image handle in the UEFI handle database for the SMM Driver // DriverEntry->ImageHandle = NULL; Status = gBS->InstallMultipleProtocolInterfaces ( &DriverEntry->ImageHandle, &gEfiLoadedImageProtocolGuid, DriverEntry->LoadedImage, NULL ); // // Print the load address and the PDB file name if it is available // DEBUG_CODE_BEGIN (); UINTN Index; UINTN StartIndex; CHAR8 EfiFileName[256]; DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Loading SMM driver at 0x%11p EntryPoint=0x%11p ", (VOID *)(UINTN) ImageContext.ImageAddress, FUNCTION_ENTRY_POINT (ImageContext.EntryPoint))); // // Print Module Name by Pdb file path. // Windows and Unix style file path are all trimmed correctly. // if (ImageContext.PdbPointer != NULL) { StartIndex = 0; for (Index = 0; ImageContext.PdbPointer[Index] != 0; Index++) { if ((ImageContext.PdbPointer[Index] == '\\') || (ImageContext.PdbPointer[Index] == '/')) { StartIndex = Index + 1; } } // // Copy the PDB file name to our temporary string, and replace .pdb with .efi // The PDB file name is limited in the range of 0~255. // If the length is bigger than 255, trim the redudant characters to avoid overflow in array boundary. // for (Index = 0; Index < sizeof (EfiFileName) - 4; Index++) { EfiFileName[Index] = ImageContext.PdbPointer[Index + StartIndex]; if (EfiFileName[Index] == 0) { EfiFileName[Index] = '.'; } if (EfiFileName[Index] == '.') { EfiFileName[Index + 1] = 'e'; EfiFileName[Index + 2] = 'f'; EfiFileName[Index + 3] = 'i'; EfiFileName[Index + 4] = 0; break; } } if (Index == sizeof (EfiFileName) - 4) { EfiFileName[Index] = 0; } DEBUG ((DEBUG_INFO | DEBUG_LOAD, "%a", EfiFileName)); // &Image->ImageContext.PdbPointer[StartIndex])); } DEBUG ((DEBUG_INFO | DEBUG_LOAD, "\n")); DEBUG_CODE_END (); // // Free buffer allocated by Fv->ReadSection. // // The UEFI Boot Services FreePool() function must be used because Fv->ReadSection // used the UEFI Boot Services AllocatePool() function // Status = gBS->FreePool(Buffer); return Status; }
/** Relocate this image under 4G memory for IPF. @param ImageHandle Handle of driver image. @param SystemTable Pointer to system table. @retval EFI_SUCCESS Image successfully relocated. @retval EFI_ABORTED Failed to relocate image. **/ EFI_STATUS RelocateImageUnder4GIfNeeded ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; UINTN NumberOfPages; EFI_PHYSICAL_ADDRESS LoadedImageBase; PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; EFI_PHYSICAL_ADDRESS MemoryAddress; EFI_HANDLE NewImageHandle; Status = gBS->HandleProtocol ( ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID *) &LoadedImage ); if (!EFI_ERROR (Status)) { LoadedImageBase = (EFI_PHYSICAL_ADDRESS) (UINTN) LoadedImage->ImageBase; if (LoadedImageBase > 0xffffffff) { NumberOfPages = (UINTN) (DivU64x32(LoadedImage->ImageSize, EFI_PAGE_SIZE) + 1); // // Allocate buffer below 4GB here // Status = AllocateLegacyMemory ( AllocateMaxAddress, 0x7FFFFFFF, NumberOfPages, // do we have to convert this to pages?? &MemoryAddress ); if (EFI_ERROR (Status)) { return Status; } ZeroMem (&ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT)); ImageContext.Handle = (VOID *)(UINTN)LoadedImageBase; ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory; // // Get information about the image being loaded // Status = PeCoffLoaderGetImageInfo (&ImageContext); if (EFI_ERROR (Status)) { return Status; } ImageContext.ImageAddress = (PHYSICAL_ADDRESS)MemoryAddress; // // Align buffer on section boundary // ImageContext.ImageAddress += ImageContext.SectionAlignment - 1; ImageContext.ImageAddress &= ~((PHYSICAL_ADDRESS)ImageContext.SectionAlignment - 1); // // Load the image to our new buffer // Status = PeCoffLoaderLoadImage (&ImageContext); if (EFI_ERROR (Status)) { gBS->FreePages (MemoryAddress, NumberOfPages); return Status; } // // Relocate the image in our new buffer // Status = PeCoffLoaderRelocateImage (&ImageContext); if (EFI_ERROR (Status)) { gBS->FreePages (MemoryAddress, NumberOfPages); return Status; } // // Create a new handle with gEfiCallerIdGuid to be used as the ImageHandle fore the reloaded image // NewImageHandle = NULL; Status = gBS->InstallProtocolInterface ( &NewImageHandle, &gEfiCallerIdGuid, EFI_NATIVE_INTERFACE, NULL ); // // Flush the instruction cache so the image data is written before we execute it // InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize); Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)(ImageContext.EntryPoint)) (NewImageHandle, SystemTable); if (EFI_ERROR (Status)) { gBS->FreePages (MemoryAddress, NumberOfPages); return Status; } // // return error directly the BS will unload this image // return EFI_ABORTED; } } return EFI_SUCCESS; }
/** Loads and relocates a PE/COFF image into memory. If the image is not relocatable, it will not be loaded into memory and be loaded as XIP image. @param Pe32Data - The base address of the PE/COFF file that is to be loaded and relocated @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 @retval EFI_SUCCESS The file was loaded and relocated @retval EFI_OUT_OF_RESOURCES There was not enough memory to load and relocate the PE/COFF file @retval EFI_WARN_BUFFER_TOO_SMALL There is not enough heap to allocate the requested size. This will not prevent the XIP image from being invoked. **/ EFI_STATUS LoadAndRelocatePeCoffImage ( IN VOID *Pe32Data, OUT EFI_PHYSICAL_ADDRESS *ImageAddress, OUT UINT64 *ImageSize, OUT EFI_PHYSICAL_ADDRESS *EntryPoint ) { EFI_STATUS Status; PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; PEI_CORE_INSTANCE *Private; UINT64 AlignImageSize; BOOLEAN IsXipImage; EFI_STATUS ReturnStatus; Private = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer ()); ReturnStatus = EFI_SUCCESS; IsXipImage = FALSE; ZeroMem (&ImageContext, sizeof (ImageContext)); ImageContext.Handle = Pe32Data; Status = GetImageReadFunction (&ImageContext); ASSERT_EFI_ERROR (Status); Status = PeCoffLoaderGetImageInfo (&ImageContext); if (EFI_ERROR (Status)) { return Status; } // // XIP image that ImageAddress is same to Image handle. // if (ImageContext.ImageAddress == (EFI_PHYSICAL_ADDRESS)(UINTN) Pe32Data) { IsXipImage = TRUE; } // // When Image has no reloc section, it can't be relocated into memory. // if (ImageContext.RelocationsStripped && (Private->PeiMemoryInstalled) && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME || PcdGetBool (PcdShadowPeimOnS3Boot))) { DEBUG ((EFI_D_INFO|EFI_D_LOAD, "The image at 0x%08x without reloc section can't be loaded into memory\n", (UINTN) Pe32Data)); } // // Set default base address to current image address. // ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) Pe32Data; // // Allocate Memory for the image when memory is ready, boot mode is not S3, and image is relocatable. // if ((!ImageContext.RelocationsStripped) && (Private->PeiMemoryInstalled) && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME || PcdGetBool (PcdShadowPeimOnS3Boot))) { // // Allocate more buffer to avoid buffer overflow. // if (ImageContext.IsTeImage) { AlignImageSize = ImageContext.ImageSize + ((EFI_TE_IMAGE_HEADER *) Pe32Data)->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER); } else { AlignImageSize = ImageContext.ImageSize; } if (ImageContext.SectionAlignment > EFI_PAGE_SIZE) { AlignImageSize += ImageContext.SectionAlignment; } if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0 && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) { Status = GetPeCoffImageFixLoadingAssignedAddress(&ImageContext, Private); if (EFI_ERROR (Status)){ DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED ERROR: Failed to load module at fixed address. \n")); // // The PEIM is not assiged valid address, try to allocate page to load it. // ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) AllocatePages (EFI_SIZE_TO_PAGES ((UINT32) AlignImageSize)); } } else { ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) AllocatePages (EFI_SIZE_TO_PAGES ((UINT32) AlignImageSize)); } if (ImageContext.ImageAddress != 0) { // // Adjust the Image Address to make sure it is section alignment. // if (ImageContext.SectionAlignment > EFI_PAGE_SIZE) { ImageContext.ImageAddress = (ImageContext.ImageAddress + ImageContext.SectionAlignment - 1) & ~((UINTN)ImageContext.SectionAlignment - 1); } // // Fix alignment requirement when Load IPF TeImage into memory. // Skip the reserved space for the stripped PeHeader when load TeImage into memory. // if (ImageContext.IsTeImage) { ImageContext.ImageAddress = ImageContext.ImageAddress + ((EFI_TE_IMAGE_HEADER *) Pe32Data)->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER); } } else { // // No enough memory resource. // if (IsXipImage) { // // XIP image can still be invoked. // ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) Pe32Data; ReturnStatus = EFI_WARN_BUFFER_TOO_SMALL; } else { // // Non XIP image can't be loaded because no enough memory is allocated. // ASSERT (FALSE); return EFI_OUT_OF_RESOURCES; } } } // // 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 // if (ImageContext.ImageAddress != (EFI_PHYSICAL_ADDRESS)(UINTN) Pe32Data) { InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize); } *ImageAddress = ImageContext.ImageAddress; *ImageSize = ImageContext.ImageSize; *EntryPoint = ImageContext.EntryPoint; return ReturnStatus; }
/** Entrypoint of Boot script exector driver, this function will be executed in normal boot phase and invoked by DXE dispatch. @param[in] ImageHandle The firmware allocated handle for the EFI image. @param[in] SystemTable A pointer to the EFI System Table. @retval EFI_SUCCESS The entry point is executed successfully. @retval other Some error occurs when executing this entry point. **/ EFI_STATUS EFIAPI BootScriptExecutorEntryPoint ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { UINT8 *Buffer; UINTN BufferSize; UINTN Pages; EFI_PHYSICAL_ADDRESS FfsBuffer; PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; BOOT_SCRIPT_EXECUTOR_VARIABLE *EfiBootScriptExecutorVariable; EFI_PHYSICAL_ADDRESS BootScriptExecutorBuffer; EFI_STATUS Status; VOID *DevicePath; EFI_HANDLE NewImageHandle; // // Test if the gEfiCallerIdGuid of this image is already installed. if not, the entry // point is loaded by DXE code which is the first time loaded. or else, it is already // be reloaded be itself.This is a work-around // Status = gBS->LocateProtocol (&gEfiCallerIdGuid, NULL, &DevicePath); if (EFI_ERROR (Status)) { // // This is the first-time loaded by DXE core. reload itself to NVS mem // // // A workarouond: Here we install a dummy handle // NewImageHandle = NULL; Status = gBS->InstallProtocolInterface ( &NewImageHandle, &gEfiCallerIdGuid, EFI_NATIVE_INTERFACE, NULL ); Status = GetSectionFromAnyFv ( &gEfiCallerIdGuid, EFI_SECTION_PE32, 0, (VOID **) &Buffer, &BufferSize ); ImageContext.Handle = Buffer; ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory; // // Get information about the image being loaded // Status = PeCoffLoaderGetImageInfo (&ImageContext); if (EFI_ERROR (Status)) { return Status; } Pages = EFI_SIZE_TO_PAGES(BufferSize + ImageContext.SectionAlignment); FfsBuffer = 0xFFFFFFFF; Status = gBS->AllocatePages ( AllocateMaxAddress, EfiACPIMemoryNVS, Pages, &FfsBuffer ); if (EFI_ERROR (Status)) { return EFI_OUT_OF_RESOURCES; } ImageContext.ImageAddress = (PHYSICAL_ADDRESS)(UINTN)FfsBuffer; // // Align buffer on section boundry // ImageContext.ImageAddress += ImageContext.SectionAlignment - 1; ImageContext.ImageAddress &= ~(ImageContext.SectionAlignment - 1); // // Load the image to our new buffer // Status = PeCoffLoaderLoadImage (&ImageContext); if (EFI_ERROR (Status)) { gBS->FreePages (FfsBuffer, Pages); return Status; } // // Relocate the image in our new buffer // Status = PeCoffLoaderRelocateImage (&ImageContext); if (EFI_ERROR (Status)) { PeCoffLoaderUnloadImage (&ImageContext); gBS->FreePages (FfsBuffer, Pages); return Status; } // // Flush the instruction cache so the image data is written before we execute it // InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize); Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)(ImageContext.EntryPoint)) (NewImageHandle, SystemTable); if (EFI_ERROR (Status)) { gBS->FreePages (FfsBuffer, Pages); return Status; } // // Additional step for BootScript integrity // Save BootScriptExecutor image // Status = SaveLockBox ( &mBootScriptExecutorImageGuid, (VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize ); ASSERT_EFI_ERROR (Status); Status = SetLockBoxAttributes (&mBootScriptExecutorImageGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE); ASSERT_EFI_ERROR (Status); } else { // // the entry point is invoked after reloading. following code only run in ACPI NVS // BufferSize = sizeof (BOOT_SCRIPT_EXECUTOR_VARIABLE); BootScriptExecutorBuffer = 0xFFFFFFFF; Pages = EFI_SIZE_TO_PAGES(BufferSize); Status = gBS->AllocatePages ( AllocateMaxAddress, EfiACPIMemoryNVS, Pages, &BootScriptExecutorBuffer ); if (EFI_ERROR (Status)) { return EFI_OUT_OF_RESOURCES; } EfiBootScriptExecutorVariable = (BOOT_SCRIPT_EXECUTOR_VARIABLE *)(UINTN)BootScriptExecutorBuffer; EfiBootScriptExecutorVariable->BootScriptExecutorEntrypoint = (UINTN) S3BootScriptExecutorEntryFunction ; Status = SaveLockBox ( &gEfiBootScriptExecutorVariableGuid, &BootScriptExecutorBuffer, sizeof(BootScriptExecutorBuffer) ); ASSERT_EFI_ERROR (Status); // // Additional step for BootScript integrity // Save BootScriptExecutor context // Status = SaveLockBox ( &gEfiBootScriptExecutorContextGuid, EfiBootScriptExecutorVariable, sizeof(*EfiBootScriptExecutorVariable) ); ASSERT_EFI_ERROR (Status); Status = SetLockBoxAttributes (&gEfiBootScriptExecutorContextGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE); ASSERT_EFI_ERROR (Status); } return EFI_SUCCESS; }
/** Relocate this image under 4G memory. @param ImageHandle Handle of driver image. @param SystemTable Pointer to system table. @retval EFI_SUCCESS Image successfully relocated. @retval EFI_ABORTED Failed to relocate image. **/ EFI_STATUS RelocateImageUnder4GIfNeeded ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; UINT8 *Buffer; UINTN BufferSize; EFI_HANDLE NewImageHandle; UINTN Pages; EFI_PHYSICAL_ADDRESS FfsBuffer; PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; VOID *Interface; // // If it is already <4G, no need do relocate // if ((UINTN)RelocateImageUnder4GIfNeeded < 0xFFFFFFFF) { return EFI_SUCCESS; } // // If locate gEfiCallerIdGuid success, it means 2nd entry. // Status = gBS->LocateProtocol (&gEfiCallerIdGuid, NULL, &Interface); if (!EFI_ERROR (Status)) { DEBUG ((DEBUG_INFO, "FspNotifyDxe - 2nd entry\n")); return EFI_SUCCESS; } DEBUG ((DEBUG_INFO, "FspNotifyDxe - 1st entry\n")); // // Here we install a dummy handle // NewImageHandle = NULL; Status = gBS->InstallProtocolInterface ( &NewImageHandle, &gEfiCallerIdGuid, EFI_NATIVE_INTERFACE, NULL ); ASSERT_EFI_ERROR (Status); // // Reload image itself to <4G mem // Status = GetSectionFromAnyFv ( &gEfiCallerIdGuid, EFI_SECTION_PE32, 0, (VOID **) &Buffer, &BufferSize ); ASSERT_EFI_ERROR (Status); ImageContext.Handle = Buffer; ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory; // // Get information about the image being loaded // Status = PeCoffLoaderGetImageInfo (&ImageContext); ASSERT_EFI_ERROR (Status); if (ImageContext.SectionAlignment > EFI_PAGE_SIZE) { Pages = EFI_SIZE_TO_PAGES ((UINTN) (ImageContext.ImageSize + ImageContext.SectionAlignment)); } else { Pages = EFI_SIZE_TO_PAGES ((UINTN) ImageContext.ImageSize); } FfsBuffer = 0xFFFFFFFF; Status = gBS->AllocatePages ( AllocateMaxAddress, EfiBootServicesCode, Pages, &FfsBuffer ); ASSERT_EFI_ERROR (Status); ImageContext.ImageAddress = (PHYSICAL_ADDRESS)(UINTN)FfsBuffer; // // Align buffer on section boundry // ImageContext.ImageAddress += ImageContext.SectionAlignment - 1; ImageContext.ImageAddress &= ~((EFI_PHYSICAL_ADDRESS)(ImageContext.SectionAlignment - 1)); // // Load the image to our new buffer // Status = PeCoffLoaderLoadImage (&ImageContext); ASSERT_EFI_ERROR (Status); // // Relocate the image in our new buffer // Status = PeCoffLoaderRelocateImage (&ImageContext); ASSERT_EFI_ERROR (Status); // // Free the buffer allocated by ReadSection since the image has been relocated in the new buffer // gBS->FreePool (Buffer); // // Flush the instruction cache so the image data is written before we execute it // InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize); DEBUG ((DEBUG_INFO, "Loading driver at 0x%08x EntryPoint=0x%08x\n", (UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.EntryPoint)); Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)(ImageContext.EntryPoint)) (NewImageHandle, gST); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "Error: Image at 0x%08x start failed: %r\n", ImageContext.ImageAddress, Status)); gBS->FreePages (FfsBuffer, Pages); } // // return error to unload >4G copy, if we already relocate itself to <4G. // return EFI_ALREADY_STARTED; }
/** Loads and relocates a PE/COFF image into memory. If the image is not relocatable, it will not be loaded into memory and be loaded as XIP image. @param FileHandle - Pointer to the FFS file header of the image. @param Pe32Data - The base address of the PE/COFF file that is to be loaded and relocated @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 @retval EFI_SUCCESS The file was loaded and relocated @retval EFI_OUT_OF_RESOURCES There was not enough memory to load and relocate the PE/COFF file @retval EFI_WARN_BUFFER_TOO_SMALL There is not enough heap to allocate the requested size. This will not prevent the XIP image from being invoked. **/ EFI_STATUS LoadAndRelocatePeCoffImage ( IN EFI_PEI_FILE_HANDLE FileHandle, IN VOID *Pe32Data, OUT EFI_PHYSICAL_ADDRESS *ImageAddress, OUT UINT64 *ImageSize, OUT EFI_PHYSICAL_ADDRESS *EntryPoint ) { EFI_STATUS Status; PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; PEI_CORE_INSTANCE *Private; UINT64 AlignImageSize; BOOLEAN IsXipImage; EFI_STATUS ReturnStatus; BOOLEAN IsS3Boot; BOOLEAN IsPeiModule; BOOLEAN IsRegisterForShadow; EFI_FV_FILE_INFO FileInfo; Private = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer ()); ReturnStatus = EFI_SUCCESS; IsXipImage = FALSE; ZeroMem (&ImageContext, sizeof (ImageContext)); ImageContext.Handle = Pe32Data; ImageContext.ImageRead = PeiImageRead; Status = PeCoffLoaderGetImageInfo (&ImageContext); if (EFI_ERROR (Status)) { return Status; } // // Initilize local IsS3Boot and IsRegisterForShadow variable // IsS3Boot = FALSE; if (Private->HobList.HandoffInformationTable->BootMode == BOOT_ON_S3_RESUME) { IsS3Boot = TRUE; } IsRegisterForShadow = FALSE; if ((Private->CurrentFileHandle == FileHandle) && (Private->Fv[Private->CurrentPeimFvCount].PeimState[Private->CurrentPeimCount] == PEIM_STATE_REGISTER_FOR_SHADOW)) { IsRegisterForShadow = TRUE; } // // XIP image that ImageAddress is same to Image handle. // if (ImageContext.ImageAddress == (EFI_PHYSICAL_ADDRESS)(UINTN) Pe32Data) { IsXipImage = TRUE; } // // Get file type first // Status = PeiServicesFfsGetFileInfo (FileHandle, &FileInfo); ASSERT_EFI_ERROR (Status); // // Check whether the file type is PEI module. // IsPeiModule = FALSE; if (FileInfo.FileType == EFI_FV_FILETYPE_PEI_CORE || FileInfo.FileType == EFI_FV_FILETYPE_PEIM || FileInfo.FileType == EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER) { IsPeiModule = TRUE; } // // When Image has no reloc section, it can't be relocated into memory. // if (ImageContext.RelocationsStripped && (Private->PeiMemoryInstalled) && ((!IsPeiModule) || (!IsS3Boot && (PcdGetBool (PcdShadowPeimOnBoot) || IsRegisterForShadow)) || (IsS3Boot && PcdGetBool (PcdShadowPeimOnS3Boot)))) { DEBUG ((EFI_D_INFO|EFI_D_LOAD, "The image at 0x%08x without reloc section can't be loaded into memory\n", (UINTN) Pe32Data)); } // // Set default base address to current image address. // ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) Pe32Data; // // Allocate Memory for the image when memory is ready, and image is relocatable. // On normal boot, PcdShadowPeimOnBoot decides whether load PEIM or PeiCore into memory. // On S3 boot, PcdShadowPeimOnS3Boot decides whether load PEIM or PeiCore into memory. // if ((!ImageContext.RelocationsStripped) && (Private->PeiMemoryInstalled) && ((!IsPeiModule) || (!IsS3Boot && (PcdGetBool (PcdShadowPeimOnBoot) || IsRegisterForShadow)) || (IsS3Boot && PcdGetBool (PcdShadowPeimOnS3Boot)))) { // // Allocate more buffer to avoid buffer overflow. // if (ImageContext.IsTeImage) { AlignImageSize = ImageContext.ImageSize + ((EFI_TE_IMAGE_HEADER *) Pe32Data)->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER); } else { AlignImageSize = ImageContext.ImageSize; } if (ImageContext.SectionAlignment > EFI_PAGE_SIZE) { AlignImageSize += ImageContext.SectionAlignment; } if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0 && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) { Status = GetPeCoffImageFixLoadingAssignedAddress(&ImageContext, Private); if (EFI_ERROR (Status)){ DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED ERROR: Failed to load module at fixed address. \n")); // // The PEIM is not assiged valid address, try to allocate page to load it. // Status = PeiServicesAllocatePages (EfiBootServicesCode, EFI_SIZE_TO_PAGES ((UINT32) AlignImageSize), &ImageContext.ImageAddress); } } else { Status = PeiServicesAllocatePages (EfiBootServicesCode, EFI_SIZE_TO_PAGES ((UINT32) AlignImageSize), &ImageContext.ImageAddress); } if (!EFI_ERROR (Status)) { // // Adjust the Image Address to make sure it is section alignment. // if (ImageContext.SectionAlignment > EFI_PAGE_SIZE) { ImageContext.ImageAddress = (ImageContext.ImageAddress + ImageContext.SectionAlignment - 1) & ~((UINTN)ImageContext.SectionAlignment - 1); } // // Fix alignment requirement when Load IPF TeImage into memory. // Skip the reserved space for the stripped PeHeader when load TeImage into memory. // if (ImageContext.IsTeImage) { ImageContext.ImageAddress = ImageContext.ImageAddress + ((EFI_TE_IMAGE_HEADER *) Pe32Data)->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER); } } else { // // No enough memory resource. // if (IsXipImage) { // // XIP image can still be invoked. // ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) Pe32Data; ReturnStatus = EFI_WARN_BUFFER_TOO_SMALL; } else { // // Non XIP image can't be loaded because no enough memory is allocated. // ASSERT (FALSE); return EFI_OUT_OF_RESOURCES; } } } // // Load the image to our new buffer // Status = PeCoffLoaderLoadImage (&ImageContext); if (EFI_ERROR (Status)) { if (ImageContext.ImageError == IMAGE_ERROR_INVALID_SECTION_ALIGNMENT) { DEBUG ((DEBUG_ERROR, "PEIM Image Address 0x%11p doesn't meet with section alignment 0x%x.\n", (VOID*)(UINTN)ImageContext.ImageAddress, ImageContext.SectionAlignment)); } 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 // if (ImageContext.ImageAddress != (EFI_PHYSICAL_ADDRESS)(UINTN) Pe32Data) { InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize); } *ImageAddress = ImageContext.ImageAddress; *ImageSize = ImageContext.ImageSize; *EntryPoint = ImageContext.EntryPoint; return ReturnStatus; }
/** Loads and relocates a PE/COFF image into memory. If the image is not relocatable, it will not be loaded into memory and be loaded as XIP image. @param Pe32Data - The base address of the PE/COFF file that is to be loaded and relocated @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 @retval EFI_SUCCESS The file was loaded and relocated @retval EFI_OUT_OF_RESOURCES There was not enough memory to load and relocate the PE/COFF file **/ EFI_STATUS LoadAndRelocatePeCoffImage ( IN VOID *Pe32Data, OUT EFI_PHYSICAL_ADDRESS *ImageAddress, OUT UINT64 *ImageSize, OUT EFI_PHYSICAL_ADDRESS *EntryPoint ) { EFI_STATUS Status; PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; PEI_CORE_INSTANCE *Private; Private = PEI_CORE_INSTANCE_FROM_PS_THIS (GetPeiServicesTablePointer ()); ZeroMem (&ImageContext, sizeof (ImageContext)); ImageContext.Handle = Pe32Data; Status = GetImageReadFunction (&ImageContext); ASSERT_EFI_ERROR (Status); Status = PeCoffLoaderGetImageInfo (&ImageContext); if (EFI_ERROR (Status)) { return Status; } // // When Image has no reloc section, it can't be relocated into memory. // if (ImageContext.RelocationsStripped && (Private->PeiMemoryInstalled) && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) { DEBUG ((EFI_D_INFO|EFI_D_LOAD, "The image at 0x%08x without reloc section can't be loaded into memory\n", (UINTN) Pe32Data)); } // // Set default base address to current image address. // ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) Pe32Data; // // Allocate Memory for the image when memory is ready, boot mode is not S3, and image is relocatable. // if ((!ImageContext.RelocationsStripped) && (Private->PeiMemoryInstalled) && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) { if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) { Status = GetPeCoffImageFixLoadingAssignedAddress(&ImageContext, Private); if (EFI_ERROR (Status)){ DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED ERROR: Failed to load module at fixed address. \n")); // // The PEIM is not assiged valid address, try to allocate page to load it. // ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) AllocatePages (EFI_SIZE_TO_PAGES ((UINT32) ImageContext.ImageSize)); } } else { ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) AllocatePages (EFI_SIZE_TO_PAGES ((UINT32) ImageContext.ImageSize)); } ASSERT (ImageContext.ImageAddress != 0); if (ImageContext.ImageAddress == 0) { return EFI_OUT_OF_RESOURCES; } // // Skip the reserved space for the stripped PeHeader when load TeImage into memory. // if (ImageContext.IsTeImage) { ImageContext.ImageAddress = ImageContext.ImageAddress + ((EFI_TE_IMAGE_HEADER *) Pe32Data)->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER); } } // // 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 // if ((!ImageContext.RelocationsStripped) && (Private->PeiMemoryInstalled) && (Private->HobList.HandoffInformationTable->BootMode != BOOT_ON_S3_RESUME)) { InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize); } *ImageAddress = ImageContext.ImageAddress; *ImageSize = ImageContext.ImageSize; *EntryPoint = ImageContext.EntryPoint; return EFI_SUCCESS; }
/** This routine is entry point of ScriptSave driver. @param ImageHandle Handle for this drivers loaded image protocol. @param SystemTable EFI system table. @retval EFI_OUT_OF_RESOURCES No enough resource @retval EFI_SUCCESS Succesfully installed the ScriptSave driver. @retval other Errors occured. **/ EFI_STATUS EFIAPI InitializeScriptSaveOnS3SaveState ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { UINT8 *Buffer; UINTN BufferSize; PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; BOOT_SCRIPT_THUNK_DATA *BootScriptThunkData; EFI_STATUS Status; VOID *DevicePath; EFI_PHYSICAL_ADDRESS MemoryAddress; UINTN PageNumber; EFI_HANDLE NewImageHandle; // // Test if the gEfiCallerIdGuid of this image is already installed. if not, the entry // point is loaded by DXE code which is the first time loaded. or else, it is already // be reloaded be itself.This is a work-around // Status = gBS->LocateProtocol (&gEfiCallerIdGuid, NULL, &DevicePath); if (EFI_ERROR (Status)) { // // This is the first-time loaded by DXE core. reload itself to RESERVED mem // // // A workaround: Here we install a dummy handle // NewImageHandle = NULL; Status = gBS->InstallProtocolInterface ( &NewImageHandle, &gEfiCallerIdGuid, EFI_NATIVE_INTERFACE, NULL ); ASSERT_EFI_ERROR (Status); Status = GetSectionFromAnyFv ( &gEfiCallerIdGuid, EFI_SECTION_PE32, 0, (VOID **) &Buffer, &BufferSize ); ASSERT_EFI_ERROR (Status); ImageContext.Handle = Buffer; ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory; // // Get information about the image being loaded // Status = PeCoffLoaderGetImageInfo (&ImageContext); ASSERT_EFI_ERROR (Status); MemoryAddress = SIZE_4GB - 1; if (ImageContext.SectionAlignment > EFI_PAGE_SIZE) { PageNumber = EFI_SIZE_TO_PAGES ((UINTN) (ImageContext.ImageSize + ImageContext.SectionAlignment)); } else { PageNumber = EFI_SIZE_TO_PAGES ((UINTN) ImageContext.ImageSize); } Status = gBS->AllocatePages ( AllocateMaxAddress, EfiReservedMemoryType, PageNumber, &MemoryAddress ); ASSERT_EFI_ERROR (Status); ImageContext.ImageAddress = (PHYSICAL_ADDRESS)(UINTN)MemoryAddress; // // Align buffer on section boundry // ImageContext.ImageAddress += ImageContext.SectionAlignment - 1; ImageContext.ImageAddress &= ~(ImageContext.SectionAlignment - 1); // // Load the image to our new buffer // Status = PeCoffLoaderLoadImage (&ImageContext); ASSERT_EFI_ERROR (Status); // // Relocate the image in our new buffer // Status = PeCoffLoaderRelocateImage (&ImageContext); ASSERT_EFI_ERROR (Status); // // Free the buffer allocated by ReadSection since the image has been relocated in the new buffer // gBS->FreePool (Buffer); // // Flush the instruction cache so the image data is written before we execute it // InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize); RegisterMemoryProfileImage ( &gEfiCallerIdGuid, ImageContext.ImageAddress, ImageContext.ImageSize, EFI_FV_FILETYPE_DRIVER ); Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)(ImageContext.EntryPoint)) (NewImageHandle, SystemTable); ASSERT_EFI_ERROR (Status); // // Additional step for BootScriptThunk integrity // // // Allocate BootScriptThunkData // BootScriptThunkData = AllocatePool (sizeof (BOOT_SCRIPT_THUNK_DATA)); ASSERT (BootScriptThunkData != NULL); BootScriptThunkData->BootScriptThunkBase = ImageContext.ImageAddress; BootScriptThunkData->BootScriptThunkLength = ImageContext.ImageSize; // // Set BootScriptThunkData // PcdSet64 (BootScriptThunkDataPtr, (UINT64)(UINTN)BootScriptThunkData); return EFI_SUCCESS; } else { // // the entry point is invoked after reloading. following code only run in RESERVED mem // // // Locate and cache PI S3 Save State Protocol. // Status = gBS->LocateProtocol ( &gEfiS3SaveStateProtocolGuid, NULL, (VOID **) &mS3SaveState ); ASSERT_EFI_ERROR (Status); return gBS->InstallProtocolInterface ( &mHandle, &gEfiBootScriptSaveProtocolGuid, EFI_NATIVE_INTERFACE, &mS3ScriptSave ); } }
/** Load the SMM Core image into SMRAM and executes the SMM Core from SMRAM. @param[in] SmramRange Descriptor for the range of SMRAM to reload the currently executing image. @param[in] Context Context to pass into SMM Core @return EFI_STATUS **/ EFI_STATUS ExecuteSmmCoreFromSmram ( IN EFI_SMRAM_DESCRIPTOR *SmramRange, IN VOID *Context ) { EFI_STATUS Status; VOID *SourceBuffer; UINTN SourceSize; PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; UINTN PageCount; EFI_PHYSICAL_ADDRESS DestinationBuffer; EFI_IMAGE_ENTRY_POINT EntryPoint; // // Search all Firmware Volumes for a PE/COFF image in a file of type SMM_CORE // Status = GetSectionFromAnyFvByFileType ( EFI_FV_FILETYPE_SMM_CORE, 0, EFI_SECTION_PE32, 0, &SourceBuffer, &SourceSize ); if (EFI_ERROR (Status)) { return Status; } // // Initilize ImageContext // ImageContext.Handle = SourceBuffer; ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory; // // Get information about the image being loaded // Status = PeCoffLoaderGetImageInfo (&ImageContext); if (EFI_ERROR (Status)) { return Status; } // // if Loading module at Fixed Address feature is enabled, the SMM core driver will be loaded to // the address assigned by build tool. // if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) { // // Get the fixed loading address assigned by Build tool // Status = GetPeCoffImageFixLoadingAssignedAddress (&ImageContext); if (!EFI_ERROR (Status)) { // // Since the memory range to load SMM CORE will be cut out in SMM core, so no need to allocate and free this range // PageCount = 0; } else { DEBUG ((EFI_D_INFO, "LOADING MODULE FIXED ERROR: Loading module at fixed address at address failed\n")); // // Allocate memory for the image being loaded from the EFI_SRAM_DESCRIPTOR // specified by SmramRange // PageCount = (UINTN)EFI_SIZE_TO_PAGES((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment); ASSERT ((SmramRange->PhysicalSize & EFI_PAGE_MASK) == 0); ASSERT (SmramRange->PhysicalSize > EFI_PAGES_TO_SIZE (PageCount)); SmramRange->PhysicalSize -= EFI_PAGES_TO_SIZE (PageCount); DestinationBuffer = SmramRange->CpuStart + SmramRange->PhysicalSize; // // Align buffer on section boundry // ImageContext.ImageAddress = DestinationBuffer; } } else { // // Allocate memory for the image being loaded from the EFI_SRAM_DESCRIPTOR // specified by SmramRange // PageCount = (UINTN)EFI_SIZE_TO_PAGES((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment); ASSERT ((SmramRange->PhysicalSize & EFI_PAGE_MASK) == 0); ASSERT (SmramRange->PhysicalSize > EFI_PAGES_TO_SIZE (PageCount)); SmramRange->PhysicalSize -= EFI_PAGES_TO_SIZE (PageCount); DestinationBuffer = SmramRange->CpuStart + SmramRange->PhysicalSize; // // Align buffer on section boundry // ImageContext.ImageAddress = DestinationBuffer; } ImageContext.ImageAddress += ImageContext.SectionAlignment - 1; ImageContext.ImageAddress &= ~(ImageContext.SectionAlignment - 1); // // Print debug message showing SMM Core load address. // DEBUG ((DEBUG_INFO, "SMM IPL loading SMM Core at SMRAM address %p\n", (VOID *)(UINTN)ImageContext.ImageAddress)); // // Load the image to our new buffer // Status = PeCoffLoaderLoadImage (&ImageContext); if (!EFI_ERROR (Status)) { // // Relocate the image in our new buffer // Status = PeCoffLoaderRelocateImage (&ImageContext); if (!EFI_ERROR (Status)) { // // Flush the instruction cache so the image data are written before we execute it // InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize); // // Print debug message showing SMM Core entry point address. // DEBUG ((DEBUG_INFO, "SMM IPL calling SMM Core at SMRAM address %p\n", (VOID *)(UINTN)ImageContext.EntryPoint)); // // Execute image // EntryPoint = (EFI_IMAGE_ENTRY_POINT)(UINTN)ImageContext.EntryPoint; Status = EntryPoint ((EFI_HANDLE)Context, gST); } } // // If the load operation, relocate operation, or the image execution return an // error, then free memory allocated from the EFI_SRAM_DESCRIPTOR specified by // SmramRange // if (EFI_ERROR (Status)) { SmramRange->PhysicalSize += EFI_PAGES_TO_SIZE (PageCount); } // // Always free memory allocted by GetFileBufferByFilePath () // FreePool (SourceBuffer); return Status; }
/** Relocate this image to reserved memory. @param ImageHandle Handle of driver image. @param SystemTable Pointer to system table. @retval EFI_SUCCESS Image successfully relocated. @retval EFI_ABORTED Failed to relocate image. **/ EFI_STATUS RelocateImageToReserved ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; EFI_STATUS Status; UINT8 *Buffer; UINTN BufferSize; EFI_HANDLE NewImageHandle; UINTN Pages; EFI_PHYSICAL_ADDRESS FfsBuffer; PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; VOID *Interface; // // If locate gEfiCallerIdGuid success, it means 2nd entry. // Status = gBS->LocateProtocol (&gEfiCallerIdGuid, NULL, &Interface); if (!EFI_ERROR (Status)) { DEBUG ((EFI_D_INFO, "StmService - 2nd entry\n")); return EFI_SUCCESS; } DEBUG ((EFI_D_INFO, "StmService - 1st entry\n")); // // Reload image itself to <4G mem // Status = GetSectionFromAnyFv ( &gEfiCallerIdGuid, EFI_SECTION_PE32, 0, (VOID **) &Buffer, &BufferSize ); ASSERT_EFI_ERROR (Status); ImageContext.Handle = Buffer; ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory; // // Get information about the image being loaded // Status = PeCoffLoaderGetImageInfo (&ImageContext); ASSERT_EFI_ERROR (Status); if (ImageContext.SectionAlignment > EFI_PAGE_SIZE) { Pages = EFI_SIZE_TO_PAGES ((UINTN) (ImageContext.ImageSize + ImageContext.SectionAlignment)); } else { Pages = EFI_SIZE_TO_PAGES ((UINTN) ImageContext.ImageSize); } FfsBuffer = 0xFFFFFFFF; Status = gBS->AllocatePages ( AllocateMaxAddress, EfiReservedMemoryType, Pages, &FfsBuffer ); ASSERT_EFI_ERROR (Status); ImageContext.ImageAddress = (PHYSICAL_ADDRESS)(UINTN)FfsBuffer; // // Align buffer on section boundry // ImageContext.ImageAddress += ImageContext.SectionAlignment - 1; ImageContext.ImageAddress &= ~((EFI_PHYSICAL_ADDRESS)(ImageContext.SectionAlignment - 1)); // // Load the image to our new buffer // Status = PeCoffLoaderLoadImage (&ImageContext); ASSERT_EFI_ERROR (Status); // // Relocate the image in our new buffer // Status = PeCoffLoaderRelocateImage (&ImageContext); ASSERT_EFI_ERROR (Status); // // Free the buffer allocated by ReadSection since the image has been relocated in the new buffer // gBS->FreePool (Buffer); // // Flush the instruction cache so the image data is written before we execute it // InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize); // // install loaded image // LoadedImage = AllocateZeroPool (sizeof(EFI_LOADED_IMAGE_PROTOCOL)); ASSERT (LoadedImage != NULL); LoadedImage->Revision = EFI_LOADED_IMAGE_PROTOCOL_REVISION; LoadedImage->ParentHandle = NULL; LoadedImage->SystemTable = gST; LoadedImage->DeviceHandle = NULL; LoadedImage->LoadOptionsSize = 0; LoadedImage->LoadOptions = NULL; LoadedImage->ImageBase = (VOID *)(UINTN)ImageContext.ImageAddress; LoadedImage->ImageSize = ImageContext.ImageSize; LoadedImage->ImageCodeType = EfiReservedMemoryType; LoadedImage->ImageDataType = EfiReservedMemoryType; LoadedImage->Unload = NULL; NewImageHandle = NULL; Status = gBS->InstallMultipleProtocolInterfaces ( &NewImageHandle, &gEfiCallerIdGuid, LoadedImage, NULL ); ASSERT_EFI_ERROR (Status); DEBUG ((EFI_D_INFO, "NewImageHandle - 0x%x\n", NewImageHandle)); // // Call entrypoint // DEBUG ((EFI_D_INFO, "Loading driver at 0x%08x EntryPoint=0x%08x\n", (UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.EntryPoint)); Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)(ImageContext.EntryPoint)) (NewImageHandle, gST); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "Error: Image at 0x%08x start failed: %r\n", ImageContext.ImageAddress, Status)); gBS->FreePages (FfsBuffer, Pages); } // // return error to unload DXE copy, if we already relocate itself to reserved memory. // return EFI_ACCESS_DENIED; }