23. PatchableInModule PCD 및 GenPatchPcdTable/PatchPcdValue 유틸리티를 통해 PCD를 변경하는 방법
PatchableInModule PCD class에 대해서 알아보자.
[PcdsPatchableInModule] 섹션에서 DEC(UefiLessonsPkg.dec) 파일에 새 PCD를 추가한다.
[PcdsPatchableInModule]
gUefiLessonsPkgTokenSpaceGuid.PcdPatchableInt32|0x31313131|UINT32|0xFCDA11B5INF(PCDLessons.inf)에 마찬가지로 추가해준다.
[PatchPcd]
gUefiLessonsPkgTokenSpaceGuid.PcdPatchableInt32PCDLesson.c 파일에서 PCD 값을 출력해내려면, PatchPcdGet 또는 Generic PcdGet을 사용해야 한다.
두 방법 모두 테스트 해보자.
Print(L"PcdPatchableInt32=0x%x\n", PatchPcdGet32(PcdPatchableInt32));
Print(L"PcdPatchableInt32=0x%x\n", PcdGet32(PcdPatchableInt32));FS0:\> PCDLesson.efi
...
PcdPatchableInt32=0x31313131
PcdPatchableInt32=0x31313131빌드 이후 AutoGen 파일은 각각 다음과 같다.
$ cat Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/PCDLesson/PCDLesson/DEBUG/AutoGen.h
---
#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)https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Library/PcdLib.h 따르면,
전처리기 코드를 풀면, 두 호출이 동일한 변수로 해독되는 것을 확인할 수 있다.
아래는 AutoGen.c에서 할당되는 volatile 변수이다.
따라서, FixedAtBuild와 FeatureFlag PCD의 주요한 차이점은 volatile로 정의된 변수와 SET 함수가 차단되지 않는다는 것이다.
런타임 시 PCD 값 수정
지금부터는 PCD를 설정해보겠다. 우리가 알고 있는 바와 같이, 두 가지 방법이 있다.
PatchPcdSet<Type> 혹은 generic PcdSet<Type>S API 중 하나를 사용할 수 있다.
자세한 사항은 PcdLib.h를 참고하자. https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Library/PcdLib.h
PcdSet32S는 값을 반환하는 매크로로 해독된다는 것을 기억하고 있도록 하자. 예를 들어,
따라서 다음과 같은 오류를 원하지 않는 경우에는,
아래 코드와 함께 사용해야 한다.
PcdSet32S와 다르게 PatchPcdSet32 API 함수는 이러한 것이 필요치 않으므로, 다음처럼 간단하게 사용할 수 있다.
PCDLesson.c 애플리케이션 코드에서 두 SET 메소드를 모두 테스트한다.
위의 코드를 올바르게 빌드하고 실행하면, 다음의 결과가 표시된다.
PCD 패치
이 섹션에서는 PCD 기본값에 16진수(HEX)를 할당하거나 이 PCD 유형의 이름을 PatchableInModule로 지정한 이유에 대해 언급한다.
이 PCD 타입은 바이너리 PE/COFF 이미지(즉, 최종 *.efi 파일)에서 PCD의 값이 변경될 수 있기 때문에 그렇게 이름 붙였다고 말할 수 있다. 이를 위해 두 가지 유틸리티가 사용된다.
GenPatchPcdTable - 이 툴은 맵 파일을 파싱하여 EFI 이미지에 대한 패치 가능한 PCD 오프셋을 가져오는 데 사용된다.
PatchPcdValue - 이 툴은 실제로 PCD 값을 패치하는 데 사용된다.
EDKII에서 이러한 유틸리티에 대한 매뉴얼을 제공하고 있다. https://github.com/tianocore/edk2/blob/master/BaseTools/UserManuals/PatchPcdValue_Utility_Man_Page.rtf
GenPatchPcdTable Tool
GenPatchPcdTable부터 시작해보겠다. 먼저 이 도구에 대한 도움말을 확인해보자.
이제 PatchPcdTable를 만들어보겠다.
*.efi 파일의 경우, 다음 중 하나를 사용할 수 있다.
*.map 파일의 경우, 다음 중 하나를 사용할 수 있다.
맵 파일에서 PCD를 어떻게 찾을 수 있을지 궁금한 경우, 다음 코드를 사용하면 PCD를 찾을 수 있다.
보다시피 PCD의 기본값은 0x5380 오프셋 아래에 있다.(해당 값은 0x5380 값이 아닌 다른 값이 나올 수도 있다. 원문에서는 0x55A0을 기준으로 기술하고 있다.
이제 앱 빌드DEBUG 폴더에서 GenPatchPcdTable을 실행하여 PCDLessonPatchPcdTalbe을 생성해보자.
생성된 PCDLessonPatchPcdTable 파일을 체크하면 다음과 같다.
보다시피, 맵 파일에서 본 것과 동일한 오프셋을 가진다.
이제 *.efl 파일의 기본 PCD 값을 마지막으로 살펴보겠다. (오프셋 값에 주의하도록 하자.)
PatchPcdValue Tool
PatchPcdValue 툴에 대한 도움말은 다음과 같다.
이제, 이를 사용하여 *.elf 파일에서 PCD를 패치해본다.
hexdump 값을 다시 찾아보면,
바이너리에서 PCD를 성공적으로 변경할 수 있었다.
이제 수정된 PCDLesson.efi 파일을 UEFI 공유 디스크에 복사하여 OVMF에서 앱을 실행해보자.
Last updated