UEFI+BIOS全局配置數(shù)據(jù)庫的設計與實現(xiàn)
引言
BIOS是一組固化到計算機主板上一個ROM芯片中的程 序,它保存著計算機最重要的基本輸入輸出的程序、系統(tǒng)設 計信息、開機后自檢程序和系統(tǒng)自啟動程序。人們經(jīng)常需要重 新對FLASH芯片進行編程以便升級BIOS,以便獲得新的功能。
UEFI BIOS是目前最主流的一個BIOS架構,約占超過 70%的計算機,服務器和嵌入式市場。它是對老的BIOS開 發(fā)模式的一種徹底的革新,打破了 BIOS只能用匯編語言開發(fā) 和只能應用在計算機和服務器市場的局限性,當前越來越多的 嵌入式設備、平板、手持設備、工控設備、通信設備等都在 它的應用行列。
采用UEFI BIOS開發(fā)架構EDKII的架構,可保證同一份 核心代碼運行在不同的硬件平臺之上,僅僅需要針對平臺的特 定性來設置一些特定的參數(shù),這是EDKII架構中最難也是最 核心的一個設計部分,也就是要研究全局配置數(shù)據(jù)庫PCD。
1 UEFI 和 EDKII 簡介
2000 年,Intel 向 業(yè)界展 示了 BIOS 的 新 一 代 接口程序 EFI(Extensible FirmwareInterface),并將此技術應用于其安騰服務器平臺上。EFI 是由Intel 推出的一種在未來的電腦系統(tǒng)中用來替代 BIOS 的升級方案。2005 年,在工業(yè)界達成共識的基礎上,Intel 將 EFI 規(guī)范交給了一個由微軟、AMD、惠普等公司共同參與的工業(yè)聯(lián)盟進行管理,并將實現(xiàn)該規(guī)范的核心代碼開源于網(wǎng)站上。與此同時,EFI 也正式更名為 UEFI(Unified Extensible FirmwareInterface)。UEFI 聯(lián)盟將負責開發(fā)、管理和推廣 UEFI 規(guī)范。
UEFI 定義了操作系統(tǒng)與系統(tǒng)硬件平臺固件之間的開放接口。該規(guī)范定義的接口包括平臺相關信息、啟動服務例程以及操作系統(tǒng)運行時服務例程。操作系統(tǒng)裝載器與操作系統(tǒng)可通過接口調用這些服務例程。UEFI 規(guī)范是一個公開的純接口定義,它不依賴于某個特定的 BIOS 制造商或某個特定的 BIOS的實現(xiàn),它僅僅定義了平臺固件必須實現(xiàn)的接口,以及操作系統(tǒng)可能使用的一系列接口與數(shù)據(jù)結構,其實現(xiàn)的方式與細節(jié)均取決于該規(guī)范的實現(xiàn)者。UEFI 規(guī)范還定義了固件驅動程序模型,使得所有遵循此模型開發(fā)的固件驅動程序能夠互相協(xié)作。
不同于傳統(tǒng)的 BIOS 實現(xiàn),EDKII 基于現(xiàn)代軟件體系設計的思想,對 UEFI Framework 采用模塊化設計,并根據(jù)其執(zhí)行流程主要劃分為 :SEC、PEI、DXE、BDS、TSL、RT 和AL 等 7 個階段,其運行機理如圖 1 所示。
SEC(Security)是平臺上電后最先執(zhí)行的步驟。這個階段的主要目的是對平臺固件進行驗證,確保選擇的平臺固件映 像沒有被破壞。主要工作是初始化臨時內存區(qū)并對平臺早期初 始化代碼進行驗證。
PEI (Pre-EFI Initialization)階段有兩個主要任務:確定 重新啟動的來源和做盡可能少的工作以便尋找和初始化內存, 為DXE階段提供少量的固定內存。
DXE (Driver Execution Environment)被設計來處理與外 圍設備的通信,它通過加載驅動的方式(輪詢檢測)來為操作 系統(tǒng)的啟動管理構建環(huán)境。
BDS (Boot Device Selection)是 UEFI 擁有平臺控制權 的最后一個階段。BDS與DXE階段一起工作,為啟動操作系 統(tǒng)建立控制臺。
TSL (Transient System Load)即操作系統(tǒng)啟動管理器嘗 試引導操作系統(tǒng)的階段。
RT (Run Time)是操作系統(tǒng)啟動運行后,UEFI提供的 一組運行時服務。
AL (After Life)階段,即最后一個階段,其提供一種機 制來保證用戶在有意或者無意的情況下終止操作系統(tǒng)后,讓 UEFI重新獲得系統(tǒng)控制權。
2全局配置數(shù)據(jù)庫PCD的設計實現(xiàn)
EDKII中PCD根據(jù)其作用的時間,分兩大類,一類 是在編譯過程中起作用,這類PCD等同于C語言中的全局 靜態(tài)變量,包含 FeatureFlag PCD,F(xiàn)ixedAtBuild PCD 以及 PatchableInModule PCD三種。這類PCD跟全局配置數(shù)據(jù)庫 沒有關系,所以本文不做過多介紹。另一類是平臺初始化過 程中起作用,包括 DynamicDefault PCD,DynamicHII PCD, 和DynamicVpd PC三種應用在源代碼組件發(fā)布的PCD,以及 與之對應的 DynamicExDefault PCD,DynamicExHII PCD 和 DynamicExVpd PCD――專門應用在編譯好的二進制組件發(fā)布 中的三種PCD。
2.1 PCD的分類和區(qū)別
從大面上,全局配置數(shù)據(jù)庫中存放的PCD被分為兩個大 類Dynamic和DynamicEx,每個大類又各分三個小類Default PCD,HII PCD 和 VPD PCD。
Dynamic和DynamicEx的作用局域完全一樣,唯一的區(qū) 別就是源代碼級別的發(fā)布還是編譯好的代碼發(fā)布。如果上層開 發(fā)者給二級開發(fā)者提供的是所有驅動的源代碼,那么二級開 發(fā)者可以直接修改源代碼來改變某個參數(shù)的值,此時只要把 該配置參數(shù)設置為Dynamic形式的即可滿足要求。否則,必 須用DynamicEx的。DynamicEx的PCD在保護上層開發(fā)者 的版權和代碼發(fā)布權限提供了更多層次的選擇空間。
Default PCD :在初始化過程中,可以被PEI,DXE和 RT階段的幾乎所有驅動所使用,一般是前面的驅動修改,后 面的驅動讀取。這是不同的驅動,不同的階段之間有效信息交 互和傳遞的一種方法。該PCD的作用空間是一次加電過程, 所修改的數(shù)值在系統(tǒng)斷電后會自動回復到默認初始狀態(tài)。
HII PCD :作用空間和Default PCD 一樣,主要的區(qū)別是 HII的PCD可以把修改的數(shù)值直接保存到BIOS NOR Flash芯 片的NVRAM區(qū)域。這樣一旦修改,再計算機下次啟動的時候, 訪問的就是上次修改的新數(shù)值。
VPD PCD :作用空間和上面兩種相同,主要區(qū)別是VPD PCD是只讀的不能修改,但是它也有自己的優(yōu)勢。因為VPD PCD是的初始值是保存在BIOS固件的一段二進制數(shù)據(jù)空間 上的所以在固件編譯完成后,可以在不依賴編譯器重新編譯 情況下,對該PCD的數(shù)值進行直接的重復設置。
2.2設計原理分析
在EDKII源代碼編譯中,編譯工具集的AutoGen會 遍歷整個平臺所有驅動和頂層結構文件生成AutoGen.h和 AutoGen.c兩個關鍵文件。這兩個文件將作為后面C編譯器的 自動包換的頭文件輸入,參與C語言的系統(tǒng)級編譯過程,最 終生成這個平臺的全局配置數(shù)據(jù)庫。
下面通過一個NT32模擬平臺中的例子來進行過程說明。
首先在NT32的頂層平臺文件DEC, DSC和INF文件中 依次做如下聲明。
MdeModulePkg.dec
[PcdsFixedAtBuild, PcdsDynamic, PcdsDynamicEx]
gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariabl eBase|0x0|UINT32|0x30000001
Nt32Pkg.dsc
[PcdsDynamicExDefault.common.DEFAULT]
gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariabl eBase|0xf000
WinNtFlashMapPei.inf
[Pcd]
gEfiNt32PkgTokenSpaceGuid.PcdWinNtFlashNvStorageVariable
Base
通過該聲明,定義了一個DynamicExDefault類型的 PCD,其類型為UINT32,初始默認數(shù)值為0xf000,并且驅 動模塊WinNtFlashMapPei要使用該配置數(shù)據(jù)。
接著用EDKII的BaseTools對該源代碼架構進行編譯, AutoGen工具會在遍歷完整個代碼之后,在相應的PCD驅動 編譯目錄下面自動生成AutoGen.h和AutoGen.c兩個文件,如下所示:
Aut oGe n.h (Bu ild \ NT32\ DEBUG_MYTOOLS\I A32\
MdeModulePkg\Universal\PCD\Pei\Pcd\DEBUG)
#define PEI_LOCAL_TOKEN_NUMBER_TABLE_SIZE 3
TOC \o "1-5" \h \z
typedef struct {
UINT32PcdFlashNvStorageVariableBase_a1aff049_
fdeb_442a_b320_13ab4cb72bbc[1];
DYNAMICEX_MAPPING ExMapTable[PEI_EXMAPPING_ TABLE_SIZE];
UINT32LocalTokenNumberTable[PEI_LOCAL_
TOKEN_NUMBER_TABLE_SIZE];
GUIDGuidTable[PEI_GUID_TABLE_SIZE];
UINT8StringTable[1] ; /* _ */
SIZE_INFO SizeTable[PEI_SIZE_TABLE_SIZE];
UINT8SkuIdTable[PEI_SKUID_TABLE_SIZE];
SKU_ID SystemSkuId ;
} PEI_PCD_DATABASE_INIT ;
AutoGen.c (Build\NT32\DEBUG_MYTOOLS\IA32\
MdeModulePkg\Universal\PCD\Pei\Pcd\DEBUG)
PEI_PCD_DATABASE_INIT gPEIPcdDbInit = {
{ OxfOOOU ), /* PcdFlashNvStorageVariableBase_a1aff049_ fdeb_442a_b320_13ab4cb72bbc[1] */
/* ExMapTable */ {{ 0x30000001U, 2U, 0U }, },
/* LocalTokenNumberTable */
{
offsetof( PEI_PCD_DATABASE , Uninit. PcdFlashNvStorageFtwSpareBase_a1aff049_fdeb_442a_ b320_13ab4cb72bbc) | PCD_TYPE_DATA | PCD_DATUM_ TYPE_UINT32,
offsetof ( PEI_PCD_DATABASE , Init. PcdFlashNvStorageVariableBase_a1aff049_fdeb_442a_ b320_13ab4cb72bbc) | PCD_TYPE_DATA | PCD_DATUM_ TYPE_UINT32,
},
/* GuidTable */
{{ 0xA1AFF049, OxFDEB, 0x442a, { 0xB3, 0x20, 0x13, 0xAB, 0x4C, 0xB7, 0x2B, 0xBC }}, },
//gEfiMdeModulePkgTokenSpaceGuid
/* StringTable */ /* SizeTable *//* SkuIdTable */
};
AutoGen.h自動生成的是該數(shù)據(jù)庫的結構定義文件,它 定義了各個PCD在該數(shù)據(jù)庫中存放的數(shù)據(jù)位置、類型、偏移 量等信息。AutoGen.c則配合AutoGen.h詳細列出了各個比特 位置存放的具體數(shù)值。
當WinNtFlashMapPei驅動模塊中想要訪問該PCD數(shù)值
的時候,只需要在C語言中引用PcdGet32Ex (gEfiMdeModul ePkgTokenSpaceGuid, 0x30000001)。這時就會自動掃描 Init. ExMapTable和Init.GuidTable兩張數(shù)據(jù)庫表取得該PCD對應 的 LocalTokenNumber 數(shù)值"2U"。
而后根據(jù)映射LocalTokenNumber的數(shù)值 找 到“ offsetof ( PEI_PCD_DATABASE , Init. PcdFlashNvStorageVariableBase_a1aff049_fdeb_442a_ b320_13ab4cb72bbc) | PCD_TYPE_DATA | PCD_DATUM_ TYPE_UINT32"。
通過在 C 語言中解析 “offsetof (PEI_PCD_DATABASE, Init.PcdFlashNvStorageVariableBase_a1aff049_fdeb_442a_ b320_13ab4cb72bbc) | PCD_TYPE_DATA | PCD_DATUM_ TYPE_UINT32"的定義,就可以得到該PCD在數(shù)據(jù)庫中的 偏移量、PCD類型和數(shù)據(jù)類型信息。
其過程如圖 2 所示 :
3設計局限性和改進方法
在該數(shù)據(jù)庫生成過程中,離不開對MS, ICC或者GCC 編譯器的支持,這樣DynamicEx所宣稱的二進制固件發(fā)布模 式受到約束。換言之,想要完全的二進制驅動組件的發(fā)布,必 須讓EDKII整個平臺PCD的生成過程脫離對任何編譯器的 依賴性。
針對這個設計要求,提出了新的設計架構,其流程圖如圖3 所示 :
在新的架構中,主要改變的是AutoGen的組件,EDKII 的編譯工具集依然會遍歷整個架構的所有驅動和上層配置 文件,但它會直接生成PCD數(shù)據(jù)庫,同時生成一份包含改 數(shù)據(jù)庫結構的AutoGen.h文件和一份空的只包含注釋信息AutoGen.c 文件。AutoGen.h 和 AutoGen.c 依然采用 PEI/DXE驅動的源代碼編譯,只不過 PCD 數(shù)據(jù)庫不在依賴該過程產生,因此稍加改動,就可使 DynamicEx 真正發(fā)揮其所宣稱的作用。
4 結 語
EDKII 的 PCB 數(shù)據(jù)庫目前在國內沒有任何論文研究發(fā)表過,本文主要針對這個空白領域,分析和研究了 EDKII 最核心、最關鍵的全局數(shù)據(jù)設置數(shù)據(jù)庫 PCD 的設計和實現(xiàn),并指出了其設計的不足。隨著 UEFI BIOS 的廣泛應用,越來越多的軍用板卡、通信主板、嵌入式設備和服務器也會轉移到這個架構上。如果用一個穩(wěn)定不變的核心代碼來支持不同的設備,必然會減少維護成本,提高開發(fā)效率,以及提高設備的質量,這就是本文所研究的 PCD 技術的意義所在。
20211223_61c35c0e24e78__UEFI