UEFI开发探索101 – PCD探究
(請保留-> 作者: 羅冰 https://blog.csdn.net/luobing4365)
PCD探究
- 1 PCD簡介
- 2 如何使用PCD
- 2.1 PCD的類型
- FixedAtBuild類型
- FeatureFlag類型
- PatchableInModule類型
- Dynamic類型、DynamicHii類型和DynamicVpd類型
- DynamicEx類型
- 2.2 訪問PCD變量
- 2.3 PCD的聲明和使用
- 3 試著寫個例子
從《UEFI編程實踐》出版后,一系列的事情接踵而來,終于在今天,算是告一段落了。
這段時間,有不少機會和業(yè)內人員討論UEFI和BIOS。反思自己對這個領域的理解,深感自己理論的不足。
看過《UEFI編程實踐》的網友,應該能了解,書中對于概念的理論部分,闡述得相對較少。我一般都是遵循“提出問題-介紹UEFI相關知識-提供實例”的框架,圍繞某一課題進行研究。
其中的一個原因,是因為我本來就是奔著實踐為目的,將平時開發(fā)中所遇到的課題逐漸展開討論。另一個原因,是沒有深入到EDK2的具體實現(xiàn)去。
因此,從UEFI開發(fā)探索第101篇開始,我想逐漸轉向對EDK2的代碼研究了。如之前研究PCI Option ROM開發(fā)一樣,這次設立的目標包括:
我了解這是一個不小的目標,會遇到不少的困難,興趣所在,倒不是特別畏懼。本來的想法,是在樹莓派上進行實驗,在lab-z(博客:https://www.lab-z.com/)的建議下,覺得OvmfPkg做實驗更方便些。
主題確定,后續(xù)想到哪里不熟就補足哪里的知識。嗯,先從EDK2全局配置的關鍵核心-PCD開始研究。
1 PCD簡介
Platform Configuration Database(PCD)是EDK2用來進行全局配置的機制,在代碼復用、模塊化方面發(fā)揮巨大作用。
PCD是把代碼里面的可配置選項抽取出來,platform需要修改的時候,可以不用去修改源代碼。其參數(shù)的配置,可以在編譯過程中、運行時中都可以進行,甚至在二進制文件中也可以配置。
這種設計方式就比較讓人著迷,這也使得定制化更為容易,代碼更容易維護。
早期我一直以為PCD如同C/C++中的宏,用來提取公用代碼,這是錯誤的。它提供的功能更為廣泛,也更復雜。
首先直觀地看下平常程序中用到的PCD,以前幾篇中的Diskdump工程為例,使用如下命令編譯,提取出其所用的PCD信息:
C:\vUDK2018\edk2>build -Y PCD -y pcd.log -p RobinPkg\RobinPkg.dsc -m RobinPkg\Applications\Diskdump\Diskdump.inf -a IA32輸出的信息,存在了pcd.log中。查看下log信息:
圖1 Diskdump中用到的PCD
觀察一下,可以看到許多編程時壓根就沒注意到的PCD參數(shù)。Diskdump使用了MdePkg和ShellPkg中的Protocol,因此也用到了其相關的PCD。
對于PCD的文檔,可以參考:
EDK2代碼:
MdeModulePkg\Universal\PCD\Dxe\Pcd.inf
https://github.com/tianocore/tianocore.github.io/wiki/EDK-II-Documents:
《EDK II Platform Configuration Database Infrastructure Description》
《EDK II Platform Description(DSC) File Specification》
《EDK II Package Declaration(DEC) File Format Specification》
《EDK II Build Specification》
https://uefi.org/specifications:
《Platform Initialization(PI) Specification》
2 如何使用PCD
PCD可以使用于UEFI存在的大部分時間,除了在SEC階段、早期的PEI和DXE階段,基本都可以訪問。在使用前,我們需要搞清楚PCD的結構和類型。
2.1 PCD的類型
PCD變量的格式有點像結構體:
TokenSpaceGuidCName.PcdCName其中,TokenSpaceGuidCName是GUID,而PcdCName是變量名,兩者組合構成了一個PCD變量。
PCD有如下的類型。
FixedAtBuild類型
它在編譯階段確定,是靜態(tài)值,在運行階段或二進制形態(tài)下都不可改。可以認為它就是一個宏了。
FeatureFlag類型
它實際上和FixedAtBuild是同一類型,返回一個Bool類型(True或False),可用于判斷條件。
PatchableInModule類型
此類型的變量值在編譯的時候確定,它在編譯后的二進制文件上使用工具修改。與FixedAtBuild不同,它只能影響一個模塊(作用域在一個模塊)。
Dynamic類型、DynamicHii類型和DynamicVpd類型
Dynamic類型變量的作用域是整個系統(tǒng),它是動態(tài)的PCD,可以在UEFI運行過程中修改。
DynamicHii類型與Dynamic類型存儲的位置不同,Dynamic類型可以認為是存在于Memory中,再加載是會失去原始設置的;而DynamicHii類型是存在Efi variable中的(NVRAM中),其修改時非易失性的。
而DynamicVpd類型變量是只讀的,不可寫的,一般出廠確定。
DynamicEx類型
與Dynamic類型類似,相當于加強版。其與Dynamic類型的區(qū)別,在于是否使用二進制文件中的PCD。比如FSP,如果要使用其中的PCD變量,則FSP中的PCD類型必須設置為### DynamicEx類型。
2.2 訪問PCD變量
為管理PCD變量,PEI提供了PCD_PPI和EFI_PEI_PCD_PPI;DXE提供了PCD_PROTOCOL和EFI_PCD_PROTOCOL。
不過,為了方便使用,EDK2中引入了PCD Library,把這些訪問細節(jié)隱藏了起來。(MdePkg\Include\Library\PcdLib.h)
庫中包含如下函數(shù):
PcdGetXX() PcdSetXX() PcdGetExXX() PcdSetExXX() PcdToken() PCDSetSku() PcdGetNextToken() PcdGetNextTokenSpace() CallBackOnSet() CancelCallBack()其中,XX可以為8、16、32、Size、Ptr或者Boolean。
2.3 PCD的聲明和使用
PCD的使用,基本可以按照如下流程進行。
其格式為:
TokenSpaceGuidCname.PcdCname|DefaultValue|DatumType|Token如前所述,PcdCname為變量名,DefaultValue為其默認值,DatumType是PCD的數(shù)據(jù)類型,Token是一個32位的整型,在DEC中每個PCD都有一個獨有的Token。
DatumType可以是BOOLEAN、UINT8、UINT16、UINT32、UINT64或VOID *型。
可以在DSC文件中設置相應PCD變量的值,比如:
此設置過程不是必須的,如果沒有設置,則使用DEC文件中的默認值。
在模塊的INF文件中,需要聲明PCD變量,才可以在源碼中使用。比如:
只需要列出PCD變量名就可以了,其他信息不用列出。
完成上述工作后,就可以在源代碼中,使用PCD庫函數(shù)訪問PCD變量了。示例如下:(摘自MdeModulePkg\Application\HelloWorld\HelloWorld.c)
if (FeaturePcdGet (PcdHelloWorldPrintEnable)) {for (Index = 0; Index < PcdGet32 (PcdHelloWorldPrintTimes); Index ++) {//// Use UefiLib Print API to print string to UEFI console//Print ((CHAR16*)PcdGetPtr (PcdHelloWorldPrintString));}}3 試著寫個例子
在UEFI應用開發(fā)或者Option ROM開發(fā)中,基本上不用PCD變量。但并不妨礙在UEFI應用上使用它們,我們試著在RobinPkg的某個Application上,來使用PCD變量。
我選擇之前開發(fā)的Diskdump工程,改名為Pcdtouch,嘗試使用PCD變量。當然,隨便選一個其他的工程也可以,剛好這個工程就在眼前,就隨手在它上面改造了。
修改步驟如下:
1. 修改RobinPkg.dec
添加如下語句:
2. 修改Pcdtouch.inf
DSC文件中可以修改PCD變量的值,這里我們不需要修改,不用去改DSC文件。
直接修改INF文件就可以了,添加將要在源程序中用到的PCD變量:
[FeaturePcd]gEfiMdeModulePkgTokenSpaceGuid.PcdHelloWorldPrintEnable ## CONSUMES[Pcd]gEfiMdeModulePkgTokenSpaceGuid.PcdHelloWorldPrintString ## SOMETIMES_CONSUMESgEfiMdeModulePkgTokenSpaceGuid.PcdHelloWorldPrintTimes ## SOMETIMES_CONSUMESgRobinPkgPcdSampleGuid.PcdtouchStrgRobinPkgPcdSampleGuid.PcdtouchValue除了在DEC文件中添加的兩個PCD變量外,還把MdeModulePkg中的幾個PCD變量也聲明了,待會在程序中要用。
3. 在源程序Pcdtouch.c中添加代碼
主要是修改main程序:
至此修改完成。編譯后在模擬器中運行,結果如下:
圖2 Pcdtouch運行結果
在編寫過程中,得到的一些經驗:
程序中,應該是通過TokenSpaceGuidCname和Token來唯一確定PCD變量的,PcdCname是方便程序員識別的(待確認);
而對于Dynamic類型,DEC中是在[PcdsDynamic]下定義,在DSC中則在[PcdsDynamicDefault](或者PcdsDynamicHii、PcdsDynamicVpd)。名字都是確定的,可查看DSC和DEC文件規(guī)范;
后續(xù)再繼續(xù)加深理解。
Gitee地址:https://gitee.com/luobing4365/uefi-exolorer
項目代碼位于:/ FF RobinPkg/RobinPkg/Applications/Pcdtouch下
總結
以上是生活随笔為你收集整理的UEFI开发探索101 – PCD探究的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【matplotlib】画图怎样将中文为
- 下一篇: 北京理工大学计算机面试题,北京理工大学自