UEFI其他类型的工程模块(除标准应用程序工程模块)
Shell应用工程模块
标准应用程序工程模块,它 的 入参有很多系统参数需要处理,还有很多其他的命令行参数处理,很不方便。但一般的应用程序都需要在Shell下去执行,它就需要带命令行参数。edk2就提供了Shell应用程序工程模块
用户入口函数
INTN
EFIAPI
ShellAppMain (
IN UINTN Argc,
IN CHAR16 **Argv
)
{
UINTN Index;
if (Argc == 1) {
Print (L"Argv[1] = NULL\n");
}
for (Index = 1; Index < Argc; Index++) {
Print(L"Argv[%d]: \"%s\"\n", Index, Argv[Index]);
}
return 0;
}
Shell应用程序模块的入口函数都是INIT ShellAppMain函数,它 的入参里面没有了系统参数,我们要使用系统表这些系统参数,就需要gST这些全局量。
工程文件
Shell应用程序的工程文件和标准应用程序的工程文件有区别部分区别:
MODULE_TYPE和标准应用程序一样是UEFI_APPLICATION,但是它的ENTRY_POINT必须是ShellCEntryLib,并且必须要在源文件中实现ShellAppMain。必须要有MdePkg/MdePkg.dec和ShellPkg/ShellPkg.dec声明文件。必须要有ShellCEntryLib库,一般还要使用系统表,需要有UefiBootServicesTableLib库。
[Defines]
INF_VERSION = 0x00010006
BASE_NAME = ShellCTestApp
FILE_GUID = 7a6ca3b8-ee1b-489c-b300-24544a7bd418
MODULE_TYPE = UEFI_APPLICATION
VERSION_STRING = 1.0
ENTRY_POINT = ShellCEntryLib
[Sources]
ShellCTestApp.c
[Packages]
MdePkg/MdePkg.dec
ShellPkg/ShellPkg.dec
[LibraryClasses]
ShellCEntryLib
UefiLib
UEFI入口函数ShellCEntryLib
Shell应用程序的入口函数是ShellCEntryLib,它的原型在ShellPkg/Library/UefiShellCEntryLib/UefiShellCEntryLib.c下面:
EFI_STATUS
EFIAPI
ShellCEntryLib (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
###################################
Status = SystemTable->BootServices->OpenProtocol(ImageHandle,
&gEfiShellParametersProtocolGuid,
(VOID **)&EfiShellParametersProtocol,
ImageHandle,
NULL,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (!EFI_ERROR(Status)) {
//
// use shell 2.0 interface
//
ReturnFromMain = ShellAppMain (
EfiShellParametersProtocol->Argc,
EfiShellParametersProtocol->Argv
);
} else {
###################################
}
}
它的入参和标准应用程序的入参是一样的,它会去打开EFI_SHELL_PAEAMETERS_PROTOCOL,通过这个protocol获得ShellAppMain的入参,就是首先获取命令行参数,然后再调用用户的入口函数ShellAppMain去打开Shell。
使用main函数的应用程序工程模块
使用main函数的应用程序工程模块会使用StdLib,在StdLib中提供了ShellAppMain函数,我们自己实现main函数作为程序的入口函数供ShellAppMain去调用,真正的模块入口函数是ShellCEntryLib,调用过程是:ShellCEntryLib———>ShellAppMain——>main
使用main函数的应用程序工程模块要在AppPkg环境下才能编译成功,所以需要将main.inf添加到AppPkg.dsc文件的[Components]块下。
自己没遇到过这种,和shell应用程序工程模块用法一样
库模块
在开发uefi工程过程中,会使用到大量的库。库也有源文件、工程文件,其他模块要使用库,要将这个库添加到包的dsc声明文件中
UefiLib.inf:
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = UefiLib
MODULE_UNI_FILE = UefiLib.uni
FILE_GUID = 3a004ba5-efe0-4a61-9f1a-267a46ae5ba9
MODULE_TYPE = UEFI_DRIVER
VERSION_STRING = 1.0
LIBRARY_CLASS = UefiLib|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER SMM_CORE
CONSTRUCTOR = UefiLibConstructor
BaseDebugLibNull.inf:
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = BaseDebugLibNull
MODULE_UNI_FILE = BaseDebugLibNull.uni
FILE_GUID = 9ba1d976-0624-41a3-8650-28165e8d9ae8
MODULE_TYPE = BASE
VERSION_STRING = 1.0
LIBRARY_CLASS = DebugLib
可以看到库的工程文件和其他应用程序有很大的区别。没有ENTRY_POINT;它会指定 MODULE_TYPE是BASE函数DRIVER等类型;通过LIBRARY_CLASS设定库名,指定库的适用范围,让它仅能被特定的模块调用
其他模块要使用这个库,就将库添加到自己的dsc文件中:
[LibraryClasses]
UefiLib|MdePkg/Library/UefiLib/UefiLib.inf
然后在自己的inf中添加这个库:
[LibraryClasses]
UefiLib
然后在源文件中就可以使用这个库了
库如果要在使用之前需要初始化,那要在库的工程文件中指定CONSTRUCTOR和DESTRUCTOR
驱动模块
驱动和应用程序的最大区别就是驱动会常驻内存,而应用程序在执行完毕之后就会从内存中清除。
驱动类型
1、符合UEFI驱动模型的驱动,驱动模型是UEFI_DRIVER,称为UEFI驱动
2、不遵循UEFI驱动模型的驱动,包括类型:DXE_DRIVER、DXE_SAL_DRIVER、DXE_SMM_DRIVER、DXE_RUNTIME_DRIVER,称为DXE驱动
驱动
工程文件
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = UefiLib
MODULE_UNI_FILE = UefiLib.uni
FILE_GUID = 3a004ba5-efe0-4a61-9f1a-267a46ae5ba9
MODULE_TYPE = UEFI_DRIVER
VERSION_STRING = 1.0
LIBRARY_CLASS = UefiLib|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER SMM_CORE
CONSTRUCTOR = UefiLibConstructor
参考:UEFI原理与编程《戴正华》