UEFI——PCD研究

  今天看UiAPP下的入口函数InitializeUserInterface()时看见一个PcdGet32,不明白是干什么的,VSCode上显示的是本函数相关的信息(显然不对 ),后面搜索不到相关的源码。在这里插入图片描述之后就去补充了相关的知识,记录一下,算是一个比较简单浅显的版本。

1 PCD OVERVIEW

PCD(Platform Configuration Database),是一个UEFI下可访问的数据库,EDK2用来进行全局配置,对代码复用,模块化开发有巨大的帮助。
  具体来说就是,代码中进行平台配置相关的东西,platform需要改的时候不用去修改代码了。在编译的时候,运行的时候,甚至是生成了二进制的时候都可以配置、修改。更容易有针对性的设计,对代码的维护也会方便很多。(有点类似于.uni和.Vfr的机制)
  虽然在EDK2源码中他涉及到的宏很多,但是这种方式确实是有别于C/C++的宏,并不是简单的公用代码的提取,或者说完全不是一个东西。

PCD变量格式

TokenSpaceGuidCName.PcdCName

其中TokenSpaceGuidCName是一个GUID,而PcdCName是这个PCD变量的名字,这两个加在一起构成了一个PCD变量。


2 PCD USAGE

2.1 PCD TYPES

PCD可以分为两类:
1)有三个分别是:FixedAtBuild PCD , FeatureFlag PCDPatchableInModule PCD , 其中 FixedAtBuild PCDFeatureFlag PCD 在编译的时候起作用的,静态的。类似于C中的静态全局变量,但是后面不能修改。在定义的时候就赋值了,之后是不能用代码修改的,只能是在.dec/.dsc中修改。
PatchableInModule PCD在编译完成后的二进制文件上是可以用特殊的办法更改的。后面详细介绍。
2)Dynamic/DynamicEx PCD 等其它的 可以称为动态的,在UEFI运行的时候可以get,还可以用set宏修改,作用域是system级,在代码中传递和使用。(比前面的复杂一些)

FixedAtBuild

编译阶段确定的值,整个UEFI运行阶段不可改的静态值,二进制下也不可以改,可以认为是一个宏,const全局变量。是一个module level,并非系统级别的。即是说不同模块可以配置不同PCD的值。

FeatureFlag

也是编译时确定的静态设置,看名字中有个Flag也能猜出来这是个Boolean类型的,他和FixedAtBuild最大的区别就是他返回值就是一个TURE或者FALSE。用于判断条件中,也是一个module level的。

PatchableInModule

在编译时确定值,和FixedAtBuild一样也是module level,只能影响一个模块,不会影响其他的模块,相当于一个inf 的 source范围。不同是他在编译后的二进制文件中可以用工具修改,并且他不是const 的全局变量。

Dynamic/DynamicEx

动态值,在整个UEFI运行的过程中,有人会get,有人会set,是一直可以改变的值,system level,作用域是整个system。整个BIOS代码每个模块访问这个Dynamic PCD 都是共享同一个值,如果某个模块修改了他的值,那么其他模块访问的就是修改以后的值了。通过set宏来改变。Dynamic 有三个子类DynamicHIIDynamicVpdDynamicEx。区别目前还不是特别理解,只知道DynamicExDynamic的加强版,如果在代码中没有二进制形式,或者二进制文件没有用到PCD,那么这里使用的PCD 类型就是Dynamic的,但是如果是用binary方式集成进来了,要使用二进制中的PCD就必须要用DynamicEx类型的PCD。

DynamicHII/DynamicVpd

DynamicHII与Dynamic不同,后者是放在memory中的,也就是说修改了再加载的话会丢失上一次的值,获取到最新define的值。而DynamicHII是放在EFI variable(NVRAM中)的,修改是非易失性的,就是set了以后下次加载还是这次set的值。
DynamicVpd ReadOnly,不可写。存放系统的default section,厂商的出厂设置就放在这里,是必不会也不可被修改的。

2.2 EXAMPLE

原本计划介绍 FixedAtBuild 类型的,但是我看到的代码中的PcdSetupVideoHorizontalResolutionPatchableInModule类型的,这两个类型的访问方式没什么不同,后者只是可以在二进制文件生成之后修改,而前者不可以。
PcdSetupVideoHorizontalResolution在源码中的位置:
在这里插入图片描述
可以看到也是有这个PcdGet32宏,我也是因为没找到这个的定义才进行相关知识的学习。

  1. 在.dec文件中声明这个PCD变量:

在这里插入图片描述
源码:

[PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]
  gEfiMdeModulePkgTokenSpaceGuid.PcdSetupVideoHorizontalResolution|800|UINT32|0x4000000b

介绍一下声明的格式:
  他这里有两句,第一句[PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx],声明了这个PCD的类型,就前面介绍的PCD类型。
  第二句的规则是这样的:

#Comment
PcdTokenSpaceGuidName.PcdTokenName|Value[|DatumType[|MaxSize]]|Token

PcdTokenSpaceGuidName.PcdTokenName前面已经介绍过了,不可以重复,也不可以轻易改变,这两个共同构成一个PCD变量。Value也叫做DefaultValue 就是这个PCD变量的默认值,如果你在后面的.dsc文件中没有修改他的值,他就是用这个默认值。DatumType是这个PCD变量的数据类型有UINT 8 16 32 等等,如果是VOID * 的话还要在MaxSize部分写上这个Buffer的最大值,比如128、256等等。Token是UINT 32类型的,每个.dec文件中的PCD都有独一无二的Token。

他是符合BNF的,#后面的是注释,[ ]内的是可选项,没有应该也可以。

  1. 在.dsc中可以修改
    在这里插入图片描述
    修改的规则:
[Pcds...]
PcdTokenSpaceGuidName.PcdTokenName|Value[|DatumType[|MaximumDatumSize]]

这些字段的值和前面的一样,[ ]内的也是可选的,不是必须包括的。一般的写法就是PcdTokenSpaceGuidName.PcdTokenName|Value,像图片里面的那样。
将原本的800改成了640,当然这还不是同一个文件下的dsc文件,从侧面也证实了这确实是一个全局变量。

PCD可以在.dsc文件中进行修改,包括PCD的值和类型,假如PCD在.dec文件中进行了定义,在inf文件中使用,但在.dsc中并没有重新set,这时候PCD就会使用默认值(.dec中的Value),类型则是支持的最初的类型,类型也是有一个优先级,优先考虑FixAtBuild,其次PatchInModule,然后Dynamic,DynamicEx。(这部分不确定)

3.在.inf文件中引用
在这里插入图片描述

[Pcd] 
PcdTokenSpaceGuidName.PcdTokenName|[Value]

一般的写法就是列出这个变量的名字,值是不管的。

3 AutoGen

AutoGen.h
在这里插入图片描述
这里可以看见 在AutoGen.h 中 将 _PCD_PATCHABLE_VALUE_PcdSetupVideoHorizontalResolution 设置成了800u

AutoGen.c
在这里插入图片描述
然后最精彩的操作在于,他通过一些的#define 将_PCD_PATCHABLE_VALUE_PcdSetupVideoHorizontalResolution这个变量改成PcdSetupVideoHorizontalResolution 加上前缀_PCD_GET_MODE_32_,而后面的PcdGet32()中直接用##拼接这个变量名就可以直接得到他的值,所以也算知道了PcdGet32()这个函数的来龙去脉了。
在这里插入图片描述

4 PCD LIBRARY

为了方便代码的编写。引入了PCDLib,这里面有常用的接口可以使用,我之前看到的PcdGet32()就在其中。
在这里插入图片描述

这里面有许多好用的函数,比如

  PcdGetXX()
  PcdSetXX() 
  PcdGetExXX()
  PcdSetEx()
  PcdToken() 
  PcdSetSku()
  PcdGetNextToken() 
  PcdGetNextTokenSpace()
  CallBackOnSet() 
  CancelCallBack() 

其中“XX" = 8 16 32 Size Ptr Boolean

而我们最常使用的就是PcdGetXX()PcdSetXX()

最后:动态的PCD机制还不太了解,而修改二进制文件中的PCD还需要去实践。

参考博客:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值