From 975acdb2b502268eab376205debfa6c412be0e61 Mon Sep 17 00:00:00 2001 From: Konstantin Aladyshev Date: Thu, 4 Aug 2022 17:47:22 +0300 Subject: Update patchable pcd lesson Signed-off-by: Konstantin Aladyshev --- Lessons/Lesson_23/README.md | 166 +++++++++++++++++++++++++------------------- 1 file changed, 94 insertions(+), 72 deletions(-) (limited to 'Lessons') diff --git a/Lessons/Lesson_23/README.md b/Lessons/Lesson_23/README.md index bae429d..67ebe62 100644 --- a/Lessons/Lesson_23/README.md +++ b/Lessons/Lesson_23/README.md @@ -1,107 +1,125 @@ -Now let's explore `PatchableInModule` PCD. +Now let's explore `PatchableInModule` PCD class. -Add PCD to DEC file UefiLessonsPkg/UefiLessonsPkg.dec: +Add new PCD to DEC file `UefiLessonsPkg/UefiLessonsPkg.dec` under the `[PcdsPatchableInModule]` section: ``` [PcdsPatchableInModule] - gUefiLessonsPkgTokenSpaceGuid.PcdMyPatchableVar32|0x31313131|UINT32|0x00000004 + gUefiLessonsPkgTokenSpaceGuid.PcdPatchableInt32|0x31313131|UINT32|0xFCDA11B5 ``` -Populate it to INF UefiLessonsPkg/PCDLesson/PCDLesson.inf: + +Populate it to INF `UefiLessonsPkg/PCDLesson/PCDLesson.inf`: ``` [PatchPcd] - gUefiLessonsPkgTokenSpaceGuid.PcdMyPatchableVar32 + gUefiLessonsPkgTokenSpaceGuid.PcdPatchableInt32 ``` To get a value of PCD in a *.c file either `PatchPcdGet` or generic `PcdGet` should be used. Let's test both methods: ``` -Print(L"PcdMyPatchableVar32=%d\n", PatchPcdGet32(PcdMyPatchableVar32)); -Print(L"PcdMyPatchableVar32=%d\n", PcdGet32(PcdMyPatchableVar32)); +Print(L"PcdPatchableInt32=0x%x\n", PatchPcdGet32(PcdPatchableInt32)); +Print(L"PcdPatchableInt32=0x%x\n", PcdGet32(PcdPatchableInt32)); ``` -Now build and look to AutoGen files: +Now build and look to AutoGen files. -Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/PCDLesson/PCDLesson/DEBUG/AutoGen.h +`Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/PCDLesson/PCDLesson/DEBUG/AutoGen.h`: ``` -#define _PCD_TOKEN_PcdMyPatchableVar32 0U -#define _PCD_PATCHABLE_VALUE_PcdMyPatchableVar32 ((UINT32)0x31313131U) -extern volatile UINT32 _gPcd_BinaryPatch_PcdMyPatchableVar32; -#define _PCD_GET_MODE_32_PcdMyPatchableVar32 _gPcd_BinaryPatch_PcdMyPatchableVar32 -#define _PCD_PATCHABLE_PcdMyPatchableVar32_SIZE 4 -#define _PCD_GET_MODE_SIZE_PcdMyPatchableVar32 _gPcd_BinaryPatch_Size_PcdMyPatchableVar32 -extern UINTN _gPcd_BinaryPatch_Size_PcdMyPatchableVar32; -#define _PCD_SET_MODE_32_PcdMyPatchableVar32(Value) (_gPcd_BinaryPatch_PcdMyPatchableVar32 = (Value)) -#define _PCD_SET_MODE_32_S_PcdMyPatchableVar32(Value) ((_gPcd_BinaryPatch_PcdMyPatchableVar32 = (Value)), RETURN_SUCCESS) +#define _PCD_TOKEN_PcdPatchableInt32 0U +#define _PCD_PATCHABLE_VALUE_PcdPatchableInt32 ((UINT32)0x31313131U) +extern volatile UINT32 _gPcd_BinaryPatch_PcdPatchableInt32; +#define _PCD_GET_MODE_32_PcdPatchableInt32 _gPcd_BinaryPatch_PcdPatchableInt32 +#define _PCD_PATCHABLE_PcdPatchableInt32_SIZE 4 +#define _PCD_GET_MODE_SIZE_PcdPatchableInt32 _gPcd_BinaryPatch_Size_PcdPatchableInt32 +extern UINTN _gPcd_BinaryPatch_Size_PcdPatchableInt32; +#define _PCD_SET_MODE_32_PcdPatchableInt32(Value) (_gPcd_BinaryPatch_PcdPatchableInt32 = (Value)) +#define _PCD_SET_MODE_32_S_PcdPatchableInt32(Value) ((_gPcd_BinaryPatch_PcdPatchableInt32 = (Value)), RETURN_SUCCESS) ``` -Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/PCDLesson/PCDLesson/DEBUG/AutoGen.c + +`Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/PCDLesson/PCDLesson/DEBUG/AutoGen.c`: ``` -volatile UINT32 _gPcd_BinaryPatch_PcdMyPatchableVar32 = _PCD_PATCHABLE_VALUE_PcdMyPatchableVar32; -GLOBAL_REMOVE_IF_UNREFERENCED UINTN _gPcd_BinaryPatch_Size_PcdMyPatchableVar32 = 4; +volatile UINT32 _gPcd_BinaryPatch_PcdPatchableInt32 = _PCD_PATCHABLE_VALUE_PcdPatchableInt32; +GLOBAL_REMOVE_IF_UNREFERENCED UINTN _gPcd_BinaryPatch_Size_PcdPatchableInt32 = 4; ``` -So in this case our call to `PcdGet32(PcdMyPatchableVar32)` would be expanded to: +According to 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): ``` -PcdGet32(PcdMyPatchableVar32) --> _PCD_GET_MODE_32_PcdMyPatchableVar32 --> _gPcd_BinaryPatch_PcdMyPatchableVar32 +#define PatchPcdGet32(TokenName) _gPcd_BinaryPatch_##TokenName +... +#define PcdGet32(TokenName) _PCD_GET_MODE_32_##TokenName ``` -This variable would be assigned in `AutoGen.c`: + +If you unravel preprocessor code, you'll see that both calls translate to the same variable: ``` -volatile UINT32 _gPcd_BinaryPatch_PcdMyPatchableVar32 = ((UINT32)0x31313131U); +PatchPcdGet32(PcdPatchableInt32) -> _gPcd_BinaryPatch_PcdPatchableInt32 + +PcdGet32(PcdPatchableInt32) -> _PCD_GET_MODE_32_PcdPatchableInt32 -> _gPcd_BinaryPatch_PcdPatchableInt32 ``` -So the main difference from the FixedAtBuild and FeatureFlag PCDs is that variable defined as `volatile` and set functions aren't blocked. -Let's try to set our PCD then. As with get, there are two possibilities. You can use either `PatchPcdSet` or generic `PcdSetS`. +This is a `volatile` variable that is assigned in the `AutoGen.c`: +``` +volatile UINT32 _gPcd_BinaryPatch_PcdPatchableInt32 = _PCD_PATCHABLE_VALUE_PcdPatchableInt32 // = ((UINT32)0x31313131U) +``` -Keep in mind that `PcdSet32S` unravels to a macro returning a value. -https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Library/PcdLib.h: +So the main difference from the `FixedAtBuild` and `FeatureFlag` PCDs is that the variable defined as `volatile` and the set functions aren't blocked. + +# PCD value modification at run-time + +Let's try to set our PCD then. As with get, there are two possibilities. You can use either `PatchPcdSet` or generic `PcdSetS` API [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 PatchPcdSet32(TokenName, Value) (_gPcd_BinaryPatch_##TokenName = (Value)) +... #define PcdSet32S(TokenName, Value) _PCD_SET_MODE_32_S_##TokenName ((Value)) ``` -Therefore: + +Keep in mind that `PcdSet32S` unravels to a macro returning a value, for example: ``` -PcdSet32S(PcdMyPatchableVar32, 44) --> _PCD_SET_MODE_32_S_PcdMyPatchableVar32 ((Value)) --> ((_gPcd_BinaryPatch_PcdMyPatchableVar32 = (Value)), RETURN_SUCCESS) +PcdSet32S(PcdPatchableInt32, 44) --> _PCD_SET_MODE_32_S_PcdPatchableInt32 ((44)) --> ((_gPcd_BinaryPatch_PcdPatchableInt32 = (44)), RETURN_SUCCESS) ``` So if you don't want such error: ``` -/home/kostr/tiano/edk2/Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/PCDLesson/PCDLesson/DEBUG/AutoGen.h:108:106: error: right-hand operand of comma expression has no effect [-Werror=unused-value] - 108 | #define _PCD_SET_MODE_32_S_PcdMyPatchableVar32(Value) ((_gPcd_BinaryPatch_PcdMyPatchableVar32 = (Value)), RETURN_SUCCESS) +/<...>/Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/PCDLesson/PCDLesson/DEBUG/AutoGen.h:108:106: error: right-hand operand of comma expression has no effect [-Werror=unused-value] + 108 | #define _PCD_SET_MODE_32_S_PcdPatchableInt32(Value) ((_gPcd_BinaryPatch_PcdPatchableInt32 = (Value)), RETURN_SUCCESS) | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~. ``` You should use something like this: ``` -RETURN_STATUS PcdStatus = PcdSet32S(PcdMyPatchableVar32, 44); -Print(L"PcdStatus=%r\n", PcdStatus); +EFI_STATUS Status = PcdSet32S(PcdPatchableInt32, 44); +Print(L"Status=%r\n", Status); ``` -Alternatively you can use `PatchPcdSet32` which don't require such thing as it is defined as follows: +The native `PatchPcdSet32` API function doesn't require such thing, so you can use it simply as this: ``` -#define PatchPcdSet32(TokenName, Value) (_gPcd_BinaryPatch_##TokenName = (Value)) +PatchPcdSet32(PcdPatchableInt32, 43); ``` Test both set methods in app code: ``` -Print(L"PcdMyPatchableVar32=0x%x\n", PcdGet32(PcdMyPatchableVar32)); -RETURN_STATUS PcdStatus = PcdSet32S(PcdMyPatchableVar32, 44); -Print(L"PcdStatus=%r\n", PcdStatus); -Print(L"PcdMyPatchableVar32=%d\n", PcdGet32(PcdMyPatchableVar32)); -PatchPcdSet32(PcdMyPatchableVar32, 45); -Print(L"PcdMyPatchableVar32=%d\n", PatchPcdGet32(PcdMyPatchableVar32)); +Print(L"PcdPatchableInt32=0x%x\n", PatchPcdGet32(PcdPatchableInt32)); +Print(L"PcdPatchableInt32=0x%x\n", PcdGet32(PcdPatchableInt32)); +PatchPcdSet32(PcdPatchableInt32, 43); +Print(L"PcdPatchableInt32=%d\n", PatchPcdGet32(PcdPatchableInt32)); +EFI_STATUS Status = PcdSet32S(PcdPatchableInt32, 44); +Print(L"Status=%r\n", Status); +Print(L"PcdPatchableInt32=%d\n", PatchPcdGet32(PcdPatchableInt32)); ``` - -Now if you execute our app under OVMF prints for patchable PCDs would output: +Now if you build and execute our app under OVMF you would get the following output: ``` -PcdMyPatchableVar32=0x31313131 -PcdStatus=Success -PcdMyPatchableVar32=44 -PcdMyPatchableVar32=45 +FS0:\> PCDLesson.efi +... +PcdPatchableInt32=0x31313131 +PcdPatchableInt32=0x31313131 +PcdPatchableInt32=43 +Status=Success +PcdPatchableInt32=44 ``` -_________________________________ +# PCD Patching -In case you've wondered why I've assigned a hex value for PCD default value or why this PCD type is named `PatchableInModule` this section is for you. +In case you've wondered why I've assigned a hex value for the PCD default value or why this PCD type is named `PatchableInModule` this section is for you. -This PCD type is named like that because the value of this PCD can be changed in a binary PE/COFF image (*.efi file). To do this two utilities are used: +This PCD type is named like that because the value of this PCD can be changed in a binary PE/COFF image (i.e. the final `*.efi` file). To do this two utilities are used: - `GenPatchPcdTable` - this tool is used to get the patchable PCD offset for the EFI image by parsing the map file - `PatchPcdValue` - this tool is used to actually patch PCD value @@ -129,7 +147,7 @@ Options: ``` Now let's create a `PatchPcdTable` for our app: -For the *.efi file we can use one of: +For the `*.efi` file we can use one of: ``` Build/UefiLessonsPkg/RELEASE_GCC5/X64/PCDLesson.efi Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/PCDLesson/PCDLesson/OUTPUT/PCDLesson.efi @@ -140,16 +158,17 @@ For the *.map file we can use one of: Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/PCDLesson/PCDLesson/DEBUG/PCDLesson.map Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/PCDLesson/PCDLesson/OUTPUT/PCDLesson.map ``` + In case you wonder how our PCD can be found in a map file, execute: ``` -$ grep MyPatchableVar32 Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/PCDLesson/PCDLesson/DEBUG/PCDLesson.map -A2 - .data._gPcd_BinaryPatch_PcdMyPatchableVar32 - 0x0000000000001920 0x4 /tmp/PCDLesson.dll.m6t8YL.ltrans0.ltrans.o - *fill* 0x0000000000001924 0xc +$ grep PatchableInt32 Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/PCDLesson/PCDLesson/DEBUG/PCDLesson.map -A2 + .data._gPcd_BinaryPatch_PcdPatchableInt32 + 0x00000000000055a0 0x4 /tmp/PCDLesson.dll.96BX4a.ltrans0.ltrans.o + *fill* 0x00000000000055a4 0xc ``` -So as you can see the default value for our PCD is placed under 0x1920 offset. +So as you can see the default value for our PCD is placed under the 0x55a0 offset. -Now let's execute `GenPatchPcdTable` and create a file `PCDLessonPatchPcdTable` in app Build DEBUG folder: +Now let's execute `GenPatchPcdTable` and create a file `PCDLessonPatchPcdTable` in the app Build `DEBUG` folder: ``` ./BaseTools/BinWrappers/PosixLike/GenPatchPcdTable \ -m Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/PCDLesson/PCDLesson/DEBUG/PCDLesson.map \ @@ -161,15 +180,15 @@ Checkout the created `PCDLessonPatchPcdTable` file. ``` $ cat Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/PCDLesson/PCDLesson/DEBUG/PCDLessonPatchPcdTable PCD Name Offset Section Name -PcdMyPatchableVar32 0x1920 .data +PcdPatchableInt32 0x55A0 .data ``` As you can see it has the same offset that we've seen in a map file. Now let's get a final look at our default PCD value in an *.elf file: ``` -hexdump -s 0x1920 Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/PCDLesson/PCDLesson/DEBUG/PCDLesson.efi -n 4 -0001920 3131 3131 -0001924 +hexdump -s 0x55A0 Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/PCDLesson/PCDLesson/DEBUG/PCDLesson.efi -n 4 +00055a0 3131 3131 +00055a4 ``` Checkout help for the `PatchPcdValue` tool: @@ -202,24 +221,27 @@ Options: Now use it to patch our PCD in an *.elf file: ``` ./BaseTools/BinWrappers/PosixLike/PatchPcdValue \ - --offset=0x1920 \ + --offset=0x55a0 \ --value=0xDEADDEAD \ --type=UINT32 \ Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/PCDLesson/PCDLesson/DEBUG/PCDLesson.efi ``` Look at hexdump again: ``` -$ hexdump -s 0x1920 Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/PCDLesson/PCDLesson/DEBUG/PCDLesson.efi -n 4 -0001920 dead dead -0001924 +$ hexdump -s 0x55A0 Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/PCDLesson/PCDLesson/DEBUG/PCDLesson.efi -n 4 +00055a0 dead dead +00055a4 ``` We've successfully changed our PCD in a binary! -Now if you execute our app under OVMF prints for patchable PCDs would output: +Now copy the modified `Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/PCDLesson/PCDLesson/DEBUG/PCDLesson.efi` file to the UEFI shared disk and execute our app under OVMF: ``` -PcdMyPatchableVar32=0xDEADDEAD -PcdStatus=Success -PcdMyPatchableVar32=44 -PcdMyPatchableVar32=45 +FS0:\> PCDLesson.efi +... +PcdPatchableInt32=0xDEADDEAD +PcdPatchableInt32=0xDEADDEAD +PcdPatchableInt32=43 +Status=Success +PcdPatchableInt32=44 ``` -- cgit v1.2.3-18-g5258