应用模块
应用模块包含标准应用程序模块,shell应用程序模块,以及main应用程序模块
标准应用程序模块
它是所有其他应用程序模块的基础,作为一个模块来说,同样由源文件和工程文件(.inf)组成。
它的特征如下:(1) .inf中的ENTRY_POINT一般设置为UefiMain,这是一个约定俗称的名字,所以这个规则并不是一定的。 (2) 指定的ENTRY_POINT入口函数必须要在模块源文件中有对应的实现。 (3).inf中的MODULE_TYPE必须设置为UEFI_APPLICATION
例如:
[Defines] INF_VERSION = 0x00010006 BASE_NAME = TestApp FILE_GUID = 7C04A583-9E3E-4f1c-AD65-E05268D0B4D1 MODULE_TYPE = UEFI_APPLICATION VERSION_STRING = 1.0 ENTRY_POINT = UefiMain
shell应用程序模块
故名思意,这是一种方便在uefi shell环境中执行的应用程序模块,可以方便的处理shell传入的命令行参数。
它的特征如下:(1) ENTRY_POINT必须设置为ShellCEntryLib (2) MODULE_TYPE必须设置为UEFI_APPLICATION (3) [Packages]中需要引用MdePkg和ShellPkg这两个包 (4) [LibraryClasses]中必须依赖ShellCEntryLib (5) 源文件中必须要定义函数EFIAPI ShellAppMain (IN UINTN Argc, IN CHAR16 **Argv)
例如:
[Defines] INF_VERSION = 0x00010006 BASE_NAME = Hello FILE_GUID = a912f198-7f0e-4803-b908-b757b806ec83 MODULE_TYPE = UEFI_APPLICATION VERSION_STRING = 0.1 ENTRY_POINT = ShellCEntryLib # VALID_ARCHITECTURES = IA32 X64 IPF [Sources] Hello.c [Packages] MdePkg/MdePkg.dec ShellPkg/ShellPkg.dec [LibraryClasses] UefiLib ShellCEntryLib
这类模块的运行都是从ShellCEntryLib开始,这个函数是在ShellCEntryLib中实现的,在其中会调用一个名为ShellAppMain的函数,这也就是为什么我们需要在源文件中必须实现ShellAppMain的原因。
main应用程序模块
熟悉C语言的应该都知道此函数,UEFI中也支持这种类型的应用程序模块,但是这种类型的模块需要依赖libc库。特征如下:(1) ENTRY_POINT必须设置为ShellCEntryLib。 (2) MODULE_TYPE必须设置为UEFI_APPLICATION (3) [Packages]中除了引用MdePkg和ShellPkg这两个包之外,还有StdLib包 (4) [LibraryClasses]中必须依赖ShellCEntryLib,LibC和LibStdio库 (5) 源文件中必须要定义main函数,和普通的C语言编程定义的格式一样。
库模块
一个大型工程中肯定缺少不了库,库作为一个公用模块,能够极大的复用代码,提高开发效率,UEFI中同样支持库模块,它的特征如下:
(1) MODULE_TYPE必须设置为BASE
(2) 必须要定义LIBRARY_CLASS为库名
(3) 不要设置入口函数ENTRY_POINT
驱动模块
驱动分为两种类型,一种为UEFI驱动,另一种为DXE驱动。UEFI驱动是符合UEFI驱动模型的一种模块,框架定义了如何驱动硬件以及如何提供服务(Protocol的绑定)。而DXE驱动主要是用于实现一些特殊功能的模块,简化驱动的开发,比如我们想仅仅提供一种服务,而不驱动硬件,那么可以采用DXE驱动的形式来简化此功能的实现。在UEFI中,驱动模块和应用模块都运行在同一个地址空间,不像Linux分为应用空间和内核空间,它们最大的区别是:应用程序只在运行时存在于内存在,而驱动是常驻内存的。所以对于一个服务来说,我们需要它常驻内存就必须通过驱动的方式来安装。
UEFI驱动和DXE驱动的最大区别是UEFI驱动需要按照UEFI定义的框架来实现一个驱动,而DXE驱动没有这个限制,更加自由,比如我们仅仅想提供一个服务,那么只需要在DXE驱动的ENTRY_POINT中去实现Procotol即可,而如果要通过UEFI驱动实现,当然是可以的,只是会稍微复杂一些。
它的特征如下:
(1) 它也有ENTRY_POINT入口函数,并且在驱动load时执行此入口函数,该函数需要在源文件中定义
(2) MODULE_TYPE被设置为UEFI_DRIVER或者DXE_DRIVER
(3) [LibraryClasses]块中必须要包含UefiDriverEntryPoint
Protocol
Protocol在UEFI是一个很重要的概念,它可以认为是一个服务,一个service和client之间的接口,通过上文,我们已经了解到,服务是需要常驻内存的,那么一般Protocol是实现在UEFI驱动模块和DXE驱动模块中的。当驱动模块作为Protocol的服务提供者加载以后,那么应用程序就可以作为客户端来使用此服务了。BootService提供了InstallProtocolInterface和OpenProtocol相关的一些操作。