diff options
Diffstat (limited to 'MdeModulePkg/Core/Dxe/Image/Image.c')
| -rw-r--r-- | MdeModulePkg/Core/Dxe/Image/Image.c | 3914 |
1 files changed, 1957 insertions, 1957 deletions
diff --git a/MdeModulePkg/Core/Dxe/Image/Image.c b/MdeModulePkg/Core/Dxe/Image/Image.c index 37fc74d5d1..ad18fe8c21 100644 --- a/MdeModulePkg/Core/Dxe/Image/Image.c +++ b/MdeModulePkg/Core/Dxe/Image/Image.c @@ -1,1957 +1,1957 @@ -/** @file
- Core image handling services to load and unload PeImage.
-
-Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "DxeMain.h"
-#include "Image.h"
-
-//
-// Module Globals
-//
-LOADED_IMAGE_PRIVATE_DATA *mCurrentImage = NULL;
-
-typedef struct {
- LIST_ENTRY Link;
- EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL *Emulator;
- UINT16 MachineType;
-} EMULATOR_ENTRY;
-
-STATIC LIST_ENTRY mAvailableEmulators;
-STATIC EFI_EVENT mPeCoffEmuProtocolRegistrationEvent;
-STATIC VOID *mPeCoffEmuProtocolNotifyRegistration;
-
-//
-// This code is needed to build the Image handle for the DXE Core
-//
-LOADED_IMAGE_PRIVATE_DATA mCorePrivateImage = {
- LOADED_IMAGE_PRIVATE_DATA_SIGNATURE, // Signature
- NULL, // Image handle
- EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER, // Image type
- TRUE, // If entrypoint has been called
- NULL, // EntryPoint
- {
- EFI_LOADED_IMAGE_INFORMATION_REVISION, // Revision
- NULL, // Parent handle
- NULL, // System handle
-
- NULL, // Device handle
- NULL, // File path
- NULL, // Reserved
-
- 0, // LoadOptionsSize
- NULL, // LoadOptions
-
- NULL, // ImageBase
- 0, // ImageSize
- EfiBootServicesCode, // ImageCodeType
- EfiBootServicesData // ImageDataType
- },
- (EFI_PHYSICAL_ADDRESS)0, // ImageBasePage
- 0, // NumberOfPages
- NULL, // FixupData
- 0, // Tpl
- EFI_SUCCESS, // Status
- 0, // ExitDataSize
- NULL, // ExitData
- NULL, // JumpBuffer
- NULL, // JumpContext
- 0, // Machine
- NULL, // PeCoffEmu
- NULL, // RuntimeData
- NULL // LoadedImageDevicePath
-};
-//
-// The field is define for Loading modules at fixed address feature to tracker the PEI code
-// memory range usage. It is a bit mapped array in which every bit indicates the correspoding memory page
-// available or not.
-//
-GLOBAL_REMOVE_IF_UNREFERENCED UINT64 *mDxeCodeMemoryRangeUsageBitMap = NULL;
-
-typedef struct {
- UINT16 MachineType;
- CHAR16 *MachineTypeName;
-} MACHINE_TYPE_INFO;
-
-GLOBAL_REMOVE_IF_UNREFERENCED MACHINE_TYPE_INFO mMachineTypeInfo[] = {
- { EFI_IMAGE_MACHINE_IA32, L"IA32" },
- { EFI_IMAGE_MACHINE_IA64, L"IA64" },
- { EFI_IMAGE_MACHINE_X64, L"X64" },
- { EFI_IMAGE_MACHINE_ARMTHUMB_MIXED, L"ARM" },
- { EFI_IMAGE_MACHINE_AARCH64, L"AARCH64" },
- { EFI_IMAGE_MACHINE_RISCV64, L"RISCV64" },
- { EFI_IMAGE_MACHINE_LOONGARCH64, L"LOONGARCH64" },
-};
-
-UINT16 mDxeCoreImageMachineType = 0;
-
-/**
- Return machine type name.
-
- @param MachineType The machine type
-
- @return machine type name
-**/
-CHAR16 *
-GetMachineTypeName (
- UINT16 MachineType
- )
-{
- UINTN Index;
-
- for (Index = 0; Index < sizeof (mMachineTypeInfo)/sizeof (mMachineTypeInfo[0]); Index++) {
- if (mMachineTypeInfo[Index].MachineType == MachineType) {
- return mMachineTypeInfo[Index].MachineTypeName;
- }
- }
-
- return L"<Unknown>";
-}
-
-/**
- Notification event handler registered by CoreInitializeImageServices () to
- keep track of which PE/COFF image emulators are available.
-
- @param Event The Event that is being processed, not used.
- @param Context Event Context, not used.
-
-**/
-STATIC
-VOID
-EFIAPI
-PeCoffEmuProtocolNotify (
- IN EFI_EVENT Event,
- IN VOID *Context
- )
-{
- EFI_STATUS Status;
- UINTN BufferSize;
- EFI_HANDLE EmuHandle;
- EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL *Emulator;
- EMULATOR_ENTRY *Entry;
-
- EmuHandle = NULL;
- Emulator = NULL;
-
- while (TRUE) {
- BufferSize = sizeof (EmuHandle);
- Status = CoreLocateHandle (
- ByRegisterNotify,
- NULL,
- mPeCoffEmuProtocolNotifyRegistration,
- &BufferSize,
- &EmuHandle
- );
- if (EFI_ERROR (Status)) {
- //
- // If no more notification events exit
- //
- return;
- }
-
- Status = CoreHandleProtocol (
- EmuHandle,
- &gEdkiiPeCoffImageEmulatorProtocolGuid,
- (VOID **)&Emulator
- );
- if (EFI_ERROR (Status) || (Emulator == NULL)) {
- continue;
- }
-
- Entry = AllocateZeroPool (sizeof (*Entry));
- ASSERT (Entry != NULL);
-
- Entry->Emulator = Emulator;
- Entry->MachineType = Entry->Emulator->MachineType;
-
- InsertTailList (&mAvailableEmulators, &Entry->Link);
- }
-}
-
-/**
- Add the Image Services to EFI Boot Services Table and install the protocol
- interfaces for this image.
-
- @param HobStart The HOB to initialize
-
- @return Status code.
-
-**/
-EFI_STATUS
-CoreInitializeImageServices (
- IN VOID *HobStart
- )
-{
- EFI_STATUS Status;
- LOADED_IMAGE_PRIVATE_DATA *Image;
- EFI_PHYSICAL_ADDRESS DxeCoreImageBaseAddress;
- UINT64 DxeCoreImageLength;
- VOID *DxeCoreEntryPoint;
- EFI_PEI_HOB_POINTERS DxeCoreHob;
-
- //
- // Searching for image hob
- //
- DxeCoreHob.Raw = HobStart;
- while ((DxeCoreHob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, DxeCoreHob.Raw)) != NULL) {
- if (CompareGuid (&DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.Name, &gEfiHobMemoryAllocModuleGuid)) {
- //
- // Find Dxe Core HOB
- //
- break;
- }
-
- DxeCoreHob.Raw = GET_NEXT_HOB (DxeCoreHob);
- }
-
- ASSERT (DxeCoreHob.Raw != NULL);
-
- DxeCoreImageBaseAddress = DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.MemoryBaseAddress;
- DxeCoreImageLength = DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.MemoryLength;
- DxeCoreEntryPoint = (VOID *)(UINTN)DxeCoreHob.MemoryAllocationModule->EntryPoint;
- gDxeCoreFileName = &DxeCoreHob.MemoryAllocationModule->ModuleName;
-
- //
- // Initialize the fields for an internal driver
- //
- Image = &mCorePrivateImage;
-
- Image->EntryPoint = (EFI_IMAGE_ENTRY_POINT)(UINTN)DxeCoreEntryPoint;
- Image->ImageBasePage = DxeCoreImageBaseAddress;
- Image->NumberOfPages = (UINTN)(EFI_SIZE_TO_PAGES ((UINTN)(DxeCoreImageLength)));
- Image->Tpl = gEfiCurrentTpl;
- Image->Info.ImageBase = (VOID *)(UINTN)DxeCoreImageBaseAddress;
- Image->Info.ImageSize = DxeCoreImageLength;
-
- //
- // Install the protocol interfaces for this image
- //
- Status = CoreInstallProtocolInterface (
- &Image->Handle,
- &gEfiLoadedImageProtocolGuid,
- EFI_NATIVE_INTERFACE,
- &Image->Info
- );
- ASSERT_EFI_ERROR (Status);
-
- mCurrentImage = Image;
-
- //
- // Fill in DXE globals
- //
- mDxeCoreImageMachineType = PeCoffLoaderGetMachineType (Image->Info.ImageBase);
- gDxeCoreImageHandle = Image->Handle;
- gDxeCoreLoadedImage = &Image->Info;
-
- //
- // Create the PE/COFF emulator protocol registration event
- //
- Status = CoreCreateEvent (
- EVT_NOTIFY_SIGNAL,
- TPL_CALLBACK,
- PeCoffEmuProtocolNotify,
- NULL,
- &mPeCoffEmuProtocolRegistrationEvent
- );
- ASSERT_EFI_ERROR (Status);
-
- //
- // Register for protocol notifications on this event
- //
- Status = CoreRegisterProtocolNotify (
- &gEdkiiPeCoffImageEmulatorProtocolGuid,
- mPeCoffEmuProtocolRegistrationEvent,
- &mPeCoffEmuProtocolNotifyRegistration
- );
- ASSERT_EFI_ERROR (Status);
-
- InitializeListHead (&mAvailableEmulators);
-
- ProtectUefiImage (&Image->Info, Image->LoadedImageDevicePath);
-
- return Status;
-}
-
-/**
- Read image file (specified by UserHandle) into user specified buffer with specified offset
- and length.
-
- @param UserHandle Image file handle
- @param Offset Offset to the source file
- @param ReadSize For input, pointer of size to read; For output,
- pointer of size actually read.
- @param Buffer Buffer to write into
-
- @retval EFI_SUCCESS Successfully read the specified part of file
- into buffer.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreReadImageFile (
- IN VOID *UserHandle,
- IN UINTN Offset,
- IN OUT UINTN *ReadSize,
- OUT VOID *Buffer
- )
-{
- UINTN EndPosition;
- IMAGE_FILE_HANDLE *FHand;
-
- if ((UserHandle == NULL) || (ReadSize == NULL) || (Buffer == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
-
- if (MAX_ADDRESS - Offset < *ReadSize) {
- return EFI_INVALID_PARAMETER;
- }
-
- FHand = (IMAGE_FILE_HANDLE *)UserHandle;
- ASSERT (FHand->Signature == IMAGE_FILE_HANDLE_SIGNATURE);
-
- //
- // Move data from our local copy of the file
- //
- EndPosition = Offset + *ReadSize;
- if (EndPosition > FHand->SourceSize) {
- *ReadSize = (UINT32)(FHand->SourceSize - Offset);
- }
-
- if (Offset >= FHand->SourceSize) {
- *ReadSize = 0;
- }
-
- CopyMem (Buffer, (CHAR8 *)FHand->Source + Offset, *ReadSize);
- return EFI_SUCCESS;
-}
-
-/**
- To check memory usage bit map array to figure out if the memory range the image will be loaded in is available or not. If
- memory range is available, the function will mark the corresponding bits to 1 which indicates the memory range is used.
- The function is only invoked when load modules at fixed address feature is enabled.
-
- @param ImageBase The base address the image will be loaded at.
- @param ImageSize The size of the image
-
- @retval EFI_SUCCESS The memory range the image will be loaded in is available
- @retval EFI_NOT_FOUND The memory range the image will be loaded in is not available
-**/
-EFI_STATUS
-CheckAndMarkFixLoadingMemoryUsageBitMap (
- IN EFI_PHYSICAL_ADDRESS ImageBase,
- IN UINTN ImageSize
- )
-{
- UINT32 DxeCodePageNumber;
- UINT64 DxeCodeSize;
- EFI_PHYSICAL_ADDRESS DxeCodeBase;
- UINTN BaseOffsetPageNumber;
- UINTN TopOffsetPageNumber;
- UINTN Index;
-
- //
- // The DXE code range includes RuntimeCodePage range and Boot time code range.
- //
- DxeCodePageNumber = PcdGet32 (PcdLoadFixAddressRuntimeCodePageNumber);
- DxeCodePageNumber += PcdGet32 (PcdLoadFixAddressBootTimeCodePageNumber);
- DxeCodeSize = EFI_PAGES_TO_SIZE (DxeCodePageNumber);
- DxeCodeBase = gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress - DxeCodeSize;
-
- //
- // If the memory usage bit map is not initialized, do it. Every bit in the array
- // indicate the status of the corresponding memory page, available or not
- //
- if (mDxeCodeMemoryRangeUsageBitMap == NULL) {
- mDxeCodeMemoryRangeUsageBitMap = AllocateZeroPool (((DxeCodePageNumber/64) + 1)*sizeof (UINT64));
- }
-
- //
- // If the Dxe code memory range is not allocated or the bit map array allocation failed, return EFI_NOT_FOUND
- //
- if (!gLoadFixedAddressCodeMemoryReady || (mDxeCodeMemoryRangeUsageBitMap == NULL)) {
- return EFI_NOT_FOUND;
- }
-
- //
- // Test the memory range for loading the image in the DXE code range.
- //
- if ((gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress < ImageBase + ImageSize) ||
- (DxeCodeBase > ImageBase))
- {
- return EFI_NOT_FOUND;
- }
-
- //
- // Test if the memory is avalaible or not.
- //
- BaseOffsetPageNumber = EFI_SIZE_TO_PAGES ((UINT32)(ImageBase - DxeCodeBase));
- TopOffsetPageNumber = EFI_SIZE_TO_PAGES ((UINT32)(ImageBase + ImageSize - DxeCodeBase));
- for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index++) {
- if ((mDxeCodeMemoryRangeUsageBitMap[Index / 64] & LShiftU64 (1, (Index % 64))) != 0) {
- //
- // This page is already used.
- //
- return EFI_NOT_FOUND;
- }
- }
-
- //
- // Being here means the memory range is available. So mark the bits for the memory range
- //
- for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index++) {
- mDxeCodeMemoryRangeUsageBitMap[Index / 64] |= LShiftU64 (1, (Index % 64));
- }
-
- return EFI_SUCCESS;
-}
-
-/**
-
- Get the fixed loading address from image header assigned by build tool. This function only be called
- when Loading module at Fixed address feature enabled.
-
- @param ImageContext Pointer to the image context structure that describes the PE/COFF
- image that needs to be examined by this function.
- @retval EFI_SUCCESS An fixed loading address is assigned to this image by build tools .
- @retval EFI_NOT_FOUND The image has no assigned fixed loading address.
-
-**/
-EFI_STATUS
-GetPeCoffImageFixLoadingAssignedAddress (
- IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
- )
-{
- UINTN SectionHeaderOffset;
- EFI_STATUS Status;
- EFI_IMAGE_SECTION_HEADER SectionHeader;
- EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr;
- UINT16 Index;
- UINTN Size;
- UINT16 NumberOfSections;
- IMAGE_FILE_HANDLE *Handle;
- UINT64 ValueInSectionHeader;
-
- Status = EFI_NOT_FOUND;
-
- //
- // Get PeHeader pointer
- //
- Handle = (IMAGE_FILE_HANDLE *)ImageContext->Handle;
- ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((CHAR8 *)Handle->Source + ImageContext->PeCoffHeaderOffset);
- SectionHeaderOffset = ImageContext->PeCoffHeaderOffset +
- sizeof (UINT32) +
- sizeof (EFI_IMAGE_FILE_HEADER) +
- ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader;
- NumberOfSections = ImgHdr->Pe32.FileHeader.NumberOfSections;
-
- //
- // Get base address from the first section header that doesn't point to code section.
- //
- for (Index = 0; Index < NumberOfSections; Index++) {
- //
- // Read section header from file
- //
- Size = sizeof (EFI_IMAGE_SECTION_HEADER);
- Status = ImageContext->ImageRead (
- ImageContext->Handle,
- SectionHeaderOffset,
- &Size,
- &SectionHeader
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- if (Size != sizeof (EFI_IMAGE_SECTION_HEADER)) {
- return EFI_NOT_FOUND;
- }
-
- Status = EFI_NOT_FOUND;
-
- if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_CNT_CODE) == 0) {
- //
- // Build tool will save the address in PointerToRelocations & PointerToLineNumbers fields in the first section header
- // that doesn't point to code section in image header, as well as ImageBase field of image header. And there is an
- // assumption that when the feature is enabled, if a module is assigned a loading address by tools, PointerToRelocations
- // & PointerToLineNumbers fields should NOT be Zero, or else, these 2 fields should be set to Zero
- //
- ValueInSectionHeader = ReadUnaligned64 ((UINT64 *)&SectionHeader.PointerToRelocations);
- if (ValueInSectionHeader != 0) {
- //
- // When the feature is configured as load module at fixed absolute address, the ImageAddress field of ImageContext
- // hold the specified address. If the feature is configured as load module at fixed offset, ImageAddress hold an offset
- // relative to top address
- //
- if ((INT64)PcdGet64 (PcdLoadModuleAtFixAddressEnable) < 0) {
- ImageContext->ImageAddress = gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress + (INT64)(INTN)ImageContext->ImageAddress;
- }
-
- //
- // Check if the memory range is available.
- //
- Status = CheckAndMarkFixLoadingMemoryUsageBitMap (ImageContext->ImageAddress, (UINTN)(ImageContext->ImageSize + ImageContext->SectionAlignment));
- }
-
- break;
- }
-
- SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
- }
-
- DEBUG ((DEBUG_INFO|DEBUG_LOAD, "LOADING MODULE FIXED INFO: Loading module at fixed address 0x%11p. Status = %r \n", (VOID *)(UINTN)(ImageContext->ImageAddress), Status));
- return Status;
-}
-
-/**
- Decides whether a PE/COFF image can execute on this system, either natively
- or via emulation/interpretation. In the latter case, the PeCoffEmu member
- of the LOADED_IMAGE_PRIVATE_DATA struct pointer is populated with a pointer
- to the emulator protocol that supports this image.
-
- @param[in, out] Image LOADED_IMAGE_PRIVATE_DATA struct pointer
-
- @retval TRUE The image is supported
- @retval FALSE The image is not supported
-
-**/
-STATIC
-BOOLEAN
-CoreIsImageTypeSupported (
- IN OUT LOADED_IMAGE_PRIVATE_DATA *Image
- )
-{
- LIST_ENTRY *Link;
- EMULATOR_ENTRY *Entry;
-
- for (Link = GetFirstNode (&mAvailableEmulators);
- !IsNull (&mAvailableEmulators, Link);
- Link = GetNextNode (&mAvailableEmulators, Link))
- {
- Entry = BASE_CR (Link, EMULATOR_ENTRY, Link);
- if (Entry->MachineType != Image->ImageContext.Machine) {
- continue;
- }
-
- if (Entry->Emulator->IsImageSupported (
- Entry->Emulator,
- Image->ImageContext.ImageType,
- Image->Info.FilePath
- ))
- {
- Image->PeCoffEmu = Entry->Emulator;
- return TRUE;
- }
- }
-
- return EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Image->ImageContext.Machine) ||
- EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED (Image->ImageContext.Machine);
-}
-
-/**
- Loads, relocates, and invokes a PE/COFF image
-
- @param BootPolicy If TRUE, indicates that the request originates
- from the boot manager, and that the boot
- manager is attempting to load FilePath as a
- boot selection.
- @param Pe32Handle The handle of PE32 image
- @param Image PE image to be loaded
- @param DstBuffer The buffer to store the image
- @param EntryPoint A pointer to the entry point
- @param Attribute The bit mask of attributes to set for the load
- PE image
-
- @retval EFI_SUCCESS The file was loaded, relocated, and invoked
- @retval EFI_OUT_OF_RESOURCES There was not enough memory to load and
- relocate the PE/COFF file
- @retval EFI_INVALID_PARAMETER Invalid parameter
- @retval EFI_BUFFER_TOO_SMALL Buffer for image is too small
-
-**/
-EFI_STATUS
-CoreLoadPeImage (
- IN BOOLEAN BootPolicy,
- IN VOID *Pe32Handle,
- IN LOADED_IMAGE_PRIVATE_DATA *Image,
- IN EFI_PHYSICAL_ADDRESS DstBuffer OPTIONAL,
- OUT EFI_PHYSICAL_ADDRESS *EntryPoint OPTIONAL,
- IN UINT32 Attribute
- )
-{
- EFI_STATUS Status;
- BOOLEAN DstBufAlocated;
- UINTN Size;
-
- ZeroMem (&Image->ImageContext, sizeof (Image->ImageContext));
-
- Image->ImageContext.Handle = Pe32Handle;
- Image->ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE)CoreReadImageFile;
-
- //
- // Get information about the image being loaded
- //
- Status = PeCoffLoaderGetImageInfo (&Image->ImageContext);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- if (!CoreIsImageTypeSupported (Image)) {
- //
- // The PE/COFF loader can support loading image types that can be executed.
- // If we loaded an image type that we can not execute return EFI_UNSUPPORTED.
- //
- DEBUG ((
- DEBUG_ERROR,
- "Image type %s can't be loaded on %s UEFI system.\n",
- GetMachineTypeName (Image->ImageContext.Machine),
- GetMachineTypeName (mDxeCoreImageMachineType)
- ));
- return EFI_UNSUPPORTED;
- }
-
- //
- // Set EFI memory type based on ImageType
- //
- switch (Image->ImageContext.ImageType) {
- case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION:
- Image->ImageContext.ImageCodeMemoryType = EfiLoaderCode;
- Image->ImageContext.ImageDataMemoryType = EfiLoaderData;
- break;
- case EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER:
- Image->ImageContext.ImageCodeMemoryType = EfiBootServicesCode;
- Image->ImageContext.ImageDataMemoryType = EfiBootServicesData;
- break;
- case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER:
- case EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER:
- Image->ImageContext.ImageCodeMemoryType = EfiRuntimeServicesCode;
- Image->ImageContext.ImageDataMemoryType = EfiRuntimeServicesData;
- break;
- default:
- Image->ImageContext.ImageError = IMAGE_ERROR_INVALID_SUBSYSTEM;
- return EFI_UNSUPPORTED;
- }
-
- //
- // Allocate memory of the correct memory type aligned on the required image boundary
- //
- DstBufAlocated = FALSE;
- if (DstBuffer == 0) {
- //
- // Allocate Destination Buffer as caller did not pass it in
- //
-
- if (Image->ImageContext.SectionAlignment > EFI_PAGE_SIZE) {
- Size = (UINTN)Image->ImageContext.ImageSize + Image->ImageContext.SectionAlignment;
- } else {
- Size = (UINTN)Image->ImageContext.ImageSize;
- }
-
- Image->NumberOfPages = EFI_SIZE_TO_PAGES (Size);
-
- //
- // If the image relocations have not been stripped, then load at any address.
- // Otherwise load at the address at which it was linked.
- //
- // Memory below 1MB should be treated reserved for CSM and there should be
- // no modules whose preferred load addresses are below 1MB.
- //
- Status = EFI_OUT_OF_RESOURCES;
- //
- // If Loading Module At Fixed Address feature is enabled, the module should be loaded to
- // a specified address.
- //
- if (PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0 ) {
- Status = GetPeCoffImageFixLoadingAssignedAddress (&(Image->ImageContext));
-
- if (EFI_ERROR (Status)) {
- //
- // If the code memory is not ready, invoke CoreAllocatePage with AllocateAnyPages to load the driver.
- //
- DEBUG ((DEBUG_INFO|DEBUG_LOAD, "LOADING MODULE FIXED ERROR: Loading module at fixed address failed since specified memory is not available.\n"));
-
- Status = CoreAllocatePages (
- AllocateAnyPages,
- (EFI_MEMORY_TYPE)(Image->ImageContext.ImageCodeMemoryType),
- Image->NumberOfPages,
- &Image->ImageContext.ImageAddress
- );
- }
- } else {
- if ((PcdGetBool (PcdImageLargeAddressLoad) && ((Image->ImageContext.ImageAddress) >= 0x100000)) ||
- Image->ImageContext.RelocationsStripped)
- {
- Status = CoreAllocatePages (
- AllocateAddress,
- (EFI_MEMORY_TYPE)(Image->ImageContext.ImageCodeMemoryType),
- Image->NumberOfPages,
- &Image->ImageContext.ImageAddress
- );
- }
-
- if (EFI_ERROR (Status) && !Image->ImageContext.RelocationsStripped) {
- Status = CoreAllocatePages (
- AllocateAnyPages,
- (EFI_MEMORY_TYPE)(Image->ImageContext.ImageCodeMemoryType),
- Image->NumberOfPages,
- &Image->ImageContext.ImageAddress
- );
- }
- }
-
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- DstBufAlocated = TRUE;
- } else {
- //
- // Caller provided the destination buffer
- //
-
- if (Image->ImageContext.RelocationsStripped && (Image->ImageContext.ImageAddress != DstBuffer)) {
- //
- // If the image relocations were stripped, and the caller provided a
- // destination buffer address that does not match the address that the
- // image is linked at, then the image cannot be loaded.
- //
- return EFI_INVALID_PARAMETER;
- }
-
- if ((Image->NumberOfPages != 0) &&
- (Image->NumberOfPages <
- (EFI_SIZE_TO_PAGES ((UINTN)Image->ImageContext.ImageSize + Image->ImageContext.SectionAlignment))))
- {
- Image->NumberOfPages = EFI_SIZE_TO_PAGES ((UINTN)Image->ImageContext.ImageSize + Image->ImageContext.SectionAlignment);
- return EFI_BUFFER_TOO_SMALL;
- }
-
- Image->NumberOfPages = EFI_SIZE_TO_PAGES ((UINTN)Image->ImageContext.ImageSize + Image->ImageContext.SectionAlignment);
- Image->ImageContext.ImageAddress = DstBuffer;
- }
-
- Image->ImageBasePage = Image->ImageContext.ImageAddress;
- if (!Image->ImageContext.IsTeImage) {
- Image->ImageContext.ImageAddress =
- (Image->ImageContext.ImageAddress + Image->ImageContext.SectionAlignment - 1) &
- ~((UINTN)Image->ImageContext.SectionAlignment - 1);
- }
-
- //
- // Load the image from the file into the allocated memory
- //
- Status = PeCoffLoaderLoadImage (&Image->ImageContext);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- //
- // If this is a Runtime Driver, then allocate memory for the FixupData that
- // is used to relocate the image when SetVirtualAddressMap() is called. The
- // relocation is done by the Runtime AP.
- //
- if ((Attribute & EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION) != 0) {
- if (Image->ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) {
- Image->ImageContext.FixupData = AllocateRuntimePool ((UINTN)(Image->ImageContext.FixupDataSize));
- if (Image->ImageContext.FixupData == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Done;
- }
- }
- }
-
- //
- // Relocate the image in memory
- //
- Status = PeCoffLoaderRelocateImage (&Image->ImageContext);
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- //
- // Flush the Instruction Cache
- //
- InvalidateInstructionCacheRange ((VOID *)(UINTN)Image->ImageContext.ImageAddress, (UINTN)Image->ImageContext.ImageSize);
-
- //
- // Copy the machine type from the context to the image private data.
- //
- Image->Machine = Image->ImageContext.Machine;
-
- //
- // Get the image entry point.
- //
- Image->EntryPoint = (EFI_IMAGE_ENTRY_POINT)(UINTN)Image->ImageContext.EntryPoint;
-
- //
- // Fill in the image information for the Loaded Image Protocol
- //
- Image->Type = Image->ImageContext.ImageType;
- Image->Info.ImageBase = (VOID *)(UINTN)Image->ImageContext.ImageAddress;
- Image->Info.ImageSize = Image->ImageContext.ImageSize;
- Image->Info.ImageCodeType = (EFI_MEMORY_TYPE)(Image->ImageContext.ImageCodeMemoryType);
- Image->Info.ImageDataType = (EFI_MEMORY_TYPE)(Image->ImageContext.ImageDataMemoryType);
- if ((Attribute & EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION) != 0) {
- if (Image->ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) {
- //
- // Make a list off all the RT images so we can let the RT AP know about them.
- //
- Image->RuntimeData = AllocateRuntimePool (sizeof (EFI_RUNTIME_IMAGE_ENTRY));
- if (Image->RuntimeData == NULL) {
- goto Done;
- }
-
- Image->RuntimeData->ImageBase = Image->Info.ImageBase;
- Image->RuntimeData->ImageSize = (UINT64)(Image->Info.ImageSize);
- Image->RuntimeData->RelocationData = Image->ImageContext.FixupData;
- Image->RuntimeData->Handle = Image->Handle;
- InsertTailList (&gRuntime->ImageHead, &Image->RuntimeData->Link);
- InsertImageRecord (Image->RuntimeData);
- }
- }
-
- //
- // Fill in the entry point of the image if it is available
- //
- if (EntryPoint != NULL) {
- *EntryPoint = Image->ImageContext.EntryPoint;
- }
-
- //
- // 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 driver at 0x%11p EntryPoint=0x%11p ",
- (VOID *)(UINTN)Image->ImageContext.ImageAddress,
- FUNCTION_ENTRY_POINT (Image->ImageContext.EntryPoint)
- ));
-
- //
- // Print Module Name by Pdb file path.
- // Windows and Unix style file path are all trimmed correctly.
- //
- if (Image->ImageContext.PdbPointer != NULL) {
- StartIndex = 0;
- for (Index = 0; Image->ImageContext.PdbPointer[Index] != 0; Index++) {
- if ((Image->ImageContext.PdbPointer[Index] == '\\') || (Image->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] = Image->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 ();
-
- return EFI_SUCCESS;
-
-Done:
-
- //
- // Free memory.
- //
-
- if (DstBufAlocated) {
- CoreFreePages (Image->ImageContext.ImageAddress, Image->NumberOfPages);
- Image->ImageContext.ImageAddress = 0;
- Image->ImageBasePage = 0;
- }
-
- if (Image->ImageContext.FixupData != NULL) {
- CoreFreePool (Image->ImageContext.FixupData);
- }
-
- return Status;
-}
-
-/**
- Get the image's private data from its handle.
-
- @param ImageHandle The image handle
-
- @return Return the image private data associated with ImageHandle.
-
-**/
-LOADED_IMAGE_PRIVATE_DATA *
-CoreLoadedImageInfo (
- IN EFI_HANDLE ImageHandle
- )
-{
- EFI_STATUS Status;
- EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
- LOADED_IMAGE_PRIVATE_DATA *Image;
-
- Status = CoreHandleProtocol (
- ImageHandle,
- &gEfiLoadedImageProtocolGuid,
- (VOID **)&LoadedImage
- );
- if (!EFI_ERROR (Status)) {
- Image = LOADED_IMAGE_PRIVATE_DATA_FROM_THIS (LoadedImage);
- } else {
- DEBUG ((DEBUG_LOAD, "CoreLoadedImageInfo: Not an ImageHandle %p\n", ImageHandle));
- Image = NULL;
- }
-
- return Image;
-}
-
-/**
- Unloads EFI image from memory.
-
- @param Image EFI image
- @param FreePage Free allocated pages
-
-**/
-VOID
-CoreUnloadAndCloseImage (
- IN LOADED_IMAGE_PRIVATE_DATA *Image,
- IN BOOLEAN FreePage
- )
-{
- EFI_STATUS Status;
- UINTN HandleCount;
- EFI_HANDLE *HandleBuffer;
- UINTN HandleIndex;
- EFI_GUID **ProtocolGuidArray;
- UINTN ArrayCount;
- UINTN ProtocolIndex;
- EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfo;
- UINTN OpenInfoCount;
- UINTN OpenInfoIndex;
-
- HandleBuffer = NULL;
- ProtocolGuidArray = NULL;
-
- if (Image->Started) {
- UnregisterMemoryProfileImage (Image);
- }
-
- UnprotectUefiImage (&Image->Info, Image->LoadedImageDevicePath);
-
- if (Image->PeCoffEmu != NULL) {
- //
- // If the PE/COFF Emulator protocol exists we must unregister the image.
- //
- Image->PeCoffEmu->UnregisterImage (Image->PeCoffEmu, Image->ImageBasePage);
- }
-
- //
- // Unload image, free Image->ImageContext->ModHandle
- //
- PeCoffLoaderUnloadImage (&Image->ImageContext);
-
- //
- // Free our references to the image handle
- //
- if (Image->Handle != NULL) {
- Status = CoreLocateHandleBuffer (
- AllHandles,
- NULL,
- NULL,
- &HandleCount,
- &HandleBuffer
- );
- if (!EFI_ERROR (Status)) {
- for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {
- Status = CoreProtocolsPerHandle (
- HandleBuffer[HandleIndex],
- &ProtocolGuidArray,
- &ArrayCount
- );
- if (!EFI_ERROR (Status)) {
- for (ProtocolIndex = 0; ProtocolIndex < ArrayCount; ProtocolIndex++) {
- Status = CoreOpenProtocolInformation (
- HandleBuffer[HandleIndex],
- ProtocolGuidArray[ProtocolIndex],
- &OpenInfo,
- &OpenInfoCount
- );
- if (!EFI_ERROR (Status)) {
- for (OpenInfoIndex = 0; OpenInfoIndex < OpenInfoCount; OpenInfoIndex++) {
- if (OpenInfo[OpenInfoIndex].AgentHandle == Image->Handle) {
- Status = CoreCloseProtocol (
- HandleBuffer[HandleIndex],
- ProtocolGuidArray[ProtocolIndex],
- Image->Handle,
- OpenInfo[OpenInfoIndex].ControllerHandle
- );
- }
- }
-
- if (OpenInfo != NULL) {
- CoreFreePool (OpenInfo);
- }
- }
- }
-
- if (ProtocolGuidArray != NULL) {
- CoreFreePool (ProtocolGuidArray);
- }
- }
- }
-
- if (HandleBuffer != NULL) {
- CoreFreePool (HandleBuffer);
- }
- }
-
- CoreRemoveDebugImageInfoEntry (Image->Handle);
-
- Status = CoreUninstallProtocolInterface (
- Image->Handle,
- &gEfiLoadedImageDevicePathProtocolGuid,
- Image->LoadedImageDevicePath
- );
-
- Status = CoreUninstallProtocolInterface (
- Image->Handle,
- &gEfiLoadedImageProtocolGuid,
- &Image->Info
- );
-
- if (Image->ImageContext.HiiResourceData != 0) {
- Status = CoreUninstallProtocolInterface (
- Image->Handle,
- &gEfiHiiPackageListProtocolGuid,
- (VOID *)(UINTN)Image->ImageContext.HiiResourceData
- );
- }
- }
-
- if (Image->RuntimeData != NULL) {
- if (Image->RuntimeData->Link.ForwardLink != NULL) {
- //
- // Remove the Image from the Runtime Image list as we are about to Free it!
- //
- RemoveEntryList (&Image->RuntimeData->Link);
- RemoveImageRecord (Image->RuntimeData);
- }
-
- CoreFreePool (Image->RuntimeData);
- }
-
- //
- // Free the Image from memory
- //
- if ((Image->ImageBasePage != 0) && FreePage) {
- CoreFreePages (Image->ImageBasePage, Image->NumberOfPages);
- }
-
- //
- // Done with the Image structure
- //
- if (Image->Info.FilePath != NULL) {
- CoreFreePool (Image->Info.FilePath);
- }
-
- if (Image->LoadedImageDevicePath != NULL) {
- CoreFreePool (Image->LoadedImageDevicePath);
- }
-
- if (Image->FixupData != NULL) {
- CoreFreePool (Image->FixupData);
- }
-
- CoreFreePool (Image);
-}
-
-/**
- Loads an EFI image into memory and returns a handle to the image.
-
- @param BootPolicy If TRUE, indicates that the request originates
- from the boot manager, and that the boot
- manager is attempting to load FilePath as a
- boot selection.
- @param ParentImageHandle The caller's image handle.
- @param FilePath The specific file path from which the image is
- loaded.
- @param SourceBuffer If not NULL, a pointer to the memory location
- containing a copy of the image to be loaded.
- @param SourceSize The size in bytes of SourceBuffer.
- @param DstBuffer The buffer to store the image
- @param NumberOfPages If not NULL, it inputs a pointer to the page
- number of DstBuffer and outputs a pointer to
- the page number of the image. If this number is
- not enough, return EFI_BUFFER_TOO_SMALL and
- this parameter contains the required number.
- @param ImageHandle Pointer to the returned image handle that is
- created when the image is successfully loaded.
- @param EntryPoint A pointer to the entry point
- @param Attribute The bit mask of attributes to set for the load
- PE image
-
- @retval EFI_SUCCESS The image was loaded into memory.
- @retval EFI_NOT_FOUND The FilePath was not found.
- @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
- @retval EFI_BUFFER_TOO_SMALL The buffer is too small
- @retval EFI_UNSUPPORTED The image type is not supported, or the device
- path cannot be parsed to locate the proper
- protocol for loading the file.
- @retval EFI_OUT_OF_RESOURCES Image was not loaded due to insufficient
- resources.
- @retval EFI_LOAD_ERROR Image was not loaded because the image format was corrupt or not
- understood.
- @retval EFI_DEVICE_ERROR Image was not loaded because the device returned a read error.
- @retval EFI_ACCESS_DENIED Image was not loaded because the platform policy prohibits the
- image from being loaded. NULL is returned in *ImageHandle.
- @retval EFI_SECURITY_VIOLATION Image was loaded and an ImageHandle was created with a
- valid EFI_LOADED_IMAGE_PROTOCOL. However, the current
- platform policy specifies that the image should not be started.
-
-**/
-EFI_STATUS
-CoreLoadImageCommon (
- IN BOOLEAN BootPolicy,
- IN EFI_HANDLE ParentImageHandle,
- IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
- IN VOID *SourceBuffer OPTIONAL,
- IN UINTN SourceSize,
- IN EFI_PHYSICAL_ADDRESS DstBuffer OPTIONAL,
- IN OUT UINTN *NumberOfPages OPTIONAL,
- OUT EFI_HANDLE *ImageHandle,
- OUT EFI_PHYSICAL_ADDRESS *EntryPoint OPTIONAL,
- IN UINT32 Attribute
- )
-{
- LOADED_IMAGE_PRIVATE_DATA *Image;
- LOADED_IMAGE_PRIVATE_DATA *ParentImage;
- IMAGE_FILE_HANDLE FHand;
- EFI_STATUS Status;
- EFI_STATUS SecurityStatus;
- EFI_HANDLE DeviceHandle;
- UINT32 AuthenticationStatus;
- EFI_DEVICE_PATH_PROTOCOL *OriginalFilePath;
- EFI_DEVICE_PATH_PROTOCOL *HandleFilePath;
- EFI_DEVICE_PATH_PROTOCOL *InputFilePath;
- EFI_DEVICE_PATH_PROTOCOL *Node;
- UINTN FilePathSize;
- BOOLEAN ImageIsFromFv;
- BOOLEAN ImageIsFromLoadFile;
-
- SecurityStatus = EFI_SUCCESS;
-
- ASSERT (gEfiCurrentTpl < TPL_NOTIFY);
- ParentImage = NULL;
-
- //
- // The caller must pass in a valid ParentImageHandle
- //
- if ((ImageHandle == NULL) || (ParentImageHandle == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
-
- ParentImage = CoreLoadedImageInfo (ParentImageHandle);
- if (ParentImage == NULL) {
- DEBUG ((DEBUG_LOAD|DEBUG_ERROR, "LoadImageEx: Parent handle not an image handle\n"));
- return EFI_INVALID_PARAMETER;
- }
-
- ZeroMem (&FHand, sizeof (IMAGE_FILE_HANDLE));
- FHand.Signature = IMAGE_FILE_HANDLE_SIGNATURE;
- OriginalFilePath = FilePath;
- InputFilePath = FilePath;
- HandleFilePath = FilePath;
- DeviceHandle = NULL;
- Status = EFI_SUCCESS;
- AuthenticationStatus = 0;
- ImageIsFromFv = FALSE;
- ImageIsFromLoadFile = FALSE;
-
- //
- // If the caller passed a copy of the file, then just use it
- //
- if (SourceBuffer != NULL) {
- FHand.Source = SourceBuffer;
- FHand.SourceSize = SourceSize;
- Status = CoreLocateDevicePath (&gEfiDevicePathProtocolGuid, &HandleFilePath, &DeviceHandle);
- if (EFI_ERROR (Status)) {
- DeviceHandle = NULL;
- }
-
- if (SourceSize > 0) {
- Status = EFI_SUCCESS;
- } else {
- Status = EFI_LOAD_ERROR;
- }
- } else {
- if (FilePath == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- //
- // Try to get the image device handle by checking the match protocol.
- //
- Node = NULL;
- Status = CoreLocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &HandleFilePath, &DeviceHandle);
- if (!EFI_ERROR (Status)) {
- ImageIsFromFv = TRUE;
- } else {
- HandleFilePath = FilePath;
- Status = CoreLocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &HandleFilePath, &DeviceHandle);
- if (EFI_ERROR (Status)) {
- if (!BootPolicy) {
- HandleFilePath = FilePath;
- Status = CoreLocateDevicePath (&gEfiLoadFile2ProtocolGuid, &HandleFilePath, &DeviceHandle);
- }
-
- if (EFI_ERROR (Status)) {
- HandleFilePath = FilePath;
- Status = CoreLocateDevicePath (&gEfiLoadFileProtocolGuid, &HandleFilePath, &DeviceHandle);
- if (!EFI_ERROR (Status)) {
- ImageIsFromLoadFile = TRUE;
- Node = HandleFilePath;
- }
- }
- }
- }
-
- //
- // Get the source file buffer by its device path.
- //
- FHand.Source = GetFileBufferByFilePath (
- BootPolicy,
- FilePath,
- &FHand.SourceSize,
- &AuthenticationStatus
- );
- if (FHand.Source == NULL) {
- Status = EFI_NOT_FOUND;
- } else {
- FHand.FreeBuffer = TRUE;
- if (ImageIsFromLoadFile) {
- //
- // LoadFile () may cause the device path of the Handle be updated.
- //
- OriginalFilePath = AppendDevicePath (DevicePathFromHandle (DeviceHandle), Node);
- }
- }
- }
-
- if (EFI_ERROR (Status)) {
- Image = NULL;
- goto Done;
- }
-
- if (gSecurity2 != NULL) {
- //
- // Verify File Authentication through the Security2 Architectural Protocol
- //
- SecurityStatus = gSecurity2->FileAuthentication (
- gSecurity2,
- OriginalFilePath,
- FHand.Source,
- FHand.SourceSize,
- BootPolicy
- );
- if (!EFI_ERROR (SecurityStatus) && ImageIsFromFv) {
- //
- // When Security2 is installed, Security Architectural Protocol must be published.
- //
- ASSERT (gSecurity != NULL);
-
- //
- // Verify the Authentication Status through the Security Architectural Protocol
- // Only on images that have been read using Firmware Volume protocol.
- //
- SecurityStatus = gSecurity->FileAuthenticationState (
- gSecurity,
- AuthenticationStatus,
- OriginalFilePath
- );
- }
- } else if ((gSecurity != NULL) && (OriginalFilePath != NULL)) {
- //
- // Verify the Authentication Status through the Security Architectural Protocol
- //
- SecurityStatus = gSecurity->FileAuthenticationState (
- gSecurity,
- AuthenticationStatus,
- OriginalFilePath
- );
- }
-
- //
- // Check Security Status.
- //
- if (EFI_ERROR (SecurityStatus) && (SecurityStatus != EFI_SECURITY_VIOLATION)) {
- if (SecurityStatus == EFI_ACCESS_DENIED) {
- //
- // Image was not loaded because the platform policy prohibits the image from being loaded.
- // It's the only place we could meet EFI_ACCESS_DENIED.
- //
- *ImageHandle = NULL;
- }
-
- Status = SecurityStatus;
- Image = NULL;
- goto Done;
- }
-
- //
- // Allocate a new image structure
- //
- Image = AllocateZeroPool (sizeof (LOADED_IMAGE_PRIVATE_DATA));
- if (Image == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Done;
- }
-
- //
- // Pull out just the file portion of the DevicePath for the LoadedImage FilePath
- //
- FilePath = OriginalFilePath;
- if (DeviceHandle != NULL) {
- Status = CoreHandleProtocol (DeviceHandle, &gEfiDevicePathProtocolGuid, (VOID **)&HandleFilePath);
- if (!EFI_ERROR (Status)) {
- FilePathSize = GetDevicePathSize (HandleFilePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL);
- FilePath = (EFI_DEVICE_PATH_PROTOCOL *)(((UINT8 *)FilePath) + FilePathSize);
- }
- }
-
- //
- // Initialize the fields for an internal driver
- //
- Image->Signature = LOADED_IMAGE_PRIVATE_DATA_SIGNATURE;
- Image->Info.SystemTable = gDxeCoreST;
- Image->Info.DeviceHandle = DeviceHandle;
- Image->Info.Revision = EFI_LOADED_IMAGE_PROTOCOL_REVISION;
- Image->Info.FilePath = DuplicateDevicePath (FilePath);
- Image->Info.ParentHandle = ParentImageHandle;
-
- if (NumberOfPages != NULL) {
- Image->NumberOfPages = *NumberOfPages;
- } else {
- Image->NumberOfPages = 0;
- }
-
- //
- // Install the protocol interfaces for this image
- // don't fire notifications yet
- //
- Status = CoreInstallProtocolInterfaceNotify (
- &Image->Handle,
- &gEfiLoadedImageProtocolGuid,
- EFI_NATIVE_INTERFACE,
- &Image->Info,
- FALSE
- );
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- //
- // Load the image. If EntryPoint is Null, it will not be set.
- //
- Status = CoreLoadPeImage (BootPolicy, &FHand, Image, DstBuffer, EntryPoint, Attribute);
- if (EFI_ERROR (Status)) {
- if ((Status == EFI_BUFFER_TOO_SMALL) || (Status == EFI_OUT_OF_RESOURCES)) {
- if (NumberOfPages != NULL) {
- *NumberOfPages = Image->NumberOfPages;
- }
- }
-
- goto Done;
- }
-
- if (NumberOfPages != NULL) {
- *NumberOfPages = Image->NumberOfPages;
- }
-
- //
- // Register the image in the Debug Image Info Table if the attribute is set
- //
- if ((Attribute & EFI_LOAD_PE_IMAGE_ATTRIBUTE_DEBUG_IMAGE_INFO_TABLE_REGISTRATION) != 0) {
- CoreNewDebugImageInfoEntry (EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL, &Image->Info, Image->Handle);
- }
-
- //
- // Check whether we are loading a runtime image that lacks support for
- // IBT/BTI landing pads.
- //
- if ((Image->ImageContext.ImageCodeMemoryType == EfiRuntimeServicesCode) &&
- ((Image->ImageContext.DllCharacteristicsEx & EFI_IMAGE_DLLCHARACTERISTICS_EX_FORWARD_CFI_COMPAT) == 0))
- {
- gMemoryAttributesTableForwardCfi = FALSE;
- }
-
- //
- // Reinstall loaded image protocol to fire any notifications
- //
- Status = CoreReinstallProtocolInterface (
- Image->Handle,
- &gEfiLoadedImageProtocolGuid,
- &Image->Info,
- &Image->Info
- );
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- //
- // If DevicePath parameter to the LoadImage() is not NULL, then make a copy of DevicePath,
- // otherwise Loaded Image Device Path Protocol is installed with a NULL interface pointer.
- //
- if (OriginalFilePath != NULL) {
- Image->LoadedImageDevicePath = DuplicateDevicePath (OriginalFilePath);
- }
-
- //
- // Install Loaded Image Device Path Protocol onto the image handle of a PE/COFE image
- //
- Status = CoreInstallProtocolInterface (
- &Image->Handle,
- &gEfiLoadedImageDevicePathProtocolGuid,
- EFI_NATIVE_INTERFACE,
- Image->LoadedImageDevicePath
- );
- if (EFI_ERROR (Status)) {
- goto Done;
- }
-
- //
- // Install HII Package List Protocol onto the image handle
- //
- if (Image->ImageContext.HiiResourceData != 0) {
- Status = CoreInstallProtocolInterface (
- &Image->Handle,
- &gEfiHiiPackageListProtocolGuid,
- EFI_NATIVE_INTERFACE,
- (VOID *)(UINTN)Image->ImageContext.HiiResourceData
- );
- if (EFI_ERROR (Status)) {
- goto Done;
- }
- }
-
- ProtectUefiImage (&Image->Info, Image->LoadedImageDevicePath);
-
- //
- // Success. Return the image handle
- //
- *ImageHandle = Image->Handle;
-
-Done:
- //
- // All done accessing the source file
- // If we allocated the Source buffer, free it
- //
- if (FHand.FreeBuffer) {
- CoreFreePool (FHand.Source);
- }
-
- if (OriginalFilePath != InputFilePath) {
- CoreFreePool (OriginalFilePath);
- }
-
- //
- // There was an error. If there's an Image structure, free it
- //
- if (EFI_ERROR (Status)) {
- if (Image != NULL) {
- CoreUnloadAndCloseImage (Image, (BOOLEAN)(DstBuffer == 0));
- Image = NULL;
- }
- } else if (EFI_ERROR (SecurityStatus)) {
- Status = SecurityStatus;
- }
-
- //
- // Track the return status from LoadImage.
- //
- if (Image != NULL) {
- Image->LoadImageStatus = Status;
- }
-
- return Status;
-}
-
-/**
- Loads an EFI image into memory and returns a handle to the image.
-
- @param BootPolicy If TRUE, indicates that the request originates
- from the boot manager, and that the boot
- manager is attempting to load FilePath as a
- boot selection.
- @param ParentImageHandle The caller's image handle.
- @param FilePath The specific file path from which the image is
- loaded.
- @param SourceBuffer If not NULL, a pointer to the memory location
- containing a copy of the image to be loaded.
- @param SourceSize The size in bytes of SourceBuffer.
- @param ImageHandle Pointer to the returned image handle that is
- created when the image is successfully loaded.
-
- @retval EFI_SUCCESS The image was loaded into memory.
- @retval EFI_NOT_FOUND The FilePath was not found.
- @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
- @retval EFI_UNSUPPORTED The image type is not supported, or the device
- path cannot be parsed to locate the proper
- protocol for loading the file.
- @retval EFI_OUT_OF_RESOURCES Image was not loaded due to insufficient
- resources.
- @retval EFI_LOAD_ERROR Image was not loaded because the image format was corrupt or not
- understood.
- @retval EFI_DEVICE_ERROR Image was not loaded because the device returned a read error.
- @retval EFI_ACCESS_DENIED Image was not loaded because the platform policy prohibits the
- image from being loaded. NULL is returned in *ImageHandle.
- @retval EFI_SECURITY_VIOLATION Image was loaded and an ImageHandle was created with a
- valid EFI_LOADED_IMAGE_PROTOCOL. However, the current
- platform policy specifies that the image should not be started.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreLoadImage (
- IN BOOLEAN BootPolicy,
- IN EFI_HANDLE ParentImageHandle,
- IN EFI_DEVICE_PATH_PROTOCOL *FilePath,
- IN VOID *SourceBuffer OPTIONAL,
- IN UINTN SourceSize,
- OUT EFI_HANDLE *ImageHandle
- )
-{
- EFI_STATUS Status;
- EFI_HANDLE Handle;
-
- PERF_LOAD_IMAGE_BEGIN (NULL);
-
- Status = CoreLoadImageCommon (
- BootPolicy,
- ParentImageHandle,
- FilePath,
- SourceBuffer,
- SourceSize,
- (EFI_PHYSICAL_ADDRESS)(UINTN)NULL,
- NULL,
- ImageHandle,
- NULL,
- EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION | EFI_LOAD_PE_IMAGE_ATTRIBUTE_DEBUG_IMAGE_INFO_TABLE_REGISTRATION
- );
-
- Handle = NULL;
- if (!EFI_ERROR (Status)) {
- //
- // ImageHandle will be valid only Status is success.
- //
- Handle = *ImageHandle;
- }
-
- PERF_LOAD_IMAGE_END (Handle);
-
- return Status;
-}
-
-/**
- Transfer control to a loaded image's entry point.
-
- @param ImageHandle Handle of image to be started.
- @param ExitDataSize Pointer of the size to ExitData
- @param ExitData Pointer to a pointer to a data buffer that
- includes a Null-terminated string,
- optionally followed by additional binary data.
- The string is a description that the caller may
- use to further indicate the reason for the
- image's exit.
-
- @retval EFI_INVALID_PARAMETER Invalid parameter
- @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
- @retval EFI_SECURITY_VIOLATION The current platform policy specifies that the image should not be started.
- @retval EFI_SUCCESS Successfully transfer control to the image's
- entry point.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreStartImage (
- IN EFI_HANDLE ImageHandle,
- OUT UINTN *ExitDataSize,
- OUT CHAR16 **ExitData OPTIONAL
- )
-{
- EFI_STATUS Status;
- LOADED_IMAGE_PRIVATE_DATA *Image;
- LOADED_IMAGE_PRIVATE_DATA *LastImage;
- UINT64 HandleDatabaseKey;
- UINTN SetJumpFlag;
- EFI_HANDLE Handle;
-
- Handle = ImageHandle;
-
- Image = CoreLoadedImageInfo (ImageHandle);
- if ((Image == NULL) || Image->Started) {
- return EFI_INVALID_PARAMETER;
- }
-
- if (EFI_ERROR (Image->LoadImageStatus)) {
- return Image->LoadImageStatus;
- }
-
- //
- // The image to be started must have the machine type supported by DxeCore.
- //
- if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Image->Machine) &&
- (Image->PeCoffEmu == NULL))
- {
- //
- // Do not ASSERT here, because image might be loaded via EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED
- // But it can not be started.
- //
- DEBUG ((DEBUG_ERROR, "Image type %s can't be started ", GetMachineTypeName (Image->Machine)));
- DEBUG ((DEBUG_ERROR, "on %s UEFI system.\n", GetMachineTypeName (mDxeCoreImageMachineType)));
- return EFI_UNSUPPORTED;
- }
-
- if (Image->PeCoffEmu != NULL) {
- Status = Image->PeCoffEmu->RegisterImage (
- Image->PeCoffEmu,
- Image->ImageBasePage,
- EFI_PAGES_TO_SIZE (Image->NumberOfPages),
- &Image->EntryPoint
- );
- if (EFI_ERROR (Status)) {
- DEBUG ((
- DEBUG_LOAD | DEBUG_ERROR,
- "CoreLoadPeImage: Failed to register foreign image with emulator - %r\n",
- Status
- ));
- return Status;
- }
- }
-
- PERF_START_IMAGE_BEGIN (Handle);
-
- //
- // Push the current start image context, and
- // link the current image to the head. This is the
- // only image that can call Exit()
- //
- HandleDatabaseKey = CoreGetHandleDatabaseKey ();
- LastImage = mCurrentImage;
- mCurrentImage = Image;
- Image->Tpl = gEfiCurrentTpl;
-
- //
- // Set long jump for Exit() support
- // JumpContext must be aligned on a CPU specific boundary.
- // Overallocate the buffer and force the required alignment
- //
- Image->JumpBuffer = AllocatePool (sizeof (BASE_LIBRARY_JUMP_BUFFER) + BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT);
- if (Image->JumpBuffer == NULL) {
- //
- // Image may be unloaded after return with failure,
- // then ImageHandle may be invalid, so use NULL handle to record perf log.
- //
- PERF_START_IMAGE_END (NULL);
-
- //
- // Pop the current start image context
- //
- mCurrentImage = LastImage;
-
- return EFI_OUT_OF_RESOURCES;
- }
-
- Image->JumpContext = ALIGN_POINTER (Image->JumpBuffer, BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT);
-
- SetJumpFlag = SetJump (Image->JumpContext);
- //
- // The initial call to SetJump() must always return 0.
- // Subsequent calls to LongJump() cause a non-zero value to be returned by SetJump().
- //
- if (SetJumpFlag == 0) {
- RegisterMemoryProfileImage (Image, (Image->ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION ? EFI_FV_FILETYPE_APPLICATION : EFI_FV_FILETYPE_DRIVER));
- //
- // Call the image's entry point
- //
- Image->Started = TRUE;
- Image->Status = Image->EntryPoint (ImageHandle, Image->Info.SystemTable);
-
- //
- // Add some debug information if the image returned with error.
- // This make the user aware and check if the driver image have already released
- // all the resource in this situation.
- //
- DEBUG_CODE_BEGIN ();
- if (EFI_ERROR (Image->Status)) {
- DEBUG ((DEBUG_ERROR, "Error: Image at %11p start failed: %r\n", Image->Info.ImageBase, Image->Status));
- }
-
- DEBUG_CODE_END ();
-
- //
- // If the image returns, exit it through Exit()
- //
- CoreExit (ImageHandle, Image->Status, 0, NULL);
- }
-
- //
- // Image has completed. Verify the tpl is the same
- //
- ASSERT (Image->Tpl == gEfiCurrentTpl);
- CoreRestoreTpl (Image->Tpl);
-
- CoreFreePool (Image->JumpBuffer);
-
- //
- // Pop the current start image context
- //
- mCurrentImage = LastImage;
-
- //
- // UEFI Specification - StartImage() - EFI 1.10 Extension
- // To maintain compatibility with UEFI drivers that are written to the EFI
- // 1.02 Specification, StartImage() must monitor the handle database before
- // and after each image is started. If any handles are created or modified
- // when an image is started, then EFI_BOOT_SERVICES.ConnectController() must
- // be called with the Recursive parameter set to TRUE for each of the newly
- // created or modified handles before StartImage() returns.
- //
- if (Image->Type != EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {
- CoreConnectHandlesByKey (HandleDatabaseKey);
- }
-
- //
- // Handle the image's returned ExitData
- //
- DEBUG_CODE_BEGIN ();
- if ((Image->ExitDataSize != 0) || (Image->ExitData != NULL)) {
- DEBUG ((DEBUG_LOAD, "StartImage: ExitDataSize %d, ExitData %p", (UINT32)Image->ExitDataSize, Image->ExitData));
- if (Image->ExitData != NULL) {
- DEBUG ((DEBUG_LOAD, " (%s)", Image->ExitData));
- }
-
- DEBUG ((DEBUG_LOAD, "\n"));
- }
-
- DEBUG_CODE_END ();
-
- //
- // Return the exit data to the caller
- //
- if ((ExitData != NULL) && (ExitDataSize != NULL)) {
- *ExitDataSize = Image->ExitDataSize;
- *ExitData = Image->ExitData;
- } else {
- //
- // Caller doesn't want the exit data, free it
- //
- CoreFreePool (Image->ExitData);
- Image->ExitData = NULL;
- }
-
- //
- // Save the Status because Image will get destroyed if it is unloaded.
- //
- Status = Image->Status;
-
- //
- // If the image returned an error, or if the image is an application
- // unload it
- //
- if (EFI_ERROR (Image->Status) || (Image->Type == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION)) {
- CoreUnloadAndCloseImage (Image, TRUE);
- //
- // ImageHandle may be invalid after the image is unloaded, so use NULL handle to record perf log.
- //
- Handle = NULL;
- }
-
- //
- // Done
- //
- PERF_START_IMAGE_END (Handle);
- return Status;
-}
-
-/**
- Terminates the currently loaded EFI image and returns control to boot services.
-
- @param ImageHandle Handle that identifies the image. This
- parameter is passed to the image on entry.
- @param Status The image's exit code.
- @param ExitDataSize The size, in bytes, of ExitData. Ignored if
- ExitStatus is EFI_SUCCESS.
- @param ExitData Pointer to a data buffer that includes a
- Null-terminated Unicode string, optionally
- followed by additional binary data. The string
- is a description that the caller may use to
- further indicate the reason for the image's
- exit.
-
- @retval EFI_INVALID_PARAMETER Image handle is NULL or it is not current
- image.
- @retval EFI_SUCCESS Successfully terminates the currently loaded
- EFI image.
- @retval EFI_ACCESS_DENIED Should never reach there.
- @retval EFI_OUT_OF_RESOURCES Could not allocate pool
-
-**/
-EFI_STATUS
-EFIAPI
-CoreExit (
- IN EFI_HANDLE ImageHandle,
- IN EFI_STATUS Status,
- IN UINTN ExitDataSize,
- IN CHAR16 *ExitData OPTIONAL
- )
-{
- LOADED_IMAGE_PRIVATE_DATA *Image;
- EFI_TPL OldTpl;
-
- //
- // Prevent possible reentrance to this function
- // for the same ImageHandle
- //
- OldTpl = CoreRaiseTpl (TPL_NOTIFY);
-
- Image = CoreLoadedImageInfo (ImageHandle);
- if (Image == NULL) {
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
-
- if (!Image->Started) {
- //
- // The image has not been started so just free its resources
- //
- CoreUnloadAndCloseImage (Image, TRUE);
- Status = EFI_SUCCESS;
- goto Done;
- }
-
- //
- // Image has been started, verify this image can exit
- //
- if (Image != mCurrentImage) {
- DEBUG ((DEBUG_LOAD|DEBUG_ERROR, "Exit: Image is not exitable image\n"));
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
-
- //
- // Set status
- //
- Image->Status = Status;
-
- //
- // If there's ExitData info, move it
- //
- if (ExitData != NULL) {
- Image->ExitDataSize = ExitDataSize;
- Image->ExitData = AllocatePool (Image->ExitDataSize);
- if (Image->ExitData == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto Done;
- }
-
- CopyMem (Image->ExitData, ExitData, Image->ExitDataSize);
- }
-
- CoreRestoreTpl (OldTpl);
- //
- // return to StartImage
- //
- LongJump (Image->JumpContext, (UINTN)-1);
-
- //
- // If we return from LongJump, then it is an error
- //
- ASSERT (FALSE);
- Status = EFI_ACCESS_DENIED;
-Done:
- CoreRestoreTpl (OldTpl);
- return Status;
-}
-
-/**
- Unloads an image.
-
- @param ImageHandle Handle that identifies the image to be
- unloaded.
-
- @retval EFI_SUCCESS The image has been unloaded.
- @retval EFI_UNSUPPORTED The image has been started, and does not support
- unload.
- @retval EFI_INVALID_PARAMPETER ImageHandle is not a valid image handle.
-
-**/
-EFI_STATUS
-EFIAPI
-CoreUnloadImage (
- IN EFI_HANDLE ImageHandle
- )
-{
- EFI_STATUS Status;
- LOADED_IMAGE_PRIVATE_DATA *Image;
-
- Image = CoreLoadedImageInfo (ImageHandle);
- if (Image == NULL ) {
- //
- // The image handle is not valid
- //
- Status = EFI_INVALID_PARAMETER;
- goto Done;
- }
-
- if (Image->Started) {
- //
- // The image has been started, request it to unload.
- //
- Status = EFI_UNSUPPORTED;
- if (Image->Info.Unload != NULL) {
- Status = Image->Info.Unload (ImageHandle);
- }
- } else {
- //
- // This Image hasn't been started, thus it can be unloaded
- //
- Status = EFI_SUCCESS;
- }
-
- if (!EFI_ERROR (Status)) {
- //
- // if the Image was not started or Unloaded O.K. then clean up
- //
- CoreUnloadAndCloseImage (Image, TRUE);
- }
-
-Done:
- return Status;
-}
+/** @file + Core image handling services to load and unload PeImage. + +Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "DxeMain.h" +#include "Image.h" + +// +// Module Globals +// +LOADED_IMAGE_PRIVATE_DATA *mCurrentImage = NULL; + +typedef struct { + LIST_ENTRY Link; + EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL *Emulator; + UINT16 MachineType; +} EMULATOR_ENTRY; + +STATIC LIST_ENTRY mAvailableEmulators; +STATIC EFI_EVENT mPeCoffEmuProtocolRegistrationEvent; +STATIC VOID *mPeCoffEmuProtocolNotifyRegistration; + +// +// This code is needed to build the Image handle for the DXE Core +// +LOADED_IMAGE_PRIVATE_DATA mCorePrivateImage = { + LOADED_IMAGE_PRIVATE_DATA_SIGNATURE, // Signature + NULL, // Image handle + EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER, // Image type + TRUE, // If entrypoint has been called + NULL, // EntryPoint + { + EFI_LOADED_IMAGE_INFORMATION_REVISION, // Revision + NULL, // Parent handle + NULL, // System handle + + NULL, // Device handle + NULL, // File path + NULL, // Reserved + + 0, // LoadOptionsSize + NULL, // LoadOptions + + NULL, // ImageBase + 0, // ImageSize + EfiBootServicesCode, // ImageCodeType + EfiBootServicesData // ImageDataType + }, + (EFI_PHYSICAL_ADDRESS)0, // ImageBasePage + 0, // NumberOfPages + NULL, // FixupData + 0, // Tpl + EFI_SUCCESS, // Status + 0, // ExitDataSize + NULL, // ExitData + NULL, // JumpBuffer + NULL, // JumpContext + 0, // Machine + NULL, // PeCoffEmu + NULL, // RuntimeData + NULL // LoadedImageDevicePath +}; +// +// The field is define for Loading modules at fixed address feature to tracker the PEI code +// memory range usage. It is a bit mapped array in which every bit indicates the correspoding memory page +// available or not. +// +GLOBAL_REMOVE_IF_UNREFERENCED UINT64 *mDxeCodeMemoryRangeUsageBitMap = NULL; + +typedef struct { + UINT16 MachineType; + CHAR16 *MachineTypeName; +} MACHINE_TYPE_INFO; + +GLOBAL_REMOVE_IF_UNREFERENCED MACHINE_TYPE_INFO mMachineTypeInfo[] = { + { EFI_IMAGE_MACHINE_IA32, L"IA32" }, + { EFI_IMAGE_MACHINE_IA64, L"IA64" }, + { EFI_IMAGE_MACHINE_X64, L"X64" }, + { EFI_IMAGE_MACHINE_ARMTHUMB_MIXED, L"ARM" }, + { EFI_IMAGE_MACHINE_AARCH64, L"AARCH64" }, + { EFI_IMAGE_MACHINE_RISCV64, L"RISCV64" }, + { EFI_IMAGE_MACHINE_LOONGARCH64, L"LOONGARCH64" }, +}; + +UINT16 mDxeCoreImageMachineType = 0; + +/** + Return machine type name. + + @param MachineType The machine type + + @return machine type name +**/ +CHAR16 * +GetMachineTypeName ( + UINT16 MachineType + ) +{ + UINTN Index; + + for (Index = 0; Index < sizeof (mMachineTypeInfo)/sizeof (mMachineTypeInfo[0]); Index++) { + if (mMachineTypeInfo[Index].MachineType == MachineType) { + return mMachineTypeInfo[Index].MachineTypeName; + } + } + + return L"<Unknown>"; +} + +/** + Notification event handler registered by CoreInitializeImageServices () to + keep track of which PE/COFF image emulators are available. + + @param Event The Event that is being processed, not used. + @param Context Event Context, not used. + +**/ +STATIC +VOID +EFIAPI +PeCoffEmuProtocolNotify ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + UINTN BufferSize; + EFI_HANDLE EmuHandle; + EDKII_PECOFF_IMAGE_EMULATOR_PROTOCOL *Emulator; + EMULATOR_ENTRY *Entry; + + EmuHandle = NULL; + Emulator = NULL; + + while (TRUE) { + BufferSize = sizeof (EmuHandle); + Status = CoreLocateHandle ( + ByRegisterNotify, + NULL, + mPeCoffEmuProtocolNotifyRegistration, + &BufferSize, + &EmuHandle + ); + if (EFI_ERROR (Status)) { + // + // If no more notification events exit + // + return; + } + + Status = CoreHandleProtocol ( + EmuHandle, + &gEdkiiPeCoffImageEmulatorProtocolGuid, + (VOID **)&Emulator + ); + if (EFI_ERROR (Status) || (Emulator == NULL)) { + continue; + } + + Entry = AllocateZeroPool (sizeof (*Entry)); + ASSERT (Entry != NULL); + + Entry->Emulator = Emulator; + Entry->MachineType = Entry->Emulator->MachineType; + + InsertTailList (&mAvailableEmulators, &Entry->Link); + } +} + +/** + Add the Image Services to EFI Boot Services Table and install the protocol + interfaces for this image. + + @param HobStart The HOB to initialize + + @return Status code. + +**/ +EFI_STATUS +CoreInitializeImageServices ( + IN VOID *HobStart + ) +{ + EFI_STATUS Status; + LOADED_IMAGE_PRIVATE_DATA *Image; + EFI_PHYSICAL_ADDRESS DxeCoreImageBaseAddress; + UINT64 DxeCoreImageLength; + VOID *DxeCoreEntryPoint; + EFI_PEI_HOB_POINTERS DxeCoreHob; + + // + // Searching for image hob + // + DxeCoreHob.Raw = HobStart; + while ((DxeCoreHob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, DxeCoreHob.Raw)) != NULL) { + if (CompareGuid (&DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.Name, &gEfiHobMemoryAllocModuleGuid)) { + // + // Find Dxe Core HOB + // + break; + } + + DxeCoreHob.Raw = GET_NEXT_HOB (DxeCoreHob); + } + + ASSERT (DxeCoreHob.Raw != NULL); + + DxeCoreImageBaseAddress = DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.MemoryBaseAddress; + DxeCoreImageLength = DxeCoreHob.MemoryAllocationModule->MemoryAllocationHeader.MemoryLength; + DxeCoreEntryPoint = (VOID *)(UINTN)DxeCoreHob.MemoryAllocationModule->EntryPoint; + gDxeCoreFileName = &DxeCoreHob.MemoryAllocationModule->ModuleName; + + // + // Initialize the fields for an internal driver + // + Image = &mCorePrivateImage; + + Image->EntryPoint = (EFI_IMAGE_ENTRY_POINT)(UINTN)DxeCoreEntryPoint; + Image->ImageBasePage = DxeCoreImageBaseAddress; + Image->NumberOfPages = (UINTN)(EFI_SIZE_TO_PAGES ((UINTN)(DxeCoreImageLength))); + Image->Tpl = gEfiCurrentTpl; + Image->Info.ImageBase = (VOID *)(UINTN)DxeCoreImageBaseAddress; + Image->Info.ImageSize = DxeCoreImageLength; + + // + // Install the protocol interfaces for this image + // + Status = CoreInstallProtocolInterface ( + &Image->Handle, + &gEfiLoadedImageProtocolGuid, + EFI_NATIVE_INTERFACE, + &Image->Info + ); + ASSERT_EFI_ERROR (Status); + + mCurrentImage = Image; + + // + // Fill in DXE globals + // + mDxeCoreImageMachineType = PeCoffLoaderGetMachineType (Image->Info.ImageBase); + gDxeCoreImageHandle = Image->Handle; + gDxeCoreLoadedImage = &Image->Info; + + // + // Create the PE/COFF emulator protocol registration event + // + Status = CoreCreateEvent ( + EVT_NOTIFY_SIGNAL, + TPL_CALLBACK, + PeCoffEmuProtocolNotify, + NULL, + &mPeCoffEmuProtocolRegistrationEvent + ); + ASSERT_EFI_ERROR (Status); + + // + // Register for protocol notifications on this event + // + Status = CoreRegisterProtocolNotify ( + &gEdkiiPeCoffImageEmulatorProtocolGuid, + mPeCoffEmuProtocolRegistrationEvent, + &mPeCoffEmuProtocolNotifyRegistration + ); + ASSERT_EFI_ERROR (Status); + + InitializeListHead (&mAvailableEmulators); + + ProtectUefiImage (&Image->Info, Image->LoadedImageDevicePath); + + return Status; +} + +/** + Read image file (specified by UserHandle) into user specified buffer with specified offset + and length. + + @param UserHandle Image file handle + @param Offset Offset to the source file + @param ReadSize For input, pointer of size to read; For output, + pointer of size actually read. + @param Buffer Buffer to write into + + @retval EFI_SUCCESS Successfully read the specified part of file + into buffer. + +**/ +EFI_STATUS +EFIAPI +CoreReadImageFile ( + IN VOID *UserHandle, + IN UINTN Offset, + IN OUT UINTN *ReadSize, + OUT VOID *Buffer + ) +{ + UINTN EndPosition; + IMAGE_FILE_HANDLE *FHand; + + if ((UserHandle == NULL) || (ReadSize == NULL) || (Buffer == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (MAX_ADDRESS - Offset < *ReadSize) { + return EFI_INVALID_PARAMETER; + } + + FHand = (IMAGE_FILE_HANDLE *)UserHandle; + ASSERT (FHand->Signature == IMAGE_FILE_HANDLE_SIGNATURE); + + // + // Move data from our local copy of the file + // + EndPosition = Offset + *ReadSize; + if (EndPosition > FHand->SourceSize) { + *ReadSize = (UINT32)(FHand->SourceSize - Offset); + } + + if (Offset >= FHand->SourceSize) { + *ReadSize = 0; + } + + CopyMem (Buffer, (CHAR8 *)FHand->Source + Offset, *ReadSize); + return EFI_SUCCESS; +} + +/** + To check memory usage bit map array to figure out if the memory range the image will be loaded in is available or not. If + memory range is available, the function will mark the corresponding bits to 1 which indicates the memory range is used. + The function is only invoked when load modules at fixed address feature is enabled. + + @param ImageBase The base address the image will be loaded at. + @param ImageSize The size of the image + + @retval EFI_SUCCESS The memory range the image will be loaded in is available + @retval EFI_NOT_FOUND The memory range the image will be loaded in is not available +**/ +EFI_STATUS +CheckAndMarkFixLoadingMemoryUsageBitMap ( + IN EFI_PHYSICAL_ADDRESS ImageBase, + IN UINTN ImageSize + ) +{ + UINT32 DxeCodePageNumber; + UINT64 DxeCodeSize; + EFI_PHYSICAL_ADDRESS DxeCodeBase; + UINTN BaseOffsetPageNumber; + UINTN TopOffsetPageNumber; + UINTN Index; + + // + // The DXE code range includes RuntimeCodePage range and Boot time code range. + // + DxeCodePageNumber = PcdGet32 (PcdLoadFixAddressRuntimeCodePageNumber); + DxeCodePageNumber += PcdGet32 (PcdLoadFixAddressBootTimeCodePageNumber); + DxeCodeSize = EFI_PAGES_TO_SIZE (DxeCodePageNumber); + DxeCodeBase = gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress - DxeCodeSize; + + // + // If the memory usage bit map is not initialized, do it. Every bit in the array + // indicate the status of the corresponding memory page, available or not + // + if (mDxeCodeMemoryRangeUsageBitMap == NULL) { + mDxeCodeMemoryRangeUsageBitMap = AllocateZeroPool (((DxeCodePageNumber/64) + 1)*sizeof (UINT64)); + } + + // + // If the Dxe code memory range is not allocated or the bit map array allocation failed, return EFI_NOT_FOUND + // + if (!gLoadFixedAddressCodeMemoryReady || (mDxeCodeMemoryRangeUsageBitMap == NULL)) { + return EFI_NOT_FOUND; + } + + // + // Test the memory range for loading the image in the DXE code range. + // + if ((gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress < ImageBase + ImageSize) || + (DxeCodeBase > ImageBase)) + { + return EFI_NOT_FOUND; + } + + // + // Test if the memory is avalaible or not. + // + BaseOffsetPageNumber = EFI_SIZE_TO_PAGES ((UINT32)(ImageBase - DxeCodeBase)); + TopOffsetPageNumber = EFI_SIZE_TO_PAGES ((UINT32)(ImageBase + ImageSize - DxeCodeBase)); + for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index++) { + if ((mDxeCodeMemoryRangeUsageBitMap[Index / 64] & LShiftU64 (1, (Index % 64))) != 0) { + // + // This page is already used. + // + return EFI_NOT_FOUND; + } + } + + // + // Being here means the memory range is available. So mark the bits for the memory range + // + for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index++) { + mDxeCodeMemoryRangeUsageBitMap[Index / 64] |= LShiftU64 (1, (Index % 64)); + } + + return EFI_SUCCESS; +} + +/** + + Get the fixed loading address from image header assigned by build tool. This function only be called + when Loading module at Fixed address feature enabled. + + @param ImageContext Pointer to the image context structure that describes the PE/COFF + image that needs to be examined by this function. + @retval EFI_SUCCESS An fixed loading address is assigned to this image by build tools . + @retval EFI_NOT_FOUND The image has no assigned fixed loading address. + +**/ +EFI_STATUS +GetPeCoffImageFixLoadingAssignedAddress ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ) +{ + UINTN SectionHeaderOffset; + EFI_STATUS Status; + EFI_IMAGE_SECTION_HEADER SectionHeader; + EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr; + UINT16 Index; + UINTN Size; + UINT16 NumberOfSections; + IMAGE_FILE_HANDLE *Handle; + UINT64 ValueInSectionHeader; + + Status = EFI_NOT_FOUND; + + // + // Get PeHeader pointer + // + Handle = (IMAGE_FILE_HANDLE *)ImageContext->Handle; + ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((CHAR8 *)Handle->Source + ImageContext->PeCoffHeaderOffset); + SectionHeaderOffset = ImageContext->PeCoffHeaderOffset + + sizeof (UINT32) + + sizeof (EFI_IMAGE_FILE_HEADER) + + ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader; + NumberOfSections = ImgHdr->Pe32.FileHeader.NumberOfSections; + + // + // Get base address from the first section header that doesn't point to code section. + // + for (Index = 0; Index < NumberOfSections; Index++) { + // + // Read section header from file + // + Size = sizeof (EFI_IMAGE_SECTION_HEADER); + Status = ImageContext->ImageRead ( + ImageContext->Handle, + SectionHeaderOffset, + &Size, + &SectionHeader + ); + if (EFI_ERROR (Status)) { + return Status; + } + + if (Size != sizeof (EFI_IMAGE_SECTION_HEADER)) { + return EFI_NOT_FOUND; + } + + Status = EFI_NOT_FOUND; + + if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_CNT_CODE) == 0) { + // + // Build tool will save the address in PointerToRelocations & PointerToLineNumbers fields in the first section header + // that doesn't point to code section in image header, as well as ImageBase field of image header. And there is an + // assumption that when the feature is enabled, if a module is assigned a loading address by tools, PointerToRelocations + // & PointerToLineNumbers fields should NOT be Zero, or else, these 2 fields should be set to Zero + // + ValueInSectionHeader = ReadUnaligned64 ((UINT64 *)&SectionHeader.PointerToRelocations); + if (ValueInSectionHeader != 0) { + // + // When the feature is configured as load module at fixed absolute address, the ImageAddress field of ImageContext + // hold the specified address. If the feature is configured as load module at fixed offset, ImageAddress hold an offset + // relative to top address + // + if ((INT64)PcdGet64 (PcdLoadModuleAtFixAddressEnable) < 0) { + ImageContext->ImageAddress = gLoadModuleAtFixAddressConfigurationTable.DxeCodeTopAddress + (INT64)(INTN)ImageContext->ImageAddress; + } + + // + // Check if the memory range is available. + // + Status = CheckAndMarkFixLoadingMemoryUsageBitMap (ImageContext->ImageAddress, (UINTN)(ImageContext->ImageSize + ImageContext->SectionAlignment)); + } + + break; + } + + SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER); + } + + DEBUG ((DEBUG_INFO|DEBUG_LOAD, "LOADING MODULE FIXED INFO: Loading module at fixed address 0x%11p. Status = %r \n", (VOID *)(UINTN)(ImageContext->ImageAddress), Status)); + return Status; +} + +/** + Decides whether a PE/COFF image can execute on this system, either natively + or via emulation/interpretation. In the latter case, the PeCoffEmu member + of the LOADED_IMAGE_PRIVATE_DATA struct pointer is populated with a pointer + to the emulator protocol that supports this image. + + @param[in, out] Image LOADED_IMAGE_PRIVATE_DATA struct pointer + + @retval TRUE The image is supported + @retval FALSE The image is not supported + +**/ +STATIC +BOOLEAN +CoreIsImageTypeSupported ( + IN OUT LOADED_IMAGE_PRIVATE_DATA *Image + ) +{ + LIST_ENTRY *Link; + EMULATOR_ENTRY *Entry; + + for (Link = GetFirstNode (&mAvailableEmulators); + !IsNull (&mAvailableEmulators, Link); + Link = GetNextNode (&mAvailableEmulators, Link)) + { + Entry = BASE_CR (Link, EMULATOR_ENTRY, Link); + if (Entry->MachineType != Image->ImageContext.Machine) { + continue; + } + + if (Entry->Emulator->IsImageSupported ( + Entry->Emulator, + Image->ImageContext.ImageType, + Image->Info.FilePath + )) + { + Image->PeCoffEmu = Entry->Emulator; + return TRUE; + } + } + + return EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Image->ImageContext.Machine) || + EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED (Image->ImageContext.Machine); +} + +/** + Loads, relocates, and invokes a PE/COFF image + + @param BootPolicy If TRUE, indicates that the request originates + from the boot manager, and that the boot + manager is attempting to load FilePath as a + boot selection. + @param Pe32Handle The handle of PE32 image + @param Image PE image to be loaded + @param DstBuffer The buffer to store the image + @param EntryPoint A pointer to the entry point + @param Attribute The bit mask of attributes to set for the load + PE image + + @retval EFI_SUCCESS The file was loaded, relocated, and invoked + @retval EFI_OUT_OF_RESOURCES There was not enough memory to load and + relocate the PE/COFF file + @retval EFI_INVALID_PARAMETER Invalid parameter + @retval EFI_BUFFER_TOO_SMALL Buffer for image is too small + +**/ +EFI_STATUS +CoreLoadPeImage ( + IN BOOLEAN BootPolicy, + IN VOID *Pe32Handle, + IN LOADED_IMAGE_PRIVATE_DATA *Image, + IN EFI_PHYSICAL_ADDRESS DstBuffer OPTIONAL, + OUT EFI_PHYSICAL_ADDRESS *EntryPoint OPTIONAL, + IN UINT32 Attribute + ) +{ + EFI_STATUS Status; + BOOLEAN DstBufAlocated; + UINTN Size; + + ZeroMem (&Image->ImageContext, sizeof (Image->ImageContext)); + + Image->ImageContext.Handle = Pe32Handle; + Image->ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE)CoreReadImageFile; + + // + // Get information about the image being loaded + // + Status = PeCoffLoaderGetImageInfo (&Image->ImageContext); + if (EFI_ERROR (Status)) { + return Status; + } + + if (!CoreIsImageTypeSupported (Image)) { + // + // The PE/COFF loader can support loading image types that can be executed. + // If we loaded an image type that we can not execute return EFI_UNSUPPORTED. + // + DEBUG (( + DEBUG_ERROR, + "Image type %s can't be loaded on %s UEFI system.\n", + GetMachineTypeName (Image->ImageContext.Machine), + GetMachineTypeName (mDxeCoreImageMachineType) + )); + return EFI_UNSUPPORTED; + } + + // + // Set EFI memory type based on ImageType + // + switch (Image->ImageContext.ImageType) { + case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION: + Image->ImageContext.ImageCodeMemoryType = EfiLoaderCode; + Image->ImageContext.ImageDataMemoryType = EfiLoaderData; + break; + case EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER: + Image->ImageContext.ImageCodeMemoryType = EfiBootServicesCode; + Image->ImageContext.ImageDataMemoryType = EfiBootServicesData; + break; + case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER: + case EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER: + Image->ImageContext.ImageCodeMemoryType = EfiRuntimeServicesCode; + Image->ImageContext.ImageDataMemoryType = EfiRuntimeServicesData; + break; + default: + Image->ImageContext.ImageError = IMAGE_ERROR_INVALID_SUBSYSTEM; + return EFI_UNSUPPORTED; + } + + // + // Allocate memory of the correct memory type aligned on the required image boundary + // + DstBufAlocated = FALSE; + if (DstBuffer == 0) { + // + // Allocate Destination Buffer as caller did not pass it in + // + + if (Image->ImageContext.SectionAlignment > EFI_PAGE_SIZE) { + Size = (UINTN)Image->ImageContext.ImageSize + Image->ImageContext.SectionAlignment; + } else { + Size = (UINTN)Image->ImageContext.ImageSize; + } + + Image->NumberOfPages = EFI_SIZE_TO_PAGES (Size); + + // + // If the image relocations have not been stripped, then load at any address. + // Otherwise load at the address at which it was linked. + // + // Memory below 1MB should be treated reserved for CSM and there should be + // no modules whose preferred load addresses are below 1MB. + // + Status = EFI_OUT_OF_RESOURCES; + // + // If Loading Module At Fixed Address feature is enabled, the module should be loaded to + // a specified address. + // + if (PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0 ) { + Status = GetPeCoffImageFixLoadingAssignedAddress (&(Image->ImageContext)); + + if (EFI_ERROR (Status)) { + // + // If the code memory is not ready, invoke CoreAllocatePage with AllocateAnyPages to load the driver. + // + DEBUG ((DEBUG_INFO|DEBUG_LOAD, "LOADING MODULE FIXED ERROR: Loading module at fixed address failed since specified memory is not available.\n")); + + Status = CoreAllocatePages ( + AllocateAnyPages, + (EFI_MEMORY_TYPE)(Image->ImageContext.ImageCodeMemoryType), + Image->NumberOfPages, + &Image->ImageContext.ImageAddress + ); + } + } else { + if ((PcdGetBool (PcdImageLargeAddressLoad) && ((Image->ImageContext.ImageAddress) >= 0x100000)) || + Image->ImageContext.RelocationsStripped) + { + Status = CoreAllocatePages ( + AllocateAddress, + (EFI_MEMORY_TYPE)(Image->ImageContext.ImageCodeMemoryType), + Image->NumberOfPages, + &Image->ImageContext.ImageAddress + ); + } + + if (EFI_ERROR (Status) && !Image->ImageContext.RelocationsStripped) { + Status = CoreAllocatePages ( + AllocateAnyPages, + (EFI_MEMORY_TYPE)(Image->ImageContext.ImageCodeMemoryType), + Image->NumberOfPages, + &Image->ImageContext.ImageAddress + ); + } + } + + if (EFI_ERROR (Status)) { + return Status; + } + + DstBufAlocated = TRUE; + } else { + // + // Caller provided the destination buffer + // + + if (Image->ImageContext.RelocationsStripped && (Image->ImageContext.ImageAddress != DstBuffer)) { + // + // If the image relocations were stripped, and the caller provided a + // destination buffer address that does not match the address that the + // image is linked at, then the image cannot be loaded. + // + return EFI_INVALID_PARAMETER; + } + + if ((Image->NumberOfPages != 0) && + (Image->NumberOfPages < + (EFI_SIZE_TO_PAGES ((UINTN)Image->ImageContext.ImageSize + Image->ImageContext.SectionAlignment)))) + { + Image->NumberOfPages = EFI_SIZE_TO_PAGES ((UINTN)Image->ImageContext.ImageSize + Image->ImageContext.SectionAlignment); + return EFI_BUFFER_TOO_SMALL; + } + + Image->NumberOfPages = EFI_SIZE_TO_PAGES ((UINTN)Image->ImageContext.ImageSize + Image->ImageContext.SectionAlignment); + Image->ImageContext.ImageAddress = DstBuffer; + } + + Image->ImageBasePage = Image->ImageContext.ImageAddress; + if (!Image->ImageContext.IsTeImage) { + Image->ImageContext.ImageAddress = + (Image->ImageContext.ImageAddress + Image->ImageContext.SectionAlignment - 1) & + ~((UINTN)Image->ImageContext.SectionAlignment - 1); + } + + // + // Load the image from the file into the allocated memory + // + Status = PeCoffLoaderLoadImage (&Image->ImageContext); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // If this is a Runtime Driver, then allocate memory for the FixupData that + // is used to relocate the image when SetVirtualAddressMap() is called. The + // relocation is done by the Runtime AP. + // + if ((Attribute & EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION) != 0) { + if (Image->ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) { + Image->ImageContext.FixupData = AllocateRuntimePool ((UINTN)(Image->ImageContext.FixupDataSize)); + if (Image->ImageContext.FixupData == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + } + } + + // + // Relocate the image in memory + // + Status = PeCoffLoaderRelocateImage (&Image->ImageContext); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Flush the Instruction Cache + // + InvalidateInstructionCacheRange ((VOID *)(UINTN)Image->ImageContext.ImageAddress, (UINTN)Image->ImageContext.ImageSize); + + // + // Copy the machine type from the context to the image private data. + // + Image->Machine = Image->ImageContext.Machine; + + // + // Get the image entry point. + // + Image->EntryPoint = (EFI_IMAGE_ENTRY_POINT)(UINTN)Image->ImageContext.EntryPoint; + + // + // Fill in the image information for the Loaded Image Protocol + // + Image->Type = Image->ImageContext.ImageType; + Image->Info.ImageBase = (VOID *)(UINTN)Image->ImageContext.ImageAddress; + Image->Info.ImageSize = Image->ImageContext.ImageSize; + Image->Info.ImageCodeType = (EFI_MEMORY_TYPE)(Image->ImageContext.ImageCodeMemoryType); + Image->Info.ImageDataType = (EFI_MEMORY_TYPE)(Image->ImageContext.ImageDataMemoryType); + if ((Attribute & EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION) != 0) { + if (Image->ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) { + // + // Make a list off all the RT images so we can let the RT AP know about them. + // + Image->RuntimeData = AllocateRuntimePool (sizeof (EFI_RUNTIME_IMAGE_ENTRY)); + if (Image->RuntimeData == NULL) { + goto Done; + } + + Image->RuntimeData->ImageBase = Image->Info.ImageBase; + Image->RuntimeData->ImageSize = (UINT64)(Image->Info.ImageSize); + Image->RuntimeData->RelocationData = Image->ImageContext.FixupData; + Image->RuntimeData->Handle = Image->Handle; + InsertTailList (&gRuntime->ImageHead, &Image->RuntimeData->Link); + InsertImageRecord (Image->RuntimeData); + } + } + + // + // Fill in the entry point of the image if it is available + // + if (EntryPoint != NULL) { + *EntryPoint = Image->ImageContext.EntryPoint; + } + + // + // 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 driver at 0x%11p EntryPoint=0x%11p ", + (VOID *)(UINTN)Image->ImageContext.ImageAddress, + FUNCTION_ENTRY_POINT (Image->ImageContext.EntryPoint) + )); + + // + // Print Module Name by Pdb file path. + // Windows and Unix style file path are all trimmed correctly. + // + if (Image->ImageContext.PdbPointer != NULL) { + StartIndex = 0; + for (Index = 0; Image->ImageContext.PdbPointer[Index] != 0; Index++) { + if ((Image->ImageContext.PdbPointer[Index] == '\\') || (Image->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] = Image->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 (); + + return EFI_SUCCESS; + +Done: + + // + // Free memory. + // + + if (DstBufAlocated) { + CoreFreePages (Image->ImageContext.ImageAddress, Image->NumberOfPages); + Image->ImageContext.ImageAddress = 0; + Image->ImageBasePage = 0; + } + + if (Image->ImageContext.FixupData != NULL) { + CoreFreePool (Image->ImageContext.FixupData); + } + + return Status; +} + +/** + Get the image's private data from its handle. + + @param ImageHandle The image handle + + @return Return the image private data associated with ImageHandle. + +**/ +LOADED_IMAGE_PRIVATE_DATA * +CoreLoadedImageInfo ( + IN EFI_HANDLE ImageHandle + ) +{ + EFI_STATUS Status; + EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; + LOADED_IMAGE_PRIVATE_DATA *Image; + + Status = CoreHandleProtocol ( + ImageHandle, + &gEfiLoadedImageProtocolGuid, + (VOID **)&LoadedImage + ); + if (!EFI_ERROR (Status)) { + Image = LOADED_IMAGE_PRIVATE_DATA_FROM_THIS (LoadedImage); + } else { + DEBUG ((DEBUG_LOAD, "CoreLoadedImageInfo: Not an ImageHandle %p\n", ImageHandle)); + Image = NULL; + } + + return Image; +} + +/** + Unloads EFI image from memory. + + @param Image EFI image + @param FreePage Free allocated pages + +**/ +VOID +CoreUnloadAndCloseImage ( + IN LOADED_IMAGE_PRIVATE_DATA *Image, + IN BOOLEAN FreePage + ) +{ + EFI_STATUS Status; + UINTN HandleCount; + EFI_HANDLE *HandleBuffer; + UINTN HandleIndex; + EFI_GUID **ProtocolGuidArray; + UINTN ArrayCount; + UINTN ProtocolIndex; + EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfo; + UINTN OpenInfoCount; + UINTN OpenInfoIndex; + + HandleBuffer = NULL; + ProtocolGuidArray = NULL; + + if (Image->Started) { + UnregisterMemoryProfileImage (Image); + } + + UnprotectUefiImage (&Image->Info, Image->LoadedImageDevicePath); + + if (Image->PeCoffEmu != NULL) { + // + // If the PE/COFF Emulator protocol exists we must unregister the image. + // + Image->PeCoffEmu->UnregisterImage (Image->PeCoffEmu, Image->ImageBasePage); + } + + // + // Unload image, free Image->ImageContext->ModHandle + // + PeCoffLoaderUnloadImage (&Image->ImageContext); + + // + // Free our references to the image handle + // + if (Image->Handle != NULL) { + Status = CoreLocateHandleBuffer ( + AllHandles, + NULL, + NULL, + &HandleCount, + &HandleBuffer + ); + if (!EFI_ERROR (Status)) { + for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) { + Status = CoreProtocolsPerHandle ( + HandleBuffer[HandleIndex], + &ProtocolGuidArray, + &ArrayCount + ); + if (!EFI_ERROR (Status)) { + for (ProtocolIndex = 0; ProtocolIndex < ArrayCount; ProtocolIndex++) { + Status = CoreOpenProtocolInformation ( + HandleBuffer[HandleIndex], + ProtocolGuidArray[ProtocolIndex], + &OpenInfo, + &OpenInfoCount + ); + if (!EFI_ERROR (Status)) { + for (OpenInfoIndex = 0; OpenInfoIndex < OpenInfoCount; OpenInfoIndex++) { + if (OpenInfo[OpenInfoIndex].AgentHandle == Image->Handle) { + Status = CoreCloseProtocol ( + HandleBuffer[HandleIndex], + ProtocolGuidArray[ProtocolIndex], + Image->Handle, + OpenInfo[OpenInfoIndex].ControllerHandle + ); + } + } + + if (OpenInfo != NULL) { + CoreFreePool (OpenInfo); + } + } + } + + if (ProtocolGuidArray != NULL) { + CoreFreePool (ProtocolGuidArray); + } + } + } + + if (HandleBuffer != NULL) { + CoreFreePool (HandleBuffer); + } + } + + CoreRemoveDebugImageInfoEntry (Image->Handle); + + Status = CoreUninstallProtocolInterface ( + Image->Handle, + &gEfiLoadedImageDevicePathProtocolGuid, + Image->LoadedImageDevicePath + ); + + Status = CoreUninstallProtocolInterface ( + Image->Handle, + &gEfiLoadedImageProtocolGuid, + &Image->Info + ); + + if (Image->ImageContext.HiiResourceData != 0) { + Status = CoreUninstallProtocolInterface ( + Image->Handle, + &gEfiHiiPackageListProtocolGuid, + (VOID *)(UINTN)Image->ImageContext.HiiResourceData + ); + } + } + + if (Image->RuntimeData != NULL) { + if (Image->RuntimeData->Link.ForwardLink != NULL) { + // + // Remove the Image from the Runtime Image list as we are about to Free it! + // + RemoveEntryList (&Image->RuntimeData->Link); + RemoveImageRecord (Image->RuntimeData); + } + + CoreFreePool (Image->RuntimeData); + } + + // + // Free the Image from memory + // + if ((Image->ImageBasePage != 0) && FreePage) { + CoreFreePages (Image->ImageBasePage, Image->NumberOfPages); + } + + // + // Done with the Image structure + // + if (Image->Info.FilePath != NULL) { + CoreFreePool (Image->Info.FilePath); + } + + if (Image->LoadedImageDevicePath != NULL) { + CoreFreePool (Image->LoadedImageDevicePath); + } + + if (Image->FixupData != NULL) { + CoreFreePool (Image->FixupData); + } + + CoreFreePool (Image); +} + +/** + Loads an EFI image into memory and returns a handle to the image. + + @param BootPolicy If TRUE, indicates that the request originates + from the boot manager, and that the boot + manager is attempting to load FilePath as a + boot selection. + @param ParentImageHandle The caller's image handle. + @param FilePath The specific file path from which the image is + loaded. + @param SourceBuffer If not NULL, a pointer to the memory location + containing a copy of the image to be loaded. + @param SourceSize The size in bytes of SourceBuffer. + @param DstBuffer The buffer to store the image + @param NumberOfPages If not NULL, it inputs a pointer to the page + number of DstBuffer and outputs a pointer to + the page number of the image. If this number is + not enough, return EFI_BUFFER_TOO_SMALL and + this parameter contains the required number. + @param ImageHandle Pointer to the returned image handle that is + created when the image is successfully loaded. + @param EntryPoint A pointer to the entry point + @param Attribute The bit mask of attributes to set for the load + PE image + + @retval EFI_SUCCESS The image was loaded into memory. + @retval EFI_NOT_FOUND The FilePath was not found. + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value. + @retval EFI_BUFFER_TOO_SMALL The buffer is too small + @retval EFI_UNSUPPORTED The image type is not supported, or the device + path cannot be parsed to locate the proper + protocol for loading the file. + @retval EFI_OUT_OF_RESOURCES Image was not loaded due to insufficient + resources. + @retval EFI_LOAD_ERROR Image was not loaded because the image format was corrupt or not + understood. + @retval EFI_DEVICE_ERROR Image was not loaded because the device returned a read error. + @retval EFI_ACCESS_DENIED Image was not loaded because the platform policy prohibits the + image from being loaded. NULL is returned in *ImageHandle. + @retval EFI_SECURITY_VIOLATION Image was loaded and an ImageHandle was created with a + valid EFI_LOADED_IMAGE_PROTOCOL. However, the current + platform policy specifies that the image should not be started. + +**/ +EFI_STATUS +CoreLoadImageCommon ( + IN BOOLEAN BootPolicy, + IN EFI_HANDLE ParentImageHandle, + IN EFI_DEVICE_PATH_PROTOCOL *FilePath, + IN VOID *SourceBuffer OPTIONAL, + IN UINTN SourceSize, + IN EFI_PHYSICAL_ADDRESS DstBuffer OPTIONAL, + IN OUT UINTN *NumberOfPages OPTIONAL, + OUT EFI_HANDLE *ImageHandle, + OUT EFI_PHYSICAL_ADDRESS *EntryPoint OPTIONAL, + IN UINT32 Attribute + ) +{ + LOADED_IMAGE_PRIVATE_DATA *Image; + LOADED_IMAGE_PRIVATE_DATA *ParentImage; + IMAGE_FILE_HANDLE FHand; + EFI_STATUS Status; + EFI_STATUS SecurityStatus; + EFI_HANDLE DeviceHandle; + UINT32 AuthenticationStatus; + EFI_DEVICE_PATH_PROTOCOL *OriginalFilePath; + EFI_DEVICE_PATH_PROTOCOL *HandleFilePath; + EFI_DEVICE_PATH_PROTOCOL *InputFilePath; + EFI_DEVICE_PATH_PROTOCOL *Node; + UINTN FilePathSize; + BOOLEAN ImageIsFromFv; + BOOLEAN ImageIsFromLoadFile; + + SecurityStatus = EFI_SUCCESS; + + ASSERT (gEfiCurrentTpl < TPL_NOTIFY); + ParentImage = NULL; + + // + // The caller must pass in a valid ParentImageHandle + // + if ((ImageHandle == NULL) || (ParentImageHandle == NULL)) { + return EFI_INVALID_PARAMETER; + } + + ParentImage = CoreLoadedImageInfo (ParentImageHandle); + if (ParentImage == NULL) { + DEBUG ((DEBUG_LOAD|DEBUG_ERROR, "LoadImageEx: Parent handle not an image handle\n")); + return EFI_INVALID_PARAMETER; + } + + ZeroMem (&FHand, sizeof (IMAGE_FILE_HANDLE)); + FHand.Signature = IMAGE_FILE_HANDLE_SIGNATURE; + OriginalFilePath = FilePath; + InputFilePath = FilePath; + HandleFilePath = FilePath; + DeviceHandle = NULL; + Status = EFI_SUCCESS; + AuthenticationStatus = 0; + ImageIsFromFv = FALSE; + ImageIsFromLoadFile = FALSE; + + // + // If the caller passed a copy of the file, then just use it + // + if (SourceBuffer != NULL) { + FHand.Source = SourceBuffer; + FHand.SourceSize = SourceSize; + Status = CoreLocateDevicePath (&gEfiDevicePathProtocolGuid, &HandleFilePath, &DeviceHandle); + if (EFI_ERROR (Status)) { + DeviceHandle = NULL; + } + + if (SourceSize > 0) { + Status = EFI_SUCCESS; + } else { + Status = EFI_LOAD_ERROR; + } + } else { + if (FilePath == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Try to get the image device handle by checking the match protocol. + // + Node = NULL; + Status = CoreLocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &HandleFilePath, &DeviceHandle); + if (!EFI_ERROR (Status)) { + ImageIsFromFv = TRUE; + } else { + HandleFilePath = FilePath; + Status = CoreLocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &HandleFilePath, &DeviceHandle); + if (EFI_ERROR (Status)) { + if (!BootPolicy) { + HandleFilePath = FilePath; + Status = CoreLocateDevicePath (&gEfiLoadFile2ProtocolGuid, &HandleFilePath, &DeviceHandle); + } + + if (EFI_ERROR (Status)) { + HandleFilePath = FilePath; + Status = CoreLocateDevicePath (&gEfiLoadFileProtocolGuid, &HandleFilePath, &DeviceHandle); + if (!EFI_ERROR (Status)) { + ImageIsFromLoadFile = TRUE; + Node = HandleFilePath; + } + } + } + } + + // + // Get the source file buffer by its device path. + // + FHand.Source = GetFileBufferByFilePath ( + BootPolicy, + FilePath, + &FHand.SourceSize, + &AuthenticationStatus + ); + if (FHand.Source == NULL) { + Status = EFI_NOT_FOUND; + } else { + FHand.FreeBuffer = TRUE; + if (ImageIsFromLoadFile) { + // + // LoadFile () may cause the device path of the Handle be updated. + // + OriginalFilePath = AppendDevicePath (DevicePathFromHandle (DeviceHandle), Node); + } + } + } + + if (EFI_ERROR (Status)) { + Image = NULL; + goto Done; + } + + if (gSecurity2 != NULL) { + // + // Verify File Authentication through the Security2 Architectural Protocol + // + SecurityStatus = gSecurity2->FileAuthentication ( + gSecurity2, + OriginalFilePath, + FHand.Source, + FHand.SourceSize, + BootPolicy + ); + if (!EFI_ERROR (SecurityStatus) && ImageIsFromFv) { + // + // When Security2 is installed, Security Architectural Protocol must be published. + // + ASSERT (gSecurity != NULL); + + // + // Verify the Authentication Status through the Security Architectural Protocol + // Only on images that have been read using Firmware Volume protocol. + // + SecurityStatus = gSecurity->FileAuthenticationState ( + gSecurity, + AuthenticationStatus, + OriginalFilePath + ); + } + } else if ((gSecurity != NULL) && (OriginalFilePath != NULL)) { + // + // Verify the Authentication Status through the Security Architectural Protocol + // + SecurityStatus = gSecurity->FileAuthenticationState ( + gSecurity, + AuthenticationStatus, + OriginalFilePath + ); + } + + // + // Check Security Status. + // + if (EFI_ERROR (SecurityStatus) && (SecurityStatus != EFI_SECURITY_VIOLATION)) { + if (SecurityStatus == EFI_ACCESS_DENIED) { + // + // Image was not loaded because the platform policy prohibits the image from being loaded. + // It's the only place we could meet EFI_ACCESS_DENIED. + // + *ImageHandle = NULL; + } + + Status = SecurityStatus; + Image = NULL; + goto Done; + } + + // + // Allocate a new image structure + // + Image = AllocateZeroPool (sizeof (LOADED_IMAGE_PRIVATE_DATA)); + if (Image == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + // + // Pull out just the file portion of the DevicePath for the LoadedImage FilePath + // + FilePath = OriginalFilePath; + if (DeviceHandle != NULL) { + Status = CoreHandleProtocol (DeviceHandle, &gEfiDevicePathProtocolGuid, (VOID **)&HandleFilePath); + if (!EFI_ERROR (Status)) { + FilePathSize = GetDevicePathSize (HandleFilePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL); + FilePath = (EFI_DEVICE_PATH_PROTOCOL *)(((UINT8 *)FilePath) + FilePathSize); + } + } + + // + // Initialize the fields for an internal driver + // + Image->Signature = LOADED_IMAGE_PRIVATE_DATA_SIGNATURE; + Image->Info.SystemTable = gDxeCoreST; + Image->Info.DeviceHandle = DeviceHandle; + Image->Info.Revision = EFI_LOADED_IMAGE_PROTOCOL_REVISION; + Image->Info.FilePath = DuplicateDevicePath (FilePath); + Image->Info.ParentHandle = ParentImageHandle; + + if (NumberOfPages != NULL) { + Image->NumberOfPages = *NumberOfPages; + } else { + Image->NumberOfPages = 0; + } + + // + // Install the protocol interfaces for this image + // don't fire notifications yet + // + Status = CoreInstallProtocolInterfaceNotify ( + &Image->Handle, + &gEfiLoadedImageProtocolGuid, + EFI_NATIVE_INTERFACE, + &Image->Info, + FALSE + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Load the image. If EntryPoint is Null, it will not be set. + // + Status = CoreLoadPeImage (BootPolicy, &FHand, Image, DstBuffer, EntryPoint, Attribute); + if (EFI_ERROR (Status)) { + if ((Status == EFI_BUFFER_TOO_SMALL) || (Status == EFI_OUT_OF_RESOURCES)) { + if (NumberOfPages != NULL) { + *NumberOfPages = Image->NumberOfPages; + } + } + + goto Done; + } + + if (NumberOfPages != NULL) { + *NumberOfPages = Image->NumberOfPages; + } + + // + // Register the image in the Debug Image Info Table if the attribute is set + // + if ((Attribute & EFI_LOAD_PE_IMAGE_ATTRIBUTE_DEBUG_IMAGE_INFO_TABLE_REGISTRATION) != 0) { + CoreNewDebugImageInfoEntry (EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL, &Image->Info, Image->Handle); + } + + // + // Check whether we are loading a runtime image that lacks support for + // IBT/BTI landing pads. + // + if ((Image->ImageContext.ImageCodeMemoryType == EfiRuntimeServicesCode) && + ((Image->ImageContext.DllCharacteristicsEx & EFI_IMAGE_DLLCHARACTERISTICS_EX_FORWARD_CFI_COMPAT) == 0)) + { + gMemoryAttributesTableForwardCfi = FALSE; + } + + // + // Reinstall loaded image protocol to fire any notifications + // + Status = CoreReinstallProtocolInterface ( + Image->Handle, + &gEfiLoadedImageProtocolGuid, + &Image->Info, + &Image->Info + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // If DevicePath parameter to the LoadImage() is not NULL, then make a copy of DevicePath, + // otherwise Loaded Image Device Path Protocol is installed with a NULL interface pointer. + // + if (OriginalFilePath != NULL) { + Image->LoadedImageDevicePath = DuplicateDevicePath (OriginalFilePath); + } + + // + // Install Loaded Image Device Path Protocol onto the image handle of a PE/COFE image + // + Status = CoreInstallProtocolInterface ( + &Image->Handle, + &gEfiLoadedImageDevicePathProtocolGuid, + EFI_NATIVE_INTERFACE, + Image->LoadedImageDevicePath + ); + if (EFI_ERROR (Status)) { + goto Done; + } + + // + // Install HII Package List Protocol onto the image handle + // + if (Image->ImageContext.HiiResourceData != 0) { + Status = CoreInstallProtocolInterface ( + &Image->Handle, + &gEfiHiiPackageListProtocolGuid, + EFI_NATIVE_INTERFACE, + (VOID *)(UINTN)Image->ImageContext.HiiResourceData + ); + if (EFI_ERROR (Status)) { + goto Done; + } + } + + ProtectUefiImage (&Image->Info, Image->LoadedImageDevicePath); + + // + // Success. Return the image handle + // + *ImageHandle = Image->Handle; + +Done: + // + // All done accessing the source file + // If we allocated the Source buffer, free it + // + if (FHand.FreeBuffer) { + CoreFreePool (FHand.Source); + } + + if (OriginalFilePath != InputFilePath) { + CoreFreePool (OriginalFilePath); + } + + // + // There was an error. If there's an Image structure, free it + // + if (EFI_ERROR (Status)) { + if (Image != NULL) { + CoreUnloadAndCloseImage (Image, (BOOLEAN)(DstBuffer == 0)); + Image = NULL; + } + } else if (EFI_ERROR (SecurityStatus)) { + Status = SecurityStatus; + } + + // + // Track the return status from LoadImage. + // + if (Image != NULL) { + Image->LoadImageStatus = Status; + } + + return Status; +} + +/** + Loads an EFI image into memory and returns a handle to the image. + + @param BootPolicy If TRUE, indicates that the request originates + from the boot manager, and that the boot + manager is attempting to load FilePath as a + boot selection. + @param ParentImageHandle The caller's image handle. + @param FilePath The specific file path from which the image is + loaded. + @param SourceBuffer If not NULL, a pointer to the memory location + containing a copy of the image to be loaded. + @param SourceSize The size in bytes of SourceBuffer. + @param ImageHandle Pointer to the returned image handle that is + created when the image is successfully loaded. + + @retval EFI_SUCCESS The image was loaded into memory. + @retval EFI_NOT_FOUND The FilePath was not found. + @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value. + @retval EFI_UNSUPPORTED The image type is not supported, or the device + path cannot be parsed to locate the proper + protocol for loading the file. + @retval EFI_OUT_OF_RESOURCES Image was not loaded due to insufficient + resources. + @retval EFI_LOAD_ERROR Image was not loaded because the image format was corrupt or not + understood. + @retval EFI_DEVICE_ERROR Image was not loaded because the device returned a read error. + @retval EFI_ACCESS_DENIED Image was not loaded because the platform policy prohibits the + image from being loaded. NULL is returned in *ImageHandle. + @retval EFI_SECURITY_VIOLATION Image was loaded and an ImageHandle was created with a + valid EFI_LOADED_IMAGE_PROTOCOL. However, the current + platform policy specifies that the image should not be started. + +**/ +EFI_STATUS +EFIAPI +CoreLoadImage ( + IN BOOLEAN BootPolicy, + IN EFI_HANDLE ParentImageHandle, + IN EFI_DEVICE_PATH_PROTOCOL *FilePath, + IN VOID *SourceBuffer OPTIONAL, + IN UINTN SourceSize, + OUT EFI_HANDLE *ImageHandle + ) +{ + EFI_STATUS Status; + EFI_HANDLE Handle; + + PERF_LOAD_IMAGE_BEGIN (NULL); + + Status = CoreLoadImageCommon ( + BootPolicy, + ParentImageHandle, + FilePath, + SourceBuffer, + SourceSize, + (EFI_PHYSICAL_ADDRESS)(UINTN)NULL, + NULL, + ImageHandle, + NULL, + EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION | EFI_LOAD_PE_IMAGE_ATTRIBUTE_DEBUG_IMAGE_INFO_TABLE_REGISTRATION + ); + + Handle = NULL; + if (!EFI_ERROR (Status)) { + // + // ImageHandle will be valid only Status is success. + // + Handle = *ImageHandle; + } + + PERF_LOAD_IMAGE_END (Handle); + + return Status; +} + +/** + Transfer control to a loaded image's entry point. + + @param ImageHandle Handle of image to be started. + @param ExitDataSize Pointer of the size to ExitData + @param ExitData Pointer to a pointer to a data buffer that + includes a Null-terminated string, + optionally followed by additional binary data. + The string is a description that the caller may + use to further indicate the reason for the + image's exit. + + @retval EFI_INVALID_PARAMETER Invalid parameter + @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate + @retval EFI_SECURITY_VIOLATION The current platform policy specifies that the image should not be started. + @retval EFI_SUCCESS Successfully transfer control to the image's + entry point. + +**/ +EFI_STATUS +EFIAPI +CoreStartImage ( + IN EFI_HANDLE ImageHandle, + OUT UINTN *ExitDataSize, + OUT CHAR16 **ExitData OPTIONAL + ) +{ + EFI_STATUS Status; + LOADED_IMAGE_PRIVATE_DATA *Image; + LOADED_IMAGE_PRIVATE_DATA *LastImage; + UINT64 HandleDatabaseKey; + UINTN SetJumpFlag; + EFI_HANDLE Handle; + + Handle = ImageHandle; + + Image = CoreLoadedImageInfo (ImageHandle); + if ((Image == NULL) || Image->Started) { + return EFI_INVALID_PARAMETER; + } + + if (EFI_ERROR (Image->LoadImageStatus)) { + return Image->LoadImageStatus; + } + + // + // The image to be started must have the machine type supported by DxeCore. + // + if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Image->Machine) && + (Image->PeCoffEmu == NULL)) + { + // + // Do not ASSERT here, because image might be loaded via EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED + // But it can not be started. + // + DEBUG ((DEBUG_ERROR, "Image type %s can't be started ", GetMachineTypeName (Image->Machine))); + DEBUG ((DEBUG_ERROR, "on %s UEFI system.\n", GetMachineTypeName (mDxeCoreImageMachineType))); + return EFI_UNSUPPORTED; + } + + if (Image->PeCoffEmu != NULL) { + Status = Image->PeCoffEmu->RegisterImage ( + Image->PeCoffEmu, + Image->ImageBasePage, + EFI_PAGES_TO_SIZE (Image->NumberOfPages), + &Image->EntryPoint + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_LOAD | DEBUG_ERROR, + "CoreLoadPeImage: Failed to register foreign image with emulator - %r\n", + Status + )); + return Status; + } + } + + PERF_START_IMAGE_BEGIN (Handle); + + // + // Push the current start image context, and + // link the current image to the head. This is the + // only image that can call Exit() + // + HandleDatabaseKey = CoreGetHandleDatabaseKey (); + LastImage = mCurrentImage; + mCurrentImage = Image; + Image->Tpl = gEfiCurrentTpl; + + // + // Set long jump for Exit() support + // JumpContext must be aligned on a CPU specific boundary. + // Overallocate the buffer and force the required alignment + // + Image->JumpBuffer = AllocatePool (sizeof (BASE_LIBRARY_JUMP_BUFFER) + BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT); + if (Image->JumpBuffer == NULL) { + // + // Image may be unloaded after return with failure, + // then ImageHandle may be invalid, so use NULL handle to record perf log. + // + PERF_START_IMAGE_END (NULL); + + // + // Pop the current start image context + // + mCurrentImage = LastImage; + + return EFI_OUT_OF_RESOURCES; + } + + Image->JumpContext = ALIGN_POINTER (Image->JumpBuffer, BASE_LIBRARY_JUMP_BUFFER_ALIGNMENT); + + SetJumpFlag = SetJump (Image->JumpContext); + // + // The initial call to SetJump() must always return 0. + // Subsequent calls to LongJump() cause a non-zero value to be returned by SetJump(). + // + if (SetJumpFlag == 0) { + RegisterMemoryProfileImage (Image, (Image->ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION ? EFI_FV_FILETYPE_APPLICATION : EFI_FV_FILETYPE_DRIVER)); + // + // Call the image's entry point + // + Image->Started = TRUE; + Image->Status = Image->EntryPoint (ImageHandle, Image->Info.SystemTable); + + // + // Add some debug information if the image returned with error. + // This make the user aware and check if the driver image have already released + // all the resource in this situation. + // + DEBUG_CODE_BEGIN (); + if (EFI_ERROR (Image->Status)) { + DEBUG ((DEBUG_ERROR, "Error: Image at %11p start failed: %r\n", Image->Info.ImageBase, Image->Status)); + } + + DEBUG_CODE_END (); + + // + // If the image returns, exit it through Exit() + // + CoreExit (ImageHandle, Image->Status, 0, NULL); + } + + // + // Image has completed. Verify the tpl is the same + // + ASSERT (Image->Tpl == gEfiCurrentTpl); + CoreRestoreTpl (Image->Tpl); + + CoreFreePool (Image->JumpBuffer); + + // + // Pop the current start image context + // + mCurrentImage = LastImage; + + // + // UEFI Specification - StartImage() - EFI 1.10 Extension + // To maintain compatibility with UEFI drivers that are written to the EFI + // 1.02 Specification, StartImage() must monitor the handle database before + // and after each image is started. If any handles are created or modified + // when an image is started, then EFI_BOOT_SERVICES.ConnectController() must + // be called with the Recursive parameter set to TRUE for each of the newly + // created or modified handles before StartImage() returns. + // + if (Image->Type != EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) { + CoreConnectHandlesByKey (HandleDatabaseKey); + } + + // + // Handle the image's returned ExitData + // + DEBUG_CODE_BEGIN (); + if ((Image->ExitDataSize != 0) || (Image->ExitData != NULL)) { + DEBUG ((DEBUG_LOAD, "StartImage: ExitDataSize %d, ExitData %p", (UINT32)Image->ExitDataSize, Image->ExitData)); + if (Image->ExitData != NULL) { + DEBUG ((DEBUG_LOAD, " (%s)", Image->ExitData)); + } + + DEBUG ((DEBUG_LOAD, "\n")); + } + + DEBUG_CODE_END (); + + // + // Return the exit data to the caller + // + if ((ExitData != NULL) && (ExitDataSize != NULL)) { + *ExitDataSize = Image->ExitDataSize; + *ExitData = Image->ExitData; + } else { + // + // Caller doesn't want the exit data, free it + // + CoreFreePool (Image->ExitData); + Image->ExitData = NULL; + } + + // + // Save the Status because Image will get destroyed if it is unloaded. + // + Status = Image->Status; + + // + // If the image returned an error, or if the image is an application + // unload it + // + if (EFI_ERROR (Image->Status) || (Image->Type == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION)) { + CoreUnloadAndCloseImage (Image, TRUE); + // + // ImageHandle may be invalid after the image is unloaded, so use NULL handle to record perf log. + // + Handle = NULL; + } + + // + // Done + // + PERF_START_IMAGE_END (Handle); + return Status; +} + +/** + Terminates the currently loaded EFI image and returns control to boot services. + + @param ImageHandle Handle that identifies the image. This + parameter is passed to the image on entry. + @param Status The image's exit code. + @param ExitDataSize The size, in bytes, of ExitData. Ignored if + ExitStatus is EFI_SUCCESS. + @param ExitData Pointer to a data buffer that includes a + Null-terminated Unicode string, optionally + followed by additional binary data. The string + is a description that the caller may use to + further indicate the reason for the image's + exit. + + @retval EFI_INVALID_PARAMETER Image handle is NULL or it is not current + image. + @retval EFI_SUCCESS Successfully terminates the currently loaded + EFI image. + @retval EFI_ACCESS_DENIED Should never reach there. + @retval EFI_OUT_OF_RESOURCES Could not allocate pool + +**/ +EFI_STATUS +EFIAPI +CoreExit ( + IN EFI_HANDLE ImageHandle, + IN EFI_STATUS Status, + IN UINTN ExitDataSize, + IN CHAR16 *ExitData OPTIONAL + ) +{ + LOADED_IMAGE_PRIVATE_DATA *Image; + EFI_TPL OldTpl; + + // + // Prevent possible reentrance to this function + // for the same ImageHandle + // + OldTpl = CoreRaiseTpl (TPL_NOTIFY); + + Image = CoreLoadedImageInfo (ImageHandle); + if (Image == NULL) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + if (!Image->Started) { + // + // The image has not been started so just free its resources + // + CoreUnloadAndCloseImage (Image, TRUE); + Status = EFI_SUCCESS; + goto Done; + } + + // + // Image has been started, verify this image can exit + // + if (Image != mCurrentImage) { + DEBUG ((DEBUG_LOAD|DEBUG_ERROR, "Exit: Image is not exitable image\n")); + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + // + // Set status + // + Image->Status = Status; + + // + // If there's ExitData info, move it + // + if (ExitData != NULL) { + Image->ExitDataSize = ExitDataSize; + Image->ExitData = AllocatePool (Image->ExitDataSize); + if (Image->ExitData == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + CopyMem (Image->ExitData, ExitData, Image->ExitDataSize); + } + + CoreRestoreTpl (OldTpl); + // + // return to StartImage + // + LongJump (Image->JumpContext, (UINTN)-1); + + // + // If we return from LongJump, then it is an error + // + ASSERT (FALSE); + Status = EFI_ACCESS_DENIED; +Done: + CoreRestoreTpl (OldTpl); + return Status; +} + +/** + Unloads an image. + + @param ImageHandle Handle that identifies the image to be + unloaded. + + @retval EFI_SUCCESS The image has been unloaded. + @retval EFI_UNSUPPORTED The image has been started, and does not support + unload. + @retval EFI_INVALID_PARAMPETER ImageHandle is not a valid image handle. + +**/ +EFI_STATUS +EFIAPI +CoreUnloadImage ( + IN EFI_HANDLE ImageHandle + ) +{ + EFI_STATUS Status; + LOADED_IMAGE_PRIVATE_DATA *Image; + + Image = CoreLoadedImageInfo (ImageHandle); + if (Image == NULL ) { + // + // The image handle is not valid + // + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + if (Image->Started) { + // + // The image has been started, request it to unload. + // + Status = EFI_UNSUPPORTED; + if (Image->Info.Unload != NULL) { + Status = Image->Info.Unload (ImageHandle); + } + } else { + // + // This Image hasn't been started, thus it can be unloaded + // + Status = EFI_SUCCESS; + } + + if (!EFI_ERROR (Status)) { + // + // if the Image was not started or Unloaded O.K. then clean up + // + CoreUnloadAndCloseImage (Image, TRUE); + } + +Done: + return Status; +} |
