UEFI——PCD的简单使用

一、PCD的定义及概念

在UEFI固件接口中,PCD(Platform Configuration Database)是一个用于存储和访问平台特定配置信息的机制。PCD允许UEFI驱动程序和应用程序在运行时获取和设置平台相关的参数,而无需硬编码这些值。PCD变量可以被动态的读取和修改。(类似于C语言中的宏而区别于宏)

PCD的种类可以分为两大类:

(1)在编译过程中起作用,包含PcdsFeatureFlag , PcdsFixedAtBuild 以及 PatchableInModule;其中FeatureFlag 类型PCD只能定义为Bool值,FixedAtBuild可以支持多种数据类型UINIT32、UINT8、VOID* 等,PcdsPatchableInModule类型PCD在编译阶段可以被GenPatchPcdTable修改其值,并且在运行时也可以改变其值(PatchableInModule 本质上就讲PCD存放在EFI module的data 段 )。

(2)在运行过程中起作用,这类PCD包括PcdsDynamicDefault、PcdsDynamicExDefault、 PcdsDynamicHii、PcdsDynamicExHii、PcdsDynamicVpd、PcdsDynamicExVpd、PcdsDynamic 、PcdsDynamicEx;
其中, PcdsDynamicDefault与PcdsDynamicExDefault在Runtime阶段可以被改变, 但是当内存掉电后change值将会丢失,格式如下: 

不同类型的PCD在文件中对应的块名称不同,使用多种类型的PCD要分别在INF文件中对应的块中引用。

 如果一个PCD被声明多种类型且在INF文件中引用时都放 [Pcd] 块中,编译工具会根据优先级决定PCD的类型:PcdsFixedAtBuild > PcdsPatchableInModule > PcdsDynamicDefault >

【PCD与宏的区别】

 PCD用于存储和访问平台特定的配置信息。这些配置信息可以在固件映像构建时设置,也可以在固件运行时动态地读取和修改。PCD变量用于控制固件的行为,如硬件设置、性能选项、调试级别等。宏定义用于在编译时替换代码中的文本。宏定义通常用于代码重用、代码简化、避免重复代码编写等,一旦定义是不可变的。

二、PCD的简单使用

 1、编写MyHelloWorldPCD.c

FeaturePcdGet宏是一个获取FeaturePcd变量的值的宏定义,使用了预处理器宏_PCD_GET_MODE_BOOL_,它将TokenName替换为FeaturePcd变量的Token Space和名称,其代码原型为:

/**
  Retrieves a Boolean PCD feature flag based on a token name.
  根据token名称检索布尔PCD特征标识

  Returns the Boolean value for the PCD feature flag specified by TokenName.
  If TokenName is not a valid token in the token space, then the module will not build.
  If TokenName is not a feature flag PCD, then the module will not build.

  @param   TokenName  The name of the PCD token to retrieve a current value for.

  @return  Boolean value for the PCD feature flag.

**/
#define FeaturePcdGet(TokenName)  _PCD_GET_MODE_BOOL_##TokenName

利用PcdGet32(TokenName)获取32位PCD值,代码原型为

/**
  Retrieves a 32-bit PCD token value based on a token name.
  根据Token名称检索一个32位的PCD token值

  Returns the 32-bit value for the token specified by TokenName.
  If TokenName is not a valid token in the token space, then the module will not build.

  @param   TokenName  The name of the PCD token to retrieve a current value for.

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

**/

PcdGetPtr(TokenName)检索指向PCD token缓冲区的指针,代码原型为:

/**
  Retrieves a pointer to a PCD token buffer based on a token name.
  根据token名称检索PCD token缓冲区的指针

  Returns a pointer to the buffer for the token specified by TokenName.
  If TokenName is not a valid token in the token space, then the module will not build.

  @param   TokenName  The name of the PCD token to retrieve a current value for.

  @return  A pointer to the buffer. //返回一个指向缓冲区的指针

**/
#define PcdGetPtr(TokenName)  _PCD_GET_MODE_PTR_##TokenName

完整代码为:

#include <uefi.h> 
#include <Library/UefiLib.h> 
#include <Library/BaseLib.h>
#include <Library/DebugLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/PcdLib.h>

EFI_STATUS
EFIAPI
MyHelloWorldPCDEntry(
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
)
{ 
  EFI_STATUS  Status = EFI_SUCCESS;
  UINT32  PrintTimes ;
  UINT32  i ;
  CONST CHAR16 *PrintStr; 
  // DEBUG ((EFI_D_ERROR , "[MyHelloWorldPCD] MyHelloWorldPCDEntry Start..\n"));
  Print(L"[MyHelloWorldPCD] MyHelloWorldPCDEntry Start..\n");
  
  if (!FeaturePcdGet(PcdMyHelloWorldPrintEnable)){ //PcdMyHelloWorldPrintEnable是一个token 名称,返回一个Boolean值
	Print (L"[MyHelloWorldPCD] PcdHelloWorldPrintEnable ..\n");
	
	PrintTimes = PcdGet32(PcdMyHelloWorldPrintTimes);
	for (i = 0; i < PrintTimes; i++){
		PrintStr = PcdGetPtr(PcdHelloWorldPrintString);
	    Print (L"[MyHelloWorldPCD]  Pcd  Str = %s\n",PrintStr);
	}
  }
  
  // DEBUG ((EFI_D_ERROR , "[MyHelloWorldPCD] MyHelloWorldPCDEntry End..\n"));
  Print(L"[MyHelloWorldPCD] MyHelloWorldPCDEntry End..\n");
 
  return Status;
}

 使用PCD要在INF文件中引用

#use to operate bool value
[FeaturePcd]
  gEfiMdeModulePkgTokenSpaceGuid.PcdMyHelloWorldPrintEnable  ## CONSUMES

[Pcd]
  gEfiMdeModulePkgTokenSpaceGuid.PcdHelloWorldPrintString  ## CONSUMES
  gEfiMdeModulePkgTokenSpaceGuid.PcdHelloWorldPrintTimes    ## SOMETIMES_CONSUMES

使用PCD要在DEC文件中声明

...
 [PcdsFeatureFlag]
  gEfiMdeModulePkgTokenSpaceGuid.PcdMyHelloWorldPrintEnable|FALSE|BOOLEAN|0x0001200d
  //PcdMyHelloWorldPrintEnable是PCD变量的名称;FALSE是PCD变量的默认值;BOOLEAN是PCD变量的数据类型;0x0001200d是PCD token的值,用于在PCD数据库中表示和引用特定的PCD变量。

 [PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]
  # @Prompt HellowWorld print times.
  gEfiMdeModulePkgTokenSpaceGuid.PcdHelloWorldPrintTimes|3|UINT32|0x40000005

  # @Prompt HelloWorld print string.
  gEfiMdeModulePkgTokenSpaceGuid.PcdHelloWorldPrintString|L"UEFI Hello World!\n"|VOID*|0x40000004
  ...

在DSC文件中修改(如果没有修改会使用DEC中默认的PCD值)

[...Pcd...]

PcdTokenSpaceGuidName.PcdTokenName | Value [ | DatumType[ |MaximumDatumSize ] ]

运行代码生成EFI文件,并将efi文件拷贝到虚拟盘HDD_BOOT.img中运行,运行结果如下:

参考文章

EFI 基础教程 (八)- PCD 简单使用

PCD配置和使用 

  • 14
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值