diff options
-rw-r--r-- | Lessons_uncategorized/Lesson_FDF_FV/README.md | 423 |
1 files changed, 423 insertions, 0 deletions
diff --git a/Lessons_uncategorized/Lesson_FDF_FV/README.md b/Lessons_uncategorized/Lesson_FDF_FV/README.md new file mode 100644 index 0000000..4a1af40 --- /dev/null +++ b/Lessons_uncategorized/Lesson_FDF_FV/README.md @@ -0,0 +1,423 @@ +Now it is time to look at Firmware Volumes (`FV`) and how they are described in the FDF file. + +`Firmware Volume` is one of the region types in FD. If you declare some region as FV, you must provide its name `<FVname>` and define a separate section `[FV.<FVname>]`: +``` +[FD.<FDname>] +... + +0xXXXX|0xYYYY +FV = <FVname> + + +[FV.<FVname>] +... +``` + +Firmware volume is a region with a special formatting which is defined by the `UEFI Platform Initialization (PI) specification (Volume 3: Shared Architectural Elements)`. + +At the start of each FV is a special header `EFI_FIRMWARE_VOLUME_HEADER` ([https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Pi/PiFirmwareVolume.h](https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Pi/PiFirmwareVolume.h)): +``` +EFI_FIRMWARE_VOLUME_HEADER + +Summary: +Describes the features and layout of the firmware volume. + +Prototype: +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 BlockMap[]; +} EFI_FIRMWARE_VOLUME_HEADER + +Parameters: +ZeroVector The first 16 bytes are reserved to allow for the reset vector of processors whose reset vector is at address 0 +FileSystemGuid Declares the file system with which the firmware volume is formatted +FvLength Length in bytes of the complete firmware volume, including the header +Signature Set to {'_','F','V','H'} +Attributes Declares capabilities and power-on defaults for the firmware volume +HeaderLength Length in bytes of the complete firmware volume header +Checksum A 16-bit checksum of the firmware volume header. A valid header sums to zero +ExtHeaderOffset Offset, relative to the start of the header, of the extended header (EFI_FIRMWARE_VOLUME_EXT_HEADER) or zero if there is no extended header +Reserved In this version of the specification, this field must always be set to zero +Revision Set to 2. Future versions of this specification may define new header fields and will increment the Revision field accordingly +FvBlockMap[] An array of run-length encoded FvBlockMapEntry structures. The array is terminated with an entry of {0,0} + +FvBlockMapEntry.NumBlocks The number of blocks in the run. +FvBlockMapEntry.BlockLength The length of each block in the run + +Description: +A firmware volume based on a block device begins with a header that describes the features and layout of the firmware volume. This header includes a description of the capabilities, state, and block map of the device. +``` + +The rest of the data in the FV region is organized via files in a filesystem. The filesystem in this case is called a `firmware file system (FFS)`. The FFS defines how files are stored in flash. The type of the FFS that is used is defined by the the header GUID field `EFI_FIRMWARE_VOLUME_HEADER.FileSystemGuid`. + +Currently the UEFI Platform Initialization (PI) specification defines two filesystems: +``` +#define EFI_FIRMWARE_FILE_SYSTEM2_GUID \ + { 0x8c8ce578, 0x8a3d, 0x4f1c, { 0x99, 0x35, 0x89, 0x61, 0x85, 0xc3, 0x2d, 0xd3 } } + +#define EFI_FIRMWARE_FILE_SYSTEM3_GUID \ + { 0x5473c07a, 0x3dcb, 0x4dca, { 0xbd, 0x6f, 0x1e, 0x96, 0x89, 0xe7, 0x34, 0x9a } } +``` + +The main difference between them is that `EFI_FIRMWARE_FILE_SYSTEM3` supports files with a size `>16MB`. For the rest of the article we would describe `EFI_FIRMWARE_FILE_SYSTEM2`. + +Each file in the filesystem would have a header `EFI_FFS_FILE_HEADER` ([https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Pi/PiFirmwareFile.h](https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Pi/PiFirmwareFile.h)): +```cpp +EFI_FFS_FILE_HEADER + +Summary: +Each file begins with a header that describes the state and contents of the file. The header is 8-byte aligned with respect to the beginning of the firmware volume + +Prototype: +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; + +Parameters: +Name This GUID is the file name. It is used to uniquely identify the file. There may be only one instance of a file with the file name GUID of Name + in any given firmware volume, except if the file type is EFI_FV_FILETYPE_FFS_PAD +IntegrityCheck Used to verify the integrity of the file +Type Identifies the type of file +Attributes Declares various file attribute bits +Size The length of the file in bytes, including the FFS header +State Used to track the state of the file throughout the life of the file from creation to deletion +``` + +The file formatting is defined by the `EFI_FFS_FILE_HEADER.Type` field. Specification defines these file types: + +| Name | Value | Description | +| ---- | ----- | ----------- | +| EFI_FV_FILETYPE_RAW | 0x01 | Binary data | +| EFI_FV_FILETYPE_FREEFORM | 0x02 | Sectioned data | +| EFI_FV_FILETYPE_SECURITY_CORE | 0x03 | Platform core code used during the SEC phase | +| EFI_FV_FILETYPE_PEI_CORE | 0x04 | PEI Foundation | +| EFI_FV_FILETYPE_DXE_CORE | 0x05 | DXE Foundation | +| EFI_FV_FILETYPE_PEIM | 0x06 | PEI module (PEIM) | +| EFI_FV_FILETYPE_DRIVER | 0x07 | DXE driver | +| EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER | 0x08 | Combined PEIM/DXE driver | +| EFI_FV_FILETYPE_APPLICATION | 0x09 | Application | +| EFI_FV_FILETYPE_MM | 0x0A | Contains a PE32+ image that will be loaded into MMRAM in MM Traditional Mode | +| EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE | 0x0B | Firmware volume image | +| EFI_FV_FILETYPE_COMBINED_MM_DXE | 0x0C | Contains PE32+ image that will be dispatched by the DXE Dispatcher and will also be loaded into MMRAM in MM Tradition Mode | +| EFI_FV_FILETYPE_MM_CORE | 0x0D | MM Foundation that support MM Traditional Mode | +| EFI_FV_FILETYPE_MM_STANDALONE | 0x0E | Contains a PE32+ image that will be loaded into MMRAM in MM Standalone Mode | +| EFI_FV_FILETYPE_MM_CORE_STANDALONE | 0x0F | MM Foundation that support MM Tradition Mode and MM Standalone Mode | +| EFI_FV_FILETYPE_OEM_MIN…EFI_FV_FILETYPE_OEM_MAX | 0xC0-0xDF | OEM File Types | +| EFI_FV_FILETYPE_DEBUG_MIN…EFI_FV_FILETYPE_DEBUG_MAX | 0xE0-0xEF | Debug/Test File Types | +| EFI_FV_FILETYPE_FFS_MIN…EFI_FV_FILETYPE_FFS_MAX | 0xF0-0xFF | Firmware File System Specific File Types | +| EFI_FV_FILETYPE_FFS_PAD | 0xF0 | Pad File For FFS | + + +Each file consists of sections, with each section prepended with a header `EFI_COMMON_SECTION_HEADER` ([https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Pi/PiFirmwareFile.h](https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Pi/PiFirmwareFile.h)): +```cpp +EFI_COMMON_SECTION_HEADER + +Summary: +Defines the common header for all the section types + +Prototype: +typedef struct { + UINT8 Size[3]; + EFI_SECTION_TYPE Type; +} EFI_COMMON_SECTION_HEADER; + +Parameters: +Size A 24-bit unsigned integer that contains the total size of the section in bytes, including the EFI_COMMON_SECTION_HEADER +Type Declares the section type + +Description: +The type EFI_COMMON_SECTION_HEADER defines the common header for all the section types +``` + +Specification defines following sections: +```cpp +//************************************************************ +// EFI_SECTION_TYPE +//************************************************************ +typedef UINT8 EFI_SECTION_TYPE; +//************************************************************ +// The section type EFI_SECTION_ALL is a pseudo type. It is +// used as a wild card when retrieving sections. The section +// type EFI_SECTION_ALL matches all section types. +//************************************************************ +#define EFI_SECTION_ALL 0x00 +//************************************************************ +// Encapsulation section Type values +//************************************************************ +#define EFI_SECTION_COMPRESSION 0x01 +#define EFI_SECTION_GUID_DEFINED 0x02 +#define EFI_SECTION_DISPOSABLE 0x03 +//************************************************************ +// 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_MM_DEPEX 0x1C +``` + +# Create simple Firmware Volume + +Now let's try to create a most simple firmware volume which would contain one binary file. Here is code for this structure (`UefiLessonsPkg/UefiLessonsPkg.fdf`): +``` +[FD.SimpleImage] +BaseAddress = 0x0 +Size = 0x1000 +ErasePolarity = 1 + +0x100|0x500 +FV = SimpleVolume + +[FV.SimpleVolume] +FvAlignment = 16 + +FILE RAW = 15c658f6-eb5c-4b8f-b232-d6bd7368a73e { + $(WORKDIR)/hello.txt +} +``` + +Like in FD case, we can set some characteristics of FV via predefined tokens. +In this example we have only one token setting `FvAlignment = 16`, which is placed rigth after the `[FV.SimpleVolume]`. It is the only mandatory token for the `Firmware Volume`. + +Next we define what goes into the FFS of the FV. Here we have one FILE of type `RAW`, which means that the file type `EFI_FFS_FILE_HEADER.Type` is equal to `EFI_FV_FILETYPE_RAW`. +And specification defines this type like this: +``` +EFI_FV_FILETYPE_RAW +The file type EFI_FV_FILETYPE_RAW denotes a file that does not contain sections and is treated as a raw data file +``` +The GUID value `15c658f6-eb5c-4b8f-b232-d6bd7368a73e` I've generated via `uuidgen` utility. It defines a file name for FFS and will be written to the `EFI_FFS_FILE_HEADER.Name` field. +Inside the brackets we define content for the file. In our case it is our `hello.txt` generated via `echo "hello!" > hello.txt` command. + +Let's build and check our FD image: +``` +$ hexdump Build/UefiLessonsPkg/RELEASE_GCC5/FV/SIMPLEIMAGE.fd -C +00000000 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| +* +00000100 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +00000110 78 e5 8c 8c 3d 8a 1c 4f 99 35 89 61 85 c3 2d d3 |x...=..O.5.a..-.| +00000120 00 05 00 00 00 00 00 00 5f 46 56 48 00 08 04 00 |........_FVH....| +00000130 48 00 cd e3 00 00 00 02 00 05 00 00 01 00 00 00 |H...............| +00000140 00 00 00 00 00 00 00 00 f6 58 c6 15 5c eb 8f 4b |.........X..\..K| +00000150 b2 32 d6 bd 73 68 a7 3e 5f aa 01 00 1f 00 00 f8 |.2..sh.>_.......| +00000160 68 65 6c 6c 6f 21 0a ff ff ff ff ff ff ff ff ff |hello!..........| +00000170 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| +* +00000600 +``` +Besides FD, EDKII build system also generates images for Firmware Volumes. We've generated our FV with `Offset|Size = 0x100|0x500`, therefore you can see how `SIMPLEIMAGE.fd` has 0x100 bytes of 0xff's at the start of an image, and how `SIMPLEVOLUME.Fv` starts right from its data. +``` +$ hexdump Build/UefiLessonsPkg/RELEASE_GCC5/FV/SIMPLEVOLUME.Fv -C +00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +00000010 78 e5 8c 8c 3d 8a 1c 4f 99 35 89 61 85 c3 2d d3 |x...=..O.5.a..-.| +00000020 00 05 00 00 00 00 00 00 5f 46 56 48 00 08 04 00 |........_FVH....| +00000030 48 00 cd e3 00 00 00 02 00 05 00 00 01 00 00 00 |H...............| +00000040 00 00 00 00 00 00 00 00 f6 58 c6 15 5c eb 8f 4b |.........X..\..K| +00000050 b2 32 d6 bd 73 68 a7 3e 5f aa 01 00 1f 00 00 f8 |.2..sh.>_.......| +00000060 68 65 6c 6c 6f 21 0a ff ff ff ff ff ff ff ff ff |hello!..........| +00000070 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| +* +00000500 +``` + +Firmware Volume data starts with a header. In our case: +```cpp +typedef struct { + UINT8 ZeroVector[16]; = { 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 } + EFI_GUID FileSystemGuid; = { 0x8c8ce578, 0x8a3d, 0x4f1c, { 0x99, 0x35, 0x89, 0x61, 0x85, 0xc3, 0x2d, 0xd3 } } + UINT64 FvLength; = 0x0000000000000500 + UINT32 Signature; = "_FVH" + EFI_FVB_ATTRIBUTES_2 Attributes; = 0x00040800 = (EFI_FVB2_ERASE_POLARITY | EFI_FVB2_ALIGNMENT_16) + UINT16 HeaderLength; = 0x0048 + UINT16 Checksum; = 0xe3cd + UINT16 ExtHeaderOffset; = 0x0000 + UINT8 Reserved[1]; = 0x00 + UINT8 Revision; = 0x02 + EFI_FV_BLOCK_MAP_ENTRY BlockMap[1]; = [{0x00000500, 0x00000001}, {0x00000000, 0x00000000}] +} EFI_FIRMWARE_VOLUME_HEADER; +``` + +Right after the `EFI_FIRMWARE_VOLUME_HEADER` we have a header for our only file: +```cpp +typedef struct { + EFI_GUID Name; = 15c658f6-eb5c-4b8f-b232-d6bd7368a73e + EFI_FFS_INTEGRITY_CHECK IntegrityCheck; = 0x5faa + EFI_FV_FILETYPE Type; = 0x01 + EFI_FFS_FILE_ATTRIBUTES Attributes; = 0x00 + UINT8 Size[3]; = 0x00001f + EFI_FFS_FILE_STATE State; = 0xf8 +} EFI_FFS_FILE_HEADER; +``` + +Right after that we have a content of our file `hello.txt`: +``` +$ hexdump hello.txt -C +00000000 68 65 6c 6c 6f 21 0a |hello!.| +0000000 +``` + +# VolInfo + +There is an utility `BaseTools/BinWrappers/PosixLike/VolInfo` that you can use to dump information about Firmware Volumes. Here is an example how we can use it to dump information about our Formware Volume: +``` +$ VolInfo Build/UefiLessonsPkg/RELEASE_GCC5/FV/SIMPLEVOLUME.Fv -x Build/UefiLessonsPkg/RELEASE_GCC5/FV/Guid.xref +VolInfo Version 1.0 Build Developer Build based on Revision: Unknown +ParseGuidBaseNameFile: Build/UefiLessonsPkg/RELEASE_GCC5/FV/Guid.xref +Signature: _FVH (4856465F) +Attributes: 40800 + EFI_FVB2_ERASE_POLARITY + EFI_FVB2_ALIGNMENT_16 +Header Length: 0x00000048 +File System ID: 8c8ce578-8a3d-4f1c-9935-896185c32dd3 +Revision: 0x0002 +Number of Blocks: 0x00000500 +Block Length: 0x00000001 +Total Volume Size: 0x00000500 +============================================================ +File Name: 15C658F6-EB5C-4B8F-B232-D6BD7368A73E /<...>/edk2/$(WORKDIR)/hello.txt +File Offset: 0x00000048 +File Length: 0x0000001F +File Attributes: 0x00 +File State: 0xF8 + EFI_FILE_DATA_VALID +File Type: 0x01 EFI_FV_FILETYPE_RAW +There are a total of 1 files in this FV +``` + +As you can see this utility gives us the same information that we've parsed ourselves. + +# Another file + +Let's add another file to our FFS. For a change let's initialize our next file with binary content: +``` +$ echo -n -e \\xDE\\xAD\\xBE\\xEF > DEADBEEF.txt +$ hexdump DEADBEEF.txt -C +00000000 de ad be ef |....| +00000004 +``` +Now let's add it to out FFS: +``` + +``` + +Build image and look at the Firmware Volume content: +``` +$ hexdump /home/aladyshev/tiano/2021/edk2/Build/UefiLessonsPkg/RELEASE_GCC5/FV/SIMPLEVOLUME.Fv -C +00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +00000010 78 e5 8c 8c 3d 8a 1c 4f 99 35 89 61 85 c3 2d d3 |x...=..O.5.a..-.| +00000020 00 05 00 00 00 00 00 00 5f 46 56 48 00 08 04 00 |........_FVH....| +00000030 48 00 cd e3 00 00 00 02 00 05 00 00 01 00 00 00 |H...............| +00000040 00 00 00 00 00 00 00 00 f6 58 c6 15 5c eb 8f 4b |.........X..\..K| +00000050 b2 32 d6 bd 73 68 a7 3e 5f aa 01 00 1f 00 00 f8 |.2..sh.>_.......| +00000060 68 65 6c 6c 6f 21 0a ff 5e 42 77 dd 38 d3 e7 43 |hello!..^Bw.8..C| +00000070 8e 94 1a 75 5e 0c 21 7d 01 aa 01 00 1c 00 00 f8 |...u^.!}........| +00000080 de ad be ef ff ff ff ff ff ff ff ff ff ff ff ff |................| +00000090 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| +* +00000500 +``` +Here you can see how our files follows each other in the FFS. Each og the files has its own `EFI_FFS_FILE_HEADER` with its unique Name (=GUID). The important thing to note that the filesystem is flat, files just follow one another. Therefore to find some file by GUID, we need to traverse FFS from the start. +Also here you can see that the padding byte 0xff was inserted between the files. It was inserted because according to the specification each file must start at 8 byte boundary. + +We can use `VolInfo` to see how it interprets our Firmware Volume: +``` +$ VolInfo Build/UefiLessonsPkg/RELEASE_GCC5/FV/SIMPLEVOLUME.Fv -x Build/UefiLessonsPkg/RELEASE_GCC5/FV/Guid.xref +VolInfo Version 1.0 Build Developer Build based on Revision: Unknown +ParseGuidBaseNameFile: Build/UefiLessonsPkg/RELEASE_GCC5/FV/Guid.xref +Signature: _FVH (4856465F) +Attributes: 40800 + EFI_FVB2_ERASE_POLARITY + EFI_FVB2_ALIGNMENT_16 +Header Length: 0x00000048 +File System ID: 8c8ce578-8a3d-4f1c-9935-896185c32dd3 +Revision: 0x0002 +Number of Blocks: 0x00000500 +Block Length: 0x00000001 +Total Volume Size: 0x00000500 +============================================================ +File Name: 15C658F6-EB5C-4B8F-B232-D6BD7368A73E /home/aladyshev/tiano/2021/edk2/$(WORKDIR)/hello.txt +File Offset: 0x00000048 +File Length: 0x0000001F +File Attributes: 0x00 +File State: 0xF8 + EFI_FILE_DATA_VALID +File Type: 0x01 EFI_FV_FILETYPE_RAW +============================================================ +File Name: DD77425E-D338-43E7-8E94-1A755E0C217D /home/aladyshev/tiano/2021/edk2/$(WORKDIR)/DEADBEEF.txt +File Offset: 0x00000068 +File Length: 0x0000001C +File Attributes: 0x00 +File State: 0xF8 + EFI_FILE_DATA_VALID +File Type: 0x01 EFI_FV_FILETYPE_RAW +There are a total of 2 files in this FV +``` +Indeed the FV contains 2 files of type `EFI_FV_FILETYPE_RAW`. + + +# Firmware Volume attributes + +Currently in our `Firmware Volume` we've defined only one attribute `FvAlignment`. Along with these attributes they help to set flags in the `EFI_FIRMWARE_VOLUME_HEADER.Attributes` field. +``` +FvAlignment = <...> +ERASE_POLARITY = 1|0 +MEMORY_MAPPED = TRUE|FALSE +STICKY_WRITE = TRUE|FALSE +LOCK_CAP = TRUE|FALSE +LOCK_STATUS = TRUE|FALSE +WRITE_DISABLED_CAP = TRUE|FALSE +WRITE_ENABLED_CAP = TRUE|FALSE +WRITE_STATUS = TRUE|FALSE +WRITE_LOCK_CAP = TRUE|FALSE +WRITE_LOCK_STATUS = TRUE|FALSE +READ_DISABLED_CAP = TRUE|FALSE +READ_ENABLED_CAP = TRUE|FALSE +READ_STATUS = TRUE|FALSE +READ_LOCK_CAP = TRUE|FALSE +READ_LOCK_STATUS = TRUE|FALSE +``` +The setting of these attributes will set respective `EFI_FVB2_*` flags which are defined in the [https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Pi/PiFirmwareVolume.h](https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Pi/PiFirmwareVolume.h). +You can read the meaning of these flags in the `UEFI Platform Initialization (PI) specification (Volume 3: Shared Architectural Elements)`. + +Other possible attribute is `FvNameGuid`: +``` +FvNameGuid = <GUID> +# Example: +# FvNameGuid = 763BED0D-DE9F-48F5-81F1-3E90E1B1A015 +``` +This attribute would lead to the creation of a file of type `EFI_FV_FILETYPE_FFS_PAD` (padding file) with a GUID value in its data. This file would be placed first in the FV. + +And `BlockSize`: +``` +BlockSize = <...> +``` +This token define flash chip attribute similar to the one in FD. + + +# Links + +- [\[FV\] Sections](https://edk2-docs.gitbook.io/edk-ii-fdf-specification/2_fdf_design_discussion/25_-fv-_sections) + +- [Create the FV Image File(s)](https://edk2-docs.gitbook.io/edk-ii-build-specification/10_post-build_imagegen_stage_-_flash/104_create_the_fv_image_files) + |