【UEFI基础】PCD

简介

本文将要介绍的是在UEFI中经常使用到的一种特殊的数据结构PCD,参考内容如下:

  • 《edk-ii-pcd-specification.pdf》
  • 《edk-ii-dsc-specification.pdf》
  • 《edk-ii-build-specification.pdf》
  • 《edk-ii-dec-specification.pdf》
  • 《edk-ii-idf-specification.pdf》
  • EDK代码

PCD的全称是Platform Configuration Database,它是一个存放了UEFI下可访问数据的数据库。

它的特点是可以在UEFI存在的大部分时间内访问,在【UEFI实战】在库中使用全局变量中就曾经介绍过通过PCD来传递全局变量。这里说是大部分时间内,那是因为在诸如SEC阶段,以及PEI、DXE阶段的早期,某些PCD相关的模块还没有加载起来之前,这些类型的PCD还是不能访问的。

基础说明

PCD变量的格式如下:

TokenSpaceGuidCName.PcdCName

TokenSpaceGuidCName是一个GUID,PcdCName是一个变量名,两者合起来构成了唯一的PCD变量。

PCD有下述的类型(主要的不同是在访问的方式):

FeatureFlag PCD:它最终返回的是一个TRUE或者FALSE,用于判断条件中;

PatchableInModule PCD:这种变量的值可以在编译的时候确定,这个不算特别,特别的是它可以在编译完成的二进制文件上通过工具来修改值;

FixedAtBuild PCD:静态值,在编译的时候确定,整个UEFI阶段不可变;

Dynamic PCD:前面的三种类型可以认为是静态的PCD,而这里以及之后的是动态的PCD;它的特点是可以在UEFI运行的过程中通过Set宏来修改值;在《edk-ii-build-specification.pdf》中有说明该种类型的PCD必须在DSC中在列一遍,但是实际使用似乎并不是必须的;

DynamicEx PCD:跟Dynamic PCD类似,算是加强版,使用宏PcdGetEx/PcdSetEx来访问变量;

需要注意的是上面的类型并不是在一个SPEC中定义的,前面的4中是满足EDKII规范,而最后一个满足的是PI规范,这个对使用的影响还不是很确定。

上述说的PCD是按访问的方式来分类的。

另外还需要关注的是PCD变量的值可能的类型,有BOOLEAN类型,整型(UINT8,UINT16等)以及VOID *类型。

需要注意的是BOOLEAN这种类型FixedAtBuild PCD和FeatureFlag PCD中都可以存在,但是两者实际上是不同的,访问使用的宏也是不同的,前者是FixedPcdGetBool()而后者是FeaturePcdGet()。但是后面会看到,从实现上来讲两者是一致的......

示例

下面先介绍一个简单的示例。

1. 在dec文件中声明PCD的基本信息,如下所示:

[PcdsDynamic]
  gUefiOemPkgTokenSpaceGuid.PcdOemVersion|0xFFFFFFFF|UINT32|0x40000001

在《edk-ii-dec-specification.pdf》中有说明上述内容的意义。

它分为两个部分,第一个部分[PcdsDynamic]声明了PCD的类型,PCD的多种类型后续会一一介绍。

第二部分的内容如下:

#加注释部分这里没有用到;

TokeSpaceGuidCname是一个GUID,也是在DEC中声明的,如下所示:

[Guids]
  # // {6BB4BEC8-23D8-40AF-8F24-99E7AC8601FD}
  gUefiOemPkgTokenSpaceGuid      = { 0x6bb4bec8, 0x23d8, 0x40af, { 0x8f, 0x24, 0x99, 0xe7, 0xac, 0x86, 0x01, 0xfd } }

PcdCname是PCD的名称,后续使用的时候就需要用到它。

DefaultValue是PCD的默认值,DatumType是PCD的类型,Token是一个32位的整型,在DEC中每个PCD都有一个独一无二的Token。

2. 在DSC中设置PCD的值:

  # // OEM defined dynamic PCD.
  gUefiOemPkgTokenSpaceGuid.PcdOemVersion|0x12345678

这个设置并不是必须的,如果没有整个设置,就使用在DEC中默认的值。

3. 使用:

  DEBUG ((EFI_D_ERROR, "[beni]Version: 0x%x.\n", PcdGet32(PcdOemVersion)));

要使用PcdGet32这种的宏,需要包含PcdLib这个库。

还需要在inf中包含该PCD:

[Pcd]
  gUefiOemPkgTokenSpaceGuid.PcdOemVersion

以上的代码就会打印出[beni]Version: 0x12345678。

该部分代码可以在vUDK2017: https://github.com/tianocore/edk2.git Tag vUDK2017.找到。

实现说明

下面说明各种PCD的实现。

FixedAtBuild PCD

不同的PCD类型实现方式有差异,这里首先介绍最简单的FixedAtBuild PCD

下面是一个例子:

1. 首先声明一系列的PCD:

[PcdsFixedAtBuild]
gUefiOemPkgTokenSpaceGuid.PcdTestVar1|0xA5|UINT8|0x20000001
gUefiOemPkgTokenSpaceGuid.PcdTestVar2|0xA5A5|UINT16|0x20000002
gUefiOemPkgTokenSpaceGuid.PcdTestVar3|0xA5A5A5A5|UINT32|0x20000003
gUefiOemPkgTokenSpaceGuid.PcdTestVar4|0xA5A5A5A5A5A5A5A5|UINT64|0x20000004

2. 然后在一个模块中使用:

EFI_STATUS
EFIAPI
PcdTestDriverEntry (
  IN EFI_HANDLE           ImageHandle,
  IN EFI_SYSTEM_TABLE     *SystemTable
  )
{
  EFI_STATUS         Status = EFI_SUCCESS;

  DEBUG ((EFI_D_ERROR, "[beni]PcdTestDriverEntry Start.\n"));

  DEBUG ((EFI_D_ERROR, "[beni]PcdTestVar1: 0x%x.\n", PcdGet8 (PcdTestVar1)));
  DEBUG ((EFI_D_ERROR, "[beni]PcdTestVar2: 0x%x.\n", PcdGet16 (PcdTestVar2)));
  DEBUG ((EFI_D_ERROR, "[beni]PcdTestVar3: 0x%x.\n", PcdGet32 (PcdTestVar3)));
  DEBUG ((EFI_D_ERROR, "[beni]PcdTestVar4: 0x%x.\n", PcdGet64 (PcdTestVar4)));

  DEBUG ((EFI_D_ERROR, "[beni]PcdTestDriverEntry End.\n"));

  return Status;
}

3. 编译后查看该模块编译目录中的AutoGen.c文件,可以看到如下的内容:

// Definition of PCDs used in this module
GLOBAL_REMOVE_IF_UNREFERENCED const UINT8 _gPcd_FixedAtBuild_PcdTestVar1 = _PCD_VALUE_PcdTestVar1;
GLOBAL_REMOVE_IF_UNREFERENCED const UINT16 _gPcd_FixedAtBuild_PcdTestVar2 = _PCD_VALUE_PcdTestVar2;
GLOBAL_REMOVE_IF_UNREFERENCED const UINT32 _gPcd_FixedAtBuild_PcdTestVar3 = _PCD_VALUE_PcdTestVar3;
GLOBAL_REMOVE_IF_UNREFERENCED const UINT64 _gPcd_FixedAtBuild_PcdTestVar4 = _PCD_VALUE_PcdTestVar4;

4. 这里的_PCD_VALUE_PcdTestVarx的值在AutoGen.h中声明:

// Definition of PCDs used in this module

#define _PCD_TOKEN_PcdTestVar1  107U
#define _PCD_SIZE_PcdTestVar1 1
#define _PCD_GET_MODE_SIZE_PcdTestVar1  _PCD_SIZE_PcdTestVar1 
#define _PCD_VALUE_PcdTestVar1  0xA5U
extern const  UINT8  _gPcd_FixedAtBuild_PcdTestVar1;
#define _PCD_GET_MODE_8_PcdTestVar1  _gPcd_FixedAtBuild_PcdTestVar1
//#define _PCD_SET_MODE_8_PcdTestVar1  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD

#define _PCD_TOKEN_PcdTestVar2  108U
#define _PCD_SIZE_PcdTestVar2 2
#define _PCD_GET_MODE_SIZE_PcdTestVar2  _PCD_SIZE_PcdTestVar2 
#define _PCD_VALUE_PcdTestVar2  0xA5A5U
extern const  UINT16  _gPcd_FixedAtBuild_PcdTestVar2;
#define _PCD_GET_MODE_16_PcdTestVar2  _gPcd_FixedAtBuild_PcdTestVar2
//#define _PCD_SET_MODE_16_PcdTestVar2  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD

#define _PCD_TOKEN_PcdTestVar3  109U
#define _PCD_SIZE_PcdTestVar3 4
#define _PCD_GET_MODE_SIZE_PcdTestVar3  _PCD_SIZE_PcdTestVar3 
#define _PCD_VALUE_PcdTestVar3  0xA5A5A5A5U
extern const  UINT32  _gPcd_FixedAtBuild_PcdTestVar3;
#define _PCD_GET_MODE_32_PcdTestVar3  _gPcd_FixedAtBuild_PcdTestVar3
//#define _PCD_SET_MODE_32_PcdTestVar3  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD

#define _PCD_TOKEN_PcdTestVar4  110U
#define _PCD_SIZE_PcdTestVar4 8
#define _PCD_GET_MODE_SIZE_PcdTestVar4  _PCD_SIZE_PcdTestVar4 
#define _PCD_VALUE_PcdTestVar4  0xA5A5A5A5A5A5A5A5ULL
extern const  UINT64  _gPcd_FixedAtBuild_PcdTestVar4;
#define _PCD_GET_MODE_64_PcdTestVar4  _gPcd_FixedAtBuild_PcdTestVar4
//#define _PCD_SET_MODE_64_PcdTestVar4  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD

5. 再回到2中代码里面我们访问PCD的方式如下:

PcdGet8 (PcdTestVar1))

将它展开后的结果就是_PCD_GET_MODE_8_PcdTestVar1,它在上述的AutoGen.h就已经定义了,最终的值就是0xA5。

也就是说,对应FixedAtBuild PCD来说,它就是在编译的时候通过宏的方式生成的。

也因此它是固定不变的一个值。

FeatureFlag PCD

FeatureFlag PCD跟FixedAtBuild是一样的,它相当于类型是BOOELAN的FixedAtBuild PCD,从下面的示例可以看出来:

1. 创建一个FeatureFlag PCD:

[PcdsFeatureFlag]
  gUefiOemPkgTokenSpaceGuid.PcdTestFeatureVar|FALSE|BOOLEAN|0x30000001

2. 然后在模块中使用它:

  DEBUG ((EFI_D_ERROR, "[beni]PcdTestBooleanVar: %d\n", FeaturePcdGet (PcdTestFeatureVar)));
  DEBUG ((EFI_D_ERROR, "[beni]PcdTestBooleanVar: %d\n", PcdGetBool (PcdTestFeatureVar)));

3. 注意这里使用了两种方式来访问这个变量,查看它的AutoGen.c文件:

GLOBAL_REMOVE_IF_UNREFERENCED const BOOLEAN _gPcd_FixedAtBuild_PcdTestFeatureVar = _PCD_VALUE_PcdTestFeatureVar;

4. 再查看AutoGen.h文件:

#define _PCD_TOKEN_PcdTestFeatureVar  111U
#define _PCD_SIZE_PcdTestFeatureVar 1
#define _PCD_GET_MODE_SIZE_PcdTestFeatureVar  _PCD_SIZE_PcdTestFeatureVar 
#define _PCD_VALUE_PcdTestFeatureVar  ((BOOLEAN)0U)
extern const  BOOLEAN  _gPcd_FixedAtBuild_PcdTestFeatureVar;
#define _PCD_GET_MODE_BOOL_PcdTestFeatureVar  _gPcd_FixedAtBuild_PcdTestFeatureVar
//#define _PCD_SET_MODE_BOOL_PcdTestFeatureVar  ASSERT(FALSE)  // It is not allowed to set value for a FIXED_AT_BUILD PCD

5. 可以从前缀看出来,它其实就是一个FixedAtBuild PCD。

6. 察看FeaturePcdGet和PcdGetBool两个宏:

#define FeaturePcdGet(TokenName)            _PCD_GET_MODE_BOOL_##TokenName
#define PcdGetBool(TokenName)               _PCD_GET_MODE_BOOL_##TokenName

也可以看到,他们指向的是同一种东西。

Dynamic PCD

下面介绍Dynamic PCD,首先看一个例子:

1. 创建一个Dynamic PCD(其实就是最开始的那个示例):

[PcdsDynamic]
gUefiOemPkgTokenSpaceGuid.PcdOemVersion|0xABCDDCBA|UINT32|0x40000001

2. 然后在模块中使用:

  DEBUG ((EFI_D_ERROR, "[beni]PcdOemVersion: 0x%x\n", PcdGet32 (PcdOemVersion)));

3. 编译后查看AutoGen.c文件,发现在该文件中没有找到相关的内容;

4. 再查看AutoGen.h文件,可以看到如下内容:

#define _PCD_TOKEN_PcdOemVersion  13U
#define _PCD_GET_MODE_32_PcdOemVersion  LibPcdGet32(_PCD_TOKEN_PcdOemVersion)
#define _PCD_GET_MODE_SIZE_PcdOemVersion  LibPcdGetSize(_PCD_TOKEN_PcdOemVersion)
#define _PCD_SET_MODE_32_PcdOemVersion(Value)  LibPcdSet32(_PCD_TOKEN_PcdOemVersion, (Value))
#define _PCD_SET_MODE_32_S_PcdOemVersion(Value)  LibPcdSet32S(_PCD_TOKEN_PcdOemVersion, (Value))

这里有几个明显的区别:

1)AutoGen.c中没有了PCD变量的定义;

2)PCD访问方式变了,Dynamic对应的是函数;

3)Set函数出现了;

关于PCD库函数的实现,这里以LibPcdGet32()为例(就是上例中用到的),它的实现如下:

/**
  This function provides a means by which to retrieve a value for a given PCD token.
  
  Returns the 32-bit value for the token specified by TokenNumber. 

  @param[in]  TokenNumber The PCD token number to retrieve a current value for.

  @return Returns the 32-bit value for the token specified by TokenNumber.

**/
UINT32
EFIAPI
LibPcdGet32 (
  IN UINTN             TokenNumber
  )
{
  return GetPcdProtocol()->Get32 (TokenNumber);
}

也就是说这里要依赖于Protocol(DXE阶段是Protocol,而PEI阶段是PPI)来完成操作。

这Protocol在Pcd.info模块中安装。

Pcd.inf模块分为PEI和DXE两个版本,分别放在PEI阶段和DXE阶段的最前面,只有整个模块初始化完成之后,才能够开始正常使用PCD宏来访问Dynamic PCD变量。

以DXE阶段的Pcd.inf模块为例,它主要做了两件事情:

1. 初始化该阶段使用的PCD数据库;

2. 安装各种处理PCD需要的Protocol;

在这个模块中,安装的主要的Protocol如下:

///
/// This service abstracts the ability to set/get Platform Configuration Database (PCD).
///
typedef struct {
  PCD_PROTOCOL_SET_SKU              SetSku;

  PCD_PROTOCOL_GET8                 Get8;
  PCD_PROTOCOL_GET16                Get16;
  PCD_PROTOCOL_GET32                Get32;
  PCD_PROTOCOL_GET64                Get64;
  PCD_PROTOCOL_GET_POINTER          GetPtr;
  PCD_PROTOCOL_GET_BOOLEAN          GetBool;
  PCD_PROTOCOL_GET_SIZE             GetSize;

  PCD_PROTOCOL_GET_EX_8             Get8Ex;
  PCD_PROTOCOL_GET_EX_16            Get16Ex;
  PCD_PROTOCOL_GET_EX_32            Get32Ex;
  PCD_PROTOCOL_GET_EX_64            Get64Ex;
  PCD_PROTOCOL_GET_EX_POINTER       GetPtrEx;
  PCD_PROTOCOL_GET_EX_BOOLEAN       GetBoolEx;
  PCD_PROTOCOL_GET_EX_SIZE          GetSizeEx;

  PCD_PROTOCOL_SET8                 Set8;
  PCD_PROTOCOL_SET16                Set16;
  PCD_PROTOCOL_SET32                Set32;
  PCD_PROTOCOL_SET64                Set64;
  PCD_PROTOCOL_SET_POINTER          SetPtr;
  PCD_PROTOCOL_SET_BOOLEAN          SetBool;

  PCD_PROTOCOL_SET_EX_8             Set8Ex;
  PCD_PROTOCOL_SET_EX_16            Set16Ex;
  PCD_PROTOCOL_SET_EX_32            Set32Ex;
  PCD_PROTOCOL_SET_EX_64            Set64Ex;
  PCD_PROTOCOL_SET_EX_POINTER       SetPtrEx;
  PCD_PROTOCOL_SET_EX_BOOLEAN       SetBoolEx;

  PCD_PROTOCOL_CALLBACK_ONSET       CallbackOnSet;
  PCD_PROTOCOL_CANCEL_CALLBACK      CancelCallback;
  PCD_PROTOCOL_GET_NEXT_TOKEN       GetNextToken;
  PCD_PROTOCOL_GET_NEXT_TOKENSPACE  GetNextTokenSpace;
} PCD_PROTOCOL;

这里就可以看到上文中LibPcdGet32()里面调用的Get32()函数了。

在上述GetX和SetX的函数实现中,最重要的是如下的函数:

GetWorker():

/**
  Get the PCD entry pointer in PCD database.
  
  This routine will visit PCD database to find the PCD entry according to given
  token number. The given token number is autogened by build tools and it will be 
  translated to local token number. Local token number contains PCD's type and 
  offset of PCD entry in PCD database.

  @param TokenNumber     Token's number, it is autogened by build tools
  @param GetSize         The size of token's value

  @return PCD entry pointer in PCD database

**/
VOID *
GetWorker (
  IN UINTN             TokenNumber,
  IN UINTN             GetSize
  )

SetWorker():

/**
  Set value for an PCD entry

  @param TokenNumber     Pcd token number autogenerated by build tools.
  @param Data            Value want to be set for PCD entry
  @param Size            Size of value.
  @param PtrType         If TRUE, the type of PCD entry's value is Pointer.
                         If False, the type of PCD entry's value is not Pointer.

  @retval EFI_INVALID_PARAMETER  If this PCD type is VPD, VPD PCD can not be set.
  @retval EFI_INVALID_PARAMETER  If Size can not be set to size table.
  @retval EFI_INVALID_PARAMETER  If Size of non-Ptr type PCD does not match the size information in PCD database.  
  @retval EFI_NOT_FOUND          If value type of PCD entry is intergrate, but not in
                                 range of UINT8, UINT16, UINT32, UINT64
  @retval EFI_NOT_FOUND          Can not find the PCD type according to token number.                                
**/
EFI_STATUS
SetWorker (
  IN          UINTN                   TokenNumber,
  IN          VOID                    *Data,
  IN OUT      UINTN                   *Size,
  IN          BOOLEAN                 PtrType
  )

GetWorker()的作用就是在PCD数据库里面找到对应的PCD的指针,而SetWork()的作用就是找到指针然后赋值。

到这里为止,最需要了解的就是PCD数据库是如何建立的?

从BuildPcdDxeDataBase()这个函数中可以找到答案。

查看以下的代码:

  //
  // Assign PCD Entries with default value to PCD DATABASE
  //
  mPcdDatabase.DxeDb = LocateExPcdBinary ();
  ASSERT(mPcdDatabase.DxeDb != NULL);
  PcdDxeDbLen = mPcdDatabase.DxeDb->Length + mPcdDatabase.DxeDb->UninitDataBaseSize;
  PcdDxeDb = AllocateZeroPool (PcdDxeDbLen);
  ASSERT (PcdDxeDb != NULL);
  CopyMem (PcdDxeDb, mPcdDatabase.DxeDb, mPcdDatabase.DxeDb->Length);
  FreePool (mPcdDatabase.DxeDb);
  mPcdDatabase.DxeDb = PcdDxeDb;

这里主要进行了PCD数据库的创建,它分为两个步骤:

1. 通过LocateExPcdBinary()从FFS中获取PCD已初始化变量;

2. 为未初始化的变量(默认全0)分配空间(这样做的目的应该是为了减少生成二进制的大小);

接下来需要关注的就是这个放在FFS中的PCD数据是从何而来的?

查看LocateExPcdBinary()函数里面的代码:

  //
  // Search the External Pcd database from one section of current FFS, 
  // and read it to memory
  //
  Status = GetSectionFromFfs (
             EFI_SECTION_RAW,
             0,
             (VOID **) &DxePcdDbBinary,
             &DxePcdDbSize
             );
  ASSERT_EFI_ERROR (Status);

从中可以看到PCD数据是存放在当前FFS的第一个Section开始的数据。

关于FFS,在之前的文章【UEFI基础】EDK编译生成的二进制的结构中介绍过,这里直接打开下面的文档查看:

使用二进制查看工具打开该文件,搜索PCD对应的GUID(gPcdDataBaseSignatureGuid),结果如下:

因此Dynamic PCD的数据是在编译的时候初始化并存放在BIOS二进制中的,然后在BIOS运行过程中会获取这些数据,并存放到内存中,后续就可以修改了。

DynamicEx类型的基本上一致,这里不再说明。

PatchableInModule PCD

最后剩下的是PatchableInModule PCD,下面是一个例子:

1. 在DEC中声明:

[PcdsPatchableInModule]
gUefiOemPkgTokenSpaceGuid.PcdPatchableVar|0x00ABCDEF|UINT32|0x50000001

2. 在模块中使用:

  DEBUG ((EFI_D_ERROR, "[beni]PcdPatchableVar: 0x%x\n", PcdGet32 (PcdPatchableVar)));

3. 查看AutoGen.c文件:

volatile  UINT32 _gPcd_BinaryPatch_PcdPatchableVar = _PCD_PATCHABLE_VALUE_PcdPatchableVar;
GLOBAL_REMOVE_IF_UNREFERENCED UINTN _gPcd_BinaryPatch_Size_PcdPatchableVar = 4;

4. 这里定义了PCD相关的两个变量,一个是值,注意它的类型修饰符是volatile,另一个是PCD的大小。

5. 进一步查看AutoGen.h文件,可以看到_gPcd_BinaryPatch_PcdPatchableVar当前的值:

#define _PCD_TOKEN_PcdPatchableVar  112U
#define _PCD_PATCHABLE_VALUE_PcdPatchableVar  ((UINT32)0x00ABCDEFU)
extern volatile   UINT32  _gPcd_BinaryPatch_PcdPatchableVar;
#define _PCD_GET_MODE_32_PcdPatchableVar  _gPcd_BinaryPatch_PcdPatchableVar
#define _PCD_PATCHABLE_PcdPatchableVar_SIZE 4
#define _PCD_GET_MODE_SIZE_PcdPatchableVar  _gPcd_BinaryPatch_Size_PcdPatchableVar 
extern UINTN _gPcd_BinaryPatch_Size_PcdPatchableVar; 
#define _PCD_SET_MODE_32_PcdPatchableVar(Value)  (_gPcd_BinaryPatch_PcdPatchableVar = (Value))
#define _PCD_SET_MODE_32_S_PcdPatchableVar(Value)  ((_gPcd_BinaryPatch_PcdPatchableVar = (Value)), RETURN_SUCCESS) 

6. 它的访问方式与FixedAtBuild PCD没有什么两样。

对于PatchableInModule PCD来说,唯一的差别就在于,变量是volatile的,但是这个volatile具体体现在哪里呢?我们如何对它进行Patch?

因为该PCD是可以通过外部工具来修改的,那么有一点是可以肯定的,即它是可见的,通过查看BIOS二进制就可以找到。

首先找OVMF.fd(这个是最终生成的BIOS二进制)中寻找,但是没有找到,再在DXEFV.Fv中寻找,发现了它的踪迹:

它的位置是在当前模块(即打印该PCD的模块)的只读数据区中。

同时在对应的EFI文件中也能找到:

其地址在与AutoGen同目录的map文件中也有说明:

上图中也可以发现,其它类型的PCD是没有这个。

因此理论上可以通过工具来修改这个值(在生成最终的OVMF.fd之前)。

而实际上,在EDK的源代码中,提供了操作PatchableInModule PCD的工具:

因此可以利用这两个工具来修改PCD。

这里将这两个工具(以及依赖文件)放到下述的编译中间目录:

首先是使用GenPatchPcdTable.exe来生成文件,该文件中包含所有的PatchableInModule PCD:

使用该工具之后生成了一个文件:

其内容如下:

会看到跟之前二进制里面的偏移不一样,因为是重新编译过,不要在意...

然后通过PatchPcdValue.exe来修改PCD:

这里将PcdPatchableVar的值修改成了0x88888888,比较修改前后的值:

可以看到确实是修改成功了!

具体GenPatchPcdTable.exe和PatchPcdValue.exe可以参考源代码中BaseTools\UserManuals目录下的说明。

以上的例子只是手动的修改efi文件,但是如果在编译的时候自动完成这个动作,或者在整个二进制生成之后修改PatchableInModule PCD呢?

目前这还是个疑问。

以上,就是对于UEFI PCD的所有内容的介绍。

  • 39
    点赞
  • 112
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值