aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKonstantin Aladyshev <aladyshev22@gmail.com>2022-08-03 16:15:27 +0300
committerKonstantin Aladyshev <aladyshev22@gmail.com>2022-08-03 16:15:27 +0300
commite2a415f13a7090b12f9363d51a0d1f80cafded67 (patch)
tree6f2a6a108461d71e25e3ded92aee30e1a298e4f0
parent3cf6d5377332b7d91ff2a76b0d045e81654d845f (diff)
downloadUEFI-Lessons-e2a415f13a7090b12f9363d51a0d1f80cafded67.tar.gz
UEFI-Lessons-e2a415f13a7090b12f9363d51a0d1f80cafded67.tar.bz2
UEFI-Lessons-e2a415f13a7090b12f9363d51a0d1f80cafded67.zip
Update fixed PCD lesson
Signed-off-by: Konstantin Aladyshev <aladyshev22@gmail.com>
-rw-r--r--Lessons/Lesson_20/README.md720
-rw-r--r--Lessons/Lesson_20/UefiLessonsPkg/PCDLesson/PCDLesson.c28
-rw-r--r--Lessons/Lesson_20/UefiLessonsPkg/PCDLesson/PCDLesson.inf28
-rw-r--r--Lessons/Lesson_20/UefiLessonsPkg/UefiLessonsPkg.dec62
4 files changed, 806 insertions, 32 deletions
diff --git a/Lessons/Lesson_20/README.md b/Lessons/Lesson_20/README.md
index 46a4c5b..e9ad949 100644
--- a/Lessons/Lesson_20/README.md
+++ b/Lessons/Lesson_20/README.md
@@ -17,37 +17,57 @@ Usually in is defined as a `g<PackageName>TokenSpaceGuid`, so add this to our `U
...
gUefiLessonsPkgTokenSpaceGuid = {0x150cab53, 0xad47, 0x4385, {0xb5, 0xdd, 0xbc, 0xfc, 0x76, 0xba, 0xca, 0xf0}}
```
+As for the `<Token>` values, usually the package creators just start to write them sequentially from `0x00000001`.
+Also very often when they want to indicate that some PCDs are belong to one logical group, they can start using the token numbers to indicate that. For example the token groups can be `0x1XXXXXXX`, `0x2XXXXXXX`, and so on, or something similar.
-Now we can define our PCDs in the same *.dec file. Let's start with `UINT32 PcdMyVar32 = 42`:
+In any way as the package evolve some PCD are getting added and some are getting removed. And if you use such sequential numbering this can give you headache. For example at one point you can end up in situation when you have PCDs with the tokens `0x0000000A` and `0x0000000B` and the most logical way to put your new PCD is after the one with a `0x0000000A` token. Off course you can assign PCD token to `0x0000000C` and do it, but what is the point of a sequential numbering then?
+
+Because of that I've created `./scripts/genToken.sh` script that generates random 4-byte token number:
+```
+#!/bin/bash
+
+##
+# This is a simple script that generates a random 4-byte hex value for a PCD Token
+##
+
+hexdump -vn4 -e'"0x%08X\n"' /dev/urandom
+```
+The usage is simple as this:
+```
+$ ./scripts/genToken.sh
+0x3B81CDF1
+```
+
+Now we can define our PCD in the same `*.dec` file that we've used to define `gUefiLessonsPkgTokenSpaceGuid`. Let's start with a PCD `UINT8 PcdInt8 = 0x88`:
```
[PcdsFixedAtBuild]
- gEfiUefiLessonsPkgTokenSpaceGuid.PcdMyVar32|42|UINT32|0x00000001
+ gEfiUefiLessonsPkgTokenSpaceGuid.PcdInt8|0x88|UINT8|0x3B81CDF1
```
Now create an app `PCDLesson` with the following code in its entry point function:
```
-Print(L"PcdMyVar32=%d\n", FixedPcdGet32(PcdMyVar32));
+Print(L"PcdInt8=0x%x\n", FixedPcdGet8(PcdInt8));
```
-To use `FixedPcdGet32` in our code we need to add the necessary include:
+To use `FixedPcdGet8` in our code we need to add the necessary include:
```
#include <Library/PcdLib.h>
```
-If you check out this file (https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Library/PcdLib.h) you'll see that `FixedPcdGet32` is simply a define statement:
+If you check out this file (https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Library/PcdLib.h) you'll see that `FixedPcdGet8` is simply a define statement:
```
-#define FixedPcdGet32(TokenName) _PCD_VALUE_##TokenName
+#define FixedPcdGet8(TokenName) _PCD_VALUE_##TokenName
```
If we try to build our app now, build will fail, as we don't have such define in our app:
```
-/home/kostr/tiano/edk2/MdePkg/Include/Library/PcdLib.h:97:45: error: ‘_PCD_VALUE_PcdMyVar32’ undeclared (first use in this function)
- 97 | #define FixedPcdGet32(TokenName) _PCD_VALUE_##TokenName
+/home/kostr/tiano/edk2/MdePkg/Include/Library/PcdLib.h:97:45: error: ‘_PCD_VALUE_PcdInt8’ undeclared (first use in this function)
+ 97 | #define FixedPcdGet8(TokenName) _PCD_VALUE_##TokenName
| ^~~~~~~~~~~
```
To fix this we need to add this PCD to our app `*.inf` file:
```
[FixedPcd]
- gUefiLessonsPkgTokenSpaceGuid.PcdMyVar32
+ gUefiLessonsPkgTokenSpaceGuid.PcdInt8
```
Also we need to include "dec" file that defines this PCD:
@@ -59,50 +79,692 @@ Also we need to include "dec" file that defines this PCD:
Now compilation would succeed.
-If you check out the content of autogenerated files `AutoGen.h`/`AutoGen.c`, you'll see, that our PCD is there.
+If you check out the content of autogenerated files `AutoGen.h`/`AutoGen.c`, you'll see, that our PCD is there:
-Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/PCDLesson/PCDLesson/DEBUG/AutoGen.h
+- `Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/PCDLesson/PCDLesson/DEBUG/AutoGen.h`
```
// Definition of PCDs used in this module
-#define _PCD_TOKEN_PcdMyVar32 0U
-#define _PCD_SIZE_PcdMyVar32 4
-#define _PCD_GET_MODE_SIZE_PcdMyVar32 _PCD_SIZE_PcdMyVar32
-#define _PCD_VALUE_PcdMyVar32 42U
-extern const UINT32 _gPcd_FixedAtBuild_PcdMyVar32;
-#define _PCD_GET_MODE_32_PcdMyVar32 _gPcd_FixedAtBuild_PcdMyVar32
-//#define _PCD_SET_MODE_32_PcdMyVar32 ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD
+#define _PCD_TOKEN_PcdInt8 0U
+#define _PCD_SIZE_PcdInt8 1
+#define _PCD_GET_MODE_SIZE_PcdInt8 _PCD_SIZE_PcdInt8
+#define _PCD_VALUE_PcdInt8 0x88U
+extern const UINT8 _gPcd_FixedAtBuild_PcdInt8;
+#define _PCD_GET_MODE_8_PcdInt8 _gPcd_FixedAtBuild_PcdInt8
+//#define _PCD_SET_MODE_8_PcdInt8 ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD
```
-Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/PCDLesson/PCDLesson/DEBUG/AutoGen.c
+- `Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/PCDLesson/PCDLesson/DEBUG/AutoGen.c`
```
// Definition of PCDs used in this module
-GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdMyVar32 = _PCD_VALUE_PcdMyVar32;
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gPcd_FixedAtBuild_PcdInt8 = _PCD_VALUE_PcdInt8;
```
-So in our case preprocessor expands code like this:
+So in our case the preprocessor expands code like this:
```
-FixedPcdGet32(PcdMyVar32) -> _PCD_VALUE_PcdMyVar32 -> 42U
+FixedPcdGet8(PcdInt8) -> _PCD_VALUE_PcdInt8 -> 0x88U
```
-If you execute app code under OVMF:
+If you execute app code under OVMF you would get correct value printed:
```
FS0:\> PCDLesson.efi
-PcdMyVar32=42
+PcdInt8=0x88
```
-There are multiple types of PCDs. `FixedAtBuild` PCD is only one of them. In our code we've used `FixedPcdGet` call to get PCD value, this call would only work if PCD is `FixedAtBuild`. However there is a generic `PcdGet` call that can be used to get a value of PCD regardless its type.
-https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Library/PcdLib.h:
+There are multiple types of PCDs. `FixedAtBuild` PCD is only one of them. In our code we've used `FixedPcdGet8` call to get PCD value, this call would only work if PCD is `FixedAtBuild`. However there is a generic `PcdGet8` call that can be used to get a value of PCD regardless its PCD type.
+
+[https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Library/PcdLib.h](https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Library/PcdLib.h):
```
-#define PcdGet32(TokenName) _PCD_GET_MODE_32_##TokenName
+#define PcdGet8(TokenName) _PCD_GET_MODE_8_##TokenName
```
In our case this would expand to:
```
-PcdGet32(PcdMyVar32) -> _PCD_GET_MODE_32_PcdMyVar32 -> _gPcd_FixedAtBuild_PcdMyVar32
+PcdGet8(PcdInt8) -> _PCD_GET_MODE_8_PcdInt8 -> _gPcd_FixedAtBuild_PcdInt8
```
The latter one is a variable that is defined in a `AutoGen.c` file:
```
- GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdMyVar32 = 42U;
+ GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gPcd_FixedAtBuild_PcdInt8 = _PCD_VALUE_PcdInt8 // =0x88U;
```
So as you can see result would be the same. The difference is that `PcdGet` would work with other PCD types, that we would cover in the next lessons.
+
+You can verify that this code:
+```
+Print(L"PcdInt8=%d\n", FixedPcdGet8(PcdInt8));
+Print(L"PcdInt8=%d\n", PcdGet8(PcdInt8));
+```
+Would produce the output:
+```
+FS0:\> PCDLesson.efi
+PcdInt8=0x88
+PcdInt8=0x88
+```
+
+# Other simple PCD types
+
+In the example above we've used `UINT8` as a `<DatumType>` of our PCD. Along with this type EDK2 also allows you to use other integer data types `UINT16`, `UINT32` `UINT64` integer data types and a `BOOLEAN` type.
+
+Add these PCDs to the `UefiLessonsPkg/UefiLessonsPkg.dec`:
+```
+[PcdsFixedAtBuild]
+ ...
+ gUefiLessonsPkgTokenSpaceGuid.PcdInt16|0x1616|UINT16|0x77DFB6E6
+ gUefiLessonsPkgTokenSpaceGuid.PcdInt32|0x32323232|UINT32|0xF2A48130
+ gUefiLessonsPkgTokenSpaceGuid.PcdInt64|0x6464646464646464|UINT64|0x652F4E29
+ gUefiLessonsPkgTokenSpaceGuid.PcdBool|TRUE|BOOLEAN|0x69E88A63
+```
+
+And include them in our module `UefiLessonsPkg/PCDLesson/PCDLesson.inf`:
+```
+[FixedPcd]
+ ...
+ gUefiLessonsPkgTokenSpaceGuid.PcdInt16
+ gUefiLessonsPkgTokenSpaceGuid.PcdInt32
+ gUefiLessonsPkgTokenSpaceGuid.PcdInt64
+ gUefiLessonsPkgTokenSpaceGuid.PcdBool
+```
+
+This would populate them to the `Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/PCDLesson/PCDLesson/DEBUG/AutoGen.h`:
+```
+#define _PCD_TOKEN_PcdInt16 0U
+#define _PCD_SIZE_PcdInt16 2
+#define _PCD_GET_MODE_SIZE_PcdInt16 _PCD_SIZE_PcdInt16
+#define _PCD_VALUE_PcdInt16 0x1616U
+extern const UINT16 _gPcd_FixedAtBuild_PcdInt16;
+#define _PCD_GET_MODE_16_PcdInt16 _gPcd_FixedAtBuild_PcdInt16
+//#define _PCD_SET_MODE_16_PcdInt16 ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdInt32 0U
+#define _PCD_SIZE_PcdInt32 4
+#define _PCD_GET_MODE_SIZE_PcdInt32 _PCD_SIZE_PcdInt32
+#define _PCD_VALUE_PcdInt32 0x32323232U
+extern const UINT32 _gPcd_FixedAtBuild_PcdInt32;
+#define _PCD_GET_MODE_32_PcdInt32 _gPcd_FixedAtBuild_PcdInt32
+//#define _PCD_SET_MODE_32_PcdInt32 ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdInt64 0U
+#define _PCD_SIZE_PcdInt64 8
+#define _PCD_GET_MODE_SIZE_PcdInt64 _PCD_SIZE_PcdInt64
+#define _PCD_VALUE_PcdInt64 0x6464646464646464ULL
+extern const UINT64 _gPcd_FixedAtBuild_PcdInt64;
+#define _PCD_GET_MODE_64_PcdInt64 _gPcd_FixedAtBuild_PcdInt64
+//#define _PCD_SET_MODE_64_PcdInt64 ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdBool 0U
+#define _PCD_SIZE_PcdBool 1
+#define _PCD_GET_MODE_SIZE_PcdBool _PCD_SIZE_PcdBool
+#define _PCD_VALUE_PcdBool 1U
+extern const BOOLEAN _gPcd_FixedAtBuild_PcdBool;
+#define _PCD_GET_MODE_BOOL_PcdBool _gPcd_FixedAtBuild_PcdBool
+//#define _PCD_SET_MODE_BOOL_PcdBool ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD
+```
+
+And to the `Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/PCDLesson/PCDLesson/DEBUG/AutoGen.c`:
+```
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT16 _gPcd_FixedAtBuild_PcdInt16 = _PCD_VALUE_PcdInt16;
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdInt32 = _PCD_VALUE_PcdInt32;
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT64 _gPcd_FixedAtBuild_PcdInt64 = _PCD_VALUE_PcdInt64;
+GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdBool = _PCD_VALUE_PcdBool;
+```
+
+Everything is similar to the `UINT8` case.
+
+Like before you can use either `FixedPcdGet` or `PcdGet` API to get the PCD values:
+```
+Print(L"PcdInt16=0x%x\n", FixedPcdGet16(PcdInt16));
+Print(L"PcdInt32=0x%x\n", FixedPcdGet32(PcdInt32));
+Print(L"PcdInt64=0x%x\n", FixedPcdGet64(PcdInt64));
+Print(L"PcdBool=0x%x\n", FixedPcdGetBool(PcdBool));
+Print(L"PcdInt16=0x%x\n", PcdGet16(PcdInt16));
+Print(L"PcdInt32=0x%x\n", PcdGet32(PcdInt32));
+Print(L"PcdInt64=0x%x\n", PcdGet64(PcdInt64));
+Print(L"PcdIntBool=0x%x\n", PcdGetBool(PcdBool));
+```
+
+Once again the values would be the same:
+```
+FS0:\> PCDLesson.efi
+...
+PcdInt16=0x1616
+PcdInt32=0x32323232
+PcdInt64=0x64646464
+PcdBool=0x1
+PcdInt16=0x1616
+PcdInt32=0x32323232
+PcdInt64=0x64646464
+PcdIntBool=0x1
+```
+
+# Expressions in initialization values
+
+It is possible to use expressions in initialization values. Keep in mind that when you use `|` character in you operations, you must put the expression inside the brackets `(...)`.
+
+Here are some examples:
+```
+[PcdsFixedAtBuild]
+ ...
+ gUefiLessonsPkgTokenSpaceGuid.PcdExpression|0xFF000000 + 0x00FFFFFF|UINT32|0x9C405222
+ gUefiLessonsPkgTokenSpaceGuid.PcdExpression_1|((0xFFFFFFFF & 0x000000FF) << 8) + 0x33|UINT32|0x5911C44B
+ gUefiLessonsPkgTokenSpaceGuid.PcdExpression_2|(0x00000000 | 0x00100000)|UINT32|0xAD880207
+ gUefiLessonsPkgTokenSpaceGuid.PcdExpression_3|(56 < 78) || !(23 > 44)|BOOLEAN|0x45EDE955
+```
+
+Populate them to the INF file:
+```
+[FixedPcd]
+ ...
+ gUefiLessonsPkgTokenSpaceGuid.PcdExpression
+ gUefiLessonsPkgTokenSpaceGuid.PcdExpression_1
+ gUefiLessonsPkgTokenSpaceGuid.PcdExpression_2
+ gUefiLessonsPkgTokenSpaceGuid.PcdExpression_3
+```
+
+And if you build and look at the `AutoGen.h` you'll see that values are calculated correctly:
+```
+...
+#define _PCD_VALUE_PcdExpression 4294967295U // =0xffffffff
+...
+#define _PCD_VALUE_PcdExpression_1 65331U // =0xff33
+...
+#define _PCD_VALUE_PcdExpression_2 1048576U // =0x100000
+...
+#define _PCD_VALUE_PcdExpression_3 1U
+...
+```
+
+# `VOID*` PCD data type
+
+Besides the simple types `UINT8`/`UINT16`/`UINT32`/`UINT64`/`BOOLEAN` EDKII allows to use `VOID*` type. Let's look at the ways how it can be used.
+
+## String PCDs
+
+Add these PCDs to the `UefiLessonsPkg/UefiLessonsPkg.dec`:
+```
+[PcdsFixedAtBuild]
+ ...
+ gUefiLessonsPkgTokenSpaceGuid.PcdAsciiStr|"hello"|VOID*|0xB29914B5
+ gUefiLessonsPkgTokenSpaceGuid.PcdUCS2Str|L"hello"|VOID*|0xF22124E5
+```
+In case you didn't notice the difference is in that in the first case the value provided as `"<...>"`, and in the second case as `L"<...>"`.
+
+Now add the PCDs to the `UefiLessonsPkg/PCDLesson/PCDLesson.inf`:
+```
+[FixedPcd]
+ ...
+ gUefiLessonsPkgTokenSpaceGuid.PcdAsciiStr
+ gUefiLessonsPkgTokenSpaceGuid.PcdUCS2Str
+```
+
+Build and investigate generated AutoGen files:
+
+- `Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/PCDLesson/PCDLesson/DEBUG/AutoGen.h`:
+```
+#define _PCD_TOKEN_PcdAsciiStr 0U
+#define _PCD_VALUE_PcdAsciiStr _gPcd_FixedAtBuild_PcdAsciiStr
+extern const UINT8 _gPcd_FixedAtBuild_PcdAsciiStr[6];
+#define _PCD_GET_MODE_PTR_PcdAsciiStr _gPcd_FixedAtBuild_PcdAsciiStr
+#define _PCD_SIZE_PcdAsciiStr 6
+#define _PCD_GET_MODE_SIZE_PcdAsciiStr _PCD_SIZE_PcdAsciiStr
+//#define _PCD_SET_MODE_PTR_PcdAsciiStr ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdUCS2Str 0U
+#define _PCD_VALUE_PcdUCS2Str _gPcd_FixedAtBuild_PcdUCS2Str
+extern const UINT16 _gPcd_FixedAtBuild_PcdUCS2Str[6];
+#define _PCD_GET_MODE_PTR_PcdUCS2Str _gPcd_FixedAtBuild_PcdUCS2Str
+#define _PCD_SIZE_PcdUCS2Str 12
+#define _PCD_GET_MODE_SIZE_PcdUCS2Str _PCD_SIZE_PcdUCS2Str
+//#define _PCD_SET_MODE_PTR_PcdUCS2Str ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD
+```
+- `Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/PCDLesson/PCDLesson/DEBUG/AutoGen.c`:
+```
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gPcd_FixedAtBuild_PcdAsciiStr[6] = {104, 101, 108, 108, 111, 0 };
+GLOBAL_REMOVE_IF_UNREFERENCED const UINTN _gPcd_FixedAtBuild_Size_PcdAsciiStr = 6;
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT16 _gPcd_FixedAtBuild_PcdUCS2Str[6] = {104, 101, 108, 108, 111, 0 };
+GLOBAL_REMOVE_IF_UNREFERENCED const UINTN _gPcd_FixedAtBuild_Size_PcdUCS2Str = 12;
+```
+
+As you can see the array for the `PcdAsciiStr` consists from the UINT8 elements, while the `PcdUCS2Str` array consists of `UINT16` elements.
+
+Another important difference is that the constants for the string sizes in bytes are generated (effectively it is the `sizeof()` value). These values are calculated dynamically by the build system.
+
+To get the `VOID*` fixed type PCD value you can use `FixedPcdGetPtr`/`PcdGetPtr` APIs and to get its size in bytes you can use `FixedPcdGetSize`/`PcdGetSize` APIs:
+```cpp
+Print(L"PcdAsciiStr=%a\n", FixedPcdGetPtr(PcdAsciiStr));
+Print(L"PcdAsciiStrSize=%d\n", FixedPcdGetSize(PcdAsciiStr));
+Print(L"PcdUCS2Str=%s\n", PcdGetPtr(PcdUCS2Str));
+Print(L"PcdUCS2StrSize=%d\n", PcdGetSize(PcdUCS2Str));
+```
+
+Here are results:
+```
+FS0:\> PCDLesson.efi
+...
+PcdAsciiStr=hello
+PcdAsciiStrSize=6
+PcdUCS2Str=hello
+PcdUCS2StrSize=12
+```
+
+If you want to understand preprocessor substitutions, you can unravel its logic like we did before using the defines from the [https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Library/PcdLib.h](https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Library/PcdLib.h):
+```cpp
+#define FixedPcdGetPtr(TokenName) ((VOID *)_PCD_VALUE_##TokenName)
+#define FixedPcdGetSize(TokenName) _PCD_SIZE_##TokenName
+#define PcdGetPtr(TokenName) _PCD_GET_MODE_PTR_##TokenName
+#define PcdGetSize(TokenName) _PCD_GET_MODE_SIZE_##TokenName
+```
+
+In our example we've used `"..."/L"..."` syntax for string initialization, but it is also possible to use `'...'/L'...'` syntax.
+
+## Byte Array PCDs
+
+The more general usage for `VOID*` is byte arrays.
+
+As an example add this PCD to the `UefiLessonsPkg/UefiLessonsPkg.dec`:
+```
+[PcdsFixedAtBuild]
+ ...
+ gUefiLessonsPkgTokenSpaceGuid.PcdArray|{0xA5, 0xA6, 0xA7}|VOID*|0xD5DB9A27
+```
+
+Populate it to the `UefiLessonsPkg/PCDLesson/PCDLesson.inf`:
+```
+[FixedPcd]
+ ...
+ gUefiLessonsPkgTokenSpaceGuid.PcdArray
+```
+
+And look at the AutoGen files:
+
+- `Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/PCDLesson/PCDLesson/DEBUG/AutoGen.h`:
+```
+#define _PCD_TOKEN_PcdArray 0U
+#define _PCD_VALUE_PcdArray (VOID *)_gPcd_FixedAtBuild_PcdArray
+extern const UINT8 _gPcd_FixedAtBuild_PcdArray[3];
+#define _PCD_GET_MODE_PTR_PcdArray (VOID *)_gPcd_FixedAtBuild_PcdArray
+#define _PCD_SIZE_PcdArray 3
+#define _PCD_GET_MODE_SIZE_PcdArray _PCD_SIZE_PcdArray
+//#define _PCD_SET_MODE_PTR_PcdArray ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD
+```
+- `Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/PCDLesson/PCDLesson/DEBUG/AutoGen.c`:
+```
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gPcd_FixedAtBuild_PcdArray[3] = {0xA5, 0xA6, 0xA7};
+GLOBAL_REMOVE_IF_UNREFERENCED const UINTN _gPcd_FixedAtBuild_Size_PcdArray = 3;
+```
+
+Here is a one way of how we can print elements of our array. We need the `(UINT8*)` cast as the data is cast to `(VOID *)` in `AutoGen.h`.
+```
+for (UINTN i=0; i<FixedPcdGetSize(PcdArray); i++) {
+ Print(L"PcdArray[%d]=0x%02x\n", i, ((UINT8*)FixedPcdGetPtr(PcdArray))[i]);
+}
+```
+
+Verify the output:
+```
+FS0:\> PCDLesson.efi
+...
+PcdArray[0]=0xA5
+PcdArray[1]=0xA6
+PcdArray[2]=0xA7
+```
+
+## GUID PCDs
+
+With the byte array initialization syntax you can initialize any custom structure, as soon as you understand its type. Let's take `EFI_GUID` (`=GUID`) structure:
+```
+typedef struct {
+ UINT32 Data1;
+ UINT16 Data2;
+ UINT16 Data3;
+ UINT8 Data4[8];
+} GUID;
+
+typedef GUID EFI_GUID;
+```
+
+If you want to encode GUID "f1740707-691d-4203-bfab-99e132fa4166" you can do it like this:
+```
+[PcdsFixedAtBuild]
+ ...
+ gUefiLessonsPkgTokenSpaceGuid.PcdGuidInBytes|{0x07, 0x07, 0x74, 0xF1, 0x1D, 0x69, 0x03, 0x42, 0xBF, 0xAB, 0x99, 0xE1, 0x32, 0xFA, 0x41, 0x66}|VOID*|0xB9E0CDC0
+```
+
+So as you can see you need to reshuffle some bytes to get a correct representation. This is necessary because x86 is little-endian, and in such systems bytes of a number are placed in memory from highest to lowest.
+
+So this is the thing that you need to keep in mind when you would encode byte array initializations for you custom structures.
+
+As GUIDs are excessively used in UEFI code, EDK2 has a helper syntax for GUID PCD initialization. Let's define another PCD via this helper syntax:
+```
+[PcdsFixedAtBuild]
+ ...
+ gUefiLessonsPkgTokenSpaceGuid.PcdGuid|{GUID("f1740707-691d-4203-bfab-99e132fa4166")}|VOID*|0x7F2066F7
+```
+
+Now populate both values to INF:
+```
+[FixedPcd]
+ ...
+ gUefiLessonsPkgTokenSpaceGuid.PcdGuidInBytes
+ gUefiLessonsPkgTokenSpaceGuid.PcdGuid
+```
+
+Now build and look at the AutoGen files:
+
+- `Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/PCDLesson/PCDLesson/DEBUG/AutoGen.h`
+```
+#define _PCD_TOKEN_PcdGuidInBytes 0U
+#define _PCD_VALUE_PcdGuidInBytes (VOID *)_gPcd_FixedAtBuild_PcdGuidInBytes
+extern const UINT8 _gPcd_FixedAtBuild_PcdGuidInBytes[16];
+#define _PCD_GET_MODE_PTR_PcdGuidInBytes (VOID *)_gPcd_FixedAtBuild_PcdGuidInBytes
+#define _PCD_SIZE_PcdGuidInBytes 16
+#define _PCD_GET_MODE_SIZE_PcdGuidInBytes _PCD_SIZE_PcdGuidInBytes
+//#define _PCD_SET_MODE_PTR_PcdGuidInBytes ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD
+
+#define _PCD_TOKEN_PcdGuid 0U
+#define _PCD_VALUE_PcdGuid (VOID *)_gPcd_FixedAtBuild_PcdGuid
+extern const UINT8 _gPcd_FixedAtBuild_PcdGuid[16];
+#define _PCD_GET_MODE_PTR_PcdGuid (VOID *)_gPcd_FixedAtBuild_PcdGuid
+#define _PCD_SIZE_PcdGuid 16
+#define _PCD_GET_MODE_SIZE_PcdGuid _PCD_SIZE_PcdGuid
+//#define _PCD_SET_MODE_PTR_PcdGuid ASSERT(FALSE) // It is not allowed to set value for a FIXED_AT_BUILD PCD
+```
+
+- `Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/PCDLesson/PCDLesson/DEBUG/AutoGen.c`
+```
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gPcd_FixedAtBuild_PcdGuidInBytes[16] = {0x07, 0x07, 0x74, 0xF1, 0x1D, 0x69, 0x03, 0x42, 0xBF, 0xAB, 0x99, 0xE1, 0x32, 0xFA, 0x41, 0x66};
+GLOBAL_REMOVE_IF_UNREFERENCED const UINTN _gPcd_FixedAtBuild_Size_PcdGuidInBytes = 16;
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gPcd_FixedAtBuild_PcdGuid[16] = {0x07, 0x07, 0x74, 0xF1, 0x1D, 0x69, 0x03, 0x42, 0xBF, 0xAB, 0x99, 0xE1, 0x32, 0xFA, 0x41, 0x66};
+GLOBAL_REMOVE_IF_UNREFERENCED const UINTN _gPcd_FixedAtBuild_Size_PcdGuid = 16;
+```
+
+As you can see in the output, the PCD encoding and initialization are the same in both cases.
+
+If we want to use GUIDs in code, we still need not forget to cast them from `(VOID *)` to `(EFI_GUID*)`:
+```cpp
+Print(L"PcdGuidInBytes=%g\n", *(EFI_GUID*)FixedPcdGetPtr(PcdGuidInBytes));
+Print(L"PcdGuid=%g\n", *(EFI_GUID*)FixedPcdGetPtr(PcdGuid));
+```
+
+The result of both `Print` statements would be the same:
+```
+FS0:\> PCDLesson.efi
+...
+PcdGuidInBytes=F1740707-691D-4203-BFAB-99E132FA4166
+PcdGuid=F1740707-691D-4203-BFAB-99E132FA4166
+```
+
+There are two more more methods how you can initialize PCD containing GUID. You can either use another GUID for initialization or standard C syntax for `EFI_GUID` structure initialization:
+```
+[PcdsFixedAtBuild]
+ ...
+ gUefiLessonsPkgTokenSpaceGuid.PcdGuidByPCD|{GUID(gUefiLessonsPkgTokenSpaceGuid)}|VOID*|0x0860CCD5
+ gUefiLessonsPkgTokenSpaceGuid.PcdGuidByEfiGuid|{GUID({0x150cab53, 0xad47, 0x4385, {0xb5, 0xdd, 0xbc, 0xfc, 0x76, 0xba, 0xca, 0xf0}})}|VOID*|0x613506D5
+```
+
+This would `AutoGen.c`:
+```cpp
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gPcd_FixedAtBuild_PcdGuidByPCD[16] = {0x53, 0xAB, 0x0C, 0x15, 0x47, 0xAD, 0x85, 0x43, 0xB5, 0xDD, 0xBC, 0xFC, 0x76, 0xBA, 0xCA, 0xF0};
+GLOBAL_REMOVE_IF_UNREFERENCED const UINTN _gPcd_FixedAtBuild_Size_PcdGuidByPCD = 16;
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gPcd_FixedAtBuild_PcdGuidByEfiGuid[16] = {0x53, 0xAB, 0x0C, 0x15, 0x47, 0xAD, 0x85, 0x43, 0xB5, 0xDD, 0xBC, 0xFC, 0x76, 0xBA, 0xCA, 0xF0};
+GLOBAL_REMOVE_IF_UNREFERENCED const UINTN _gPcd_FixedAtBuild_Size_PcdGuidByEfiGuid = 16;
+```
+
+## `DEVICE_PATH`
+
+Besides the `GUID(...)` helper, EDKII also has `DEVICE_PATH(...)` helper, to initialize another special UEFI structure - device path. We'll investigate this structure another time.
+
+But for an example, the paths that are printed at the start of UEFI shell are text representation of UEFI device paths:
+```
+UEFI Interactive Shell v2.2
+EDK II
+UEFI v2.70 (EDK II, 0x00010000)
+Mapping table
+ FS0: Alias(s):HD0a1:;BLK1:
+ PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)/HD(1,MBR,0xBE1AFDFA,0x3F,0xFBFC1)
+ BLK0: Alias(s):
+ PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)
+ BLK2: Alias(s):
+ PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)
+Press ESC in 5 seconds to skip startup.nsh or any other key to continue.
+```
+
+Let's use one of them for PCD initialization:
+```
+[PcdsFixedAtBuild]
+ ...
+ gUefiLessonsPkgTokenSpaceGuid.PcdDevicePath|{DEVICE_PATH("PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)")}|VOID*|0xC56EE1E2
+```
+
+This would produce the following array in the `AutoGen.c`:
+```
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gPcd_FixedAtBuild_PcdDevicePath[30] = {0x02,0x01,0x0c,0x00,0xd0,0x41,0x03,0x0a,0x00,0x00,0x00,0x00,0x01,0x01,0x06,0x00,0x01,0x01,0x03,0x01,0x08,0x00,0x00,0x00,0x00,0x00,0x7f,0xff,0x04,0x00};
+GLOBAL_REMOVE_IF_UNREFERENCED const UINTN _gPcd_FixedAtBuild_Size_PcdDevicePath = 30;
+```
+
+To verify that the array are correct, let's print created device path in our program. For this we need to include `DevicePathLib.h` header:
+```cpp
+#include <Library/DevicePathLib.h>
+```
+
+And use `ConvertDevicePathToText` function:
+```cpp
+Print(L"PcdDevicePath: %s\n", ConvertDevicePathToText((EFI_DEVICE_PATH_PROTOCOL*) FixedPcdGetPtr(PcdDevicePath), FALSE, FALSE));
+```
+
+Here is the output:
+```
+FS0:\> PCDLesson.efi
+...
+PcdDevicePath: PciRoot(0x0)/Pci(0x1,0x1)/Ata(Primary,Master,0x0)
+```
+
+## Using integer casts
+
+It is possible to initialize `VOID*` array using `UINT8(...)`, `UINT16(...)`, `UINT32(...)`, `UINT64(...)` cast helpers:
+```
+[PcdsFixedAtBuild]
+ ...
+ gUefiLessonsPkgTokenSpaceGuid.PcdIntCasts|{UINT16(0x1122), UINT32(0x33445566), UINT8(0x77), UINT64(0x8899aabbccddeeff)}|VOID*|0x647456A6
+```
+
+If you look at the `AutoGen.c` you'll see that array is initialized with respect to little-endian architecture:
+```
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gPcd_FixedAtBuild_PcdIntCasts[15] = {0x22, 0x11, 0x66, 0x55, 0x44, 0x33, 0x77, 0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x99, 0x88};
+GLOBAL_REMOVE_IF_UNREFERENCED const UINTN _gPcd_FixedAtBuild_Size_PcdIntCasts = 15;
+```
+
+## `LABEL` and `OFFSET_OF`
+
+It is possible to assign labels to some elemets and get offsets of these elements via `LABEL(...)/OFFSET_OF(...)` syntax. Example:
+```
+[PcdsFixedAtBuild]
+ ...
+ UefiLessonsPkgTokenSpaceGuid.PcdWithLabels|{ 0x0A, 0x0B, OFFSET_OF(End), 0x0C, LABEL(Start) 0x0D, LABEL(End) 0x0E, 0x0F, OFFSET_OF(Start) }|VOID*|0xD91A8BF6
+```
+
+This will give you this in `AutoGen.c`:
+```
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gPcd_FixedAtBuild_PcdWithLabels[8] = {0x0A, 0x0B, 0x05, 0x0C, 0x0D, 0x0E, 0x0F, 0x04};
+GLOBAL_REMOVE_IF_UNREFERENCED const UINTN _gPcd_FixedAtBuild_Size_PcdWithLabels = 8;
+```
+
+## Combined array initialization
+
+It is possible to combine different methods of byte array initialization:
+```
+gUefiLessonsPkgTokenSpaceGuid.PcdArrayExt|{0x11, UINT16(0x2233), UINT32(0x44556677), L"hello", "world!", GUID("09b9b358-70bd-421e-bafb-4f97e2ac7d44")}|VOID*|0x7200C5DF
+```
+
+This will give you:
+```
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gPcd_FixedAtBuild_PcdArrayExt[42] = {0x11, 0x33, 0x22, 0x77, 0x66, 0x55, 0x44, 0x68, 0x00, 0x65, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6F, 0x00, 0x00, 0x00, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x21, 0x0 0, 0x58, 0xB3, 0xB9, 0x09, 0xBD, 0x70, 0x1E, 0x42, 0xBA, 0xFB, 0x4F, 0x97, 0xE2, 0xAC, 0x7D, 0x44};
+GLOBAL_REMOVE_IF_UNREFERENCED const UINTN _gPcd_FixedAtBuild_Size_PcdArrayExt = 42;
+```
+
+# Custom types
+
+It is possible to create custom types for you PCDs.
+
+For example create this file `UefiLessonsPkg/Include/CustomPcdTypes.h`:
+```
+#ifndef CUSTOM_PCD_TYPES_H
+#define CUSTOM_PCD_TYPES_H
+
+typedef struct {
+ EFI_GUID Guid;
+ CHAR16 Name[6];
+} InnerCustomStruct;
+
+typedef struct {
+ UINT8 Val8;
+ UINT32 Val32[2];
+ InnerCustomStruct ValStruct;
+ union {
+ struct {
+ UINT8 Field1:1;
+ UINT8 Field2:4;
+ UINT8 Filed3:3;
+ } BitFields;
+ UINT8 Byte;
+ } ValUnion;
+} CustomStruct;
+
+#endif
+```
+
+You can use the created `CustomStruct` structure type and initialize its values via this sytnax:
+```
+gUefiLessonsPkgTokenSpaceGuid.PcdCustomStruct|{0}|CustomStruct|0x535D4CB5 {
+ <Packages>
+ UefiLessonsPkg/UefiLessonsPkg.dec
+ <HeaderFiles>
+ CustomPcdTypes.h
+}
+gUefiLessonsPkgTokenSpaceGuid.PcdCustomStruct.Val8|0x11
+gUefiLessonsPkgTokenSpaceGuid.PcdCustomStruct.Val32[0]|0x22334455
+gUefiLessonsPkgTokenSpaceGuid.PcdCustomStruct.Val32[1]|0x66778899
+gUefiLessonsPkgTokenSpaceGuid.PcdCustomStruct.ValStruct.Guid|{GUID("f1740707-691d-4203-bfab-99e132fa4166")}
+gUefiLessonsPkgTokenSpaceGuid.PcdCustomStruct.ValStruct.Name|L'Hello'
+gUefiLessonsPkgTokenSpaceGuid.PcdCustomStruct.ValUnion.BitFields.Field2|0xF
+```
+
+`AutoGen.c` will be created with the following data:
+```
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gPcd_FixedAtBuild_PcdCustomStruct[44] = {0x11,0x00,0x00,0x00,0x55,0x44,0x33,0x22,0x99,0x88,0x77,0x66,0x07,0x07,0x74,0xf1,0x1d,0x69,0x03,0x42,0xbf,0xab,0x99,0xe1,0x32,0xfa,0x41,0x66,0x48,0x00,0x65,0x00,0x6c,0x00,0x6c,0x00,0x6f,0x00,0x00,0x00,0x1e,0x00,0x00,0x00};
+GLOBAL_REMOVE_IF_UNREFERENCED const UINTN _gPcd_FixedAtBuild_Size_PcdCustomStruct = 44;
+```
+If you group you fields, you'll see that all of them were initialized as intendend:
+```
+{
+ 0x11, // UINT8 Val8
+ 0x00,0x00,0x00, // alignment
+ 0x55,0x44,0x33,0x22, // UINT32 Val32[0]
+ 0x99,0x88,0x77,0x66, // UINT32 Val32[1]
+ 0x07,0x07,0x74,0xf1,0x1d,0x69,0x03,0x42,0xbf,0xab,0x99,0xe1,0x32,0xfa,0x41,0x66, // InnerCustomStruct.Guid
+ 0x48,0x00,0x65,0x00,0x6c,0x00,0x6c,0x00,0x6f,0x00,0x00,0x00, // InnerCustomStruct.Name
+ 0x1e, // ValUnion
+ 0x00,0x00,0x00 // alignment
+}
+```
+
+If a field-by-filed initialization seem too long, you can use in-place C style array initialization with the help of a special `CODE(...)` syntax. But in this case you can't use helpers like `GUID(...)` or `L'...'` initialization. So the same initialization for our structure would look like this:
+```
+gUefiLessonsPkgTokenSpaceGuid.PcdCustomStruct_1|{CODE(
+ {
+ 0x11,
+ {0x22334455, 0x66778899},
+ {
+ {0xf1740707, 0x691d, 0x4203, {0xbf, 0xab, 0x99, 0xe1, 0x32, 0xfa, 0x41, 0x66}},
+ {0x0048, 0x0065, 0x006c, 0x006c, 0x006f, 0x0000}
+ },
+ {{0x0, 0xf, 0x0}}
+ }
+ )}|CustomStruct|0xC1D6B9A7 {
+ <Packages>
+ UefiLessonsPkg/UefiLessonsPkg.dec
+ <HeaderFiles>
+ CustomPcdTypes.h
+}
+```
+
+You can verify that the result is the same data, if you look at the `AutoGen.c` file:
+```
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gPcd_FixedAtBuild_PcdCustomStruct_1[44] = {0x11,0x00,0x00,0x00,0x55,0x44,0x33,0x22,0x99,0x88,0x77,0x66,0x07,0x07,0x74,0xf1,0x1d,0x69,0x03,0x42,0xbf,0xab,0x99,0xe1,0x32,0xfa,0x41,0x66,0x48,0x00,0x65,0x00,0x6c,0x00,0x6c,0x00,0x6f,0x00,0x00,0x00,0x1e,0x00,0x00,0x00};
+GLOBAL_REMOVE_IF_UNREFERENCED const UINTN _gPcd_FixedAtBuild_Size_PcdCustomStruct_1 = 44;
+```
+
+# Array with fixed sizes
+
+It is possible to fix PCD array size. Keep in mind that if you use arrays for types with sizes more that 1 byte like `UINT32[3]`, you need to cast every initialization value to the type`. To avoid this it is possible to use special `CODE(...)` syntax:
+```
+[PcdsFixedAtBuild]
+ ...
+ gUefiLessonsPkgTokenSpaceGuid.PcdArrayWithFixedSize|{0x0}|UINT8[12]|0x4C4CB9A3
+ gUefiLessonsPkgTokenSpaceGuid.PcdArrayWithFixedSize_1|{0x0}|UINT32[3]|0x285DAD21
+ gUefiLessonsPkgTokenSpaceGuid.PcdArrayWithFixedSize_2|{UINT32(0x11223344), UINT32(0x55667788), UINT32(0x99aabbcc)}|UINT32[3]|0x25D6ED26
+ gUefiLessonsPkgTokenSpaceGuid.PcdArrayWithFixedSize_3|{CODE({0x11223344, 0x55667788, 0x99aabbcc})}|UINT32[3]|0xE5BC424D
+```
+
+This will give you this in `AutoGen.c`:
+```
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gPcd_FixedAtBuild_PcdArrayWithFixedSize[8] = {0xee,0xff,0x00,0x00,0x00,0x00,0x00,0x00};
+GLOBAL_REMOVE_IF_UNREFERENCED const UINTN _gPcd_FixedAtBuild_Size_PcdArrayWithFixedSize = 8;
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gPcd_FixedAtBuild_PcdArrayWithFixedSize_1[12] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+GLOBAL_REMOVE_IF_UNREFERENCED const UINTN _gPcd_FixedAtBuild_Size_PcdArrayWithFixedSize_1 = 12;
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gPcd_FixedAtBuild_PcdArrayWithFixedSize_2[12] = {0x44,0x33,0x22,0x11,0x88,0x77,0x66,0x55,0xcc,0xbb,0xaa,0x99};
+GLOBAL_REMOVE_IF_UNREFERENCED const UINTN _gPcd_FixedAtBuild_Size_PcdArrayWithFixedSize_2 = 12;
+GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gPcd_FixedAtBuild_PcdArrayWithFixedSize_3[12] = {0x44,0x33,0x22,0x11,0x88,0x77,0x66,0x55,0xcc,0xbb,0xaa,0x99};
+GLOBAL_REMOVE_IF_UNREFERENCED const UINTN _gPcd_FixedAtBuild_Size_PcdArrayWithFixedSize_3 = 12;
+```
+
+You can also create fixed size arrays for you custom types:
+```
+gUefiLessonsPkgTokenSpaceGuid.PcdArrayWithFixedSize_4|{0x0}|CustomStruct[2]|0x0D00EE44 {
+ <Packages>
+ UefiLessonsPkg/UefiLessonsPkg.dec
+ <HeaderFiles>
+ CustomPcdTypes.h
+}
+```
+
+Here we don't do any field initialization, but for the proof of syntax you can look at the `AutoGen.c` and verify that the size of the final data array is twice of the usual one for our structure:
+```
+GLOBAL_REMOVE_IF_UNREFERENCED const UINTN _gPcd_FixedAtBuild_Size_PcdArrayWithFixedSize_4 = 88;
+```
+
+# `PcdValueInit`
+
+One interesting observation. When you use PCD with custom types, or fixed size arrays, the build system would create `PcdValueInit` folder in your `Build` directory. This directory would contain a special C program `PcdValueInit` that the build system will use to get the data for the `AutoGen.c` file:
+```
+$ find ./Build/UefiLessonsPkg/RELEASE_GCC5/PcdValueInit/
+./Build/UefiLessonsPkg/RELEASE_GCC5/PcdValueInit/
+./Build/UefiLessonsPkg/RELEASE_GCC5/PcdValueInit/PcdValueCommon.c
+./Build/UefiLessonsPkg/RELEASE_GCC5/PcdValueInit/PcdValueInit.o
+./Build/UefiLessonsPkg/RELEASE_GCC5/PcdValueInit/PcdValueInit.c
+./Build/UefiLessonsPkg/RELEASE_GCC5/PcdValueInit/PcdValueInit
+./Build/UefiLessonsPkg/RELEASE_GCC5/PcdValueInit/Input.txt
+./Build/UefiLessonsPkg/RELEASE_GCC5/PcdValueInit/PcdValueInit.d
+./Build/UefiLessonsPkg/RELEASE_GCC5/PcdValueInit/PcdValueCommon.d
+./Build/UefiLessonsPkg/RELEASE_GCC5/PcdValueInit/Output.txt
+./Build/UefiLessonsPkg/RELEASE_GCC5/PcdValueInit/PcdValueCommon.o
+./Build/UefiLessonsPkg/RELEASE_GCC5/PcdValueInit/Makefile
+```
+You can check the help message of the program:
+```
+$ ./Build/UefiLessonsPkg/RELEASE_GCC5/PcdValueInit/PcdValueInit -h
+Usage: -i <input_file> -o <output_file>
+
+optional arguments:
+ -h, --help Show this help message and exit
+ -i INPUT_FILENAME, --input INPUT_FILENAME
+ PCD Database Input file name
+ -o OUTPUT_FILENAME, --output OUTPUT_FILENAME
+ PCD Database Output file name
+```
+From this you can guess that this programm creates `Output.txt` file from the `Input.txt` file in the same directory. If you curious about the build system internals you can check these `*.txt` files or check the program sources.
+
+# Links
+
+- [https://edk2-docs.gitbook.io/edk-ii-pcd-specification/](https://edk2-docs.gitbook.io/edk-ii-pcd-specification/)
+
+- [https://edk2-docs.gitbook.io/edk-ii-dec-specification/2_dec_file_overview/210_pcd_usage](https://edk2-docs.gitbook.io/edk-ii-dec-specification/2_dec_file_overview/210_pcd_usage)
+
diff --git a/Lessons/Lesson_20/UefiLessonsPkg/PCDLesson/PCDLesson.c b/Lessons/Lesson_20/UefiLessonsPkg/PCDLesson/PCDLesson.c
index 82b4d4a..7cc7788 100644
--- a/Lessons/Lesson_20/UefiLessonsPkg/PCDLesson/PCDLesson.c
+++ b/Lessons/Lesson_20/UefiLessonsPkg/PCDLesson/PCDLesson.c
@@ -7,6 +7,7 @@
#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiLib.h>
+#include <Library/DevicePathLib.h>
#include <Library/PcdLib.h>
EFI_STATUS
@@ -16,6 +17,31 @@ UefiMain (
IN EFI_SYSTEM_TABLE *SystemTable
)
{
- Print(L"PcdMyVar32=%d\n", FixedPcdGet32(PcdMyVar32));
+ Print(L"PcdInt8=0x%x\n", FixedPcdGet8(PcdInt8));
+ Print(L"PcdInt16=0x%x\n", FixedPcdGet16(PcdInt16));
+ Print(L"PcdInt32=0x%x\n", FixedPcdGet32(PcdInt32));
+ Print(L"PcdInt64=0x%x\n", FixedPcdGet64(PcdInt64));
+ Print(L"PcdBool=0x%x\n", FixedPcdGetBool(PcdBool));
+
+ Print(L"PcdInt8=0x%x\n", PcdGet8(PcdInt8));
+ Print(L"PcdInt16=0x%x\n", PcdGet16(PcdInt16));
+ Print(L"PcdInt32=0x%x\n", PcdGet32(PcdInt32));
+ Print(L"PcdInt64=0x%x\n", PcdGet64(PcdInt64));
+ Print(L"PcdIntBool=0x%x\n", PcdGetBool(PcdBool));
+
+ Print(L"PcdAsciiStr=%a\n", FixedPcdGetPtr(PcdAsciiStr));
+ Print(L"PcdAsciiStrSize=%d\n", FixedPcdGetSize(PcdAsciiStr));
+ Print(L"PcdUCS2Str=%s\n", PcdGetPtr(PcdUCS2Str));
+ Print(L"PcdUCS2StrSize=%d\n", PcdGetSize(PcdUCS2Str));
+
+ for (UINTN i=0; i<FixedPcdGetSize(PcdArray); i++) {
+ Print(L"PcdArray[%d]=0x%02x\n", i, ((UINT8*)FixedPcdGetPtr(PcdArray))[i]);
+ }
+
+ Print(L"PcdGuidInBytes=%g\n", *(EFI_GUID*)FixedPcdGetPtr(PcdGuidInBytes));
+ Print(L"PcdGuid=%g\n", *(EFI_GUID*)FixedPcdGetPtr(PcdGuid));
+
+ Print(L"PcdDevicePath: %s\n", ConvertDevicePathToText((EFI_DEVICE_PATH_PROTOCOL*) FixedPcdGetPtr(PcdDevicePath), FALSE, FALSE));
+
return EFI_SUCCESS;
}
diff --git a/Lessons/Lesson_20/UefiLessonsPkg/PCDLesson/PCDLesson.inf b/Lessons/Lesson_20/UefiLessonsPkg/PCDLesson/PCDLesson.inf
index 3258a64..1d71c31 100644
--- a/Lessons/Lesson_20/UefiLessonsPkg/PCDLesson/PCDLesson.inf
+++ b/Lessons/Lesson_20/UefiLessonsPkg/PCDLesson/PCDLesson.inf
@@ -24,5 +24,31 @@
UefiLib
[FixedPcd]
- gUefiLessonsPkgTokenSpaceGuid.PcdMyVar32
+ gUefiLessonsPkgTokenSpaceGuid.PcdInt8
+ gUefiLessonsPkgTokenSpaceGuid.PcdInt16
+ gUefiLessonsPkgTokenSpaceGuid.PcdInt32
+ gUefiLessonsPkgTokenSpaceGuid.PcdInt64
+ gUefiLessonsPkgTokenSpaceGuid.PcdBool
+ gUefiLessonsPkgTokenSpaceGuid.PcdExpression
+ gUefiLessonsPkgTokenSpaceGuid.PcdExpression_1
+ gUefiLessonsPkgTokenSpaceGuid.PcdExpression_2
+ gUefiLessonsPkgTokenSpaceGuid.PcdExpression_3
+ gUefiLessonsPkgTokenSpaceGuid.PcdAsciiStr
+ gUefiLessonsPkgTokenSpaceGuid.PcdUCS2Str
+ gUefiLessonsPkgTokenSpaceGuid.PcdArray
+ gUefiLessonsPkgTokenSpaceGuid.PcdGuidInBytes
+ gUefiLessonsPkgTokenSpaceGuid.PcdGuid
+ gUefiLessonsPkgTokenSpaceGuid.PcdGuidByPCD
+ gUefiLessonsPkgTokenSpaceGuid.PcdGuidByEfiGuid
+ gUefiLessonsPkgTokenSpaceGuid.PcdDevicePath
+ gUefiLessonsPkgTokenSpaceGuid.PcdIntCasts
+ gUefiLessonsPkgTokenSpaceGuid.PcdWithLabels
+ gUefiLessonsPkgTokenSpaceGuid.PcdArrayExt
+ gUefiLessonsPkgTokenSpaceGuid.PcdCustomStruct
+ gUefiLessonsPkgTokenSpaceGuid.PcdCustomStruct_1
+ gUefiLessonsPkgTokenSpaceGuid.PcdArrayWithFixedSize
+ gUefiLessonsPkgTokenSpaceGuid.PcdArrayWithFixedSize_1
+ gUefiLessonsPkgTokenSpaceGuid.PcdArrayWithFixedSize_2
+ gUefiLessonsPkgTokenSpaceGuid.PcdArrayWithFixedSize_3
+ gUefiLessonsPkgTokenSpaceGuid.PcdArrayWithFixedSize_4
diff --git a/Lessons/Lesson_20/UefiLessonsPkg/UefiLessonsPkg.dec b/Lessons/Lesson_20/UefiLessonsPkg/UefiLessonsPkg.dec
index 2521626..2fb6e56 100644
--- a/Lessons/Lesson_20/UefiLessonsPkg/UefiLessonsPkg.dec
+++ b/Lessons/Lesson_20/UefiLessonsPkg/UefiLessonsPkg.dec
@@ -22,5 +22,65 @@
[Protocols]
[PcdsFixedAtBuild]
- gUefiLessonsPkgTokenSpaceGuid.PcdMyVar32|42|UINT32|0x00000001
+ gUefiLessonsPkgTokenSpaceGuid.PcdInt8|0x88|UINT8|0x3B81CDF1
+ gUefiLessonsPkgTokenSpaceGuid.PcdInt16|0x1616|UINT16|0x77DFB6E6
+ gUefiLessonsPkgTokenSpaceGuid.PcdInt32|0x32323232|UINT32|0xF2A48130
+ gUefiLessonsPkgTokenSpaceGuid.PcdInt64|0x6464646464646464|UINT64|0x652F4E29
+ gUefiLessonsPkgTokenSpaceGuid.PcdBool|TRUE|BOOLEAN|0x69E88A63
+ gUefiLessonsPkgTokenSpaceGuid.PcdExpression|0xFF000000 + 0x00FFFFFF|UINT32|0x9C405222
+ gUefiLessonsPkgTokenSpaceGuid.PcdExpression_1|((0xFFFFFFFF & 0x000000FF) << 8) + 0x33|UINT32|0x5911C44B
+ gUefiLessonsPkgTokenSpaceGuid.PcdExpression_2|(0x00000000 | 0x00100000)|UINT32|0xAD880207
+ gUefiLessonsPkgTokenSpaceGuid.PcdExpression_3|((56 < 78) || !(23 > 44))|BOOLEAN|0x45EDE955
+ gUefiLessonsPkgTokenSpaceGuid.PcdAsciiStr|"hello"|VOID*|0xB29914B5
+ gUefiLessonsPkgTokenSpaceGuid.PcdUCS2Str|L"hello"|VOID*|0xF22124E5
+ gUefiLessonsPkgTokenSpaceGuid.PcdArray|{0xa5, 0xA6, 0xA7}|VOID*|0xD5DB9A27
+ gUefiLessonsPkgTokenSpaceGuid.PcdGuidInBytes|{0x07, 0x07, 0x74, 0xF1, 0x1D, 0x69, 0x03, 0x42, 0xBF, 0xAB, 0x99, 0xE1, 0x32, 0xFA, 0x41, 0x66}|VOID*|0xB9E0CDC0
+ gUefiLessonsPkgTokenSpaceGuid.PcdGuid|{GUID("f1740707-691d-4203-bfab-99e132fa4166")}|VOID*|0x7F2066F7
+ gUefiLessonsPkgTokenSpaceGuid.PcdGuidByPCD|{GUID(gUefiLessonsPkgTokenSpaceGuid)}|VOID*|0x0860CCD5
+ gUefiLessonsPkgTokenSpaceGuid.PcdGuidByEfiGuid|{GUID({0x150cab53, 0xad47, 0x4385, {0xb5, 0xdd, 0xbc, 0xfc, 0x76, 0xba, 0xca, 0xf0}})}|VOID*|0x613506D5
+ gUefiLessonsPkgTokenSpaceGuid.PcdDevicePath|{DEVICE_PATH("PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)")}|VOID*|0xC56EE1E2
+ gUefiLessonsPkgTokenSpaceGuid.PcdIntCasts|{UINT16(0x1122), UINT32(0x33445566), UINT8(0x77), UINT64(0x8899aabbccddeeff)}|VOID*|0x647456A6
+ gUefiLessonsPkgTokenSpaceGuid.PcdWithLabels|{ 0x0A, 0x0B, OFFSET_OF(End), 0x0C, LABEL(Start) 0x0D, LABEL(End) 0x0E, 0x0F, OFFSET_OF(Start) }|VOID*|0xD91A8BF6
+ gUefiLessonsPkgTokenSpaceGuid.PcdArrayExt|{0x11, UINT16(0x2233), UINT32(0x44556677), L"hello", "world!", GUID("09b9b358-70bd-421e-bafb-4f97e2ac7d44")}|VOID*|0x7200C5DF
+ gUefiLessonsPkgTokenSpaceGuid.PcdCustomStruct|{0}|CustomStruct|0x535D4CB5 {
+ <Packages>
+ UefiLessonsPkg/UefiLessonsPkg.dec
+ <HeaderFiles>
+ CustomPcdTypes.h
+ }
+ gUefiLessonsPkgTokenSpaceGuid.PcdCustomStruct.Val8|0x11
+ gUefiLessonsPkgTokenSpaceGuid.PcdCustomStruct.Val32[0]|0x22334455
+ gUefiLessonsPkgTokenSpaceGuid.PcdCustomStruct.Val32[1]|0x66778899
+ gUefiLessonsPkgTokenSpaceGuid.PcdCustomStruct.ValStruct.Guid|{GUID("f1740707-691d-4203-bfab-99e132fa4166")}
+ gUefiLessonsPkgTokenSpaceGuid.PcdCustomStruct.ValStruct.Name|L'Hello'
+ gUefiLessonsPkgTokenSpaceGuid.PcdCustomStruct.ValUnion.BitFields.Field2|0xF
+
+ gUefiLessonsPkgTokenSpaceGuid.PcdCustomStruct_1|{CODE(
+ {
+ 0x11,
+ {0x22334455, 0x66778899},
+ {
+ {0xf1740707, 0x691d, 0x4203, {0xbf, 0xab, 0x99, 0xe1, 0x32, 0xfa, 0x41, 0x66}},
+ {0x0048, 0x0065, 0x006c, 0x006c, 0x006f, 0x0000}
+ },
+ {{0x0, 0xf, 0x0}}
+ }
+ )}|CustomStruct|0xC1D6B9A7 {
+ <Packages>
+ UefiLessonsPkg/UefiLessonsPkg.dec
+ <HeaderFiles>
+ CustomPcdTypes.h
+ }
+
+ gUefiLessonsPkgTokenSpaceGuid.PcdArrayWithFixedSize|{0x0}|UINT8[8]|0x4C4CB9A3
+ gUefiLessonsPkgTokenSpaceGuid.PcdArrayWithFixedSize_1|{0x0}|UINT32[3]|0x285DAD21
+ gUefiLessonsPkgTokenSpaceGuid.PcdArrayWithFixedSize_2|{UINT32(0x11223344), UINT32(0x55667788), UINT32(0x99aabbcc)}|UINT32[3]|0x25D6ED26
+ gUefiLessonsPkgTokenSpaceGuid.PcdArrayWithFixedSize_3|{CODE({0x11223344, 0x55667788, 0x99aabbcc})}|UINT32[3]|0xE5BC424D
+ gUefiLessonsPkgTokenSpaceGuid.PcdArrayWithFixedSize_4|{0x0}|CustomStruct[2]|0x0D00EE44 {
+ <Packages>
+ UefiLessonsPkg/UefiLessonsPkg.dec
+ <HeaderFiles>
+ CustomPcdTypes.h
+ }
+