包及.dsc、.dec、.fdf文件
前言
前面的文章中比较详细介绍了UEFI工程文件即.inf
。UEFI的包中一般都会包含一个.dsc
文件和一个dec
文件。在包生成固件Image、Option Rom Image,这个包还要包含.fdf
文件。.fdf
用于生成固件Image、Option Rom Image或可以启动Image。
- build 命令用于编译包,它需要一个
.dsc
文件,一个.dec
文件和一个或多个.inf
文件。 - GenFW 命令用于制作固件或Option Rom Image,它需要一个
.dec
文件和一个.fdf
文件。
一、.dsc文件
.inf
用于编译一个模块,而.dsc
用于编译一个Package。.dsc
文件也是包括必需部分:[Defines],[LibraryClasses],[Components]和可选部分[PCD],[BuildOptions]等。
1. 必需部分
- [Defines]块
[Defines]用于设置build相关的全局变量,这些变量可以被.dsc
文件的其它模块引用。[Defines]必须是.dsc
文件的第一个部分,格式如下:
[Defines]
宏变量名 = 值
DEFINE 宏变量名 = 值
EDK_GLOBAL 宏变量名 = 值
[Defines]中通过FEFINE和EDK_GLOBAL定义的宏可以在.dsc
文件和.fdf
文件中通过$
(宏变量名)使用。
表3-4,表3-5 分别表示[Defines]必需变量和非必须变量。
注:截图来源《UEFI原理与编程》第三章。
// /EDK2/ShellPkg/ShellPkg.dsc 示例
[Defines]PLATFORM_NAME = ShellPLATFORM_GUID = E1DC9BF8-7013-4c99-9437-795DAA45F3BDPLATFORM_VERSION = 1.0DSC_SPECIFICATION = 0x00010006OUTPUT_DIRECTORY = Build/ShellSUPPORTED_ARCHITECTURES = IA32|IPF|X64|EBC|ARM|AARCH64BUILD_TARGETS = DEBUG|RELEASESKUID_IDENTIFIER = DEFAULT
- [LibraryClasses]块
在[LibraryClasses]块定义了库的名字以及库.inf
的路径。这些库可以被[Components]块内的模块引用。
- 语法
[LibararyClasses.$
(Arch).$
(MODULE_TYPE)]
LibraryName | path/LibraryName.inf
另外还可以使用结构
[LibararyClasses.$
(Arch1).$
(MODULE_TYPE1),LibararyClasses.$
(Arch1).$
(MODULE_TYPE1)]
LibraryName | path/LibraryName.inf
$Arch
和$MODULE_TYPE
是可选项。不使用表示通用。$Arch
表示体系结构,可以是下列值之一:IA32,X64,IPF,EBC,ARM,common。common表示对所有体系结构有效。$MODULE_TYPE
表示模块的类别,块内列出的库只能提供$(MODULE_TYPE)
类别的模块连接。它可以是下列值:SEC
、PEI_CORE
、PEIM
、DEX_CORE
、DEX_SAL_DRIVER
、BASE
、DXE_SMM_DRIVER
、DXE_DRIVER
、\DXE_RUNTIME_DRIVER
、UEFI_DRIVER
、UEFI_APPLICATION
、USER_DEFINED
。
- 示例
- 语法
[LibraryClasses.common]
UefiApplicationEntryPoint|MdePkg/Library/UefiApplicationEntryPoint/UefiApplicationEntryPoint.inf
···
[LibraryClasses.ARM]
NULL|ArmPkg/Library/CompilerIntrinsicsLib/CompilerIntrinsicsLib.inf
···
[LibraryClasses.AARCH64]
NULL|ArmPkg/Library/CompilerIntrinsicsLib/CompilerIntrinsicsLib.inf
···
- [Components]块
该区域块内定义的模块都会被build工具编译并生成.efi文件,格式如下:
[Components]
path\Exectuables.inf
或者
[Components]
path\Exectuables.inf{
< LibraryClasses> # 做嵌套
LibraryName | Path/LibraryName.inf
< BuildOptions> # 嵌套块
#字块中还可以包含< Pcds*>
}
注意,path使用相对于EDK2根目录的相对路径。
示例:
[Components]
···
ShellPkg/Library/UefiDpLib/UefiDpLib.inf {< LibraryClasses>TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.infPerformanceLib|MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.infDxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf···}
2. 非必须部分
- [BuildOption]块
此部分和.inf
中的用法大致相同,可以翻阅前面的文章查看。 - [PCD]块
[PCD]块用于定义平台配置数据。它的目的是在不改动.inf
文件的情况下完成对平台的配置。
- 举例:在UEFI模拟器Nt32Pkg的
.dsc
文件Nt32Pkg.dsc中,可以通过PCD的PcdWinNtFileSystem来配置模拟器的文件系统路径。
- 举例:在UEFI模拟器Nt32Pkg的
gEFINt32PkgTokenSpaceGuid.PcdWinNtFileSystem | \
L".!..\..\..\..\EdkShellBinPkg\Bin\Ia32\Apps"|VOID*|106
数线|
将配置分为了四个部分,第一部分名字的空间,第二部分是值,第三部分是变量法类型,第四部分是变量数据的最大长度。在源文件中可以使用LibPcdGetPtr(_PCD_TOKEN_PcdWinNtFileSystem)
获得gEfiNt32PkgTokenSpaceGuid.PcdWinFileSyste
定义的值。
二、.dec文件
.dec文件定义了公开的数据和接口,供其他模块使用。它包含了必需区块[Defines]以及可选区块[Includes]、[LibraryClasses]、[Guids]、[Protocol]、[Ppis]和[PCD]几个部分。
1.[Defines]块
[Defines]块用于提供Package的名称、GUID、版本号等信息。
## /EDK2/MdePkg/MdePkg.dec
[Defines] DEC_SPECIFICATION = 0x00010005 PACKAGE_NAME = MdePkg PACKAGE_UNI_FILE = MdePkg.uni PACKAGE_GUID = 1E73767F-8F52-4603-AEB4-F29B510B6766 PACKAGE_VERSION = 1.06
2.[Includes]块
列出本Package提供的头文件所在的目录
格式:
[Includes.$(Arch)]
path
## /EDK2/MdePkg/MdePkg.dec
[Includes]Include[Includes.IA32]Include/Ia32[Includes.X64]Include/X64[Includes.IPF]Include/Ipf[Includes.EBC]Include/Ebc[Includes.ARM]Include/Arm[Includes.AARCH64]Include/AArch64
3.[LibraryClasses]块
Package可以通过.dec
文件对外提供库,每个库都必须有一个头文件,放在Include\Library目录下。本区块用于明确库和头文件的对应关系。格式:
[LibraryClasses.$(Arch)]
LibraryName | Path/LibraryHeader.h
## /EDK2/MdePkg/MdePkg.dec
[LibraryClasses]## @libraryclass Provides most usb APIs to support the Hid requests defined in Usb Hid 1.1 spec# and the standard requests defined in Usb 1.1 spec.##UefiUsbLib|Include/Library/UefiUsbLib.h## @libraryclass Provides a service to retrieve a pointer to the EFI Runtime Services Table.# Only available to DXE and UEFI module types.UefiRuntimeServicesTableLib|Include/Library/UefiRuntimeServicesTableLib.h
···
4.[Guids]块
在Package\Include\Guid目录中有很多文件,每个文件内定义了一个或几个GUID
## /EDK2/MdePkg/Include/Guid/Gpt.h
extern EFI_GUID gEfiPartTypeUnusedGuid;
extern EFI_GUID gEfiPartTypeSystemPartGuid;
extern EFI_GUID gEfiPartTypeLegacyMbrGuid;
这些定义只是声明,常量真正定义在AutoGen.c中,它的值定义在.dec文件的[Guids]区块。
## /EDK2/MdePkg/MdePkg.dec
[Guids]
## Include/Guid/Gpt.hgEfiPartTypeLegacyMbrGuid = { 0x024DEE41, 0x33E7, 0x11D3, { 0x9D, 0x69, 0x00, 0x08, 0xC7, 0x81, 0xF3, 0x9F }}## Include/Guid/Gpt.hgEfiPartTypeSystemPartGuid = { 0xC12A7328, 0xF81F, 0x11D2, { 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B }}## Include/Guid/Gpt.hgEfiPartTypeUnusedGuid = { 0x00000000, 0x0000, 0x0000, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}
当在模块工程文件的[Guids]中引用这些Guid时,这些值就会复制到AutoGen.c中。
5.[Protocols]块
与Guids类似,在Package\Include\Protocols目录下有很多头文件,每个头文件定义了一个或多个Protocol,这些Protocol的GUID值就定义在.dec文件的[Protocols]区块。
在MdePkg\Include\Protocol 目录下的BlockIo.h定义了BlockIo Protocol。
extern EFI_GUID gEfiBlockIoProtocolGuid;
gEfiBlockIoProtocolGuid 的值就定义在MdePkg.dec 的[Protocols]块内
## Include/Protocol/BlockIo.h
gEfiBlockIoProtocolGuid = { 0x964E5B21, 0x6459, 0x11D2, { 0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B }}
6.其它块
- [Ppis]用于定义源文件中用到的PPI(PPI是PEI阶段PEI模块之间通信的接口),语法类似于Protocol。
- [PCD]块是.dsc文件中[PCD]块的补充。
三、总结
本部分比较详细的介绍了.dec和.dsc文件结构和其起到的作用。对这两个文件的操作是编写UEFI程序过程中必不可少的一部分,有必要了解它们。
参考资料
- 《UEFI原理与编程》 戴正华 著。
- UEFI Spec2_6。
- EDKII GitHub