1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
|
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](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
```
# Create more `RAW` sections
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:
![FREEFORM](FREEFORM.png?raw=true)
`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
```
# FV build process
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
```
## `GenSec`
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
```
## `GenFfs`
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 |.......@...j/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
## `GenFv`
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.
|