UEFI - FV/FFS/FDF 的关系

目录

  • [1. 什么是固件卷](#1. 什么是固件卷)
  • [2. 是么是 FFS 文件](#2. 是么是 FFS 文件)
  • [3. 什么是 FDF 文件](#3. 什么是 FDF 文件)

一、UEFI 固件卷

如果一个磁盘是没有经过分区的简单状态并且没有文件系统的话是什么样的,所有的文件扁平化的分布在整个磁盘空间,没有组织逻辑,没有文件夹等等,这不是一个理想的状态。固件卷的概念就类似于磁盘分区,它是 UEFI 固件中用于存放各种固件文件,即FFS 文件的容器。里面按规定组织了各种 UEFI 文件。比如:DXE 驱动(.efi)、PEI 模块、微码(microcode)、配置数据、ACPI 表、变量存储区、Logo 图片等资源。

在 UEFI 固件镜像中,所有模块都必须放进某个 FV 里才能被固件识别和加载。一个 FV 里都放什么内容一般按照功能决定。UEFI 固件镜像通常由多个 FV 组成,例如典型分布:

text 复制代码
+----------------------------+
| SEC/PEI FV                 |
+----------------------------+
| DXE FV                     |
+----------------------------+
| NVRAM FV                   |
+----------------------------+
| Microcode FV               |
+----------------------------+

不同厂商的分布不一样,但通常有两类:

  • Boot FV:存放 SEC/PEI/DXE 核心模块 → 固件启动必须依赖。

  • Runtime / Data FV:放 ACPI 表、变量存储区域、Logo、微码等资料。

那么在 EDKII 工程中 FV 文件是怎么组织和生成的呢?

先说结论,EDKII 用 FDF 文件 描述要生成哪些 FV,典型的 FDF 文件如下:

FDF 复制代码
[FV.FVMAIN]
FvAlignment = 16
BLOCKSIZE  = 0x10000

INF  MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
INF  MdeModulePkg/Core/Dxe/DxeMain.inf
FILE RAW {
    Microcode/Microcode.bin
}

根据这个 FDF 文件,EDKII 在编译时会把.inf 描述的模块编译出的 .efi,还有.bin.raw以及其他资源文件全部打包进 FV 中。最终生成的 FV 会被合并成 *.fd 或最终固件镜像(BIOS ROM)。

在第一章开发环境搭建和第二章 EDKII 工程目录介绍中有涉及到 QEMU 虚拟机所用的 OVMF.fd 固件的编译。EDKII 工程下的OVMF 目录如下

sh 复制代码
OvmfPkg/
├── OvmfPkgX64.dsc   # 平台描述文件
├── OvmfPkgX64.fdf   # 镜像布局文件
├── PlatformDxe/     # 平台初始化驱动
├── Include/
└── Library/

OvmfPkg 目录就是我们要开发的平台的固件的相关内容,如果我们有自己的板U平台,可自己创建 xxxPkg 目录,里面要放平台描述文件和镜像布局文件,有关dsc文件在第二章中有讲。fdf文件就是上文中提到的定义要生成的 FV 文件。

二、FFS 文件

平时咱们磁盘里的文件夹中能够存放各种各样的文件,txt、exe等等,但是 FV 不行,它里面只能存放 FFS 文件。FFS 可以理解为专门给固件使用的一种文件格式,它是对模块本身加上特定信息的封装,有点类似于网络中的数据报,里面放了目标数据,但是因为要遵循特定的协议,需要进行封装。具体来说,FFS 文件的内容包括

  • 文件头(File Header):标识该模块是什么

  • 文件体(File Body):模块本身(通常是 PE32/PE32+ 的 .efi 文件)

  • 文件区块(Section):每个 Section 是一种数据类型

text 复制代码
┌─────────────────────────┐
│     FFS File Header     │  →  文件类型、GUID、校验等信息
├─────────────────────────┤
│   Section 1: PE32       │  →  模块的代码 (.efi)
├─────────────────────────┤
│   Section 2: UI Name    │  →  模块名字
├─────────────────────────┤
│   Section 3: DEPS       │  →  依赖信息
└─────────────────────────┘

常见 FFS 文件类型有

类型 用途
PEI Module PEI 阶段模块
DXE Driver DXE 驱动
RAW 原始数据,如 microcode 或 logo
FREEFORM 自定义数据块
PEI/DXE Combo 既可在 PEI 又可在 DXE 使用

三、FDF 文件

FDF 是 EDK2 编译固件时用的 固件布局描述文件。比如 OVMF 目录下

sh 复制代码
OvmfPkg/
├── OvmfPkgX64.dsc   # 平台描述文件
├── OvmfPkgX64.fdf   # 镜像布局文件
├── PlatformDxe/     # 平台初始化驱动
├── Include/
└── Library/

OvmfPkgX64.fdf 就是 OVMF 固件对应的布局描述文件。它告诉编译器要生成哪些 FV,每个 FV 里放哪些 FFS 文件,最终 Firmware 镜像如何组合。如果没有 FDF,EDK2 就不知道怎么把模块打包成一个固件 ROM。它描述了ROM 大小、地址、有哪些 Firmware Volume(FV)、 各 FV 装哪些模块(INF、BIN、Raw)、 微码、ACPI、NVRAM 等放在哪、 最终如何拼成固件镜像(FD)。前面我们已经给出了一个 FDF 文件的例子,这里再举一个简单的例子来说明

FDF 复制代码
[FV.FVMAIN]
INF  MdeModulePkg/Core/Dxe/DxeMain.inf
INF  MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf

FILE RAW {
    Microcode/Microcode.bin
}

[FV.FVMAIN]:定义一个名字叫 FVMAIN 的 Volume

INF ...:把某个 UEFI 模块(通过 INF 编译)打包进来

FILE RAW:加入一个原始文件,比如 microcode

最终这些内容会被打包成:FVMAIN.FV → 固件卷,并且会放入最终的固件镜像中。比如

sh 复制代码
~/edk2/Build/OvmfX64/DEBUG_GCC5/FV/OVMF.fd

FV 文件也会单独存在,比如

sh 复制代码
~/edk2/Build/OvmfX64/DEBUG_GCC5/FV/xxx.FV

简单描述 FV,FDS,FFS三者之间的关系

lua 复制代码
INF 文件 → 编译 → 生成 EFI 模块 → 封装成 FFS 文件 → 打包进 FV → 合并成最终固件镜像(FD)
                     ↑                                ↑
                 FDF 决定怎么打包  ←--------------------+

+-------------+      +-----------+      +-----------+      +--------+
| .inf 文件   | ---> | .efi 文件 | ---> | .ffs 文件 | ---> |  FV    |
+-------------+      +-----------+      +-----------+      +--------+
                                                             ↑
                                                             |
                                                        FDF 决定布局

上一章对 PEIM 进行了介绍,PEI 核心会扫描固件卷中的 PEIM 并逐个执行,因此再举个 PEIM 的例子:

复制代码
EDK2 源码
└── DxeIplPeim.inf
    └── DxeIplPeim.c
        ↓ 编译
       DxeIplPeim.efi
        ↓ 封装
       DxeIplPeim.ffs
        ↓ 打包进 FV(由 FDF 决定)
       PEIFV.FV
        ↓ 合并多个 FV → 最终 ROM
       OVMF.fd(就是固件 BIOS)

FV 文件内部包含多个 FFS 文件,如

复制代码
PEIFV.FV
 ├── PeiMain.ffs
 ├── DxeIplPeim.ffs
 ├── LoadFilePei.ffs
 ├── PeiCore.ffs
 └── ...

Steady Progress!

相关推荐
2401_853448235 小时前
学习FreeRTOS(第四天)
单片机·嵌入式·freertos
大聪明-PLUS10 小时前
编程语言保证是安全软件开发的基础
linux·嵌入式·arm·smarc
阿源-1 天前
UEFI-PEI 阶段的深层介绍
嵌入式·uefi·x86·edk2·固件
切糕师学AI1 天前
SWD(Serial Wire Debug,串行线调试)
嵌入式·swd·stm-32
小䌨狗狗1 天前
学习记录:RT-Thread 初始化机制
嵌入式·rtt-hread
大聪明-PLUS1 天前
在 Linux 上使用实时调度策略运行应用程序
linux·嵌入式·arm·smarc
FreakStudio2 天前
串口协议解析实战:以 R60ABD1 雷达为例,详解 MicroPython 驱动中数据与业务逻辑的分离设计
python·单片机·pycharm·嵌入式·面向对象·硬件·电子diy
大聪明-PLUS2 天前
Linux 系统中的 CPU。文章 2:平均负载
linux·嵌入式·arm·smarc