20. PCD 소개

PCD(Platform Configuration Database)는 드라이버 또는 애플리케이션이 액세스할 수 있는 다양한 현재 플랫폼 설정 또는 지침이 포함된 데이터베이스이다.

PCD에 대한 자세한 설명은 EDKII 스펙을 통해 확인할 수 있다. - https://edk2-docs.gitbook.io/edk-ii-pcd-specification/ - https://www.intel.com/content/dam/www/public/us/en/documents/white-papers/edkii-platform-config-database-entries-paper.pdf

PCD entry는 PCD라고도 불린다. 그래서 여기서도 그냥 PCD라고 부른다.

PCD entry는 DEC 파일에 정의된다.

<TokenSpaceGuidCName> 은 GUID 값이고, <Token>은 32bit 값이다. 이것들은 PCD를 식별하는 데 사용된다.

<TokenSpaceGuidCName>.<PcdCName>|<DefaultValue>|<DatumType>|<Token>

먼저 모든 PCD를 포함하는 토큰 공간을 선언한다. 일반적으로 g<PakageName>TokenSpaceGuid로 정의되기 때문에 UefiLessonsPkg/UefiLessonsPkg.dec에 추가해야 한다.

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

<Token> 값의 경우, 일반적으로 패키지 작성자는 0x00000001부터 순차적으로 쓰기 시작한다. 또한 일부 PCD가 하나의 논리 그룹에 속한다는 것을 나타내기 위해 종종 토큰 번호를 사용하여 이를 나타낼 수 있다. 예를 들어 토큰 그룹은 0x1XXXXXXX, 0x2XXXXXXX 등이 될 수 있다.

패키지가 발전함에 따라 일부 PCD가 추가되고 일부 PCD가 제거된다. 만약 순차적인 번호를 사용한다면 이것은 어려움을 줄 수 있다. 예를 들어 토큰이 0x0000000A0x0000000B인 PCD가 있는 경우 어려움이 발생할 수 있으며 새 PCD를 넣는 가장 논리적인 방법은 0x0000000A인 PCD 이후이다. 물론 PCD 토큰을 0x0000000C에 할당하여 실행할 수도 있지만, 그렇다면 순차적인 번호 지정의 의미를 알아야 한다.

순차적인 번호 지정은 힘들기 때문에 아래 스크립트를 생성했다. 아래 스크립트는 임의의 4바이트 토큰 번호를 생성하는 스크립트다.

#!/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

스크립트를 사용하면 아래와 같이 4바이트의 토큰 번호를 생성할 수 있다.

$ ./scripts/genToken.sh
0x3B81CDF1

이제 gUefiLessonsPkgTokenSpaceGuid를 정의하는 데 사용한 *.dec 파일에 PCD를 정의할 수 있다. PCD를 UINT8 PcdInt8 = 0x88 로 시작한다.

[PcdsFixedAtBuild]
  gUefiLessonsPkgTokenSpaceGuid.PcdInt8|0x88|UINT8|0x3B81CDF1

PCDLesson 애플리케이션을 생성하기 위해 UefiLessons/PCDLesson/PCDLesson.c 파일에 아래 코드를 추가한다.

#include <Library/UefiBootServicesTableLib.h>
#include <Library/UefiLib.h>
#include <Library/PcdLib.h>

EFI_STATUS
EFIAPI
UefiMain (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{
  Print(L"PcdInt8=0x%x\n", FixedPcdGet8(PcdInt8));

  return EFI_SUCCESS;
}

FixedPcdGet8을 사용하기 위해서는 헤더 파일이 필요하다. PcdLib 헤더를 추가한다.

#include <Library/PcdLib.h>

이 링크(https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Library/PcdLib.h)를 통해 FixedPcdGet8을 살펴보면 단순히 정의되어 있다는 것을 알 수 있다.

#define FixedPcdGet8(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
      |                                             ^~~~~~~~~~~

에러를 해결하기 위해서는 아직 생성하지 않았던 *.inf 파일을 생성해야 한다. 해당 파일은 HelloWorld 애플리케이션에서 사용했던 것을 복사하여 수정 해야 할 부분을 수정한 후 PCD 애플리케이션을 추가한다.

[FixedPcd]
  gUefiLessonsPkgTokenSpaceGuid.PcdInt8

추가적으로 PCD를 정의하는 dec 파일을 포함하도록 한 후 빌드를 시도하면 잘 되는 것을 볼 수 있다.

[Packages]
  ...
  UefiLessonsPkg/UefiLessonsPkg.dec

자동 생성된 파일 AutoGen.h/AutoGen.c의 내용을 확인하면 PCD가 있는 것을 확인할 수 있다.

  • Build/UefiLessonsPkg/RELEASE_GCC5/X64/UefiLessonsPkg/PCDLesson/PCDLesson/DEBUG/AutoGen.h

// Definition of PCDs used in this module

#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

// Definition of PCDs used in this module
GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gPcd_FixedAtBuild_PcdInt8 = _PCD_VALUE_PcdInt8;

따라서 프리프로세서는 아래와 같이 코드를 확장한다.

FixedPcdGet8(PcdInt8) -> _PCD_VALUE_PcdInt8 -> 0x88U

OVMF를 통해 PCDLesson 애플리케이션을 실행하면 올바른 값이 출력되는 것을 볼 수 있다.

FS0:\> PCDLesson.efi
PcdInt8=0x88

PCD에는 여러 유형이 있고 FixedAtBuild PCD는 그 중 하나이다. 코드에서는 FixedPcdGet8 호출을 사용하여 PCD 값을 얻었으며, 이 호출은 PCD가 FixedAtBuild인 경우에만 할 수 있다. FixedAtBuild와는 달리 PCD 유형에 관계없이 PCD 값을 얻는 데 사용할 수 있는 일반적인 PcdGet8 호출이 있다.

#define PcdGet8(TokenName)                 _PCD_GET_MODE_8_##TokenName

PcdGet8을 사용하면 아래와 같이 확장된다.

PcdGet8(PcdInt8) -> _PCD_GET_MODE_8_PcdInt8 -> _gPcd_FixedAtBuild_PcdInt8

AutoGen.c에서는 아래와 같이 정의되어 있다.

 GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gPcd_FixedAtBuild_PcdInt8 = _PCD_VALUE_PcdInt8   // =0x88U;

PCDLesson.c에 아래와 같이 PcdGet8FixedAtBuild를 비교할 수 있도록 수정한다.

Print(L"PcdInt8=%d\n", FixedPcdGet8(PcdInt8));
Print(L"PcdInt8=%d\n", PcdGet8(PcdInt8));

빌드 후 결과를 확인하면 동일한 것을 볼 수 있다. 다만, 차이점은 PcdGet8은 다른 PCD 유형과 함께 사용할 수 있다는 것이다.

FS0:\> PCDLesson.efi
PcdInt8=0x88
PcdInt8=0x88

다른 간단한 PCD 유형

위의 예제에서는 UINT8을 PCD의 <DatumType>로 사용했다. 이러한 유형과 함께 EDKII를 사용하면 다른 정수 데이터 유형 UINT16, UINT32 또는 UINT64 정수 데이터 유형 및 BOOLEAN 유형을 사용할 수 있다.

이러한 PCD를 UefiLessonsPkg/UefiLessonsPkg.dec에 추가한다.

[PcdsFixedAtBuild]
  ...
  gUefiLessonsPkgTokenSpaceGuid.PcdInt16|0x1616|UINT16|0x77DFB6E6
  gUefiLessonsPkgTokenSpaceGuid.PcdInt32|0x32323232|UINT32|0xF2A48130
  gUefiLessonsPkgTokenSpaceGuid.PcdInt64|0x6464646464646464|UINT64|0x652F4E29
  gUefiLessonsPkgTokenSpaceGuid.PcdBool|TRUE|BOOLEAN|0x69E88A63

또한, UefiLessonsPkg/PCDLesson/PCDLesson.inf 모듈에 포함하여야 한다.

[FixedPcd]
  ...
  gUefiLessonsPkgTokenSpaceGuid.PcdInt16
  gUefiLessonsPkgTokenSpaceGuid.PcdInt32
  gUefiLessonsPkgTokenSpaceGuid.PcdInt64
  gUefiLessonsPkgTokenSpaceGuid.PcdBool

빌드를 진행하면 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

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;

선언된 내용 살펴보면 처음에 사용했던 UINT8와 모두 비슷한 것을 알 수 있다.

이전과 같이 FixedPcdGetPcdGet API를 사용하여 PCD 값을 확인한다.

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

출력된 결과를 보면 값이 동일한 것을 볼 수 있다.

FS0:\> PCDLesson.efi
...
PcdInt16=0x1616
PcdInt32=0x32323232
PcdInt64=0x64646464
PcdBool=0x1
PcdInt16=0x1616
PcdInt32=0x32323232
PcdInt64=0x64646464
PcdIntBool=0x1

값을 초기화 할 때 사용할 수 있는 표현

값을 초기화 할 때 식을 사용할 수 있다. 연산에서 |를 사용할 때는 괄호(...) 안에 식을 넣어야 한다. 예시는 아래와 같다. UefiLessonsPkg/UefiLessonsPkg.dec에 아래와 같이 입력한다.

[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

*.dec 파일에 추가하였으니 *.inf 파일에도 추가해야 한다. 여기서는 UefiLessonsPkg/PCDLesson/PCDLesson.inf에 추가한다.

[FixedPcd]
  ...
  gUefiLessonsPkgTokenSpaceGuid.PcdExpression
  gUefiLessonsPkgTokenSpaceGuid.PcdExpression_1
  gUefiLessonsPkgTokenSpaceGuid.PcdExpression_2
  gUefiLessonsPkgTokenSpaceGuid.PcdExpression_3

빌드 후 Autogen.h 을 확인하면 값이 계산되어 들어간 것을 볼 수 있다.

...
#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 데이터 유형

EDK2에서는 UINT8, UINT16, UINT32, UINT64, BOOLEAN 외에도 VOID* 유형을 사용할 수 있다.

문자열 PCD

아래와 같은 PCD를 UefiLessonsPkg/UefiLessonsPkg.dec에 추가한다.

[PcdsFixedAtBuild]
  ...
  gUefiLessonsPkgTokenSpaceGuid.PcdAsciiStr|"hello"|VOID*|0xB29914B5
  gUefiLessonsPkgTokenSpaceGuid.PcdUCS2Str|L"hello"|VOID*|0xF22124E5

첫 번째와 두번째는 데이터를 표현에 차이가 있다. 첫 번째는 "..."로 되어있고 두 번째는 L"..."로 되어있다.

이제 PCD를 UefiLessonsPkg/PCDLesson/PCDLesson.inf에 추가한다.

[FixedPcd]
  ...
  gUefiLessonsPkgTokenSpaceGuid.PcdAsciiStr
  gUefiLessonsPkgTokenSpaceGuid.PcdUCS2Str

빌드 후 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

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;

위 파일들을 보면 알 수 있듯이 PcdAsciiStr 배열은 UINT8로 구성됐지만 PcdUCS2Str 배열은 UINT16으로 구성되어 있다.

또 다른 차이점은 문자열 크기에 대한 상수(sizeof()의 값)가 생성된다는 것이다. 이러한 값은 빌드 시스템에 의해 동적으로 계산된다.

VOID*타입인 PCD 값을 가져오려면 FixedPcdGetPtr이나 PcdGetPtrAPI를 사용하고 바이트 단위로 가져오려면 FixedPcdGetSizePcdGetSize API를 사용한다.

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

빌드 후 PCDLesson.efi를 실행하면 아래와 같이 문자열과 크기를 확인할 수 있다.

FS0:\> PCDLesson.efi
...
PcdAsciiStr=hello
PcdAsciiStrSize=6
PcdUCS2Str=hello
PcdUCS2StrSize=12

만약 프리프로세서를 대체하고 싶다면 PcdLib.h(https://github.com/tianocore/edk2/blob/master/MdePkg/Include/Library/PcdLib.h)를 사용하기 전에 했던 것처럼 할 수 있다.

#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

이 예제에서는 문자열을 초기화 할 때 "..."L"..."을 사용했지만 '...'이나 L'...'을 사용해도 된다.

Byte 배열 PCD

VOID*는 일반적으로 바이트 배열에 사용된다.

예시로 보기 위해 PCD를 UefiLessonsPkg/UefiLessonsPkg.dec에 추가한다.

[PcdsFixedAtBuild]
  ...
  gUefiLessonsPkgTokenSpaceGuid.PcdArray|{0xA5, 0xA6, 0xA7}|VOID*|0xD5DB9A27

UefiLessonsPkg/PCDLesson/PCDLesson.inf에도 추가한다.

[FixedPcd]
  ...
  gUefiLessonsPkgTokenSpaceGuid.PcdArray

AutoGen 파일을 보면 PCD 배열이 추가된 것을 볼 수 있다.

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

배열 요소를 출력하기 위해 아래 코드를 PCDLesson.c에 추가한다. AutoGen.h에서 데이터가 (VOID *)로 캐스트 될 때 (UINT8*) 캐스트가 필요하다.

for (UINTN i=0; i<FixedPcdGetSize(PcdArray); i++) {
  Print(L"PcdArray[%d]=0x%02x\n", i, ((UINT8*)FixedPcdGetPtr(PcdArray))[i]);
}

빌드 후 PCDLesson.efi를 실행하면 아래와 같이 배열이 출력되는 것을 볼 수 있다.

FS0:\> PCDLesson.efi
...
PcdArray[0]=0xA5
PcdArray[1]=0xA6
PcdArray[2]=0xA7

GUID PCD

바이트 배열 초기화 구문을 사용하면 사용자 지정 구조의 유형을 이해하는 즉시 모든 사용자 지정 구조를 초기화할 수 있다. EFI_GUID(=GUID) 구조를 살펴본다.

typedef struct {
  UINT32  Data1;
  UINT16  Data2;
  UINT16  Data3;
  UINT8   Data4[8];
} GUID;

typedef GUID EFI_GUID;

만약 GUID가 "f1740707-691d-4203-bfab-99e132fa4166"인 것을 인코딩 하려면 아래와 같이 하게 된다.

[PcdsFixedAtBuild]
  ...
  gUefiLessonsPkgTokenSpaceGuid.PcdGuidInBytes|{0x07, 0x07, 0x74, 0xF1, 0x1D, 0x69, 0x03, 0x42, 0xBF, 0xAB, 0x99, 0xE1, 0x32, 0xFA, 0x41, 0x66}|VOID*|0xB9E0CDC0

따라서 정확한 값을 얻기 위해서는 일부 바이트를 재구성해야 한다. x86은 little-endian이기 때문에 필요하며, 이러한 시스템에서 숫자의 바이트는 상위에서 하위로 메모리에 배치되기 때문이다.

그렇기 때문에 사용자 지정 구조에 대해 바이트 배열 초기화를 인코딩할 때 이점을 염두해야 한다.

UEFI 코드에서는 GUID가 과도하게 사용되기 때문에 EDKII는 GUID PCD 초기화를 위한 도우미 구문을 가지고 있다. 도우미 구문을 사용하는 방법은 아래와 같다. 도우미 구문을 사용하여 PCD를 정의한다.

[PcdsFixedAtBuild]
  ...
  gUefiLessonsPkgTokenSpaceGuid.PcdGuid|{GUID("f1740707-691d-4203-bfab-99e132fa4166")}|VOID*|0x7F2066F7

도우미를 사용하지 않을 때와 사용할 때를 비교하기 위해 UefiLessonsPkg/UefiLessonsPkg.dec에 아래 두 줄을 입력한다.

[PcdsFixedAtBuild]
  ...
  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

그리고 UefiLessonsPkg/PCDLesson/PCDLesson.inf에도 추가한다.

[FixedPcd]
  ...
  gUefiLessonsPkgTokenSpaceGuid.PcdGuidInBytes
  gUefiLessonsPkgTokenSpaceGuid.PcdGuid

빌드하고 AutoGen 파일들을 살펴보면 아래와 같이 추가된 것을 확인할 수 있다.

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

파일들을 통해 알 수 있듯이 PCD 인코딩과 초기화는 두 경우 모두 동일하다.

코드에서 GUID를 사용하려면 (VOID *)에서 (EFI_GUID*)로 GUID를 캐스팅 해야 한다.

Print(L"PcdGuidInBytes=%g\n", *(EFI_GUID*)FixedPcdGetPtr(PcdGuidInBytes));
Print(L"PcdGuid=%g\n", *(EFI_GUID*)FixedPcdGetPtr(PcdGuid));

빌드 후 PCDLesson.efi를 실행하면 출력된 결과도 동일한 것을 확인할 수 있다.

FS0:\> PCDLesson.efi
...
PcdGuidInBytes=F1740707-691D-4203-BFAB-99E132FA4166
PcdGuid=F1740707-691D-4203-BFAB-99E132FA4166

GUID가 포함된 PCD를 초기화하는 방법에는 두 가지가 더 존재한다. 다른 GUID를 초기화에 사용하거나 표준 C 구문을 EFI_GUID 구조 초기화에 사용할 수 있다.

[PcdsFixedAtBuild]
  ...
  gUefiLessonsPkgTokenSpaceGuid.PcdGuidByPCD|{GUID(gUefiLessonsPkgTokenSpaceGuid)}|VOID*|0x0860CCD5
  gUefiLessonsPkgTokenSpaceGuid.PcdGuidByEfiGuid|{GUID({0x150cab53, 0xad47, 0x4385, {0xb5, 0xdd, 0xbc, 0xfc, 0x76, 0xba, 0xca, 0xf0}})}|VOID*|0x613506D5

새롭게 빌드하고 AutoGen.c 파일을 통해 확인할 수 있다.

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

GUID(...) 도우미 외에도 EDK2에는 DEVICE_PATH(...) 도우미가 있어 다른 특별한 UEFI 구조인 Device Path를 초기화할 수 있다.

예를 들어, UEFI Shell이 시작될 때 출력되는 경로는 UEFI Device Path이다.

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.

그 중 하나를 PCD 초기화에 사용한다. UefiLessonsPkg/UefiLessonsPkg.dec에 추가한다.

[PcdsFixedAtBuild]
  ...
  gUefiLessonsPkgTokenSpaceGuid.PcdDevicePath|{DEVICE_PATH("PciRoot(0x0)/Pci(0x1,0x1)/Ata(0x0)")}|VOID*|0xC56EE1E2

UefiLessonsPkg/PCDLesson/PCDLesson.inf에도 생성한 PCD를 추가한다.

[FixedPcd]
  ...
  gUefiLessonsPkgTokenSpaceGuid.PcdDevicePath

빌드 후 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;

배열이 올바른지 확인하기 위해 프로그램에서 생성된 Device Path를 출력한다. 이를 위해 DevicePathLib.h 헤더 파일을 추가해야 한다.

#include <Library/DevicePathLib.h>

그리고 ConvertDevicePathToText 함수를 사용한다.

Print(L"PcdDevicePath: %s\n", ConvertDevicePathToText((EFI_DEVICE_PATH_PROTOCOL*) FixedPcdGetPtr(PcdDevicePath), FALSE, FALSE));

빌드 후 PCDLesson.efi를 실행하면 아래와 같은 출력을 볼 수 있다.

FS0:\> PCDLesson.efi
...
PcdDevicePath: PciRoot(0x0)/Pci(0x1,0x1)/Ata(Primary,Master,0x0)

정수 캐스트 사용

UINT8(...), UINT16(...), UINT32(...), UINT64(...) 캐스트 도우미를 사용하여 VOID* 배열을 초기화할 수 있다.

UefiLessonsPkg/UefiLessonsPkg.dec에 아래와 같이 추가한다. 앞으로 inf에 추가하는 것은 더이상 얘기하지 않을 것이니 dec에 PCD가 추가된다면 *.inf에도 추가해야 한다.

[PcdsFixedAtBuild]
  ...
  gUefiLessonsPkgTokenSpaceGuid.PcdIntCasts|{UINT16(0x1122), UINT32(0x33445566), UINT8(0x77), UINT64(0x8899aabbccddeeff)}|VOID*|0x647456A6

빌드 후 AutoGen.c를 살펴보면 little-endian 아키텍처와 관련하여 배열이 초기화되어 있음을 알 수 있다.

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과 OFFSET_OF

일부 요소에 레이블을 할당하고 LABEL(...)OFFSET_OF(...) 구문을 통해 요소의 오프셋을 가져올 수 있다.

UefiLessonsPkg/UefiLessonsPkg.dec에 추가한다.

[PcdsFixedAtBuild]
  ...
  gUefiLessonsPkgTokenSpaceGuid.PcdWithLabels|{ 0x0A, 0x0B, OFFSET_OF(End), 0x0C, LABEL(Start) 0x0D, LABEL(End) 0x0E, 0x0F, OFFSET_OF(Start) }|VOID*|0xD91A8BF6

빌드 후 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;

결합 배열 초기화

다양한 바이트 배열 초기화 방법을 결합할 수 있다. UefiLessonsPkg/UefiLessonsPkg.dec에 추가한다.

gUefiLessonsPkgTokenSpaceGuid.PcdArrayExt|{0x11, UINT16(0x2233), UINT32(0x44556677), L"hello", "world!", GUID("09b9b358-70bd-421e-bafb-4f97e2ac7d44")}|VOID*|0x7200C5DF

빌드 후 AutoGen.c를 통해 확인할 수 있다.

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;

사용자 지정 타입

PCD에 대한 사용자 지정 타입을 만들 수 있다.

예를 들어 아래 코드로 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

UefiLessonsPkg/UefiLessonsPkg.dec에 해당 파일을 포함하도록 한다.

[Includes]
  Include

생성된 CustomStructure 타입을 사용하고 이 구문을 통해 값을 초기화할 수 있다.

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를 확인하면 데이터가 생성된 것을 볼 수 있다.

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;

필드를 그룹화하면 모든 필드가 의도한 대로 초기화되었음을 알 수 있다.

{
  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
}

필드별 파일 초기화가 너무 길어 보이면 특수 CODE(...) 구문을 사용하여 C 스타일 배열 초기화를 사용할 수 있다. 그러나 이 경우 GUID(...) 또는 L'...' 초기화와 같은 도우미를 사용할 수 없다. 따라서 구조에 대한 동일한 초기화는 아래와 같다.

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
}

빌드 후 AutoGen.c 파일을 통해 결과는 같은 것을 볼 수 있다.

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;

고정 크기의 배열

PCD 배열의 크기를 구할 수 있다. UINT32[3]과 같이 크기가 1바이트를 넘는 유형의 배열을 사용하는 경우 모든 초기화 값을 유형에 캐스팅 해야 한다. 이 문제를 방지하기 위해 특수 CODE(...)를 사용할 수 있다.

[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

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;

사용자 정의 유형에 맞는 고정 크기 배열을 생성할 수도 있다.

gUefiLessonsPkgTokenSpaceGuid.PcdArrayWithFixedSize_4|{0x0}|CustomStruct[2]|0x0D00EE44 {
  <Packages>
    UefiLessonsPkg/UefiLessonsPkg.dec
  <HeaderFiles>
    CustomPcdTypes.h
}

여기서는 필드 초기화를 수행하지 않지만 구문 증명을 위해 AutoGen.c를 보고 최종 데이터 배열의 크기가 일반적인 구조의 두 배인지 확인할 수 있다.

GLOBAL_REMOVE_IF_UNREFERENCED const UINTN _gPcd_FixedAtBuild_Size_PcdArrayWithFixedSize_4 = 88;

PcdValueInit

사용자 지정 유형 또는 고정 크기 배열과 함께 PCD를 사용할 경우 빌드 시스템은 빌드 폴더에 PcdValueInit 폴더를 생성한다. 이 폴더에는 빌드 시스템이 AutoGen.c 파일의 데이터를 가져오는 데 사용할 특별한 C 프로그램 PcdValueInit이 포함된다.

$ 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

프로그램의 도움말 메시지를 확인할 수 있다.

$ ./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

이를 통해 이 프로그램은 동일한 폴더의 input.txt 파일에서 output.txt 파일을 생성한다고 추측할 수 있다. 빌드 시스템 내부에 대해 궁금한 점이 있으면 *.txt 파일을 확인하거나 프로그램 소스를 확인한다.

Last updated