aboutsummaryrefslogtreecommitdiffstats
path: root/Lessons/Lesson_20/README.md
blob: 46a4c5ba58a93481148a24ab83aaa107906ba287 (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
The Platform Configuration Database (PCD) is a database that contains a variety of current platform settings or directives that can be accessed by a driver or application.

You can checkout edk2 specification https://edk2-docs.gitbook.io/edk-ii-pcd-specification/ or https://www.intel.com/content/dam/www/public/us/en/documents/white-papers/edkii-platform-config-database-entries-paper.pdf for more explanation on PCD.

PCD entry is also called PCD, so we will use this term further.

The PCD entry is defined in a DEC file in a format:
```
<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>
```
`<TokenSpaceGuidCName>` is a GUID value, `<Token>` is a 32-bit value. Together they are used to uniqely identify PCD.

First let's declare a Token Space that would contain all our PCDs.
Usually in is defined as a `g<PackageName>TokenSpaceGuid`, so add this to our `UefiLessonsPkg/UefiLessonsPkg.dec`:
```
[Guids]
  ...
  gUefiLessonsPkgTokenSpaceGuid = {0x150cab53, 0xad47, 0x4385, {0xb5, 0xdd, 0xbc, 0xfc, 0x76, 0xba, 0xca, 0xf0}}
```

Now we can define our PCDs in the same *.dec file. Let's start with `UINT32 PcdMyVar32 = 42`:
```
[PcdsFixedAtBuild]
  gEfiUefiLessonsPkgTokenSpaceGuid.PcdMyVar32|42|UINT32|0x00000001
```

Now create an app `PCDLesson` with the following code in its entry point function:
```
Print(L"PcdMyVar32=%d\n", FixedPcdGet32(PcdMyVar32));
```
To use `FixedPcdGet32` 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:
```
#define FixedPcdGet32(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
      |                                             ^~~~~~~~~~~
```

To fix this we need to add this PCD to our app `*.inf` file:
```
[FixedPcd]
  gUefiLessonsPkgTokenSpaceGuid.PcdMyVar32
```

Also we need to include "dec" file that defines this PCD:
```
[Packages]
  ...
  UefiLessonsPkg/UefiLessonsPkg.dec
```

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.

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
```

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;
```

So in our case preprocessor expands code like this:
```
FixedPcdGet32(PcdMyVar32) -> _PCD_VALUE_PcdMyVar32 -> 42U
```

If you execute app code under OVMF:
```
FS0:\> PCDLesson.efi
PcdMyVar32=42
```

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:
```
#define PcdGet32(TokenName)                 _PCD_GET_MODE_32_##TokenName
```

In our case this would expand to:
```
PcdGet32(PcdMyVar32) -> _PCD_GET_MODE_32_PcdMyVar32 -> _gPcd_FixedAtBuild_PcdMyVar32
```
The latter one is a variable that is defined in a `AutoGen.c` file:
```
 GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdMyVar32 = 42U;
```
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.