以上图片来自《UEFI原理与编程》
LoadImage实现的功能将EFI文件加载放到内存中,创建一个image handle 插入到Handle链表中去,并且安装EFI_LOADED_IMAGE_PROTOCOL到这个image handle上。
gBS->LoadImage是一个函数指针,它实际指向CoreLoadImage函数。位于MdeModulePkg\Core\Dxe\Image\Image.c
// Loads an EFI image into memory and returns a handle to the image.
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
)
{
......省略
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
);
......省略
}
以下代码均位于CoreLoadImageCommon函数中。
typedef struct {
UINTN Signature;
EFI_HANDLE Handle;
UINTN Type;
BOOLEAN Started;
EFI_IMAGE_ENTRY_POINT EntryPoint;
EFI_LOADED_IMAGE_PROTOCOL Info;
EFI_PHYSICAL_ADDRESS ImageBasePage;
UINTN NumberOfPages;
CHAR8 *FixupData;
EFI_TPL Tpl;
EFI_STATUS Status;
UINTN ExitDataSize;
VOID *ExitData;
VOID *JumpBuffer;
BASE_LIBRARY_JUMP_BUFFER *JumpContext;
UINT16 Machine;
EFI_EBC_PROTOCOL *Ebc;
EFI_RUNTIME_IMAGE_ENTRY *RuntimeData;
EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath;
PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
EFI_STATUS LoadImageStatus;
} LOADED_IMAGE_PRIVATE_DATA;
LOADED_IMAGE_PRIVATE_DATA *Image;
其中有个重要的结构体LOADED_IMAGE_PRIVATE_DATA,Image为此结构体类型指针变量。以及EFI_LOADED_IMAGE_PROTOCOL结构体变量Info。
///
/// Can be used on any image handle to obtain information about the loaded image.
///
typedef struct {
UINT32 Revision; ///< Defines the revision of the EFI_LOADED_IMAGE_PROTOCOL structure.
///< All future revisions will be backward compatible to the current revision.
EFI_HANDLE ParentHandle; ///< Parent image's image handle. NULL if the image is loaded directly from
///< the firmware's boot manager.
EFI_SYSTEM_TABLE *SystemTable; ///< the image's EFI system table pointer.
//
// Source location of image
//
EFI_HANDLE DeviceHandle; ///< The device handle that the EFI Image was loaded from.
EFI_DEVICE_PATH_PROTOCOL *FilePath; ///< A pointer to the file path portion specific to DeviceHandle
///< that the EFI Image was loaded from.
VOID *Reserved; ///< Reserved. DO NOT USE.
//
// Images load options
//
UINT32 LoadOptionsSize;///< The size in bytes of LoadOptions.
VOID *LoadOptions; ///< A pointer to the image's binary load options.
//
// Location of where image was loaded
//
VOID *ImageBase; ///< The base address at which the image was loaded.
UINT64 ImageSize; ///< The size in bytes of the loaded image.
EFI_MEMORY_TYPE ImageCodeType; ///< The memory type that the code sections were loaded as.
EFI_MEMORY_TYPE ImageDataType; ///< The memory type that the data sections were loaded as.
EFI_IMAGE_UNLOAD Unload;
} EFI_LOADED_IMAGE_PROTOCOL;
下图函数中会创建image handle,安装LoadedImageProtocol。细节参考具体代码。
// 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 Image 到内存中:
//
// 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;
}
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
)
{
......
// Load the image from the file into the allocated memory
//
Status = PeCoffLoaderLoadImage (&Image->ImageContext);
......
Image->EntryPoint = (EFI_IMAGE_ENTRY_POINT)(UINTN)Image->ImageContext.EntryPoint;
......
}
看下面这条语句,将ImageContext.EntryPoint赋值给了Image->EntryPoint,而在CoreStartImage中有一条语句Image->Status = Image->EntryPoint (ImageHandle, Image->Info.SystemTable);相当于是Image->ImageContext.EntryPoint (ImageHandle, Image->Info.SystemTable)。对于UEFI APP,这里的ImageContext.EntryPoint就是_ModuleEntryPoint了。而_ModuleEntryPoint是如何和ImageContext.EntryPoint对应,后续慢慢探索。
Image->EntryPoint = (EFI_IMAGE_ENTRY_POINT)(UINTN)Image->ImageContext.EntryPoint;
参考:
①https://blog.csdn.net/zhangliang19950813/article/details/10640339