aboutsummaryrefslogtreecommitdiffstats
path: root/Lessons_uncategorized/Lesson_FDF/README.md
blob: 712a9c3e0f4553e285697f45c0879821f14732b9 (plain)
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
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
When we build OVMF image the final result is a flash image.

Last messages in the build log provide some information about the image generation process:
```
$ build --platform=OvmfPkg/OvmfPkgX64.dsc --arch=X64 --buildtarget=RELEASE --tagname=GCC5

<...>

Fd File Name:OVMF (/<...>/edk2/Build/OvmfX64/RELEASE_GCC5/FV/OVMF.fd)

Generate Region at Offset 0x0
   Region Size = 0x40000
   Region Name = DATA

Generate Region at Offset 0x40000
   Region Size = 0x1000
   Region Name = None

Generate Region at Offset 0x41000
   Region Size = 0x1000
   Region Name = DATA

Generate Region at Offset 0x42000
   Region Size = 0x42000
   Region Name = None

Generate Region at Offset 0x84000
   Region Size = 0x348000
   Region Name = FV

Generating FVMAIN_COMPACT FV

Generating PEIFV FV
###
Generating DXEFV FV
########
Generate Region at Offset 0x3CC000
   Region Size = 0x34000
   Region Name = FV

Generating SECFV FV
#
Fd File Name:OVMF_VARS (/<...>/edk2/Build/OvmfX64/RELEASE_GCC5/FV/OVMF_VARS.fd)

Generate Region at Offset 0x0
   Region Size = 0x40000
   Region Name = DATA

Generate Region at Offset 0x40000
   Region Size = 0x1000
   Region Name = None

Generate Region at Offset 0x41000
   Region Size = 0x1000
   Region Name = DATA

Generate Region at Offset 0x42000
   Region Size = 0x42000
   Region Name = None

Fd File Name:OVMF_CODE (/<...>/edk2/Build/OvmfX64/RELEASE_GCC5/FV/OVMF_CODE.fd)

Generate Region at Offset 0x0
   Region Size = 0x348000
   Region Name = FV

Generate Region at Offset 0x348000
   Region Size = 0x34000
   Region Name = FV

Fd File Name:MEMFD (/<...>/edk2/Build/OvmfX64/RELEASE_GCC5/FV/MEMFD.fd)

Generate Region at Offset 0x0
   Region Size = 0x6000
   Region Name = None

Generate Region at Offset 0x6000
   Region Size = 0x1000
   Region Name = None

Generate Region at Offset 0x7000
   Region Size = 0x1000
   Region Name = None

Generate Region at Offset 0x8000
   Region Size = 0x1000
   Region Name = None

Generate Region at Offset 0x9000
   Region Size = 0x2000
   Region Name = None

Generate Region at Offset 0xB000
   Region Size = 0x1000
   Region Name = None

Generate Region at Offset 0xC000
   Region Size = 0x1000
   Region Name = None
Padding region starting from offset 0xD000, with size 0x3000

Generate Region at Offset 0xD000
   Region Size = 0x3000
   Region Name = None

Generate Region at Offset 0x10000
   Region Size = 0x10000
   Region Name = None

Generate Region at Offset 0x20000
   Region Size = 0xE0000
   Region Name = FV

Generate Region at Offset 0x100000
   Region Size = 0xC00000
   Region Name = FV

GUID cross reference file can be found at /<...>/edk2/Build/OvmfX64/RELEASE_GCC5/FV/Guid.xref

FV Space Information
SECFV [13%Full] 212992 (0x34000) total, 27904 (0x6d00) used, 185088 (0x2d300) free
PEIFV [11%Full] 917504 (0xe0000) total, 102824 (0x191a8) used, 814680 (0xc6e58) free
DXEFV [22%Full] 12582912 (0xc00000) total, 2879400 (0x2befa8) used, 9703512 (0x941058) free
FVMAIN_COMPACT [27%Full] 3440640 (0x348000) total, 935208 (0xe4528) used, 2505432 (0x263ad8) free

- Done -
```

This image process is initiated because the package DSC file [`OvmfPkg/OvmfPkgX64.dsc`](https://github.com/tianocore/edk2/blob/master/OvmfPkg/OvmfPkgX64.dsc) has `FLASH_DEFINITION` identifier defined:
```
[Defines]
  ...
  FLASH_DEFINITION               = OvmfPkg/OvmfPkgX64.fdf
```

The referenced FDF file should be formatted according to the [EDK II Flash Description (FDF) File Specification](https://edk2-docs.gitbook.io/edk-ii-fdf-specification/).
This file defines the flash images generated in the end of the build.

Each image is called `Flash Device Image` and is defined by the `[FD.<name>]` section.

For example [`OvmfPkg/OvmfPkgX64.fdf`](https://github.com/tianocore/edk2/blob/master/OvmfPkg/OvmfPkgX64.fdf) has 4 such sections:
```
[FD.OVMF]
[FD.OVMF_VARS]
[FD.OVMF_CODE]
[FD.MEMFD]
```
Each of these sections leads to the `Flash Device Image` generation:
```
$ find Build/OvmfX64/RELEASE_GCC5/FV/ -name "*.fd"
Build/OvmfX64/RELEASE_GCC5/FV/OVMF.fd
Build/OvmfX64/RELEASE_GCC5/FV/OVMF_CODE.fd
Build/OvmfX64/RELEASE_GCC5/FV/OVMF_VARS.fd
Build/OvmfX64/RELEASE_GCC5/FV/MEMFD.fd
```
You can see how they are generated in the log above:
```
$ build --platform=OvmfPkg/OvmfPkgX64.dsc --arch=X64 --buildtarget=RELEASE --tagname=GCC5

<...>

Fd File Name:OVMF (/<...>/edk2/Build/OvmfX64/RELEASE_GCC5/FV/OVMF.fd)

<...>

Fd File Name:OVMF_VARS (/<...>/edk2/Build/OvmfX64/RELEASE_GCC5/FV/OVMF_VARS.fd)

<...>

Fd File Name:OVMF_CODE (/<...>/edk2/Build/OvmfX64/RELEASE_GCC5/FV/OVMF_CODE.fd)

<...>

Fd File Name:MEMFD (/<...>/edk2/Build/OvmfX64/RELEASE_GCC5/FV/MEMFD.fd)

<...>

GUID cross reference file can be found at /<...>/edk2/Build/OvmfX64/RELEASE_GCC5/FV/Guid.xref

FV Space Information
SECFV [13%Full] 212992 (0x34000) total, 27904 (0x6d00) used, 185088 (0x2d300) free
PEIFV [11%Full] 917504 (0xe0000) total, 102824 (0x191a8) used, 814680 (0xc6e58) free
DXEFV [22%Full] 12582912 (0xc00000) total, 2879400 (0x2befa8) used, 9703512 (0x941058) free
FVMAIN_COMPACT [27%Full] 3440640 (0x348000) total, 935208 (0xe4528) used, 2505432 (0x263ad8) free

- Done -
```

## `Flash Device Image` flash description tokens

The `Flash Device Image` is intendend for usage on a specific flash device, therefore the following tokens are mandatory for each FD section:
```
BaseAddress   = <...>
Size          = <...>
ErasePolarity = <...>
```
- `BaseAddress` field defines an address at which flash image would be mapped to the CPU memory
- `Size` field defines the size of the flash image
- `ErasePolarity` field defines how to fill not used space in flash image (with 0 or 1)

Most often the following two tokens are also defined:
```
BlockSize = <...>
NumBlocks = <...>
```
These tokens define block structure of a flash chip. If they are present this rule should be satisfied:
```
BlockSize * NumBlocks = Size
```

Let's look at the values for these tokens in the [`OvmfPkg/OvmfPkgX64.fdf`](https://github.com/tianocore/edk2/blob/master/OvmfPkg/OvmfPkgX64.fdf) file. Most of the tokens there are defined via defines. For their definition we should look in the `[Defines]` section:
```
[Defines]
!include OvmfPkgDefines.fdf.inc
```
As you can see this section uses `!include` directive to abstract all defines in the separate file. If you look at this file, you'll see that it contains some `if...endif` logic depending on the value of `FD_SIZE_IN_KB` variable for various configurations. In our case [`OvmfPkg/OvmfPkgX64.dsc`](https://github.com/tianocore/edk2/blob/master/OvmfPkg/OvmfPkgX64.dsc) defines `FD_SIZE_IN_KB` as `4096`:
```
[Defines]
  ...
  !ifdef $(FD_SIZE_1MB)
    DEFINE FD_SIZE_IN_KB           = 1024
  !else
  !ifdef $(FD_SIZE_2MB)
    DEFINE FD_SIZE_IN_KB           = 2048
  !else
  !ifdef $(FD_SIZE_4MB)
    DEFINE FD_SIZE_IN_KB           = 4096
  !else
    DEFINE FD_SIZE_IN_KB           = 4096
  !endif
```
Therefore we use the following defines from the [`OvmfPkg/OvmfPkgDefines.fdf.inc`](https://github.com/tianocore/edk2/blob/master/OvmfPkg/OvmfPkgDefines.fdf.inc) file:
```
DEFINE BLOCK_SIZE        = 0x1000

!if $(FD_SIZE_IN_KB) == 4096
DEFINE VARS_SIZE         = 0x84000
DEFINE VARS_BLOCKS       = 0x84
DEFINE VARS_LIVE_SIZE    = 0x40000
DEFINE VARS_SPARE_SIZE   = 0x42000

DEFINE FW_BASE_ADDRESS   = 0xFFC00000
DEFINE FW_SIZE           = 0x00400000
DEFINE FW_BLOCKS         = 0x400
DEFINE CODE_BASE_ADDRESS = 0xFFC84000
DEFINE CODE_SIZE         = 0x0037C000
DEFINE CODE_BLOCKS       = 0x37C
DEFINE FVMAIN_SIZE       = 0x00348000
DEFINE SECFV_OFFSET      = 0x003CC000
DEFINE SECFV_SIZE        = 0x34000
!endif

DEFINE MEMFD_BASE_ADDRESS = 0x800000
```

Now we can calculate the token values for each `Flash Device Image` in the [`OvmfPkg/OvmfPkgX64.fdf`](https://github.com/tianocore/edk2/blob/master/OvmfPkg/OvmfPkgX64.fdf):
```
[FD.OVMF]
BaseAddress   = $(FW_BASE_ADDRESS)   # 0xFFC00000
Size          = $(FW_SIZE)           # 0x00400000
ErasePolarity = 1
BlockSize     = $(BLOCK_SIZE)        # 0x1000
NumBlocks     = $(FW_BLOCKS)         # 0x400

...

[FD.OVMF_VARS]
BaseAddress   = $(FW_BASE_ADDRESS)   # 0xFFC00000
Size          = $(VARS_SIZE)         # 0x84000
ErasePolarity = 1
BlockSize     = $(BLOCK_SIZE)        # 0x1000
NumBlocks     = $(VARS_BLOCKS)       # 0x84

...

[FD.OVMF_CODE]
BaseAddress   = $(CODE_BASE_ADDRESS) # 0xFFC84000
Size          = $(CODE_SIZE)         # 0x0037C000
ErasePolarity = 1
BlockSize     = $(BLOCK_SIZE)        # 0x1000
NumBlocks     = $(CODE_BLOCKS)       # 0x37C

...

[FD.MEMFD]
BaseAddress   = $(MEMFD_BASE_ADDRESS) # 0x800000
Size          = 0xD00000
ErasePolarity = 1
BlockSize     = 0x10000
NumBlocks     = 0xD0
```

Here you can see that `BlockSize * NumBlocks = Size` formula is correct for every FD.

And you can verify that size of the files matches the `Size` field values (although it is not mandatory as we will see next):
```
$ printf "%x\n" `stat -c "%s"  Build/OvmfX64/RELEASE_GCC5/FV/OVMF.fd`
400000
$ printf "%x\n" `stat -c "%s"  Build/OvmfX64/RELEASE_GCC5/FV/OVMF_CODE.fd`
37c000
$ printf "%x\n" `stat -c "%s"  Build/OvmfX64/RELEASE_GCC5/FV/OVMF_VARS.fd`
84000
$ printf "%x\n" `stat -c "%s"  Build/OvmfX64/RELEASE_GCC5/FV/MEMFD.fd`
d00000
```

Couple of words about the `OVMF*.fd` images itself. Remember what commands we've used to launch QEMU:
```
qemu-system-x86_64 \
  -drive if=pflash,format=raw,file=Build/OvmfX64/RELEASE_GCC5/FV/OVMF.fd \
  ...

qemu-system-x86_64 \
  -drive if=pflash,format=raw,readonly,file=Build/OvmfX64/RELEASE_GCC5/FV/OVMF_CODE.fd \
  -drive if=pflash,format=raw,file=Build/OvmfX64/RELEASE_GCC5/FV/OVMF_VARS.fd \
  ...
```
If you look closely to the `OVMF_CODE.fd` and `OVMF_VARS.fd` you could notice that 
```
[FD.OVMF_VARS].BaseAddress + [FD.OVMF_VARS].Size = [FD.OVMF_CODE].BaseAddress
[FD.OVMF_CODE].BaseAddress + [FD.OVMF_CODE].Size = 0x100000000

[FD.OVMF].BaseAddress + [FD.OVMF].Size = 0x100000000

[FD.OVMF].BaseAddress == [FD.OVMF_VARS].BaseAddress
```
Simply speaking the `[FD.OVMF]` image is just the `[FD.OVMF_VARS]` image followed by the `[FD.OVMF_CODE]` image.

# Regions

`Flash Device Image` consists of regions. It is necessary to have at least one region in a `Flash Device Image`.

The most simple definition of region is:
```
Offset|Size
```
For example:
```
0x500|0x600
```
This is a region that starts at offset 0x500 with a size of 0x600. It is important to note that the final `Flash Device Image` size is defined by its regions and not by the `Size` token value. The none of the regions can have addresses above the `Size`.

If we want to, we can assign PCDs to the region offset/size values:
```
Offset|Size
TokenSpaceGuidCName.PcdOffsetCName | TokenSpaceGuidCName.PcdSizeCName
```
For example:
```
0x500|0x600
gEfiMyTokenSpaceGuid.PcdFlashRegionBaseAddress | gEfiMyTokenSpaceGuid.PcdFlashRegionSize
```
This way the build system will automatically override the respective PCDs. Off course these PCDs `gEfiMyTokenSpaceGuid.PcdFlashRegionBaseAddress` and `gEfiMyTokenSpaceGuid.PcdFlashRegionSize` must be defined in the DEC file. The first `<Offset>` PCD would be overriden with a respect to `FD.<...>].BaseAddress` value, i.e. it would be assigned to the `([FD.<...>].BaseAddress + <Offset>)` value.

They can be of types `PcdsFixedAtBuild` or `PcdsPatchableInModule`, but not dynamic!

Another thing that we would want to add to our region definition is a region type:
```
Offset|Size
TokenSpaceGuidCName.PcdOffsetCName | TokenSpaceGuidCName.PcdSizeCName
  RegionType
```

If `RegionType` is not present, it is considered `None` and edk2 doesn't touch this region data. It can be usefull, for example, if we define a space in flash reserved for logs.
If `RegionType` is present, it can be one of the following types: `FV`, `DATA`, `FILE`, `INF` or `CAPSULE`.

Here are some explanation for the most common ones: `FV`, `DATA`, `FILE`:

## FV region

The `FV` region type is a pointer to some `Firmware Volume`. `Firmware Volume` (`FV`) is a region with a filesystem inside. Formatting of this region is defined by the `UEFI Platform Initialization (PI) specification (Volume 3: Shared Architectural Elements)`. We will look at the `Firmware Volumes` in the next lesson.

Example:
```
0x000000|0x0C0000
FV = FVMAIN
```
In this case FDF must define the section `[FV.FVMAIN]`.

## DATA region

In the case of a `DATA` region we immediately define the data inside the region via initialized array:
```
0x0|0x50
DATA = {
  0xDE, 0xAD, 0xBE, 0xEF
}
```
This would give us a region with such data:
```
00000000  de ad be ef ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
00000010  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
*
00000050
```

If you don't want to pollute FDF file, you can create some file and put data text into it:
```
0x0|0x50
DATA = {
  !include mydata.txt
}
```
```
$ cat mydata.txt
0xDE, 0xAD, 0xBE, 0xEF
```

## FILE region

FILE region is a pointer to a binary file that will be loaded into the flash device.

For example create a simple file with text:
```
$ cat "hello!" > hello.txt
```
And define this region:
```
0x0|0x50
FILE = hello.txt
```
In the final flash image it would look like this:
```
00000000  68 65 6c 6c 6f 21 0a ff  ff ff ff ff ff ff ff ff  |hello!..........|
00000010  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
*
00000050
```

# OVMF `Flash Device Image` regions

Let's look closely to the OVMF `Flash Device Image` regions.

Start with `[FD.OVMF_VARS]` Flash Device Image:
```
[FD.OVMF_VARS]
...
!include VarStore.fdf.inc
```
As you can see all of its regions are defined in the [`OvmfPkg/VarStore.fdf.inc`](https://github.com/tianocore/edk2/blob/master/OvmfPkg/VarStore.fdf.inc) file.

If we remember that `FD_SIZE_IN_KB` is equal to `4096` in our case we can simplify `OvmfPkg/VarStore.fdf.inc` content to this:
```
0x00000000|0x00040000 # NV_VARIABLE_STORE
DATA = {
  ...
}
0x00040000|0x00001000 # NV_EVENT_LOG
0x00041000|0x00001000 # NV_FTW_WORKING
DATA = {
  ...
}
0x00042000|0x00042000 # NV_FTW_SPARE
```

Here we have two empty regions, and two regions initialized with DATA arrays.

Now we can see how FDF content corresponds to build log output:
```
Fd File Name:OVMF_VARS (/<...>/edk2/Build/OvmfX64/RELEASE_GCC5/FV/OVMF_VARS.fd)

Generate Region at Offset 0x0
   Region Size = 0x40000
   Region Name = DATA

Generate Region at Offset 0x40000
   Region Size = 0x1000
   Region Name = None

Generate Region at Offset 0x41000
   Region Size = 0x1000
   Region Name = DATA

Generate Region at Offset 0x42000
   Region Size = 0x42000
   Region Name = None
```

The `[FD.OVMF_CODE]` flash device image consists of two Firmware Volumes (for the defines definition look at the [`OvmfPkg/OvmfPkgDefines.fdf.inc`](https://github.com/tianocore/edk2/blob/master/OvmfPkg/OvmfPkgDefines.fdf.inc) content):
```
[FD.OVMF_CODE]
...
0x00000000|$(FVMAIN_SIZE)        # 0x00000000|0x00348000
FV = FVMAIN_COMPACT

$(FVMAIN_SIZE)|$(SECFV_SIZE)     # 0x00348000|0x34000
FV = SECFV
```
And here is example of a build log output for this FD from the start of the lesson:
```
Fd File Name:OVMF_CODE (/<...>/edk2/Build/OvmfX64/RELEASE_GCC5/FV/OVMF_CODE.fd)

Generate Region at Offset 0x0
   Region Size = 0x348000
   Region Name = FV

Generate Region at Offset 0x348000
   Region Size = 0x34000
   Region Name = FV
```

Finally the `[FD.OVMF]` content:
```
[FD.OVMF]
...
!include VarStore.fdf.inc

$(VARS_SIZE)|$(FVMAIN_SIZE)
FV = FVMAIN_COMPACT

$(SECFV_OFFSET)|$(SECFV_SIZE)
FV = SECFV
```
Which means:
```
0x00000000|0x00040000 # NV_VARIABLE_STORE
DATA = {
  ...
}
0x00040000|0x00001000 # NV_EVENT_LOG
0x00041000|0x00001000 # NV_FTW_WORKING
DATA = {
  ...
}
0x00042000|0x00042000 # NV_FTW_SPARE

$(VARS_SIZE)|$(FVMAIN_SIZE)      # 0x84000 | 0x00348000
FV = FVMAIN_COMPACT

$(SECFV_OFFSET)|$(SECFV_SIZE)    # 0x003CC000 | 0x34000
FV = SECFV
```
Compare it with the build log for this FD:
```
Fd File Name:OVMF (/<...>/edk2/Build/OvmfX64/RELEASE_GCC5/FV/OVMF.fd)

Generate Region at Offset 0x0
   Region Size = 0x40000
   Region Name = DATA

Generate Region at Offset 0x40000
   Region Size = 0x1000
   Region Name = None

Generate Region at Offset 0x41000
   Region Size = 0x1000
   Region Name = DATA

Generate Region at Offset 0x42000
   Region Size = 0x42000
   Region Name = None

Generate Region at Offset 0x84000
   Region Size = 0x348000
   Region Name = FV

...

Generate Region at Offset 0x3CC000
   Region Size = 0x34000
   Region Name = FV
```

# Creating `UefiLessonsPkg.fdf`

If you want to, you can experiment with FDF in our `UefiLessonsPkg` package.

For this add `FLASH_DEFINITION` define to the `UefiLessonsPkg/UefiLessonsPkg.dsc` file:
```
[Defines]
  ...
  FLASH_DEFINITION               = UefiLessonsPkg/UefiLessonsPkg.fdf

...
```
And create file `UefiLessonsPkg/UefiLessonsPkg.fdf`. For example fill it with this content:
```
[FD.SimpleImage]
BaseAddress   = 0x0
Size          = 0x1000
ErasePolarity = 1

0x00|0x50

```
Important notice: keep in mind that the FDF file must end with an empty string. In other case EDKII build would fail!

The FDF file above would produce the following FD as a build result:
```
Fd File Name:SIMPLEIMAGE (/<...>/edk2/Build/UefiLessonsPkg/RELEASE_GCC5/FV/SIMPLEIMAGE.fd)

Generate Region at Offset 0x0
   Region Size = 0x50
   Region Name = None
```
You can look at its content with a help of a `hexdump` utility:
```
$ hexdump /<...>/edk2/Build/UefiLessonsPkg/RELEASE_GCC5/FV/SIMPLEIMAGE.fd
0000000 ffff ffff ffff ffff ffff ffff ffff ffff
*
0000050
```

# Padding regions

If regions would start not from the 0x0, the build system will automatically create a padding region. For example this config:
```
[FD.SimpleImage]
BaseAddress   = 0x0
Size          = 0x1000
ErasePolarity = 1

0x60|0x300
```
Would produce the following log:
```
Fd File Name:SIMPLEIMAGE (/<...>/edk2/Build/UefiLessonsPkg/RELEASE_GCC5/FV/SIMPLEIMAGE.fd)
Padding region starting from offset 0x0, with size 0x60

Generate Region at Offset 0x0
   Region Size = 0x60
   Region Name = None

Generate Region at Offset 0x60
   Region Size = 0x300
   Region Name = None
```
And hexdump output would look like this:
```
$ hexdump /<...>/edk2/Build/UefiLessonsPkg/RELEASE_GCC5/FV/SIMPLEIMAGE.fd
0000000 ffff ffff ffff ffff ffff ffff ffff ffff
*
0000360
```
The padding region is also created if there is an unused space between two regions. For example this config:
```
[FD.SimpleImage]
BaseAddress   = 0x0
Size          = 0x1000
ErasePolarity = 1
BlockSize = 0x100
NumBlocks = 0x10

0x0|0x50

0x80|0x40
```
would produce the following build log output:
```
Fd File Name:SIMPLEIMAGE (/<...>/edk2/Build/UefiLessonsPkg/RELEASE_GCC5/FV/SIMPLEIMAGE.fd)

Generate Region at Offset 0x0
   Region Size = 0x50
   Region Name = None
Padding region starting from offset 0x50, with size 0x30

Generate Region at Offset 0x50
   Region Size = 0x30
   Region Name = None

Generate Region at Offset 0x80
   Region Size = 0x40
   Region Name = None
```
And hexdump output would look like this:
```
$ hexdump /<...>/edk2/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  |................|
*
000000c0
```

## Define PCDs from region offset and size

You can define PCDs in the DEC file `UefiLessonsPkg/UefiLessonsPkg.dec`:
```
[PcdsFixedAtBuild]
  ...
  gUefiLessonsPkgTokenSpaceGuid.Region1Offset|0|UINT32|0x00000005
  gUefiLessonsPkgTokenSpaceGuid.Region1Size|0|UINT32|0x00000006
```
And initialize them in FDF:
```
[FD.SimpleImage]
BaseAddress   = 0x0
Size          = 0x1000
ErasePolarity = 1

0x0|0x50
gUefiLessonsPkgTokenSpaceGuid.Region1Offset | gUefiLessonsPkgTokenSpaceGuid.Region1Size
```

For example if we add these PCDs to the `UefiLessonsPkg/PCDLesson/PCDLesson.inf` file:
```
[FixedPcd]
  ...
  gUefiLessonsPkgTokenSpaceGuid.Region1Offset
  gUefiLessonsPkgTokenSpaceGuid.Region1Size
 ```

The following defines would be generated in the `Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/PCDLesson/PCDLesson/DEBUG/AutoGen.h` file ready for the usage in your code:
```cpp
#define _PCD_TOKEN_Region1Offset  0U
#define _PCD_SIZE_Region1Offset 4
#define _PCD_GET_MODE_SIZE_Region1Offset  _PCD_SIZE_Region1Offset
#define _PCD_VALUE_Region1Offset  0x00000000U                               <------------
extern const  UINT32  _gPcd_FixedAtBuild_Region1Offset;
#define _PCD_GET_MODE_32_Region1Offset  _gPcd_FixedAtBuild_Region1Offset
//#define _PCD_SET_MODE_32_Region1Offset  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD

#define _PCD_TOKEN_Region1Size  0U
#define _PCD_SIZE_Region1Size 4
#define _PCD_GET_MODE_SIZE_Region1Size  _PCD_SIZE_Region1Size
#define _PCD_VALUE_Region1Size  0x00000050U                                 <------------
extern const  UINT32  _gPcd_FixedAtBuild_Region1Size;
#define _PCD_GET_MODE_32_Region1Size  _gPcd_FixedAtBuild_Region1Size
//#define _PCD_SET_MODE_32_Region1Size  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD
```

## Define DATA region

As a final example let's declare the region as DATA and initialize it:
```
[FD.SimpleImage]
BaseAddress   = 0x0
Size          = 0x1000
ErasePolarity = 1

0x0|0x50
DATA = {
  0xDE, 0xAD, 0xBE, 0xEF
}
```

This would give us the following content in the final image:
```
$ hexdump /<...>/edk2/Build/UefiLessonsPkg/RELEASE_GCC5/FV/SIMPLEIMAGE.fd -C
00000000  de ad be ef ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
00000010  ff ff ff ff ff ff ff ff  ff ff ff ff ff ff ff ff  |................|
*
00000050
```