In the last lesson we've encoded our data to FFS in the files of type RAW
(EFI_FFS_FILE_HEADER.Type = EFI_FV_FILETYPE_RAW
). It is the most simple type, in this case all of our data is written as is right after the file header.
Other file types consist 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):
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:
Name | Value | Description |
---|---|---|
EFI_SECTION_COMPRESSION | 0x01 | Encapsulation section where other sections are compressed |
EFI_SECTION_GUID_DEFINED | 0x02 | Encapsulation section where other sections have format defined by a GUID |
EFI_SECTION_DISPOSABLE | 0x03 | Encapsulation section used during the build process but not required for execution |
EFI_SECTION_PE32 | 0x10 | PE32+ Executable image |
EFI_SECTION_PIC | 0x11 | Position-Independent Code |
EFI_SECTION_TE | 0x12 | Terse Executable image |
EFI_SECTION_DXE_DEPEX | 0x13 | DXE Dependency Expression |
EFI_SECTION_VERSION | 0x14 | Version, Text and Numeric |
EFI_SECTION_USER_INTERFACE | 0x15 | User-Friendly name of the driver |
EFI_SECTION_COMPATIBILITY16 | 0x16 | DOS-style 16-bit EXE |
EFI_SECTION_FIRMWARE_VOLUME_IMAGE | 0x17 | PI Firmware Volume image |
EFI_SECTION_FREEFORM_SUBTYPE_GUID | 0x18 | Raw data with GUID in header to define format |
EFI_SECTION_RAW | 0x19 | Raw data |
EFI_SECTION_PEI_DEPEX | 0x1b | PEI Dependency Expression |
EFI_SECTION_MM_DEPEX | 0x1c | Leaf section type for determining the dispatch order for an MM Traditional driver in MM Traditional Mode or MM Standaline driver in MM Standalone Mode |
PI specification defines which sections each type of file must have. For example the file of type EFI_FV_FILETYPE_APPLICATION=0x09
must have at least one EFI_SECTION_PE32=0x10
section.
In this lesson we would work with a sectioned file without any such limitations - FREEFORM
file. In this lesson we want to investigate sections, so this is the perfect file type for this task.
According to the PI documentation the file type EFI_FV_FILETYPE_FREEFORM = 0x02
denotes a sectioned file that may contain any combination of sections.
Here is an example of how we add such file. Let's start with one RAW
section in the file.
First here is a section description from the specification:
EFI_SECTION_RAW
Summary:
A leaf section type that contains an array of zero or more bytes.
Prototype:
typedef EFI_COMMON_SECTION_HEADER EFI_RAW_SECTION;
Description:
A raw section is a leaf section that contains an array of zero or more bytes. No particular formatting of these bytes is implied by this section type
Just in case, I want to point out, that like the rest of sections, this section has a slightly different format in case if section size is above 16MB. Here and after we would inspect only "small" sections. For the "large" section format consult PI specification.
Now here is a code:
[FD.SimpleImage]
BaseAddress = 0x0
Size = 0x1000
ErasePolarity = 1
0x100|0x500
FV = SimpleVolume
[FV.SimpleVolume]
FvAlignment = 16
FILE FREEFORM = f6ed9cf0-cdc1-40a1-9909-ac6a2f435e23 {
SECTION RAW = $(WORKDIR)/hello.txt
}
hexdump
output of the resulting Firmware Volume would look like this:
$ 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 f0 9c ed f6 c1 cd a1 40 |...............@|
00000050 99 09 ac 6a 2f 43 5e 23 52 aa 02 00 23 00 00 f8 |...j/C^#R...#...|
00000060 0b 00 00 19 68 65 6c 6c 6f 21 0a ff ff ff ff ff |....hello!......|
00000070 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
*
00000500
And here is VolInfo
output. Everything is exactly as it is supposed to be. Firmware Volume contains one EFI_FV_FILETYPE_FREEFORM
file with one EFI_SECTION_RAW
:
$ 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: F6ED9CF0-CDC1-40A1-9909-AC6A2F435E23 /<...>/$(WORKDIR)/hello.txt
File Offset: 0x00000048
File Length: 0x00000023
File Attributes: 0x00
File State: 0xF8
EFI_FILE_DATA_VALID
File Type: 0x02 EFI_FV_FILETYPE_FREEFORM
------------------------------------------------------------
Type: EFI_SECTION_RAW
Size: 0x0000000B
There are a total of 1 files in this FV
Let's try to add more RAW
sections to our file. We can use the same file for the section content, it is absolutely legit:
[FD.SimpleImage]
BaseAddress = 0x0
Size = 0x1000
ErasePolarity = 1
0x100|0x500
FV = SimpleVolume
[FV.SimpleVolume]
FvAlignment = 16
FILE FREEFORM = f6ed9cf0-cdc1-40a1-9909-ac6a2f435e23 {
SECTION RAW = $(WORKDIR)/hello.txt
SECTION RAW = $(WORKDIR)/hello.txt
SECTION RAW = $(WORKDIR)/hello.txt
}
hexdump
:
$ 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 f0 9c ed f6 c1 cd a1 40 |...............@|
00000050 99 09 ac 6a 2f 43 5e 23 3a aa 02 00 3b 00 00 f8 |...j/C^#:...;...|
00000060 0b 00 00 19 68 65 6c 6c 6f 21 0a 00 0b 00 00 19 |....hello!......|
00000070 68 65 6c 6c 6f 21 0a 00 0b 00 00 19 68 65 6c 6c |hello!......hell|
00000080 6f 21 0a ff ff ff ff ff ff ff ff ff ff ff ff ff |o!..............|
00000090 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
*
00000500
If you parse it, it looks like this:
VolInfo
:
$ 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: F6ED9CF0-CDC1-40A1-9909-AC6A2F435E23 /<...>/$(WORKDIR)/hello.txt
File Offset: 0x00000048
File Length: 0x0000003B
File Attributes: 0x00
File State: 0xF8
EFI_FILE_DATA_VALID
File Type: 0x02 EFI_FV_FILETYPE_FREEFORM
------------------------------------------------------------
Type: EFI_SECTION_RAW
Size: 0x0000000B
------------------------------------------------------------
Type: EFI_SECTION_RAW
Size: 0x0000000B
------------------------------------------------------------
Type: EFI_SECTION_RAW
Size: 0x0000000B
There are a total of 1 files in this FV
Before we go any further in our investigation of section types it would be good to know a little about EDKII build process and utilities.
If you execute build
with -v
(--verbose
) argument, the EDKII build system would output a lot information about the build. In the end of the output you could see how EDKII uses its tools for image generation.
Look at the output after the string:
Generating SIMPLEVOLUME FV
The first string after the output above is:
['GenSec', '-s', 'EFI_SECTION_RAW', '-o', '<...>/Build/UefiLessonsPkg/RELEASE_GCC5/FV/Ffs/f6ed9cf0-cdc1-40a1-9909-ac6a2f435e23SIMPLEVOLUME/f6ed9cf0-cdc1-40a1-9909-ac6a2f435e23SEC1.raw', '<...>/$(WORKDIR)/hello.txt', '-v']
This means that GenSec
utility from the BaseTools was called and shows its arguments. This is the EDKII utility to construct sections from the data.
GenSec -s EFI_SECTION_RAW -o <...>/Build/UefiLessonsPkg/RELEASE_GCC5/FV/Ffs/f6ed9cf0-cdc1-40a1-9909-ac6a2f435e23SIMPLEVOLUME/f6ed9cf0-cdc1-40a1-9909-ac6a2f435e23SEC1.raw' <...>/$(WORKDIR)/hello.txt -v
You can look at the GenSec
help for the options description. After the command . edksetup.sh
this utility would be in your path. But basically this call means:
GenSec --sectiontype EFI_SECTION_RAW \
--outputfile <output_file.raw> \
<input_file> \
--verbose
You can look at the output file content:
$ hexdump /<...>/Build/UefiLessonsPkg/RELEASE_GCC5/FV/Ffs/f6ed9cf0-cdc1-40a1-9909-ac6a2f435e23SIMPLEVOLUME/f6ed9cf0-cdc1-40a1-9909-ac6a2f4
35e23SEC1.raw -C
00000000 0a 00 00 19 68 65 6c 6c 6f 0a |....hello.|
0000000a
Here you can see how the data was prepended with a section header for the RAW section.
The long path that is used here is just a:
FV/Ffs/<FILE_GUID><FV_NAME>/<FILE_GUID>SEC<SECTION NUMBER>.raw
You can see how the next section files are created with increased <SECTION NUMBER>
.
Build even saves the command, that was used to generate each section.
Right to each of the <...>.raw
files you can find <...>.raw.txt
file which includes GenSec
command that was used for the file generation.
$ cat Build/UefiLessonsPkg/RELEASE_GCC5/FV/Ffs/f6ed9cf0-cdc1-40a1-9909-ac6a2f435e23SIMPLEVOLUME/f6ed9cf0-cdc1-40a1-9909-ac6a2f435e23SEC1.raw.txt
GenSec -s EFI_SECTION_RAW -o /<...>/Build/UefiLessonsPkg/RELEASE_GCC5/FV/Ffs/f6ed9cf0-cdc1-40a1-9909-ac6a2f435e23SIMPLEVOLUME/f6ed9cf0-cdc1-40a1-9909-ac6a2f435e23SEC1.raw /<...>/$(WORKDIR)/hello.txt
After we have all of the 3 sections we can generate a file. In the output this corresponds to this call:
['GenFfs', '-t', 'EFI_FV_FILETYPE_FREEFORM', '-g', 'f6ed9cf0-cdc1-40a1-9909-ac6a2f435e23', '-o', '/home/aladyshev/edk2_patches/Build/UefiLessonsPkg/RELEASE_GCC5/FV/Ffs/f6ed9cf0-cdc1-40a1-9909-ac6a2f435e23SIMPLEVOLUME/f6ed9cf0-cdc1-40a1-9909-ac6a2f435e23.ffs', '-i', '/home/aladyshev/edk2_patches/Build/UefiLessonsPkg/RELEASE_GCC5/FV/Ffs/f6ed9cf0-cdc1-40a1-9909-ac6a2f435e23SIMPLEVOLUME/f6ed9cf0-cdc1-40a1-9909-ac6a2f435e23SEC1.raw', '-i', '/home/aladyshev/edk2_patches/Build/UefiLessonsPkg/RELEASE_GCC5/FV/Ffs/f6ed9cf0-cdc1-40a1-9909-ac6a2f435e23SIMPLEVOLUME/f6ed9cf0-cdc1-40a1-9909-ac6a2f435e23SEC2.raw', '-i', '/home/aladyshev/edk2_patches/Build/UefiLessonsPkg/RELEASE_GCC5/FV/Ffs/f6ed9cf0-cdc1-40a1-9909-ac6a2f435e23SIMPLEVOLUME/f6ed9cf0-cdc1-40a1-9909-ac6a2f435e23SEC3.raw', '-v']
GenFfs
is another utility from the BaseTools. Here is the usage above written in a more descriptive way:
GenFfs --filetype EFI_FV_FILETYPE_FREEFORM \
--fileguid f6ed9cf0-cdc1-40a1-9909-ac6a2f435e23 \
--outputfile /<...>/FV/Ffs/f6ed9cf0-cdc1-40a1-9909-ac6a2f435e23SIMPLEVOLUME/f6ed9cf0-cdc1-40a1-9909-ac6a2f435e23.ffs \
--sectionfile /<...>/FV/Ffs/f6ed9cf0-cdc1-40a1-9909-ac6a2f435e23SIMPLEVOLUME/f6ed9cf0-cdc1-40a1-9909-ac6a2f435e23SEC1.raw \
--sectionfile /<...>/FV/Ffs/f6ed9cf0-cdc1-40a1-9909-ac6a2f435e23SIMPLEVOLUME/f6ed9cf0-cdc1-40a1-9909-ac6a2f435e23SEC2.raw \
--sectionfile /<...>/FV/Ffs/f6ed9cf0-cdc1-40a1-9909-ac6a2f435e23SIMPLEVOLUME/f6ed9cf0-cdc1-40a1-9909-ac6a2f435e23SEC3.raw \
--verbose
Here you can see how the .ffs
file is constructed from the several sections that were created earlier.
You can look at the output file and see how our sections are combined and prepended with a file header:
$ hexdump Build/UefiLessonsPkg/RELEASE_GCC5/FV/Ffs/f6ed9cf0-cdc1-40a1-9909-ac6a2f435e23SIMPLEVOLUME/f6ed9cf0-cdc1-40a1-9909-ac6a2f4
35e23.ffs -C
00000000 f0 9c ed f6 c1 cd a1 40 99 09 ac 6a 2f 43 5e 23 |[email protected]/C^#|
00000010 3b aa 02 00 3a 00 00 07 0a 00 00 19 68 65 6c 6c |;...:.......hell|
00000020 6f 0a 00 00 0a 00 00 19 68 65 6c 6c 6f 0a 00 00 |o.......hello...|
00000030 0a 00 00 19 68 65 6c 6c 6f 0a |....hello.|
0000003a
Like with the sections, right to the <...>.ffs
file there would be <...>.ffs.txt
file that would contain the string of the call to the GenFfs
utility
Finally GenFv
utility is called for the Firmware Volume (FV
) generation:
['GenFv', '-a', '/<...>/Build/UefiLessonsPkg/RELEASE_GCC5/FV/Ffs/SIMPLEVOLUME.inf', '-o', '/<...>/Build/UefiLessonsPkg/RELEASE_GCC5/FV/SIMPLEVOLUME.Fv', '-i', '/<...>/Build/UefiLessonsPkg/RELEASE_GCC5/FV/SIMPLEVOLUME.inf', '-v']
Here is it in a more pleasant display:
GenFv --addrfile /<...>/Build/UefiLessonsPkg/RELEASE_GCC5/FV/Ffs/SIMPLEVOLUME.inf \
--outputfile /<...>/Build/UefiLessonsPkg/RELEASE_GCC5/FV/SIMPLEVOLUME.Fv \
--inputfile /<...>/Build/UefiLessonsPkg/RELEASE_GCC5/FV/SIMPLEVOLUME.inf \
--verbose
If you look at the content of the input file created in the build process Build/UefiLessonsPkg/RELEASE_GCC5/FV/SIMPLEVOLUME.inf
, you would see how it references the *.ffs
file that was created earlier:
[options]
EFI_BASE_ADDRESS = 0x100
EFI_BLOCK_SIZE = 0x1
EFI_NUM_BLOCKS = 0x500
[attributes]
EFI_ERASE_POLARITY = 1
EFI_FVB2_ALIGNMENT_16 = TRUE
[files]
EFI_FILE_NAME = /<...>/Build/UefiLessonsPkg/RELEASE_GCC5/FV/Ffs/f6ed9cf0-cdc1-40a1-9909-ac6a2f435e23SIMPLEVOLUME/f6ed9cf0-cdc1-40a1-9909-ac6a2f435e23.ffs
The output file SIMPLEVOLUME.Fv
is the one that we usually investigate:
$ 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 f0 9c ed f6 c1 cd a1 40 |...............@|
00000050 99 09 ac 6a 2f 43 5e 23 3b aa 02 00 3a 00 00 f8 |...j/C^#;...:...|
00000060 0a 00 00 19 68 65 6c 6c 6f 0a 00 00 0a 00 00 19 |....hello.......|
00000070 68 65 6c 6c 6f 0a 00 00 0a 00 00 19 68 65 6c 6c |hello.......hell|
00000080 6f 0a ff ff ff ff ff ff ff ff ff ff ff ff ff ff |o...............|
00000090 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
*
00000500
Now you know how modular is flash image build. build
tool that we use actually delegates many tasks to the simple utilities like GenSec
/GenFfs
/GenFv
and many intermediate files are created along the build process.