一、 编写源代码
- 编写UEFI Application
代码C:\edkii\OvmfPkg\MyHelloWorldPCD\MyHelloWorldPCD.c,
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)){
Print (L"[MyHelloWorldPCD] PcdMyHelloWorldPrintEnable ..\n");
PrintTimes = PcdGet32(PcdMyHelloWorldPrintTimes);
for (i = 0; i < PrintTimes; i++){
PrintStr = PcdGetPtr(PcdMyHelloWorldPrintString);
Print (L"[MyHelloWorldPCD] Pcd Str = %s\n",PrintStr);
}
}
// DEBUG ((EFI_D_ERROR , "[MyHelloWorldPCD] MyHelloWorldPCDEntry End..\n"));
Print(L"[MyHelloWorldPCD] MyHelloWorldPCDEntry End..\n");
return Status;
}
- 修改 C:\code\local_edkrepo_10nm\Edk2\OvmfPkg\MyHelloWorldPCD\MyHelloWorldPCD.inf
#use to operate bool value
[FeaturePcd]
gEfiMdeModulePkgTokenSpaceGuid.PcdMyHelloWorldPrintEnable ## CONSUMES
[Pcd]
gEfiMdeModulePkgTokenSpaceGuid.PcdMyHelloWorldPrintString ## CONSUMES
gEfiMdeModulePkgTokenSpaceGuid.PcdMyHelloWorldPrintTimes ## SOMETIMES_CONSUMES
- 修改 C:\code\local_edkrepo_10nm\Edk2\MdeModulePkg\MdeModulePkg.dec
...
[PcdsFeatureFlag]
gEfiMdeModulePkgTokenSpaceGuid.PcdMyHelloWorldPrintEnable|FALSE|BOOLEAN|0x0001200d
[PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]
# @Prompt HellowWorld print times.
gEfiMdeModulePkgTokenSpaceGuid.PcdHelloWorldPrintTimes|1|UINT32|0x40000005
# @Prompt HelloWorld print string.
gEfiMdeModulePkgTokenSpaceGuid.PcdHelloWorldPrintString|L"UEFI Hello World!\n"|VOID*|0x40000004
...
二、 编译生成EFI文件
运行edksetup.bat
编译整个OvmfPkg Package
三、 运行 UEFI APP MyHelloWorldPCD.efi
- 拷贝
C:\edkii\Build\OvmfX64\DEBUG_VS2013x86\FV\OVMF.fd
到C:\qemu
;拷贝C:\edkii\Build\OvmfX64\DEBUG_VS2013x86\X64\OvmfPkg\MyHelloWorldPCD\MyHelloWorldPCD\OUTPUT\MyHelloWorldPCD.efi
到 虚拟盘HDD_BOOT.img
- 执行
setup-qemu-x64.bat
| findstr MyHelloWorldPCD
, 然后在UEFI SHELL
中执行MyHelloWorldPCD.efi
,结果如下,
四、 小结
PCD(Platform Config DataBase)块用于定义平台配置数据。它的目的是在不改动.inf文件的情况下完成对平台的配置。PCD类别分为两大类:
1)在编译过程中起作用,这类PCD类似C语言中的全局静态变量,但是其值不能修改,包含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值将会丢失,格式如下:
[PcdsDynamic]
gEfiCpuTokenSpaceGuid.PcdCpuProcessorFeatureCapability|0|UNIT32|0x4000002
该PCD值为0, 类型为UNIT32,token number为0x4000002。
PcdsDynamicHii与PcdsDynamicExHii将用来定义缺省的Variable,当某个EFI Variable未定义时,一个心的non-volatile Variable将会被创建,并且default值将会被设置,格式如下:
[ PcdsDynamicHii.common.DEFAULT]
gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdPlatformBootTimeOut|L"Timeout"|gEEfiGlobalVariableGuid|0x0 | 5
例子中,Hii Variable name被设置为"TimeOut",Variable Guid设定为gEEfiGlobalVariableGuid, Variable Offset设定为0, 缺省值设定为5(PcdsDynamicHii 最终会调用Variable service)。
PcdsDynamicVpd、PcdsDynamicExVpd修饰的PCD变量将会存放在VPD数据库中(位于在Flash上),对PCD的操作将直接映射到Flash上的VPD 区域, 其格式如下:
[PcdsDynamicVpd.common.DEFAULT]
gEfiE6xxTokenSpaceGuid.PcdIgdPreAllocSize | 4 | 0x2
例子中, Pcd VpdOffset为4,初始值为2(VPD类型PCD不能使用PCD Set 接口)。
PcdsDynamic 与PcdsDynamicEx与PcdsDynamicDefault与PcdsDynamicExDefault类似,如果一个PCD module集成到PlatformBuild中,PcdsDynamic 与PcdsDynamicEx与PcdsDynamicDefault等价,即源代码中调用为PcdGetxx(PcdSampleDynamicPcd)
; 如果该module以独立的binary 发布,则要使用PcdsDynamicEx,即源代码中调用为PcdGetxx(gEfiMyTokenSpaceGuid, PcdSampleDynamicPcd)
。
本文程序主要对静态PCD的使用做了简单实现,在MdeModulePkg.dec文件中定义PcdMyHelloWorldPrintEnable、PcdHelloWorldPrintTimes、PcdHelloWorldPrintString,在MyHelloWorldPCD.inf文件中对PCD进行引用,最后在MyHelloWorldPCD.c使用PcdGetXX函数获取PCD的默认值并简单处理。