如何调用另外的 Application 我们已经研究过很多次了。这次的目标是将一个别人编译好的 EFI Application 包裹在自己编写的 Application中然后调用之。

通过这样的方式可以在一些情况下让我们在没有源代码的情况下实现一些特别的功能。

为了方便测试,我们先写一个测试的Application作为 Test Image。代码非常简单简单,没有调用 CLIB,直接在屏幕上输出 “Hello, World 2” 字样。

#include <Uefi.h>
#include <Library/UefiLib.h>
#include <Library/UefiApplicationEntryPoint.h>

extern EFI_SYSTEM_TABLE  *gST;

EFI_STATUS
EFIAPI
UefiMain (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{
  gST->ConOut->OutputString(gST->ConOut,L"Hello, World 2\r\n");  
  
  return EFI_SUCCESS;
}

接下来用工具把这个 EFI 文件转换为 C的头文件,调用者通过 Include 这个头文件来把Test Image加载到内存中。

  

再使用 gBS->LoadImage() 加载这个 Image。在加载过程中,Test Image 的地址作为 SourceBuffer参数,当这个参数不为NULL时,LoadImage函数也会知道当前要调用的Image已经存在内存中了,也不需要在从DevicePath给出的位置读取到内存中。这步之后再使用 gBS->StartImage()即可运行之。

#include  <Uefi.h>
#include  <Library/UefiLib.h>
#include  <Library/ShellCEntryLib.h>
#include  <Library/BaseMemoryLib.h>
#include  <Library/DevicePathLib.h>
#include  <Hello2.efi.h>

extern EFI_BOOT_SERVICES         *gBS;

EFI_STATUS
EFIAPI
UefiMain (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
 
{
        EFI_DEVICE_PATH  *DP;
        EFI_STATUS      Status;
        EFI_HANDLE      NewHandle;
        UINTN           ExitDataSizePtr; 
        
        DP=FileDevicePath(NULL,L"fso:\\fake.efi");
        Print(L"%s\n",ConvertDevicePathToText(DP,TRUE,FALSE));
    
        //
        // Load the image with:
        // FALSE - not from boot manager and NULL, 0 being not already in memory
        //
        Status = gBS->LoadImage(
                        FALSE,
                        ImageHandle,
                        DP,
                        (VOID*)&amp;Hello2_efi[0],
                        sizeof(Hello2_efi),
                        &amp;NewHandle);     
        if (EFI_ERROR(Status)) {
                Print(L"Load image Error!\n");
                return 0;
        }

        //
        // now start the image, passing up exit data if the caller requested it
        //
        Status = gBS->StartImage(
                     NewHandle,
                     &amp;ExitDataSizePtr,
                     NULL
              );
        if (EFI_ERROR(Status)) {
                Print(L"\nError during StartImage [%X]\n",Status);
                return 0;
        }       
        
        Status = gBS->UnloadImage(NewHandle);                        
        if (EFI_ERROR(Status)) {
                Print(L"Un-Load image Error! %r\n",Status);
                return 0;
        }        
        
        return EFI_SUCCESS;
}






运行结果:

完整的代码下载:

RunInMem

可以看到,当我们运行 rim 的时候,能够正常调用 hello2.efi 输出字符。剩下的问题是:为什么当我们UnloadImage的时候会出现错误?

Leave a Reply

电子邮件地址不会被公开。 必填项已用*标注

You may use these HTML tags and attributes:

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>