BIOS/UEFI基础——FDF文件
综述
FDF的全称是Flash Description File。
它是构成BIOS二进制的描述符,即FDF文件描述了BIOS二进制的组成结构。
本文的目的就是介绍FDF文件内部的组成以及它们是如何完成对BIOS二进制的描述。
下面首先来看下BIOS二进制的大致结构:
上述的结构中有几个需要说明关键字,一个是FD(Flash Device binary image),它就是上述的整个大的镜像;一个是FV(Firmware Volumes),它是FD的组成模块,每一个模块有一个特定的功能,比如FVMAIN通常包含的是DXE、BDS阶段的代码,它通常是被压缩过得,FV Recovery包含SEC和PEI阶段的代码,等等;还有一个FFS(Firmware File System),它是FV内部的一个结构,用来表示各个Firmware的组成。
同时FD和FV也是FDF文件中的关键字,后面会继续介绍。
下面是FD创建的一个示意图:
本文主要参考自《edk-ii-fdf-specification.pdf》(以下简称参考文档)。
它可以在https://github.com/tianocore/tianocore.github.io/wiki/EDK-II-Specifications下载到。
本文中使用到的代码示例来自https://gitee.com/jiangwei0512/vUDK2017。
最后需要注意的一点是,这里只描述编译生成的BIOS二进制,而不是真正可以放到主板上的二进制(它还要保护ME等其它的二进制)。
语法
本节介绍FDF文件的大致语法。
基本语法
先简单介绍一些FDF中使用到的基本语法:
1. 注释使用#;
2. 赋值使用SET,而使用=表示的是TOKEN,是一种特殊的类似与常量的值;
3. 可以使用整型,布尔值,EFI_GUID等值;
4. $()获取DEFINE语句定义的宏的值;
基本语句
SET语句:对PCD进行赋值,如下所示:
SET gPlatformModuleTokenSpaceGuid.PcdFlashAreaBaseAddress = $(FLASH_AREA_BASE_ADDRESS)SET gPlatformModuleTokenSpaceGuid.PcdFlashAreaSize = $(FLASH_AREA_SIZE)
DEFINE语句:定义一个宏,如下所示:
DEFINE DEBUG_ENABLE_OUTPUT = FALSE # Set to TRUE to enable debug outputDEFINE DEBUG_PRINT_ERROR_LEVEL = 0x80000040 # Flags to control amount of debug outputDEFINE DEBUG_PROPERTY_MASK = 0
定义的宏可以通过$()来访问。注意DSC文件中也会使用DEFINE语句,且定义的宏可以在FDF文件中访问。
!if语句:判断语句,为TRUE时才包含其内部的组件,其语法如下:
!if $(MACRO)或者!if $(MACRO) == "Literal String"或者!if $(MACROALPHA) == $(MACROBETA)或者!if $(MACRONUM) == 数字或者!if $(MACROBOOL) == 布尔值
注意需要与!endif语句一起使用,中间也可以有!else语句。下面是例子:
!if $(SECURE_BOOT_ENABLE) # Signature: gEfiAuthenticatedVariableGuid = { 0xaaf32c78, 0x947b, 0x439a, { 0xa1, 0x80, 0x2e, 0x14, 0x4e, 0xc3, 0x77, 0x92 } } 0x78, 0x2c, 0xf3, 0xaa, 0x7b, 0x94, 0x9a, 0x43, 0xa1, 0x80, 0x2e, 0x14, 0x4e, 0xc3, 0x77, 0x92,!else # Signature: gEfiVariableGuid = { 0xddcf3616, 0x3275, 0x4164, { 0x98, 0xb6, 0xfe, 0x85, 0x70, 0x7f, 0xfe, 0x7d }} 0x16, 0x36, 0xcf, 0xdd, 0x75, 0x32, 0x64, 0x41, 0x98, 0xb6, 0xfe, 0x85, 0x70, 0x7f, 0xfe, 0x7d,!endif
其它类似的还有!ifdef语句和!ifndef语句。
以上是比较通用的语句,还有一些需要在特定的Section中使用的语句将在之后介绍。
Section
Section的大致格式如下:
[oo.xx.zz]
上述的代码描述中,oo是必选的,而xx、zz等需要根据oo的值来确定是否存在以及具体是什么。
Section是FDF文件中最重要的组件,因为它们将FDF文件分成了若干个部分,各个部分由不同的内容构成,最终组成整个FD。
下面就介绍这些常用的Section关键字。
[Defines]
这部分Section是可选的,里面放置到的东西一般用来放宏定义和变量,下面是一个例子:
[Defines] DEFINE BLOCK_SIZE = 0x1000DEFINE FW_BASE_ADDRESS = 0xFFF00000DEFINE FW_SIZE = 0x00100000 SET gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFdBaseAddress = $(FW_BASE_ADDRESS)SET gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFirmwareFdSize = $(FW_SIZE)SET gUefiOvmfPkgTokenSpaceGuid.PcdOvmfFirmwareBlockSize = $(BLOCK_SIZE)
[FD]
关于FD这种Section关键字在之前也已经提到,它表示了一个完整的BIOS镜像。
一个FDF文件里面可以有多个FD。
[FD]关键字中的FD之后还可以接一个后缀,格式如下:
[FD.FdUiName]
这里的FdUiName表示FD的名称,可以是随意的值。
当FDF文件中只存在一个[FD] Section的时候,这个FdUiName是可选的,如果不选,则使用定义在[Defines]中的PLATFORM_NAME作为名称。
[FD]中包含若干个TOKEN,它们是几个有特殊意义的变量,如下所示:
BaseAddress:表示FD的基址,它是设备开机之后BIOS被加载到系统中的位置;
Size:表示FD的大小,单位是字节;
ErasePolarity:表示的是用1还是0擦Flash,目前基本上都是1;
BlockSize:表示Flash中一个Block的大小,一般就是4K,64K等;
NumBlocks:表示Flash中Block的个数,通常就是Size除以BlockSize;
[FD]中另外包含的一个重要的内容是FD的布局,它的结构如下:
Offset|Size[TokenSpaceGuidCName.PcdOffsetCName | TokenSpaceGuidCName.PcdSizeCName] ?[RegionType] ?
该定义在FD中开辟了一段空间,用来放置某些内容,比如FV之类的。
Offset和Size是这段空间的对于整个FD的偏移和大小;
Pcd是可选的,其实就是初始化了PCD来表示这段空间偏移和大小供后续使用,并不是必须的,它更像是C语言中的宏,你只需要设置一次,就可以在FDF文件的各处使用;
RegionType表示这段空间的类型,可以是FV、DATA、FILE、INF和CAPSULE等内容,也不是必须的,如果没用定义则表示这段空间不能去动它,它是有其它用处的,会有其它的机制(比如非易失日志)用到;
下面是一个例子:
[FD.OVMF_CODE]BaseAddress = $(CODE_BASE_ADDRESS)Size = $(CODE_SIZE)ErasePolarity = 1BlockSize = $(BLOCK_SIZE)NumBlocks = $(CODE_BLOCKS) 0x00000000|$(FVMAIN_SIZE)FV = FVMAIN_COMPACT$(FVMAIN_SIZE)|$(SECFV_SIZE)FV = SECFV ################################################################################ [FD.MEMFD]BaseAddress = $(MEMFD_BASE_ADDRESS)Size = 0xB00000ErasePolarity = 1BlockSize = 0x10000NumBlocks = 0xB0 0x000000|0x006000gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesSize 0x006000|0x001000gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageSize
上面的例子中使用了FV这个RegionType,这里再详细说明下所有的RegionType:
FV:使用的格式如下:
FV = UiFvName
这里的UiFvName是在[FV]这个Section中定义的。
DATA:使用的格式如下:
DATA = {xx}
xx可以是16进制的字节数组,下面是一个例子:
0x0058e000|0x00002000gEmulatorPkgTokenSpaceGuid.PcdEmuFlashNvStorageFtwWorkingBase|gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize#NV_FTW_WORKINGDATA = { # EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER->Signature = gEdkiiWorkingBlockSignatureGuid = # { 0x9e58292b, 0x7c68, 0x497d, { 0xa0, 0xce, 0x65, 0x0, 0xfd, 0x9f, 0x1b, 0x95 }} 0x2b, 0x29, 0x58, 0x9e, 0x68, 0x7c, 0x7d, 0x49, 0xa0, 0xce, 0x65, 0x0, 0xfd, 0x9f, 0x1b, 0x95, # Crc:UINT32 #WorkingBlockValid:1, WorkingBlockInvalid:1, Reserved 0xE2, 0x33, 0xF2, 0x03, 0xFE, 0xFF, 0xFF, 0xFF, # WriteQueueSize: UINT64 0xE0, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
xx还可以是一个!include语句,用来包含外部的数据,下面是一个例子:
0x0CA000 | 0x002000gEfiMyTokenSpaceGuid.PcdFlashNvStorageBase | gEfiMyTokenSpaceGuid.PcdFlashNvStorageSizeDATA = { !include NvStoreInit.txt}
FILE:它指向一个二进制文件,生成FD的之后这个二进制文件就会被包含进来,使用格式如下:
FILE = $(FILE_DIR)/Filename.bin
下面是一个例子:
0x00000000|0x00000200FILE = BeagleBoardPkg/ConfigurationHeader.bin
CAPSULE:使用的格式如下:
CAPSULE = UiCapsuleName
其中的UiCapsuleName是[Capsule] Section的名称。
INF:[FD]中还可以直接包含INF文件,格式如下:
INF [Options] PathAndInfFileName
INF定义在该处并不是完整的,它的类型还需要在其它地方定义。
关于直接放在[FD]中的INF的意义目前不是很清楚。
这里的Options会在[FV]章节介绍。
除了上述的内容,[FD]中也是可以包含DEFINE和SET设置的宏和变量。
[FV]
FV的主要作用就是包含组件和模块,它的格式如下:
[FV.UiFvName]
UiFvName是自定义的名称,在FD中会用到,它在文件中必须是唯一的。
FV是可以嵌套的,FV中也可以通过UiFvName来包含另外一个FV。
下面介绍[FV] Section中包含的内容:
[FV]的最开始是几个TOKEN,如下是一个例子:
[FV.STAGE1A] BlockSize = $(FLASH_BLOCK_SIZE) FvAlignment = 16 ERASE_POLARITY = 1 MEMORY_MAPPED = TRUE STICKY_WRITE = TRUE LOCK_CAP = TRUE LOCK_STATUS = TRUE WRITE_DISABLED_CAP = TRUE WRITE_ENABLED_CAP = TRUE WRITE_STATUS = TRUE WRITE_LOCK_CAP = TRUE WRITE_LOCK_STATUS = TRUE READ_DISABLED_CAP = TRUE READ_ENABLED_CAP = TRUE READ_STATUS = TRUE READ_LOCK_CAP = TRUE READ_LOCK_STATUS = TRUE
其次[FV]中也可以使用DEFINE和SET来定义宏和变量。
再其次,对于并非实际使用到Flash上的BIOS,还需要设置BLOCK_SIZE和NUM_BLOCKS,这些这边不关注。
然后介绍[FV] Section中最基本的元素INF语句,其格式如下:
INF [Options] PathAndInfFileName
其中PathAndInfFileName就是一个普通的inf文件,Options是可选项,主要有以下的一些:
RuleOverride = RuleName
表示当前INF的RULE,关于RULE,之后会在[Rule] Section中说明,RuleName是该Seciton的名称。每一个[FV]中的inf都有一个默认的RULE,这里就是覆盖默认的RULE,而使用这里提供的RULE。
USE = ARCH
表示该INF对应的架构,这个用的不多。
VERSION = "String"
该选项会在FFS中创建一个EFI_SECTION_VERSION Section。
UI = "String"
与VERSION类似,会创建一个EFI_SECTION_USER_INTERFACE Section。
与INF相关的一个元素是APRIORI语句,它指定了INF的执行顺序,下面是一个例子:
APRIORI DXE { INF MdeModulePkg/Universal/DevicePathDxe/DevicePathDxe.inf INF MdeModulePkg/Universal/PCD/Dxe/Pcd.inf!if $(SMM_REQUIRE) == FALSE INF OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf!endif}
[FV]中可以直接包含文件,使用的是FILE语句,格式如下:
FILE Type $(NAMED_GUID) [Options] FileName或者FILE Type $(NAMED_GUID) [Options] {SECTION SECTION_TYPE = FileNameSECTION SECTION_TYPE = FileName}
文件有很多的类型(Type),之类介绍常用的:
RAW:普通的二进制;
FREEFORM:有EDK支持的分区的二进制;
FV_IMAGE:这就这里介绍的[FV];
DRIVER:包含一个DXE阶段的驱动;
等等。
NAMED_GUID是表示这个文件的唯一的标记,我们可以在代码中通过这个GUID获取文件。
Options有如下可用的值:Fixed、Alignment和Checksum等,这里不一一介绍。
下面是FILE语句的例子:
FILE FREEFORM = PCD(gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdLogoFile) { SECTION RAW = MdeModulePkg/Logo/Logo.bmp}
FILE DRIVER = 5D695E11-9B3F-4b83-B25F-4A8D5D69BE07 { SECTION PE32 = Intel3.5/EFIX64/E3507X2.EFI}
从上述的例子中可以看到FILE语句下还可以包含SECTION语句,它表示了对指定文件的封装,关于SECTION语句的格式已经在前面介绍过,但是并完全,SECTION语句有很多不同的格式,这里不一一介绍,可以参考《edk-ii-fdf-specification.pdf》。
[Capsule]
CAPSULE是一个可选的Section,它的作用不太好描述,这里直接贴上参考文档上的说明:
[Capsule]的格式如下:
[Capsule.UiCapsuleName]
其中的UiCapsuleName可以是任意的名称。
[Capsule]最开始包含的是几个TOKEN:
CAPSULE_GUID:用来标记这个CAPSULE;
CAPSULE_FLAGS:目前有三个Flag,分别是PersistAcrossReset、InitiateReset和PopulateSystemTable,具体的意义参考文档上没有说明。
[Capsule]里面也可以有SET语句,INF语句和FILE语句,与之前的语法一致。
[Rule]
这个Section用来描述FFS文件的构成,FFS文件就是通过INF文件编译得到,然后组成二进制,而组成如何的二进制,就是通过[Rule]来构成的。[Rule]的格式如下:
[Rule.ARCH.MODULE_TYPE.TEMPLATE_NAME]
下面是几个例子:
[Rule.Common.SEC] FILE SEC = $(NAMED_GUID) { PE32 PE32 $(INF_OUTPUT)/$(MODULE_NAME).efi UI STRING ="$(MODULE_NAME)" Optional VERSION STRING ="$(INF_VERSION)" Optional BUILD_NUM=$(BUILD_NUMBER) } [Rule.Common.PEI_CORE] FILE PEI_CORE = $(NAMED_GUID) { PE32 PE32 Align=Auto $(INF_OUTPUT)/$(MODULE_NAME).efi UI STRING ="$(MODULE_NAME)" Optional VERSION STRING ="$(INF_VERSION)" Optional BUILD_NUM=$(BUILD_NUMBER) } [Rule.Common.PEIM] FILE PEIM = $(NAMED_GUID) { PEI_DEPEX PEI_DEPEX Optional $(INF_OUTPUT)/$(MODULE_NAME).depex PE32 PE32 Align=Auto $(INF_OUTPUT)/$(MODULE_NAME).efi UI STRING="$(MODULE_NAME)" Optional VERSION STRING="$(INF_VERSION)" Optional BUILD_NUM=$(BUILD_NUMBER) }
其内部是一个FILE语句,它跟之前在FV中使用的FILE语句结构是一样的。
此外还有[VTF]、[OptionRom]等Section,因为用的不多,这里不再介绍。
---------------------
作者:jiangwei0512
来源:CSDN
原文:https://blog.csdn.net/jiangwei0512/article/details/83685694
版权声明:本文为博主原创文章,转载请附上博文链接!
BIOS/UEFI基础——FDF文件相关推荐
- BIOS/UEFI基础——Protocol介绍
简要说明 Protocol是UEFI中的一个重要概念(事实上<UEFI SPEC>中有超过70%的内容都是在讲Protocol),下面简单说明下: 1. 首先,非常重要的一点,Protoc ...
- UEFI原理与编程第二章学习- .dsc .dec .fdf文件与包
.dsc .dec .fdf文件及包 上一篇介绍了 .inf文件, .inf文件相当于Visual Studio中的工程文件.而 .dsc(Platform Description File)则 ...
- EDK环境搭建UEFI工程模块文件介绍
一.UEFI开发环境配置 UEFI开发环境目前支持Windows,Linux,支持的平台也有很多如Intel, AMD,ARM等. 下面主要是介绍如何在windows环境下进行EDK开发. 1.获取E ...
- uefi多linux系统启动盘,DIY制作无需格BIOS+UEFI双启动U盘工具|支持syslinux+grub+boomgr+grub2多启动...
如果你想让你的U盘可启动的话,要怎么做呢,可能很多人都知道借助软件能自动实现,但那些方式都需要把U盘格式化一遍,而这个工具完全不需要,只需要把下载的文件解压到U盘根目录就能实现多启动了,支持bios和 ...
- 【UEFI基础】EDK编译生成的二进制的结构
综述 EDK代码经过编译后,会得到如下的二进制(当然还有很多中间文件,这里并不关注): xxx.Fd xxx.Fv xxx.efi 比如在编译OVMF的时候,会生成如下的文件(具体的编译方法可以参考[ ...
- deepin efi 启动u盘_【2017.12.16】启动U盘简单手动制作BIOS+UEFI的syslinux/grub/boomgr/grub2互转...
本帖最后由 lintrainwy 于 2018-1-4 15:05 编辑 文件和方法来源于网上,本人做了整合,方便U盘启动 1.BIOS方式下,这个U盘启动是syslinux 6.03+grub4do ...
- UEFI 基础教程 (一) - 运行第一个APP HelloWorld
UEFI 基础教程 (二) - 运行第一个APP HelloWorld 一.代码编写: 1.edk2/OvmfPkg/HelloWorld/HelloWorld.c: #include <Uef ...
- Grub2 引导 WIM / Slax Linux (BIOS UEFI)
文章目录 Grub2 引导 WIM / Slax Linux (BIOS & UEFI) 安装Grub2到U盘 / 硬盘 1. 准备分区格式 2.安装Grub2 3.复制Grub2 配置文件和 ...
- 天意u盘启动盘安装linux,(BIOS+UEFI双启WINPE)天意u盘维护系统技术员版V2.1
大家应该注意到了,最新的笔记本电脑都改成了UEFI而不是我们以前的bios启动了. 所以天意老师出了这个UEFI+bios双启版,修改于ISO全能版. 去掉了linux.dos菜鸟工具箱:去掉了软件工 ...
最新文章
- java helloworld代码_java学习应用篇|逃不掉的HelloWorld
- Python学习之GUI--SQL数据库连接
- 用MXnet实战深度学习之一:安装GPU版mxnet并跑一个MNIST手写数字识别 (zz)
- express 配置支持https
- 数据科学学习心得_学习数据科学时如何保持动力
- React Native与React的关系及特点
- android listview item 展开动画,android的ListView点击item使item展开的做法的实现代码
- 【vue.config.js配置configureWebpack的optimization splitChunks页面空白 - DCloud】
- c语言程序设计多个文件,c语言如何单文件变多文件(2个文件),求大神帮忙!!...
- springcloud整合nacos启动时报错‘com.netflix.client.config.IClientConfig‘ that could not be found
- 二总线 XM2BUS 通信 消防 串口 开发 CMBUS MBUS 中继 电源无极性
- STM32移植MPU6050/9250的DMP官方库(motion_driver_6.12)修改移植 DMP简单使用教程
- linux mono安装,Linux下Nginx + mono安装与配置
- 用户画像,原来是这么用的!看一个生活中的案例
- Spring学记笔记
- Python在cmd上打印彩色文字
- .git文件泄露的一次渗透darkhole2
- MySQL 基础知识入门教程
- 【论文阅读|深读】LINE: Large-scale Information Network Embedding
- 要求实现学生信息查找添加修改浏览保存从文件读取功能c语言,[c语言作业题目.doc...