📄 image.c
字号:
/*++
Copyright (c) 2004 - 2006, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
Image.c
Abstract:
Core image handling services
--*/
#include "Image.h"
#include "EfiHobLib.h"
#include "EfiPerf.h"
//
// Module Globals
//
LOADED_IMAGE_PRIVATE_DATA *mCurrentImage = NULL;
LOAD_PE32_IMAGE_PRIVATE_DATA mLoadPe32PrivateData = {
LOAD_PE32_IMAGE_PRIVATE_DATA_SIGNATURE,
NULL,
CoreLoadImageEx,
CoreUnloadImageEx
};
//
// 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, // JumpContext
0, // Machine
NULL, // Ebc
NULL, // RuntimeData
};
STATIC
EFI_STATUS
EFIAPI
CoreFlushICache (
IN EFI_PHYSICAL_ADDRESS Start,
IN UINT64 Length
);
EFI_STATUS
CoreInitializeImageServices (
IN VOID *HobStart
)
/*++
Routine Description:
Add the Image Services to EFI Boot Services Table and install the protocol
interfaces for this image.
Arguments:
HobStart - The HOB to initialize
Returns:
Status code.
--*/
{
EFI_STATUS Status;
LOADED_IMAGE_PRIVATE_DATA *Image;
EFI_PHYSICAL_ADDRESS DxeCoreImageBaseAddress;
UINT64 DxeCoreImageLength;
VOID *DxeCoreEntryPoint;
//
// Searching for image hob
//
Status = GetDxeCoreHobInfo (
HobStart,
&DxeCoreImageBaseAddress,
&DxeCoreImageLength,
&DxeCoreEntryPoint,
&gDxeCoreFileName
);
ASSERT_EFI_ERROR (Status);
//
// 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.SystemTable = gST;
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);
//
// Install Debug Mask Protocol
//
DEBUG_CODE (
if (!EFI_ERROR (Status)) {
Status = InstallCoreDebugMaskProtocol(Image->Handle);
ASSERT_EFI_ERROR (Status);
}
)
mCurrentImage = Image;
//
// Fill in DXE globals
//
gDxeCoreImageHandle = Image->Handle;
gDxeCoreLoadedImage = &Image->Info;
//
// Export DXE Core PE Loader functionality
//
return CoreInstallProtocolInterface (
&mLoadPe32PrivateData.Handle,
&gEfiLoadPeImageGuid,
EFI_NATIVE_INTERFACE,
&mLoadPe32PrivateData.Pe32Image
);
}
STATIC
EFI_STATUS
CoreLoadPeImage (
IN VOID *Pe32Handle,
IN LOADED_IMAGE_PRIVATE_DATA *Image,
IN EFI_PHYSICAL_ADDRESS DstBuffer OPTIONAL,
OUT EFI_PHYSICAL_ADDRESS *EntryPoint OPTIONAL,
IN UINT32 Attribute,
IN BOOLEAN CrossLoad
)
/*++
Routine Description:
Loads, relocates, and invokes a PE/COFF image.
Arguments:
Pe32Handle - The handle of PE32 image.
Image - PE image to be loaded.
DstBuffer - The buffer to store the image.
EntryPoint - A pointer to the entry point.
Attribute - The bit mask of attributes to set for the load PE image.
CrossLoad - Whether expect to support cross architecture loading.
Returns:
EFI_SUCCESS - The file was loaded, relocated, and invoked.
EFI_OUT_OF_RESOURCES - There was not enough memory to load and relocate the PE/COFF file.
EFI_INVALID_PARAMETER - Invalid parameter.
EFI_BUFFER_TOO_SMALL - Buffer for image is too small.
--*/
{
EFI_STATUS Status;
BOOLEAN DstBufAlocated;
UINTN Size;
DEBUG_CODE (
UINTN Index;
UINTN StartIndex;
CHAR8 EfiFileName[256];
)
EfiCommonLibZeroMem (&(Image->ImageContext), sizeof (Image->ImageContext));
Image->ImageContext.Handle = Pe32Handle;
Image->ImageContext.ImageRead = (EFI_PEI_PE_COFF_LOADER_READ_FILE) CoreReadImageFile;
//
// Get information about the image being loaded.
//
Status = gEfiPeiPeCoffLoader->GetImageInfo (gEfiPeiPeCoffLoader, &(Image->ImageContext));
if (EFI_ERROR (Status)) {
return Status;
}
//
// Check the processor architecture of the image
//
if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Image->ImageContext.Machine)) {
if (CrossLoad) {
if (!EFI_IMAGE_MACHINE_CROSS_TYPE_SUPPORTED (Image->ImageContext.Machine)) {
return EFI_UNSUPPORTED;
}
} else {
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.
//
Status = CoreAllocatePages (
AllocateAddress,
Image->ImageContext.ImageCodeMemoryType,
Image->NumberOfPages,
&Image->ImageContext.ImageAddress
);
if (EFI_ERROR (Status) && !Image->ImageContext.RelocationsStripped)
Status = CoreAllocatePages (
AllocateAnyPages,
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;
}
Size = EFI_SIZE_TO_PAGES ((UINTN) Image->ImageContext.ImageSize + Image->ImageContext.SectionAlignment);
if ((Image->NumberOfPages != 0) && (Image->NumberOfPages < Size)) {
Image->NumberOfPages = Size;
return EFI_BUFFER_TOO_SMALL;
}
Image->NumberOfPages = Size;
Image->ImageContext.ImageAddress = DstBuffer;
}
Image->ImageBasePage = Image->ImageContext.ImageAddress;
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 = gEfiPeiPeCoffLoader->LoadImage (gEfiPeiPeCoffLoader, &(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) {
if (Image->ImageContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER &&
EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Image->ImageContext.Machine)) {
Image->ImageContext.FixupData = CoreAllocateRuntimePool ((UINTN)(Image->ImageContext.FixupDataSize));
if (Image->ImageContext.FixupData == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto Done;
}
}
}
//
// Relocate the image in memory
//
Status = gEfiPeiPeCoffLoader->RelocateImage (gEfiPeiPeCoffLoader, &(Image->ImageContext));
if (EFI_ERROR (Status)) {
goto Done;
}
//
// Flush the Instruction Cache
//
Status = CoreFlushICache (Image->ImageContext.ImageAddress, Image->ImageContext.ImageSize);
if (EFI_ERROR (Status)) {
goto Done;
}
//
// Get the image entry point. If it's an EBC image, then call into the
// interpreter to create a thunk for the entry point and use the returned
// value for the entry point.
//
Image->EntryPoint = (EFI_IMAGE_ENTRY_POINT) (UINTN) Image->ImageContext.EntryPoint;
//
// Copy the machine type from the context to the image private data. This
// is needed during image unload to know if we should call an EBC protocol
// to unload the image.
//
Image->Machine = Image->ImageContext.Machine;
if (Image->ImageContext.Machine == EFI_IMAGE_MACHINE_EBC) {
//
// Locate the EBC interpreter protocol
//
Status = CoreLocateProtocol (&gEfiEbcProtocolGuid, NULL, &Image->Ebc);
if (EFI_ERROR (Status)) {
goto Done;
}
//
// Register a callback for flushing the instruction cache so that created
// thunks can be flushed.
//
Status = Image->Ebc->RegisterICacheFlush (Image->Ebc, CoreFlushICache);
if (EFI_ERROR (Status)) {
goto Done;
}
//
// Create a thunk for the image's entry point. This will be the new
// entry point for the image.
//
Status = Image->Ebc->CreateThunk (
Image->Ebc,
Image->Handle,
(VOID *)(UINTN)Image->ImageContext.EntryPoint,
(VOID **)&Image->EntryPoint
);
if (EFI_ERROR (Status)) {
goto Done;
}
}
//
// 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 = Image->ImageContext.ImageCodeMemoryType;
Image->Info.ImageDataType = Image->ImageContext.ImageDataMemoryType;
if (Attribute & EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION) {
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 = CoreAllocateRuntimePool (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);
}
}
//
// 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 (
{
DEBUG ((
EFI_D_INFO | EFI_D_LOAD,
"Loading driver at 0x%08x EntryPoint=0x%08x ",
(UINTN) Image->ImageContext.ImageAddress,
(UINTN) Image->ImageContext.EntryPoint
));
if (Image->ImageContext.PdbPointer != NULL) {
StartIndex = 0;
for (Index = 0; Image->ImageContext.PdbPointer[Index] != 0; Index++) {
if (Image->ImageContext.PdbPointer[Index] == '\\') {
StartIndex = Index + 1;
}
}
//
// Copy the PDB file name to our temporary string, and replace .pdb with .efi
//
for (Index = 0; Index < sizeof (EfiFileName); 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;
}
}
DEBUG ((EFI_D_INFO | EFI_D_LOAD, "%a", EfiFileName));
}
DEBUG ((EFI_D_INFO | EFI_D_LOAD, "\n"));
}
);
return EFI_SUCCESS;
Done:
//
// Free memory.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -