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;
}
下面是一个名为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;
}