uefi二进制文件fd
uefi 在编译最后会生成一个可以烧进rom里面的.fd文件。这个文件是根据fdf文件生成的。下面详细介绍一下fd文件中的内容都是怎么存放的。
fd文件格式描述
一个FD(Flash Device binary image),它就是一个二进制镜像文件,其中包含多个FV文件;一个FV(Firmware Volumes),它是FD的组成模块,每一个模块有一个特定的功能,比如FVMAIN通常包含的是DXE、BDS阶段的代码,它通常是被压缩过得,FV Recovery包含SEC和PEI阶段的代码,每一个FV 包含多个FFS(Firmware File System)文件,它是FV内部的一个结构,用来表示各个Firmware的组成。
上图中FV header 结构如下:
//
// Describes the features and layout of the firmware volume.
//
typedef struct {
UINT8 ZeroVector[16];
EFI_GUID FileSystemGuid;
UINT64 FvLength;
UINT32 Signature;
EFI_FVB_ATTRIBUTES_2 Attributes;
UINT16 HeaderLength;
UINT16 Checksum;
UINT16 ExtHeaderOffset;
UINT8 Reserved[1];
UINT8 Revision;
EFI_FV_BLOCK_MAP_ENTRY BlockMap[1];
} EFI_FIRMWARE_VOLUME_HEADER;
上图中FV Ext header 结构如下:
//
// Extension header pointed by ExtHeaderOffset of volume header.
//
typedef struct {
EFI_GUID FvName;
UINT32 ExtHeaderSize;
} EFI_FIRMWARE_VOLUME_EXT_HEADER;
上图中的一个firmware file 就是一个ffs ,一个ffs header 如下:
//
// Each file begins with the header that describe the
// contents and state of the files.
//
typedef struct {
EFI_GUID Name;
EFI_FFS_INTEGRITY_CHECK IntegrityCheck;
EFI_FV_FILETYPE Type;
EFI_FFS_FILE_ATTRIBUTES Attributes;
UINT8 Size[3];
EFI_FFS_FILE_STATE State;
} EFI_FFS_FILE_HEADER;
一个ffs 其实就是一个或者多个.efi 文件的封装。假如我们想从ffs里面找出一个PEI CORE 模块,那么就通过EFI_FV_FILETYPE 类型类区分就可以了,当type是EFI_FV_FILETYPE_PEI_CORE 就表示是pei core模块。
uefi中每个模块类型定义如下:
//
// File Types Definitions
//
#define EFI_FV_FILETYPE_ALL 0x00
#define EFI_FV_FILETYPE_RAW 0x01
#define EFI_FV_FILETYPE_FREEFORM 0x02
#define EFI_FV_FILETYPE_SECURITY_CORE 0x03
#define EFI_FV_FILETYPE_PEI_CORE 0x04
#define EFI_FV_FILETYPE_DXE_CORE 0x05
#define EFI_FV_FILETYPE_PEIM 0x06
#define EFI_FV_FILETYPE_DRIVER 0x07
#define EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER 0x08
#define EFI_FV_FILETYPE_APPLICATION 0x09
#define EFI_FV_FILETYPE_SMM 0x0A
#define EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE 0x0B
#define EFI_FV_FILETYPE_COMBINED_SMM_DXE 0x0C
#define EFI_FV_FILETYPE_SMM_CORE 0x0D
#define EFI_FV_FILETYPE_MM_STANDALONE 0x0E
#define EFI_FV_FILETYPE_MM_CORE_STANDALONE 0x0F
#define EFI_FV_FILETYPE_OEM_MIN 0xc0
#define EFI_FV_FILETYPE_OEM_MAX 0xdf
#define EFI_FV_FILETYPE_DEBUG_MIN 0xe0
#define EFI_FV_FILETYPE_DEBUG_MAX 0xef
#define EFI_FV_FILETYPE_FFS_MIN 0xf0
#define EFI_FV_FILETYPE_FFS_MAX 0xff
#define EFI_FV_FILETYPE_FFS_PAD 0xf0
ffs 文件除了header 外,就是section断。其中包含很多个section。section的类型如下:
//
// Leaf section Type values
//
#define EFI_SECTION_PE32 0x10
#define EFI_SECTION_PIC 0x11
#define EFI_SECTION_TE 0x12
#define EFI_SECTION_DXE_DEPEX 0x13
#define EFI_SECTION_VERSION 0x14
#define EFI_SECTION_USER_INTERFACE 0x15
#define EFI_SECTION_COMPATIBILITY16 0x16
#define EFI_SECTION_FIRMWARE_VOLUME_IMAGE 0x17
#define EFI_SECTION_FREEFORM_SUBTYPE_GUID 0x18
#define EFI_SECTION_RAW 0x19
#define EFI_SECTION_PEI_DEPEX 0x1B
#define EFI_SECTION_SMM_DEPEX 0x1C
section 段又分为头和数据段,section 头的格式如下:
typedef struct {
UINT8 Size[3];
EFI_SECTION_TYPE Type;
} EFI_COMMON_SECTION_HEADER;
我们现在用到的都是PE32格式的section。代码断和数据断都在这个section的数据段中。
fd编译过程中,生成fd 的过程如下:
每一个模块的源码编译生成.efi文件,.efi文件又被封装成ffs文件,ffs文件又被封装到FV文件中,多个FV 最后组成了fd文件。
fd文件烧写到flash后,首先知道secFv的位置,然后通过SecFv找到代码段的起始入口开始执行。执行到sec后期,会将PeiFv的位置传递过去,从PeiFv的位置找到PeiCore的File,也就是PeiCoreImage,然后再从Image中找到PE32 的Section,并找到Entry point 开始执行PeiCore的代码。