UEFI Application

来源:互联网 发布:js汉字转unicode编码 编辑:程序博客网 时间:2024/06/04 21:34
UEFI Application是一种EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION类型的EFI Image。os loader 是一种特殊的application,执行完成后不会return或者exit,相反会调用EFI boot service gBS->ExitBootServices()来将控制权从fireware 传递给os。
下面是一个名为HelloWorld的UEFI Application的inf文件,从MODULE_TYPE可以明显的看出这是一个UEFI_APPLICATION,和pei/dxe/uefi driver 不同的是UEFI_APPLICATION没有dependency relationship section
[Defines]
  INF_VERSION                    = 0x00010005
  BASE_NAME                      = HelloWorld
  MODULE_UNI_FILE                = HelloWorld.uni
  FILE_GUID                      = 6987936E-ED34-44db-AE97-1FA5E4ED2116
  MODULE_TYPE                    = UEFI_APPLICATION
  VERSION_STRING                 = 1.0
  ENTRY_POINT                    = UefiMain

#
#  This flag specifies whether HII resource section is generated into PE image.
#
  UEFI_HII_RESOURCE_SECTION      = TRUE

#
# The following information is for reference only and not required by the build tools.
#
#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC
#

[Sources]
  HelloWorld.c
  HelloWorldStr.uni

[Packages]
  MdePkg/MdePkg.dec
  MdeModulePkg/MdeModulePkg.dec

[LibraryClasses]
  UefiApplicationEntryPoint
  UefiLib
  PcdLib

[FeaturePcd]
  gEfiMdeModulePkgTokenSpaceGuid.PcdHelloWorldPrintEnable   ## CONSUMES

[Pcd]
  gEfiMdeModulePkgTokenSpaceGuid.PcdHelloWorldPrintString || gEfiMdeModulePkgTokenSpaceGuid.PcdHelloWorldPrintEnable    ## SOMETIMES_CONSUMES
  gEfiMdeModulePkgTokenSpaceGuid.PcdHelloWorldPrintTimes  || gEfiMdeModulePkgTokenSpaceGuid.PcdHelloWorldPrintEnable    ## SOMETIMES_CONSUMES

[UserExtensions.TianoCore."ExtraFiles"]
  HelloWorldExtra.uni

UEFI_APPLICATION的入口函数的原型必须是
EFI_STATUS EFIAPI UefiMain (IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE *SystemTable);
其中ImageHandle 表示当前执行的uefi application 也就是自己。SystemTable则是指向EFI System Table的一个指针。
在UefiMain 中可以通过gST得到system table,通过gBS得到boot service,通过gRT得到runtime service
通过LocateProtocol()/HandleProtocol()/ OpenProtocol() 来得到其他UEFI driver提供的protocol
还可以同GetVariable() and SetVariable()来读和写全局变量
EFI_STATUS
EFIAPI
UefiMain (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{
    UINT32 Index;
    
    Index = 0;
 
  //
  // Three PCD type (FeatureFlag, UINT32 and String) are used as the sample.
  //
  if (FeaturePcdGet (PcdHelloWorldPrintEnable)) {
      for (Index = 0; Index < PcdGet32 (PcdHelloWorldPrintTimes); Index ++) {
        //
        // Use UefiLib Print API to print string to UEFI console
        //
        Print ((CHAR16*)PcdGetPtr (PcdHelloWorldPrintString));
    }
  }

  return EFI_SUCCESS;
}
可以看到在UEFI_APPLICATION 中可以使用pcd,而pcd定义的字符串或者值一般是定义在dec中
这个程序会输出PcdHelloWorldPrintString
而这个字符串的定义如下:
./MdeModulePkg/MdeModulePkg.dec:1255:  gEfiMdeModulePkgTokenSpaceGuid.PcdHelloWorldPrintString|L"UEFI Hello World!\n"|VOID*|0x40000004

从helloworld.map 文件中可以看到_gPcd_FixedAtBuild_PcdHelloWorldPrintString 是被放在rodata段.
  .rodata._gPcd_FixedAtBuild_PcdHelloWorldPrintString
                 0x0000000000001968       0x28 /home//uefi/uefi/Build/RELEASE_GCC49/AARCH64/MdeModulePkg/Application/HelloWorld/HelloWorld/OUTPUT/HelloWorld.lib(AutoGen.obj)
                 0x0000000000001968                _gPcd_FixedAtBuild_PcdHelloWorldPrintString

例如在这个例子中,就直接使用gBS 提供的HandleProtocol
EFI_STATUS
EFIAPI
UefiMain (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{
  EFI_STATUS                     Status;
  EFI_GRAPHICS_OUTPUT_PROTOCOL   *Gop;

  Status = gBS->HandleProtocol (
                  gST->ConsoleOutHandle,
                  &gEfiGraphicsOutputProtocolGuid,
                  (VOID **) &Gop
                  );

}
因为gBS本来就是全局变量,所以可以直接用,但是也可以通过下面的方式从SystemTable中得到BootServices
EFI_STATUS
EFIAPI
PrintLibConstructor (
  IN EFI_HANDLE                ImageHandle,
  IN EFI_SYSTEM_TABLE          *SystemTable
  )
{
  EFI_STATUS                   Status;

  Status = SystemTable->BootServices->LocateProtocol (
                                        &gEfiPrint2ProtocolGuid,
                                        NULL,
                                        (VOID**) &mPrint2Protocol
                                        );
  ASSERT_EFI_ERROR (Status);
  ASSERT (mPrint2Protocol != NULL);

  return Status;
}