UEFI 之 LoadImage探索

 以上图片来自《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

https://blog.csdn.net/xzhang76/article/details/8176267/?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_utm_term~default-4.control&spm=1001.2101.3001.4242

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值