25. PCD 더 알아보기

Dynamic PCD

이제 Dynamic PCD를 모듈에 추가해보자. DEC 파일에서의 Dynamic PCD는 [PcdsDynamic] 섹션으로 들어간다.

$ vi UefiLessonsPkg/UefiLessonsPkg.dec
---
[PcdsDynamic]
  gUefiLessonsPkgTokenSpaceGuid.PcdDynamicInt32|0xCAFECAFE|UINT32|0x4F9259A3

그 다음, INF 파일에 추가해준다. INF 파일에서는 [Pcd] 섹션 아래에 넣어준다.

[Pcd]
  gUefiLessonsPkgTokenSpaceGuid.PcdDynamicInt32

*.c 코드에서 PcdGet32 / PcdSet32S API를 사용하여 변수 작업을 수행한다.

$ vi UefiLessonsPkg/PCDLesson/PCDLesson.c
---
Print(L"PcdDynamicInt32=0x%x\n", PcdGet32(PcdDynamicInt32));
PcdSet32S(PcdDynamicInt32, 0xBEEFBEEF);
Print(L"PcdDynamicInt32=0x%x\n", PcdGet32(PcdDynamicInt32));

이제 AutoGen 코드를 확인해보자. PCD는 AutoGen.c에 아무런 변화도 일으키지 않지만, AutoGen.h 파일은 다음과 같은 코드가 추가된다.

#define _PCD_TOKEN_PcdDynamicInt32  0U
#define _PCD_GET_MODE_32_PcdDynamicInt32  LibPcdGet32(_PCD_TOKEN_PcdDynamicInt32)
#define _PCD_GET_MODE_SIZE_PcdDynamicInt32  LibPcdGetSize(_PCD_TOKEN_PcdDynamicInt32)
#define _PCD_SET_MODE_32_PcdDynamicInt32(Value)  LibPcdSet32(_PCD_TOKEN_PcdDynamicInt32, (Value))
#define _PCD_SET_MODE_32_S_PcdDynamicInt32(Value)  LibPcdSet32S(_PCD_TOKEN_PcdDynamicInt32, (Value))

따라서 PcdLib.h를 참고하여 보면,

#define PcdGet32(TokenName)  _PCD_GET_MODE_32_##TokenName
#define PcdSet32S(TokenName, Value)  _PCD_SET_MODE_32_S_##TokenName    ((Value))

API 호출은 다음과 같이 변환된다.

PcdGet32(PcdDynamicInt32) -> _PCD_GET_MODE_32_PcdDynamicInt32 -> LibPcdGet32(_PCD_TOKEN_PcdDynamicInt32) -> LibPcdGet32(0U)
PcdSet32S(PcdDynamicInt32, 0xBEEFBEEF) -> _PCD_SET_MODE_32_S_PcdDynamicInt32 ((0xBEEFBEEF)) -> LibPcdSet32S(_PCD_TOKEN_PcdDynamicInt32, (0xBEEFBEEF)) -> LibPcdSet32S(0U, (0xBEEFBEEF))

원인과 결과만 모아놓자면,

PcdGet32(PcdDynamicInt32)              -> LibPcdGet32(0U)
PcdSet32S(PcdDynamicInt32, 0xBEEFBEEF) -> LibPcdSet32S(0U, (0xBEEFBEEF))

여기서 눈치가 빠른 사람은 느꼈겠지만, 어딘가 이상한 부분이 존재한다. 바로 '0'인데, LibPcdGet32의 매개변수 값은 LocalToken 번호이다. 그리고 앞선 장에서 언급한 것처럼, LocalToken 번호는 1부터 시작한다.

따라서 0은 유효하지 않은 토큰 번호이다. 여기서 애플리케이션을 빌드하고 실행하면 오류가 발생할 수 있다.

LibPcdGetLibPcdSet API는 현재 PCD 데이터베이스에 접근하기 위한 것이다. 따라서 OVMF에서 애플리케이션을 실행할 때, LibPcdGet, LibPcdSet은 OVMF PCD 데이터베이스에 접근한다.

그러나, PCD 데이터베이스는 정적이므로 이미지를 빌드할 때, 모든 PCD를 수집해야 한다. Runtime 시 데이터베이스에 더 많은 Dynamic PCD를 추가할 수 없다. 어떤 Dynamic PCD가 PCD 데이터베이스로 이동하는 지를 살펴보면, 최종 플래시 이미지로이동하는 모듈의 Dynamic PCD만 이동한다.

일반적인 원리는 다음과 같다.

  • 최종 플래시 이미지로 이동하는 [DynamicPcds]의 모든 모듈에 대해 LocalToken 번호를 할당한다. 1부터 시작하는 전역 플랫폼 레벨 할당이다.

  • 위의 모든 [DynamicPcds]을 사용하여 PCD_IS_DRIVER = PEI_PCD_DRIVER / PXE_PCD_DRIVER 모듈에 대한 PCD DB 이미지 생성

우리의 애플리케이션은 OVMF 이미지의 일부가 아니기 때문에, OVMF PCD 데이터베이스에 PcdDynamicInt32에 대해서는 아직 알지 못한다. 그리고 우리 패키지는 플래시 이미지 자체를 생성하지 않는다. 따라서 빌드 시스템은 PCD에 로컬 토큰번호를 할당할 수 없다.

따라서 Dynamic PCD가 있는 모듈이 PCD 데이터베이스가 있는 메인 펌웨어와 별도로 컴파일되었기 때문에 오류가 발생했다. 이 문제를 해결하려면 애플리케이션을 OVMF 플래시 이미지에 포함해야 한다.

OvmfPkgX64.fdf[FV.DXEFV] 섹션 끝에 이미지를 추가해야 한다.

$ vi OvmfPkg/OvmfPkgX64.fdf
---
[FV.DXEFV]
...
INF  UefiLessonsPkg/PCDLesson/PCDLesson.inf

올바른 컴파일을 위해 [Components] 섹션에도 수정을 해준다.

$ vi OvmfPkg/OvmfPkg.dsc
---
[Components]
...
UefiLessonsPkg/PCDLesson/PCDLesson.inf

이제 OVMF 이미지를 다시 빌드해야 한다.

$ build --platform=OvmfPkg/OvmfPkgX64.dsc --arch=X64 --buildtarget=RELEASE --tagname=GCC5

그리고 PCD 데이터베이스 파서 유틸리티를 실행하면, 최대 LocalToken의 개수가 하나 더 많아진 것을 확인할 수 있다. 매직 넘버 값으로 PCD를 찾을 수도 있다.

$ ./parse_pcd_db \
  --peidb "Build/OvmfX64/RELEASE_GCC5/X64/MdeModulePkg/Universal/PCD/Pei/Pcd/OUTPUT/PEIPcdDataBase.raw" \
  --dxedb "Build/OvmfX64/RELEASE_GCC5/X64/MdeModulePkg/Universal/PCD/Dxe/Pcd/OUTPUT/DXEPcdDataBase.raw"

...

DXE PCD DB
LocalTokenNumberTable:

...

46:
Token type = Data
Datum type = UINT32
Value:
0xcafecafe (=3405695742)

...

이제 애플리케이션 AutoGen 파일을 확인해보겠다. 현재 우리 애플리케이션의 OvmfX64 빌드 버전은 Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/PCDLesson 폴더에 있는 것이 아니라, Build/OvmfX64/RELEASE_GCC5/X64/UefiLessonsPkg/PCDLesson 폴더에 존재함을 기억하자.

따라서 AutoGen.h를 보면, PCD에 올바른 토큰 번호가 할당된 것을 볼 수 있다.

#define _PCD_TOKEN_PcdDynamicInt32  46U
#define _PCD_GET_MODE_32_PcdDynamicInt32  LibPcdGet32(_PCD_TOKEN_PcdDynamicInt32)
#define _PCD_GET_MODE_SIZE_PcdDynamicInt32  LibPcdGetSize(_PCD_TOKEN_PcdDynamicInt32)
#define _PCD_SET_MODE_32_PcdDynamicInt32(Value)  LibPcdSet32(_PCD_TOKEN_PcdDynamicInt32, (Value))
#define _PCD_SET_MODE_32_S_PcdDynamicInt32(Value)  LibPcdSet32S(_PCD_TOKEN_PcdDynamicInt32, (Value))

parse_pcd_db 38은 이전에 생성한 LocalToken과 정확히 일치하는 것을 알 수 있다.

이제 올바른 실행 파일을 공유 폴더에 복사해준다.

$ cp Build/OvmfX64/RELEASE_GCC5/X64/UefiLessonsPkg/PCDLesson/PCDLesson/DEBUG/PCDLesson.efi ~/UEFI_disk/

업데이트된 OVMF 이미지를 실행해준다.

FS0:\> PCDLesson.efi
...
PcdDynamicInt32=0xCAFECAFE
PcdDynamicInt32=0xBEEFBEEF

이제 Get, Set 메소드가 올바르게 작동한다.

애플리케이션을 한 번 더 실행하면, 마지막 프로그램에 대한 호출이 PCD 값을 변경함을 알 수 있다.

FS0:\> PCDLesson.efi
...
PcdDynamicInt32=0xCAFECAFE
PcdDynamicInt32=0xBEEFBEEF
FS0:\> PCDLesson.efi
...
PcdDynamicInt32=0xBEEFBEEF
PcdDynamicInt32=0xBEEFBEEF

그러나 이 내용은 해당 부팅 과정에만 해당한다. PCD 데이터베이스 모듈은 플래시에서 RAM으로 데이터베이스 파일을 로드하고 모든 PCD에 대한 변경 사항은 플래시에코드 영향을 주지 않고 현재 RAM 값만 수정한다.

따라서 QEMU를 다시 실행하면 PCD는 데이터베이스의 초기 값에서 시작된다.

FS0:\> PCDLesson.efi
...
PcdDynamicInt32=0xCAFECAFE
PcdDynamicInt32=0xBEEFBEEF

항상 OvmfPkg의 일부로 애플리케이션을 사용하는 것은 아니므로, PcdDynamicInt LocalToken이 할당되지 않은 경우 액세스를 보호하는 것이 좋다.

PcdToken 매크로를 사용하여 이를 수행할 수 있다.

#define PcdToken(TokenName)  _PCD_TOKEN_##TokenName

코드 사용법은 간단하다.

if (PcdToken(PcdDynamicInt32)) {
  Print(L"PcdDynamicInt32=0x%x\n", PcdGet32(PcdDynamicInt32));
  PcdSet32S(PcdDynamicInt32, 0xBEEFBEEF);
  Print(L"PcdDynamicInt32=0x%x\n", PcdGet32(PcdDynamicInt32));
} else {
  Print(L"PcdDynamicInt32 token is unassigned\n");
}

아직까지는 실수로 Build/OvmfX64/RELEASE_GCC5/X64/PCDLesson.efi 대신 Build/UefiLessonsPkg/RELEASE_GCC5/X64/PCDLesson.efi를 복사해도 OVMF가 중단되지는 않는다.

DynamicEx PCD

PCD 데이터베이스에 필요한 PCD가 이미 존재한다고 가정해보자. 그리고 UEFI shell에서 애플리케이션을 통해 접근하려고 한다.

Dynamic PCD로 이를 수행하는 유일한 방법은 이 애플리케이션을 이미지 빌드할 때 포함시키는 방법이다. 다른 경우에는 애플리케이션을 별도로 컴파일할 때, 빌드 시스템은 이미지 PCD DB에서 사용되는 Local Token No. 지정 시스템을 인식하고 토큰 번호로 0을 생성한다.

그러나 때로는 플래시 이미지에 대한 소스가 없다. 따라서 애플리케이션을 이미지의 일부로 컴파일하는 것은 불가능하다. 이때 무엇을 할 수 있을까?

이 경우에는 또 다른 Dynamic PCD 유형인 DynamicEx PCD가 존재한다. 이 PCD를 작동시키려면 Token Number(PCD를 선언할 때 작성하는 것) 및 Token Guid를 입력해주어야 한다.

DEC 파일에서 이 유형의 PCD는 [PcdsDynamicEx] 섹션이 포함시켜준다.

$ vi UefiLessonsPkg/UefiLessonsPkg.dec
---
[PcdsDynamicEx]
  gUefiLessonsPkgTokenSpaceGuid.PcdDynamicExInt32|0xBABEBABE|UINT32|0xAF35F3B2

그리고 INF 파일에서 [PcdEx] 섹션을 만들어준다.

$ vi UefiLessonsPkg/PCDLesson/PCDLesson.c
---
[PcdEx]
  gUefiLessonsPkgTokenSpaceGuid.PcdDynamicExInt32

마지막으로 해당 PCD를 OVMF PCD 데이터베이스에 포함해야 한다.

이는 우리가 이미 OvmfPkgX64.fdf, OvmfPkgX64.dsc에 포함해놓고 있으며, 신경 쓸 필요 없다.

$ vi OvmfPkg/OvmfPkgX64.fdf
---
[FV.DXEFV]
...
INF  UefiLessonsPkg/PCDLesson/PCDLesson.inf

$ vi OvmfPkg/OvmfPkgX64.dsc
---
[Components]
...
UefiLessonsPkg/PCDLesson/PCDLesson.inf

모든 준비가 끝났으니, 다시 OVMF 이미지를 빌드해보자.

$ build --platform=OvmfPkg/OvmfPkgX64.dsc --arch=X64 --buildtarget=RELEASE --tagname=GCC5

업데이트된 PCD 데이터베이스에 새 PCD가 추가되었는지 확인할 수 있다.

$ ./parse_pcd_db \
  --peidb "Build/OvmfX64/RELEASE_GCC5/X64/MdeModulePkg/Universal/PCD/Pei/Pcd/OUTPUT/PEIPcdDataBase.raw" \
  --dxedb "Build/OvmfX64/RELEASE_GCC5/X64/MdeModulePkg/Universal/PCD/Dxe/Pcd/OUTPUT/DXEPcdDataBase.raw"

...

DXE PCD DB
LocalTokenNumberTable:

...

51:
Token type = Data
Datum type = UINT32
DynamicEx Token = 0xaf35f3b2
DynamicEx GUID  = 150cab53-ad47-4385-b5ddbcfc76bacaf0 [gUefiLessonsPkgTokenSpaceGuid]
Value:
0xbabebabe (=3133061822)

DynamicEx 토큰 값은 DEC 파일에 넣어준 코드의 토큰 번호이다.

그리고 DynamicEx GUID 값은 동일한 DEC 파일에 선언된 토큰 공간의 GUID이다.

[Guids]
  ...
  gUefiLessonsPkgTokenSpaceGuid = {0x150cab53, 0xad47, 0x4385, {0xb5, 0xdd, 0xbc, 0xfc, 0x76, 0xba, 0xca, 0xf0}}

그리고 Autogen.h 파일을 확인해보면, 새로운 코드가 추가되어 있다.

#define _PCD_TOKEN_gUefiLessonsPkgTokenSpaceGuid_PcdDynamicExInt32  2939548594U
#define _PCD_TOKEN_PcdDynamicExInt32  _PCD_TOKEN_gUefiLessonsPkgTokenSpaceGuid_PcdDynamicExInt32
#define _PCD_GET_MODE_32_PcdDynamicExInt32  LibPcdGetEx32(&gUefiLessonsPkgTokenSpaceGuid, _PCD_TOKEN_PcdDynamicExInt32)
#define _PCD_GET_MODE_SIZE_PcdDynamicExInt32 LibPcdGetExSize(&gUefiLessonsPkgTokenSpaceGuid, _PCD_TOKEN_PcdDynamicExInt32)
#define _PCD_SET_MODE_32_PcdDynamicExInt32(Value)  LibPcdSetEx32(&gUefiLessonsPkgTokenSpaceGuid, _PCD_TOKEN_PcdDynamicExInt32, (Value))
#define _PCD_SET_MODE_32_S_PcdDynamicExInt32(Value)  LibPcdSetEx32S(&gUefiLessonsPkgTokenSpaceGuid, _PCD_TOKEN_PcdDynamicExInt32, (Value))

#define COMPAREGUID(Guid1, Guid2) (BOOLEAN)(*(CONST UINT64*)Guid1 == *(CONST UINT64*)Guid2 && *((CONST UINT64*)Guid1 + 1) == *((CONST UINT64*)Guid2 + 1))

#define __PCD_PcdDynamicExInt32_ADDR_CMP(GuidPtr)  (\
  (GuidPtr == &gUefiLessonsPkgTokenSpaceGuid) ? _PCD_TOKEN_gUefiLessonsPkgTokenSpaceGuid_PcdDynamicExInt32:0 \
  )

#define __PCD_PcdDynamicExInt32_VAL_CMP(GuidPtr)  (\
  (GuidPtr == NULL) ? 0:\
  COMPAREGUID (GuidPtr, &gUefiLessonsPkgTokenSpaceGuid) ? _PCD_TOKEN_gUefiLessonsPkgTokenSpaceGuid_PcdDynamicExInt32:0 \
  )
#define _PCD_TOKEN_EX_PcdDynamicExInt32(GuidPtr)   __PCD_PcdDynamicExInt32_ADDR_CMP(GuidPtr) ? __PCD_PcdDynamicExInt32_ADDR_CMP(GuidPtr) : __PCD_PcdDynamicExInt32_VAL_CMP(GuidPtr)

중요한 것은 UefiLessonsPkg를 빌드할 경우,

$ build

애플리케이션은 AutoGen.h 파일에서 동일한 코드를 가져온다.

따라서 OVMF 소스 코드에 대한 연결이 없더라도 빌드시스템은 필요한 PCD에 액세스하기 위해 올바른 credential을 생성한다. 우리는 패키지에 대한 다른 애플리케이션을 만들 수 있으며, 여전히 앱으로 만든 것과 동일한 CPD에 액세스하는 데 사용할 수 있다.

이것이 Dynamic 및 DynamicPCD의 주요한 차이점이다. 기본 플래시 이미지의 일부로 애플리케이션을 빌드할 필요가 없다.

이제 PCD에 접근해보겠다. 이는 PcdLib.h의 PcdGetEx32/PcdSetEx32S 함수를 통해 실행된다.

#define PcdTokenEx(Guid, TokenName)  _PCD_TOKEN_EX_##TokenName(Guid)
#define PcdGetEx32(Guid, TokenName)  LibPcdGetEx32 ((Guid), PcdTokenEx(Guid,TokenName))
#define PcdSetEx32S(Guid, TokenName, Value)  LibPcdSetEx32S ((Guid), PcdTokenEx(Guid,TokenName), (Value))

보다시피 이 경우 API 약간 다르다. 이 정의에서 Guid는 GUID를 가리키는 포인터이기에, 우리는 &gUefiLessonsPkgTokenSpaceGuid를 사용해야 한다. 코드를 보자.

Print(L"PcdDynamicExInt32=0x%x\n", PcdGetEx32(&gUefiLessonsPkgTokenSpaceGuid, PcdDynamicExInt32));
PcdSetEx32S(&gUefiLessonsPkgTokenSpaceGuid, PcdDynamicExInt32, 0x77777777);
Print(L"PcdDynamicExInt32=0x%x\n", PcdGetEx32(&gUefiLessonsPkgTokenSpaceGuid, PcdDynamicExInt32));

&gUefiLessonsPkgTokenSpaceGuid는 이미 AutoGen.c 파일에 존재하기 때문에 뭔가를 더 해줄 필요는 없다.

...
GLOBAL_REMOVE_IF_UNREFERENCED EFI_GUID gUefiLessonsPkgTokenSpaceGuid = {0x150cab53, 0xad47, 0x4385, {0xb5, 0xdd, 0xbc, 0xfc, 0x76, 0xba, 0xca, 0xf0}};
...

if/then/else 논리 때문에 전처리기가 코드를 해독하기 다소 어렵지만, 다음 인수를 사용하여 LibPcdgetEx32 / LibPcdSetEx32S 함수를 호출한다.

PcdGetEx32(gUefiLessonsPkgTokenSpaceGuid, PcdDynamicExInt32)
-> LibPcdGetEx32 ((gUefiLessonsPkgTokenSpaceGuid), PcdTokenEx(gUefiLessonsPkgTokenSpaceGuid,PcdDynamicExInt32))
-> LibPcdGetEx32 ((gUefiLessonsPkgTokenSpaceGuid), _PCD_TOKEN_EX_PcdDynamicExInt32(gUefiLessonsPkgTokenSpaceGuid))
...
-> LibPcdGetEx32 ( {0x150cab53, 0xad47, 0x4385, {0xb5, 0xdd, 0xbc, 0xfc, 0x76, 0xba, 0xca, 0xf0}}, 2939548594U)

PcdSetEx32S(gUefiLessonsPkgTokenSpaceGuid, PcdDynamicExInt32, 0x77777777)
-> LibPcdSetEx32S ((gUefiLessonsPkgTokenSpaceGuid), PcdTokenEx(gUefiLessonsPkgTokenSpaceGuid,PcdDynamicExInt32), (0x77777777))
...
-> LibPcdSetEx32S ( {0x150cab53, 0xad47, 0x4385, {0xb5, 0xdd, 0xbc, 0xfc, 0x76, 0xba, 0xca, 0xf0}}, 2939548594U, (0x77777777) )

이제 이 애플리케이션을 빌드하고 결과를 공유디스크에 복사한다. 다시 말하지만, DynamicEx PCD의 경우 패키지 빌드 결과, 즉 Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/PCDLesson/ PCDLesson/DEBUG/PCDLesson.efi 파일을 사용할 수 있다.

(빌드가 이루어지지 않을 수 있는데, 코드에 대한 검토를 진행하고 수정하도록 하겠다.)

동작은 Dynamic PCD와 유사하다. 처음으로 초기 PCD 값을 얻게 된다.

FS0:\> PCDLesson.efi
...
PcdDynamicExInt32=0xBABEBABE
PcdDynamicExInt32=0x77777777

그러나 프로그램이 PCD를 업데이트하므로 다음에 시작할 때, 업데이트된 값으로 시작한다.

FS0:\> PCDLesson.efi
...
PcdDynamicExInt32=0x77777777
PcdDynamicExInt32=0x77777777

Dynamic API 함수를 사용하여 DynamicEx PCD에 액세스

PcdGet32 / PcdSet32S 함수가 특정 Dynamic API 함수가 아니라는 점에 주의해야 한다. 이러한 기능은 DynamicEx PCD를 포함한 모든 유형의 PCD와 함께 사용할 수 있는 일반 API이다. 예를 들어, 애플리케이션에 다음 코드를 추가한다.

Print(L"PcdDynamicExInt32=0x%x\n", PcdGet32(PcdDynamicExInt32));
PcdSet32S(PcdDynamicExInt32, 0x88888888);
Print(L"PcdDynamicExInt32=0x%x\n", PcdGet32(PcdDynamicExInt32));

작동 방식에 관해서는 AutoGen.h를 참고하도록 하자.

#define _PCD_TOKEN_gUefiLessonsPkgTokenSpaceGuid_PcdDynamicExInt32  2939548594U
#define _PCD_TOKEN_PcdDynamicExInt32  _PCD_TOKEN_gUefiLessonsPkgTokenSpaceGuid_PcdDynamicExInt32
#define _PCD_GET_MODE_32_PcdDynamicExInt32  LibPcdGetEx32(&gUefiLessonsPkgTokenSpaceGuid, _PCD_TOKEN_PcdDynamicExInt32)
#define _PCD_GET_MODE_SIZE_PcdDynamicExInt32 LibPcdGetExSize(&gUefiLessonsPkgTokenSpaceGuid, _PCD_TOKEN_PcdDynamicExInt32)
#define _PCD_SET_MODE_32_PcdDynamicExInt32(Value)  LibPcdSetEx32(&gUefiLessonsPkgTokenSpaceGuid, _PCD_TOKEN_PcdDynamicExInt32, (Value))
#define _PCD_SET_MODE_32_S_PcdDynamicExInt32(Value)  LibPcdSetEx32S(&gUefiLessonsPkgTokenSpaceGuid, _PCD_TOKEN_PcdDynamicExInt32, (Value))

PcdGet32 / PcdSet32의 정의를 기억하자.

#define PcdGet32(TokenName)  _PCD_GET_MODE_32_##TokenName
#define PcdSet32S(TokenName, Value)  _PCD_SET_MODE_32_S_##TokenName    ((Value))

위의 코드는 다음과 같이 해독된다.

PcdGet32(PcdDynamicExInt32) -> _PCD_GET_MODE_32_PcdDynamicExInt32 -> LibPcdGetEx32(&gUefiLessonsPkgTokenSpaceGuid, _PCD_TOKEN_PcdDynamicExInt32)
PcdSet32S(PcdDynamicExInt32, 0x88888888) -> _PCD_SET_MODE_32_S_PcdDynamicExInt32 ((0x88888888)) -> LibPcdSetEx32S(&gUefiLessonsPkgTokenSpaceGuid, _PCD_TOKEN_PcdDynamicExInt32, (0x88888888))

애플리케이션을 다시 빌드하여 잘 작동하는 지 확인할 수 있다.

FS0:\> PCDLesson.efi
...
PcdDynamicExInt32=0xBABEBABE
PcdDynamicExInt32=0x77777777
PcdDynamicExInt32=0x77777777
PcdDynamicExInt32=0x88888888

PCD_DYNAMIC_AS_DYNAMICEX

EDKII에는 모든 Dynamic PCD를 Dynamic Ex 유형으로 쉽게 변경할 수 있는 방법이 있다. 이를 위해 Platform DSC 파일에 특수 정의를 추가하기만 하면 된다.

$ vi OvmfPkg/OvmfPkgX64.dsc
---
[Defines]
  ...
  PCD_DYNAMIC_AS_DYNAMICEX = TRUE

OVMF를 다시 빌드할 때 위의 정의를 추가하면 많은 양의 재컴파일이 발생한다.

빌드한 이후 PCD DB 파일을 확인하자.

$ ./parse_pcd_db \
  --peidb "Build/OvmfX64/RELEASE_GCC5/X64/MdeModulePkg/Universal/PCD/Pei/Pcd/OUTPUT/PEIPcdDataBase.raw" \
  --dxedb "Build/OvmfX64/RELEASE_GCC5/X64/MdeModulePkg/Universal/PCD/Dxe/Pcd/OUTPUT/DXEPcdDataBase.raw"

PEI PCD DB
LocalTokenNumberTable:

1:
Token type = Data
Datum type = UINT8 (Bool)
DynamicEx Token = 0x01100000
DynamicEx GUID  = a1aff049-fdeb-442a-b32013ab4cb72bbc [gEfiMdeModulePkgTokenSpaceGuid]
0 - unitialized

2:
Token type = Data
Datum type = UINT64
DynamicEx Token = 0x40000008
DynamicEx GUID  = a1aff049-fdeb-442a-b32013ab4cb72bbc [gEfiMdeModulePkgTokenSpaceGuid]
0 - unitialized

3:
Token type = Data
Datum type = UINT64
DynamicEx Token = 0x00030007
DynamicEx GUID  = a1aff049-fdeb-442a-b32013ab4cb72bbc [gEfiMdeModulePkgTokenSpaceGuid]
0 - unitialized

4:
Token type = Data
Datum type = UINT64
DynamicEx Token = 0x00030008
DynamicEx GUID  = a1aff049-fdeb-442a-b32013ab4cb72bbc [gEfiMdeModulePkgTokenSpaceGuid]
0 - unitialized

5:
Token type = String
Datum type = Pointer
DynamicEx Token = 0x00030005
DynamicEx GUID  = a1aff049-fdeb-442a-b32013ab4cb72bbc [gEfiMdeModulePkgTokenSpaceGuid]
CurrentSize = 1
MaxSize     = 1
Value:
00                                               | .

6:
Token type = Data
Datum type = UINT64
DynamicEx Token = 0x30001047
DynamicEx GUID  = a1aff049-fdeb-442a-b32013ab4cb72bbc [gEfiMdeModulePkgTokenSpaceGuid]
0 - unitialized

7:
Token type = Data
Datum type = UINT16
DynamicEx Token = 0x00030004
DynamicEx GUID  = a1aff049-fdeb-442a-b32013ab4cb72bbc [gEfiMdeModulePkgTokenSpaceGuid]
0 - unitialized

8:
Token type = Data
Datum type = UINT8 (Bool)
DynamicEx Token = 0x0001006f
DynamicEx GUID  = a1aff049-fdeb-442a-b32013ab4cb72bbc [gEfiMdeModulePkgTokenSpaceGuid]
0 - unitialized

9:
Token type = Data
Datum type = UINT64
DynamicEx Token = 0x00030006
DynamicEx GUID  = a1aff049-fdeb-442a-b32013ab4cb72bbc [gEfiMdeModulePkgTokenSpaceGuid]
0 - unitialized

10:
Token type = Data
Datum type = UINT32
DynamicEx Token = 0x00000001
DynamicEx GUID  = 0d3fb176-9569-4d51-a3ef7d61c64feaba [gEfiSecurityPkgTokenSpaceGuid]
0 - unitialized

11:
Token type = Data
Datum type = UINT32
DynamicEx Token = 0x00000008
DynamicEx GUID  = ac05bf33-995a-4ed4-aab8ef7ae80f5cb0 [gUefiCpuPkgTokenSpaceGuid]
0 - unitialized

12:
Token type = Data
Datum type = UINT32
DynamicEx Token = 0x00000002
DynamicEx GUID  = ac05bf33-995a-4ed4-aab8ef7ae80f5cb0 [gUefiCpuPkgTokenSpaceGuid]
Value:
0x00000040 (=64)

13:
Token type = Data
Datum type = UINT8 (Bool)
DynamicEx Token = 0x60000016
DynamicEx GUID  = ac05bf33-995a-4ed4-aab8ef7ae80f5cb0 [gUefiCpuPkgTokenSpaceGuid]
0 - unitialized

14:
Token type = Data
Datum type = UINT16
DynamicEx Token = 0x0000001b
DynamicEx GUID  = 93bb96af-b9f2-4eb8-9462e0ba74564236 [gUefiOvmfPkgTokenSpaceGuid]
0 - unitialized

15:
Token type = Data
Datum type = UINT64
DynamicEx Token = 0x00000022
DynamicEx GUID  = 93bb96af-b9f2-4eb8-9462e0ba74564236 [gUefiOvmfPkgTokenSpaceGuid]
0 - unitialized

16:
Token type = Data
Datum type = UINT64
DynamicEx Token = 0x00000023
DynamicEx GUID  = 93bb96af-b9f2-4eb8-9462e0ba74564236 [gUefiOvmfPkgTokenSpaceGuid]
0 - unitialized

17:
Token type = Data
Datum type = UINT64
DynamicEx Token = 0x00000024
DynamicEx GUID  = 93bb96af-b9f2-4eb8-9462e0ba74564236 [gUefiOvmfPkgTokenSpaceGuid]
0 - unitialized

18:
Token type = Data
Datum type = UINT64
DynamicEx Token = 0x00000025
DynamicEx GUID  = 93bb96af-b9f2-4eb8-9462e0ba74564236 [gUefiOvmfPkgTokenSpaceGuid]
0 - unitialized

19:
Token type = Data
Datum type = UINT64
DynamicEx Token = 0x00000026
DynamicEx GUID  = 93bb96af-b9f2-4eb8-9462e0ba74564236 [gUefiOvmfPkgTokenSpaceGuid]
0 - unitialized

20:
Token type = Data
Datum type = UINT64
DynamicEx Token = 0x00000027
DynamicEx GUID  = 93bb96af-b9f2-4eb8-9462e0ba74564236 [gUefiOvmfPkgTokenSpaceGuid]
Value:
0x0000000800000000 (=34359738368)

21:
Token type = Data
Datum type = UINT8 (Bool)
DynamicEx Token = 0x00000034
DynamicEx GUID  = 93bb96af-b9f2-4eb8-9462e0ba74564236 [gUefiOvmfPkgTokenSpaceGuid]
0 - unitialized

22:
Token type = Data
Datum type = UINT16
DynamicEx Token = 0x00000020
DynamicEx GUID  = 93bb96af-b9f2-4eb8-9462e0ba74564236 [gUefiOvmfPkgTokenSpaceGuid]
Value:
0x0008 (=8)
_____

DXE PCD DB
LocalTokenNumberTable:

23:
Token type = Data
Datum type = UINT32
DynamicEx Token = 0x30000013
DynamicEx GUID  = a1aff049-fdeb-442a-b32013ab4cb72bbc [gEfiMdeModulePkgTokenSpaceGuid]
0 - unitialized

24:
Token type = Data
Datum type = UINT32
DynamicEx Token = 0x30000010
DynamicEx GUID  = a1aff049-fdeb-442a-b32013ab4cb72bbc [gEfiMdeModulePkgTokenSpaceGuid]
0 - unitialized

25:
Token type = Data
Datum type = UINT64
DynamicEx Token = 0x80000001
DynamicEx GUID  = a1aff049-fdeb-442a-b32013ab4cb72bbc [gEfiMdeModulePkgTokenSpaceGuid]
0 - unitialized

26:
Token type = Data
Datum type = UINT64
DynamicEx Token = 0x00030000
DynamicEx GUID  = a1aff049-fdeb-442a-b32013ab4cb72bbc [gEfiMdeModulePkgTokenSpaceGuid]
0 - unitialized

27:
Token type = Data
Datum type = UINT64
DynamicEx Token = 0x00030001
DynamicEx GUID  = a1aff049-fdeb-442a-b32013ab4cb72bbc [gEfiMdeModulePkgTokenSpaceGuid]
0 - unitialized

28:
Token type = Data
Datum type = UINT32
DynamicEx Token = 0x4000000b
DynamicEx GUID  = a1aff049-fdeb-442a-b32013ab4cb72bbc [gEfiMdeModulePkgTokenSpaceGuid]
Value:
0x00000280 (=640)

29:
Token type = Data
Datum type = UINT32
DynamicEx Token = 0x4000000c
DynamicEx GUID  = a1aff049-fdeb-442a-b32013ab4cb72bbc [gEfiMdeModulePkgTokenSpaceGuid]
Value:
0x000001e0 (=480)

30:
Token type = Data
Datum type = UINT8
DynamicEx Token = 0x0001006a
DynamicEx GUID  = a1aff049-fdeb-442a-b32013ab4cb72bbc [gEfiMdeModulePkgTokenSpaceGuid]
0 - unitialized

31:
Token type = Data
Datum type = UINT16
DynamicEx Token = 0x00010055
DynamicEx GUID  = a1aff049-fdeb-442a-b32013ab4cb72bbc [gEfiMdeModulePkgTokenSpaceGuid]
Value:
0x0208 (=520)

32:
Token type = Data
Datum type = UINT8 (Bool)
DynamicEx Token = 0x00030003
DynamicEx GUID  = a1aff049-fdeb-442a-b32013ab4cb72bbc [gEfiMdeModulePkgTokenSpaceGuid]
0 - unitialized

33:
Token type = Data
Datum type = UINT32
DynamicEx Token = 0x40000009
DynamicEx GUID  = a1aff049-fdeb-442a-b32013ab4cb72bbc [gEfiMdeModulePkgTokenSpaceGuid]
Value:
0x00000320 (=800)

34:
Token type = Data
Datum type = UINT32
DynamicEx Token = 0x4000000a
DynamicEx GUID  = a1aff049-fdeb-442a-b32013ab4cb72bbc [gEfiMdeModulePkgTokenSpaceGuid]
Value:
0x00000258 (=600)

35:
Token type = Data
Datum type = UINT16
DynamicEx Token = 0x0000002c
DynamicEx GUID  = 914aebe7-4635-459b-aa1c11e219b03a10 [gEfiMdePkgTokenSpaceGuid]
0 - unitialized

36:
Token type = Data
Datum type = UINT8
DynamicEx Token = 0x10000009
DynamicEx GUID  = 40e064b2-0ae0-48b1-a07df8cf1e1a2310 [gEfiNetworkPkgTokenSpaceGuid]
Value:
0x01 (=1)

37:
Token type = Data
Datum type = UINT8
DynamicEx Token = 0x1000000a
DynamicEx GUID  = 40e064b2-0ae0-48b1-a07df8cf1e1a2310 [gEfiNetworkPkgTokenSpaceGuid]
Value:
0x01 (=1)

38:
Token type = Data
Datum type = UINT32
DynamicEx Token = 0xaf35f3b2
DynamicEx GUID  = 150cab53-ad47-4385-b5ddbcfc76bacaf0 [gUefiLessonsPkgTokenSpaceGuid]
Value:
0xbabebabe (=3133061822)

39:
Token type = Data
Datum type = UINT32
DynamicEx Token = 0x4f9259a3
DynamicEx GUID  = 150cab53-ad47-4385-b5ddbcfc76bacaf0 [gUefiLessonsPkgTokenSpaceGuid]
Value:
0xcafecafe (=3405695742)

40:
Token type = Data
Datum type = UINT64
DynamicEx Token = 0x00000002
DynamicEx GUID  = 93bb96af-b9f2-4eb8-9462e0ba74564236 [gUefiOvmfPkgTokenSpaceGuid]
0 - unitialized

41:
Token type = Data
Datum type = UINT8 (Bool)
DynamicEx Token = 0x00000010
DynamicEx GUID  = 93bb96af-b9f2-4eb8-9462e0ba74564236 [gUefiOvmfPkgTokenSpaceGuid]
0 - unitialized

42:
Token type = Data
Datum type = UINT8 (Bool)
DynamicEx Token = 0x00000021
DynamicEx GUID  = 93bb96af-b9f2-4eb8-9462e0ba74564236 [gUefiOvmfPkgTokenSpaceGuid]
0 - unitialized
_____

지금처럼 PcdGet32 / PcdSet32S 함수를 사용하면 DynamicEx PCD에 접근할 수 있다. 따라서 이를 이용하면 모듈에서 아무것도 변경할 필요가 없다.

AutoGen.h에 생성된 파일을 확인하자.

#define _PCD_TOKEN_gUefiLessonsPkgTokenSpaceGuid_PcdDynamicInt32  1334991267U
#define _PCD_TOKEN_PcdDynamicInt32  _PCD_TOKEN_gUefiLessonsPkgTokenSpaceGuid_PcdDynamicInt32
#define _PCD_GET_MODE_32_PcdDynamicInt32  LibPcdGetEx32(&gUefiLessonsPkgTokenSpaceGuid, _PCD_TOKEN_PcdDynamicInt32)
#define _PCD_GET_MODE_SIZE_PcdDynamicInt32 LibPcdGetExSize(&gUefiLessonsPkgTokenSpaceGuid, _PCD_TOKEN_PcdDynamicInt32)
#define _PCD_SET_MODE_32_PcdDynamicInt32(Value)  LibPcdSetEx32(&gUefiLessonsPkgTokenSpaceGuid, _PCD_TOKEN_PcdDynamicInt32, (Value))
#define _PCD_SET_MODE_32_S_PcdDynamicInt32(Value)  LibPcdSetEx32S(&gUefiLessonsPkgTokenSpaceGuid, _PCD_TOKEN_PcdDynamicInt32, (Value))

#define _PCD_TOKEN_gUefiLessonsPkgTokenSpaceGuid_PcdDynamicExInt32  2939548594U
#define _PCD_TOKEN_PcdDynamicExInt32  _PCD_TOKEN_gUefiLessonsPkgTokenSpaceGuid_PcdDynamicExInt32
#define _PCD_GET_MODE_32_PcdDynamicExInt32  LibPcdGetEx32(&gUefiLessonsPkgTokenSpaceGuid, _PCD_TOKEN_PcdDynamicExInt32)
#define _PCD_GET_MODE_SIZE_PcdDynamicExInt32 LibPcdGetExSize(&gUefiLessonsPkgTokenSpaceGuid, _PCD_TOKEN_PcdDynamicExInt32)
#define _PCD_SET_MODE_32_PcdDynamicExInt32(Value)  LibPcdSetEx32(&gUefiLessonsPkgTokenSpaceGuid, _PCD_TOKEN_PcdDynamicExInt32, (Value))
#define _PCD_SET_MODE_32_S_PcdDynamicExInt32(Value)  LibPcdSetEx32S(&gUefiLessonsPkgTokenSpaceGuid, _PCD_TOKEN_PcdDynamicExInt32, (Value))

#define COMPAREGUID(Guid1, Guid2) (BOOLEAN)(*(CONST UINT64*)Guid1 == *(CONST UINT64*)Guid2 && *((CONST UINT64*)Guid1 + 1) == *((CONST UINT64*)Guid2 + 1))

#define __PCD_PcdDynamicInt32_ADDR_CMP(GuidPtr)  (\
  (GuidPtr == &gUefiLessonsPkgTokenSpaceGuid) ? _PCD_TOKEN_gUefiLessonsPkgTokenSpaceGuid_PcdDynamicInt32:0 \
  )

#define __PCD_PcdDynamicExInt32_ADDR_CMP(GuidPtr)  (\
  (GuidPtr == &gUefiLessonsPkgTokenSpaceGuid) ? _PCD_TOKEN_gUefiLessonsPkgTokenSpaceGuid_PcdDynamicExInt32:0 \
  )

#define __PCD_PcdDynamicInt32_VAL_CMP(GuidPtr)  (\
  (GuidPtr == NULL) ? 0:\
  COMPAREGUID (GuidPtr, &gUefiLessonsPkgTokenSpaceGuid) ? _PCD_TOKEN_gUefiLessonsPkgTokenSpaceGuid_PcdDynamicInt32:0 \
  )
#define _PCD_TOKEN_EX_PcdDynamicInt32(GuidPtr)   __PCD_PcdDynamicInt32_ADDR_CMP(GuidPtr) ? __PCD_PcdDynamicInt32_ADDR_CMP(GuidPtr) : __PCD_PcdDynamicInt32_VAL_CMP(GuidPtr)

#define __PCD_PcdDynamicExInt32_VAL_CMP(GuidPtr)  (\
  (GuidPtr == NULL) ? 0:\
  COMPAREGUID (GuidPtr, &gUefiLessonsPkgTokenSpaceGuid) ? _PCD_TOKEN_gUefiLessonsPkgTokenSpaceGuid_PcdDynamicExInt32:0 \
  )
#define _PCD_TOKEN_EX_PcdDynamicExInt32(GuidPtr)   __PCD_PcdDynamicExInt32_ADDR_CMP(GuidPtr) ? __PCD_PcdDynamicExInt32_ADDR_CMP(GuidPtr) : __PCD_PcdDynamicExInt32_VAL_CMP(GuidPtr)

여기에서 두 PCD가 마지막으로 LibPcdGetEx / LibPcdSetEx 함수를 정의하는 지 알 수 있다.

OVMF가 부팅되면 애플리케이션이 예상대로 작동하는 지 확인할 수 있다.

FS0:\> PCDLesson.efi
...
PcdDynamicInt32=0xCAFECAFE
PcdDynamicInt32=0xBEEFBEEF
PcdDynamicExInt32=0xBABEBABE
PcdDynamicExInt32=0x77777777
PcdDynamicExInt32=0x77777777
PcdDynamicExInt32=0x88888888

PCD_INFO_GENERATION

또 다른 플랫폼 레벨의PCD 정의가 있다. PCD_INFO_GENERATION인데, 이 설정을 DSC 파일에 추가한다. (그리고 PCD_DYNAMIC_AS_DYNAMICEX = TRUE 제거)

$ vi OvmfPkg/OvmfPkgX64.dsc
---
[Defines]
  ...
  PCD_INFO_GENERATION = TRUE

그 다음, OVMF를 다시 컴파일하고 PCD 데이터베이스 파일을 확인한다.

$ ./parse_pcd_db \
    --peidb "Build/OvmfX64/RELEASE_GCC5/X64/MdeModulePkg/Universal/PCD/Pei/Pcd/OUTPUT/PEIPcdDataBase.raw" \
    --dxedb "Build/OvmfX64/RELEASE_GCC5/X64/MdeModulePkg/Universal/PCD/Dxe/Pcd/OUTPUT/DXEPcdDataBase.raw"

PEI PCD DB
LocalTokenNumberTable:

1:
Token type = Data
Datum type = UINT8 (Bool)
TokenSpaceName = gEfiMdeModulePkgTokenSpaceGuid
PcdName = PcdAcpiS3Enable
0 - unitialized

2:
Token type = Data
Datum type = UINT64
TokenSpaceName = gEfiMdeModulePkgTokenSpaceGuid
PcdName = PcdEmuVariableNvStoreReserved
0 - unitialized

3:
Token type = Data
Datum type = UINT64
TokenSpaceName = gEfiMdeModulePkgTokenSpaceGuid
PcdName = PcdGhcbBase
0 - unitialized

4:
Token type = Data
Datum type = UINT64
TokenSpaceName = gEfiMdeModulePkgTokenSpaceGuid
PcdName = PcdGhcbSize
0 - unitialized

5:
Token type = Data
Datum type = UINT64
TokenSpaceName = gEfiMdeModulePkgTokenSpaceGuid
PcdName = PcdPteMemoryEncryptionAddressOrMask
0 - unitialized

6:
Token type = Data
Datum type = UINT8 (Bool)
TokenSpaceName = gEfiMdeModulePkgTokenSpaceGuid
PcdName = PcdSetNxForStack
0 - unitialized

7:
Token type = Data
Datum type = UINT32
TokenSpaceName = gEfiSecurityPkgTokenSpaceGuid
PcdName = PcdOptionRomImageVerificationPolicy
0 - unitialized

8:
Token type = Data
Datum type = UINT32
TokenSpaceName = gUefiCpuPkgTokenSpaceGuid
PcdName = PcdCpuBootLogicalProcessorNumber
0 - unitialized

9:
Token type = Data
Datum type = UINT32
TokenSpaceName = gUefiCpuPkgTokenSpaceGuid
PcdName = PcdCpuMaxLogicalProcessorNumber
Value:
0x00000040 (=64)

10:
Token type = Data
Datum type = UINT8 (Bool)
TokenSpaceName = gUefiCpuPkgTokenSpaceGuid
PcdName = PcdSevEsIsEnabled
0 - unitialized

11:
Token type = Data
Datum type = UINT16
TokenSpaceName = gUefiOvmfPkgTokenSpaceGuid
PcdName = PcdOvmfHostBridgePciDevId
0 - unitialized

12:
Token type = Data
Datum type = UINT64
TokenSpaceName = gUefiOvmfPkgTokenSpaceGuid
PcdName = PcdPciIoBase
0 - unitialized

13:
Token type = Data
Datum type = UINT64
TokenSpaceName = gUefiOvmfPkgTokenSpaceGuid
PcdName = PcdPciIoSize
0 - unitialized

14:
Token type = Data
Datum type = UINT64
TokenSpaceName = gUefiOvmfPkgTokenSpaceGuid
PcdName = PcdPciMmio32Base
0 - unitialized

15:
Token type = Data
Datum type = UINT64
TokenSpaceName = gUefiOvmfPkgTokenSpaceGuid
PcdName = PcdPciMmio32Size
0 - unitialized

16:
Token type = Data
Datum type = UINT64
TokenSpaceName = gUefiOvmfPkgTokenSpaceGuid
PcdName = PcdPciMmio64Base
0 - unitialized

17:
Token type = Data
Datum type = UINT64
TokenSpaceName = gUefiOvmfPkgTokenSpaceGuid
PcdName = PcdPciMmio64Size
Value:
0x0000000800000000 (=34359738368)

18:
Token type = Data
Datum type = UINT8 (Bool)
TokenSpaceName = gUefiOvmfPkgTokenSpaceGuid
PcdName = PcdQ35SmramAtDefaultSmbase
0 - unitialized

19:
Token type = Data
Datum type = UINT16
TokenSpaceName = gUefiOvmfPkgTokenSpaceGuid
PcdName = PcdQ35TsegMbytes
Value:
0x0008 (=8)

20:
Token type = String
Datum type = Pointer
DynamicEx Token = 0x00030005
DynamicEx GUID  = a1aff049-fdeb-442a-b32013ab4cb72bbc [gEfiMdeModulePkgTokenSpaceGuid]
TokenSpaceName = gEfiMdeModulePkgTokenSpaceGuid
PcdName = PcdNvStoreDefaultValueBuffer
CurrentSize = 1
MaxSize     = 1
Value:
00                                               | .

21:
Token type = Data
Datum type = UINT16
DynamicEx Token = 0x00030004
DynamicEx GUID  = a1aff049-fdeb-442a-b32013ab4cb72bbc [gEfiMdeModulePkgTokenSpaceGuid]
TokenSpaceName = gEfiMdeModulePkgTokenSpaceGuid
PcdName = PcdSetNvStoreDefaultId
0 - unitialized

22:
Token type = Data
Datum type = UINT64
DynamicEx Token = 0x00030006
DynamicEx GUID  = a1aff049-fdeb-442a-b32013ab4cb72bbc [gEfiMdeModulePkgTokenSpaceGuid]
TokenSpaceName = gEfiMdeModulePkgTokenSpaceGuid
PcdName = PcdVpdBaseAddress64
0 - unitialized
_____

DXE PCD DB
LocalTokenNumberTable:

23:
Token type = Data
Datum type = UINT32
TokenSpaceName = gEfiMdeModulePkgTokenSpaceGuid
PcdName = PcdFlashNvStorageFtwSpareBase
0 - unitialized

24:
Token type = Data
Datum type = UINT32
TokenSpaceName = gEfiMdeModulePkgTokenSpaceGuid
PcdName = PcdFlashNvStorageFtwWorkingBase
0 - unitialized

25:
Token type = Data
Datum type = UINT64
TokenSpaceName = gEfiMdeModulePkgTokenSpaceGuid
PcdName = PcdFlashNvStorageVariableBase64
0 - unitialized

26:
Token type = Data
Datum type = UINT64
TokenSpaceName = gEfiMdeModulePkgTokenSpaceGuid
PcdName = PcdS3BootScriptTablePrivateDataPtr
0 - unitialized

27:
Token type = Data
Datum type = UINT64
TokenSpaceName = gEfiMdeModulePkgTokenSpaceGuid
PcdName = PcdS3BootScriptTablePrivateSmmDataPtr
0 - unitialized

28:
Token type = Data
Datum type = UINT32
TokenSpaceName = gEfiMdeModulePkgTokenSpaceGuid
PcdName = PcdSetupVideoHorizontalResolution
Value:
0x00000280 (=640)

29:
Token type = Data
Datum type = UINT32
TokenSpaceName = gEfiMdeModulePkgTokenSpaceGuid
PcdName = PcdSetupVideoVerticalResolution
Value:
0x000001e0 (=480)

30:
Token type = Data
Datum type = UINT8
TokenSpaceName = gEfiMdeModulePkgTokenSpaceGuid
PcdName = PcdSmbiosDocRev
0 - unitialized

31:
Token type = Data
Datum type = UINT16
TokenSpaceName = gEfiMdeModulePkgTokenSpaceGuid
PcdName = PcdSmbiosVersion
Value:
0x0208 (=520)

32:
Token type = Data
Datum type = UINT8 (Bool)
TokenSpaceName = gEfiMdeModulePkgTokenSpaceGuid
PcdName = PcdTestKeyUsed
0 - unitialized

33:
Token type = Data
Datum type = UINT32
TokenSpaceName = gEfiMdeModulePkgTokenSpaceGuid
PcdName = PcdVideoHorizontalResolution
Value:
0x00000320 (=800)

34:
Token type = Data
Datum type = UINT32
TokenSpaceName = gEfiMdeModulePkgTokenSpaceGuid
PcdName = PcdVideoVerticalResolution
Value:
0x00000258 (=600)

35:
Token type = Data
Datum type = UINT16
TokenSpaceName = gEfiMdePkgTokenSpaceGuid
PcdName = PcdPlatformBootTimeOut
0 - unitialized

36:
Token type = Data
Datum type = UINT8
TokenSpaceName = gEfiNetworkPkgTokenSpaceGuid
PcdName = PcdIPv4PXESupport
Value:
0x01 (=1)

37:
Token type = Data
Datum type = UINT8
TokenSpaceName = gEfiNetworkPkgTokenSpaceGuid
PcdName = PcdIPv6PXESupport
Value:
0x01 (=1)

38:
Token type = Data
Datum type = UINT32
TokenSpaceName = gUefiLessonsPkgTokenSpaceGuid
PcdName = PcdDynamicInt32
Value:
0xcafecafe (=3405695742)

39:
Token type = Data
Datum type = UINT64
TokenSpaceName = gUefiOvmfPkgTokenSpaceGuid
PcdName = PcdEmuVariableEvent
0 - unitialized

40:
Token type = Data
Datum type = UINT8 (Bool)
TokenSpaceName = gUefiOvmfPkgTokenSpaceGuid
PcdName = PcdOvmfFlashVariablesEnable
0 - unitialized

41:
Token type = Data
Datum type = UINT8 (Bool)
TokenSpaceName = gUefiOvmfPkgTokenSpaceGuid
PcdName = PcdQemuSmbiosValidated
0 - unitialized

42:
Token type = Data
Datum type = UINT32
DynamicEx Token = 0xaf35f3b2
DynamicEx GUID  = 150cab53-ad47-4385-b5ddbcfc76bacaf0 [gUefiLessonsPkgTokenSpaceGuid]
TokenSpaceName = gUefiLessonsPkgTokenSpaceGuid
PcdName = PcdDynamicExInt32
Value:
0xbabebabe (=3133061822)
_____

이제 모든 토큰에는 TokenSpaceName / PcdName 필드가 존재한다. 해당 필드들은 PCD 데이터베이스가 일반적으로는 비어있는 PcdNameTable 부분을 채우고 있기 때문에 존재한다.

DumpDynPcd

MdeModulePkg에는 Runtime에 Dynamic PCD 정보를 덤프하는 애플리케이션이 포함되어 있다. https://github.com/tianocore/edk2/tree/master/MdeModulePkg/Application/DumpDynPcd

빌드하려면 다음 명령을 사용하면 된다.

$ build --platform=MdeModulePkg/MdeModulePkg.dsc --module=MdeModulePkg/Application/DumpDynPcd/DumpDynPcd.inf --arch=X64 --buildtarget=RELEASE --tagname=GCC5

공유 디스크에 결과 복사

$ cp Build/MdeModule/RELEASE_GCC5/X64/DumpDynPcd.efi ~/UEFI_disk/

UEFI shell에서 이 프로그램을 실행하면, parse_pcd_db 프로그램에서 얻은 것과 유사한 출력을 얻을 수 있다.

FS0:\> DumpDynPcd.efi
Current system SKU ID: 0x0

Default Token Space
  Token = 0x00000001 - Type = BOOLEAN:DYNAMIC   - Size = 0x1 - Value = TRUE

Default Token Space
  Token = 0x00000002 - Type = UINT64:DYNAMIC    - Size = 0x8 - Value = 0x7EF4000

Default Token Space
  Token = 0x00000003 - Type = UINT64:DYNAMIC    - Size = 0x8 - Value = 0x0

Default Token Space
  Token = 0x00000004 - Type = UINT64:DYNAMIC    - Size = 0x8 - Value = 0x0

Default Token Space
  Token = 0x00000005 - Type = UINT64:DYNAMIC    - Size = 0x8 - Value = 0x0

Default Token Space
  Token = 0x00000006 - Type = BOOLEAN:DYNAMIC   - Size = 0x1 - Value = FALSE

Default Token Space
  Token = 0x00000007 - Type = UINT32:DYNAMIC    - Size = 0x4 - Value = 0x0

Default Token Space
  Token = 0x00000008 - Type = UINT32:DYNAMIC    - Size = 0x4 - Value = 0x0

Default Token Space
  Token = 0x00000009 - Type = UINT32:DYNAMIC    - Size = 0x4 - Value = 0x1

Default Token Space
  Token = 0x0000000A - Type = BOOLEAN:DYNAMIC   - Size = 0x1 - Value = FALSE

Default Token Space
  Token = 0x0000000B - Type = UINT16:DYNAMIC    - Size = 0x2 - Value = 0x1237

Default Token Space
  Token = 0x0000000C - Type = UINT64:DYNAMIC    - Size = 0x8 - Value = 0xC000

Default Token Space
  Token = 0x0000000D - Type = UINT64:DYNAMIC    - Size = 0x8 - Value = 0x4000

Default Token Space
  Token = 0x0000000E - Type = UINT64:DYNAMIC    - Size = 0x8 - Value = 0x80000000

Default Token Space
  Token = 0x0000000F - Type = UINT64:DYNAMIC    - Size = 0x8 - Value = 0x7C000000

Default Token Space
  Token = 0x00000010 - Type = UINT64:DYNAMIC    - Size = 0x8 - Value = 0x800000000

Default Token Space
  Token = 0x00000011 - Type = UINT64:DYNAMIC    - Size = 0x8 - Value = 0x800000000

Default Token Space
  Token = 0x00000012 - Type = BOOLEAN:DYNAMIC   - Size = 0x1 - Value = FALSE

Default Token Space
  Token = 0x00000013 - Type = UINT16:DYNAMIC    - Size = 0x2 - Value = 0x8

Default Token Space
  Token = 0x00000017 - Type = UINT32:DYNAMIC    - Size = 0x4 - Value = 0xFFC42000

Default Token Space
  Token = 0x00000018 - Type = UINT32:DYNAMIC    - Size = 0x4 - Value = 0xFFC41000

Default Token Space
  Token = 0x00000019 - Type = UINT64:DYNAMIC    - Size = 0x8 - Value = 0xFFC00000

Default Token Space
  Token = 0x0000001A - Type = UINT64:DYNAMIC    - Size = 0x8 - Value = 0x7B6E000

Default Token Space
  Token = 0x0000001B - Type = UINT64:DYNAMIC    - Size = 0x8 - Value = 0x0

Default Token Space
  Token = 0x0000001C - Type = UINT32:DYNAMIC    - Size = 0x4 - Value = 0x280

Default Token Space
  Token = 0x0000001D - Type = UINT32:DYNAMIC    - Size = 0x4 - Value = 0x1E0

Default Token Space
  Token = 0x0000001E - Type = UINT8:DYNAMIC     - Size = 0x1 - Value = 0x0

Default Token Space
  Token = 0x0000001F - Type = UINT16:DYNAMIC    - Size = 0x2 - Value = 0x208

Default Token Space
  Token = 0x00000020 - Type = BOOLEAN:DYNAMIC   - Size = 0x1 - Value = FALSE

Default Token Space
  Token = 0x00000021 - Type = UINT32:DYNAMIC    - Size = 0x4 - Value = 0x320

Default Token Space
  Token = 0x00000022 - Type = UINT32:DYNAMIC    - Size = 0x4 - Value = 0x258

Default Token Space
  Token = 0x00000023 - Type = UINT16:DYNAMIC    - Size = 0x2 - Value = 0x0

Default Token Space
  Token = 0x00000024 - Type = UINT8:DYNAMIC     - Size = 0x1 - Value = 0x1

Default Token Space
  Token = 0x00000025 - Type = UINT8:DYNAMIC     - Size = 0x1 - Value = 0x1

Default Token Space
  Token = 0x00000026 - Type = UINT32:DYNAMIC    - Size = 0x4 - Value = 0xCAFECAFE

Default Token Space
  Token = 0x00000027 - Type = UINT64:DYNAMIC    - Size = 0x8 - Value = 0x0

Default Token Space
  Token = 0x00000028 - Type = BOOLEAN:DYNAMIC   - Size = 0x1 - Value = TRUE

Default Token Space
  Token = 0x00000029 - Type = BOOLEAN:DYNAMIC   - Size = 0x1 - Value = TRUE

A1AFF049-FDEB-442A-B320-13AB4CB72BBC
  Token = 0x00030005 - Type = POINTER:DYNAMICEX - Size = 0x1
  00000000: 00                                               *.*

A1AFF049-FDEB-442A-B320-13AB4CB72BBC
  Token = 0x00030004 - Type = UINT16:DYNAMICEX  - Size = 0x2 - Value = 0x0

A1AFF049-FDEB-442A-B320-13AB4CB72BBC
  Token = 0x00030006 - Type = UINT64:DYNAMICEX  - Size = 0x8 - Value = 0x0

150CAB53-AD47-4385-B5DD-BCFC76BACAF0
  Token = 0xAF35F3B2 - Type = UINT32:DYNAMICEX  - Size = 0x4 - Value = 0xBABEBABE

PCD_INFO_GENERATION = TRUE 정의를 사용하여 플랫폼이 생성된 경우, 이 프로그램은 PCD 이름 정보도 표시한다.

FS0:\> DumpDynPcd.efi
Current system SKU ID: 0x0

gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiS3Enable
  Token = 0x00000001 - Type = BOOLEAN:DYNAMIC   - Size = 0x1 - Value = TRUE

gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvStoreReserved
  Token = 0x00000002 - Type = UINT64:DYNAMIC    - Size = 0x8 - Value = 0x7EF4000

gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase
  Token = 0x00000003 - Type = UINT64:DYNAMIC    - Size = 0x8 - Value = 0x0

gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbSize
  Token = 0x00000004 - Type = UINT64:DYNAMIC    - Size = 0x8 - Value = 0x0

gEfiMdeModulePkgTokenSpaceGuid.PcdPteMemoryEncryptionAddressOrMask
  Token = 0x00000005 - Type = UINT64:DYNAMIC    - Size = 0x8 - Value = 0x0

gEfiMdeModulePkgTokenSpaceGuid.PcdSetNxForStack
  Token = 0x00000006 - Type = BOOLEAN:DYNAMIC   - Size = 0x1 - Value = FALSE

gEfiSecurityPkgTokenSpaceGuid.PcdOptionRomImageVerificationPolicy
  Token = 0x00000007 - Type = UINT32:DYNAMIC    - Size = 0x4 - Value = 0x0

gUefiCpuPkgTokenSpaceGuid.PcdCpuBootLogicalProcessorNumber
  Token = 0x00000008 - Type = UINT32:DYNAMIC    - Size = 0x4 - Value = 0x0

gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber
  Token = 0x00000009 - Type = UINT32:DYNAMIC    - Size = 0x4 - Value = 0x1

gUefiCpuPkgTokenSpaceGuid.PcdSevEsIsEnabled
  Token = 0x0000000A - Type = BOOLEAN:DYNAMIC   - Size = 0x1 - Value = FALSE

gUefiOvmfPkgTokenSpaceGuid.PcdOvmfHostBridgePciDevId
  Token = 0x0000000B - Type = UINT16:DYNAMIC    - Size = 0x2 - Value = 0x1237

gUefiOvmfPkgTokenSpaceGuid.PcdPciIoBase
  Token = 0x0000000C - Type = UINT64:DYNAMIC    - Size = 0x8 - Value = 0xC000

gUefiOvmfPkgTokenSpaceGuid.PcdPciIoSize
  Token = 0x0000000D - Type = UINT64:DYNAMIC    - Size = 0x8 - Value = 0x4000

gUefiOvmfPkgTokenSpaceGuid.PcdPciMmio32Base
  Token = 0x0000000E - Type = UINT64:DYNAMIC    - Size = 0x8 - Value = 0x80000000

gUefiOvmfPkgTokenSpaceGuid.PcdPciMmio32Size
  Token = 0x0000000F - Type = UINT64:DYNAMIC    - Size = 0x8 - Value = 0x7C000000

gUefiOvmfPkgTokenSpaceGuid.PcdPciMmio64Base
  Token = 0x00000010 - Type = UINT64:DYNAMIC    - Size = 0x8 - Value = 0x800000000

gUefiOvmfPkgTokenSpaceGuid.PcdPciMmio64Size
  Token = 0x00000011 - Type = UINT64:DYNAMIC    - Size = 0x8 - Value = 0x800000000

gUefiOvmfPkgTokenSpaceGuid.PcdQ35SmramAtDefaultSmbase
  Token = 0x00000012 - Type = BOOLEAN:DYNAMIC   - Size = 0x1 - Value = FALSE

gUefiOvmfPkgTokenSpaceGuid.PcdQ35TsegMbytes
  Token = 0x00000013 - Type = UINT16:DYNAMIC    - Size = 0x2 - Value = 0x8

gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase
  Token = 0x00000017 - Type = UINT32:DYNAMIC    - Size = 0x4 - Value = 0xFFC42000

gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase
  Token = 0x00000018 - Type = UINT32:DYNAMIC    - Size = 0x4 - Value = 0xFFC41000

gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64
  Token = 0x00000019 - Type = UINT64:DYNAMIC    - Size = 0x8 - Value = 0xFFC00000

gEfiMdeModulePkgTokenSpaceGuid.PcdS3BootScriptTablePrivateDataPtr
  Token = 0x0000001A - Type = UINT64:DYNAMIC    - Size = 0x8 - Value = 0x7B6E000

gEfiMdeModulePkgTokenSpaceGuid.PcdS3BootScriptTablePrivateSmmDataPtr
  Token = 0x0000001B - Type = UINT64:DYNAMIC    - Size = 0x8 - Value = 0x0

gEfiMdeModulePkgTokenSpaceGuid.PcdSetupVideoHorizontalResolution
  Token = 0x0000001C - Type = UINT32:DYNAMIC    - Size = 0x4 - Value = 0x280

gEfiMdeModulePkgTokenSpaceGuid.PcdSetupVideoVerticalResolution
  Token = 0x0000001D - Type = UINT32:DYNAMIC    - Size = 0x4 - Value = 0x1E0

gEfiMdeModulePkgTokenSpaceGuid.PcdSmbiosDocRev
  Token = 0x0000001E - Type = UINT8:DYNAMIC     - Size = 0x1 - Value = 0x0

gEfiMdeModulePkgTokenSpaceGuid.PcdSmbiosVersion
  Token = 0x0000001F - Type = UINT16:DYNAMIC    - Size = 0x2 - Value = 0x208