高云嶺 莊克良 丁守芳
摘 要:EDKII是目前最流行的一個高度分層和抽象化UEFI BIOS的開發架構,它針對不同平臺硬件參數設置引入了新的設計概念PCD。PCD就是在計算機系統初始化過程中建立起來的一個全局平臺配置數據庫,它為整個平臺的驅動,函數庫和模塊組提供了有效的信息共享和設置機制。研究了數據庫建立和使用的流程和方法,同時指出該數據庫平臺在非源代碼發布中的一些設計弊端。
關鍵詞:EDKII;UEFI;BIOS;PCD
中圖分類號:TP393 文獻標志碼:A 文章編號:2095-1302(2014)10-00-03
0 引 言
BIOS是一組固化到計算機主板上一個ROM芯片中的程序,它保存著計算機最重要的基本輸入輸出的程序、系統設計信息、開機后自檢程序和系統自啟動程序。人們經常需要重新對FLASH芯片進行編程以便升級BIOS,以便獲得新的功能。
UEFI BIOS是目前最主流的一個BIOS架構,約占超過70%的計算機,服務器和嵌入式市場。它是對老的BIOS開發模式的一種徹底的革新,打破了BIOS只能用匯編語言開發和只能應用在計算機和服務器市場的局限性,當前越來越多的嵌入式設備、平板、手持設備、工控設備、通信設備等都在它的應用行列。
采用UEFI BIOS開發架構EDKII的架構,可保證同一份核心代碼運行在不同的硬件平臺之上,僅僅需要針對平臺的特定性來設置一些特定的參數,這是EDKII架構中最難也是最核心的一個設計部分,也就是要研究全局配置數據庫PCD。
1 UEFI和EDKII簡介
2000年,Intel向業界展示了BIOS的新一代接口程序EFI (Extensible Firmware Interface),并將此技術應用于其安騰服務器平臺上。EFI是由Intel推出的一種在未來的電腦系統中用來替代BIOS的升級方案。2005年,在工業界達成共識的基礎上,Intel將EFI規范交給了一個由微軟、AMD、惠普等公司共同參與的工業聯盟進行管理,并將實現該規范的核心代碼開源于網站上。與此同時,EFI也正式更名為UEFI(Unified Extensible Firmware Interface)。UEFI聯盟將負責開發、管理和推廣UEFI規范。
UEFI定義了操作系統與系統硬件平臺固件之間的開放接口。該規范定義的接口包括平臺相關信息、啟動服務例程以及操作系統運行時服務例程。操作系統裝載器與操作系統可通過接口調用這些服務例程。UEFI規范是一個公開的純接口定義,它不依賴于某個特定的BIOS制造商或某個特定的BIOS的實現,它僅僅定義了平臺固件必須實現的接口,以及操作系統可能使用的一系列接口與數據結構,其實現的方式與細節均取決于該規范的實現者。UEFI規范還定義了固件驅動程序模型,使得所有遵循此模型開發的固件驅動程序能夠互相協作。
不同于傳統的BIOS實現,EDKII基于現代軟件體系設計的思想,對UEFI Framework采用模塊化設計,并根據其執行流程主要劃分為:SEC、PEI、DXE、BDS、TSL、RT和AL等7個階段,其運行機理如圖1所示。
SEC(Security)是平臺上電后最先執行的步驟。這個階段的主要目的是對平臺固件進行驗證,確保選擇的平臺固件映像沒有被破壞。主要工作是初始化臨時內存區并對平臺早期初始化代碼進行驗證。
PEI(Pre-EFI Initialization)階段有兩個主要任務:確定重新啟動的來源和做盡可能少的工作以便尋找和初始化內存,為DXE階段提供少量的固定內存。
DXE(Driver Execution Environment)被設計來處理與外圍設備的通信,它通過加載驅動的方式(輪詢檢測)來為操作系統的啟動管理構建環境。
BDS(Boot Device Selection)是UEFI擁有平臺控制權的最后一個階段。BDS與DXE階段一起工作,為啟動操作系統建立控制臺。
TSL(Transient System Load)即操作系統啟動管理器嘗試引導操作系統的階段。
RT(Run Time)是操作系統啟動運行后,UEFI提供的一組運行時服務。
AL(After Life)階段,即最后一個階段,其提供一種機制來保證用戶在有意或者無意的情況下終止操作系統后,讓UEFI重新獲得系統控制權。
2 全局配置數據庫PCD的設計實現
EDKII中PCD根據其作用的時間,分兩大類,一類是在編譯過程中起作用,這類PCD等同于C語言中的全局靜態變量,包含FeatureFlag PCD, FixedAtBuild PCD以及PatchableInModule PCD三種。這類PCD跟全局配置數據庫沒有關系,所以本文不做過多介紹。另一類是平臺初始化過程中起作用,包括DynamicDefault PCD, DynamicHII PCD, 和DynamicVpd PC三種應用在源代碼組件發布的PCD,以及與之對應的DynamicExDefault PCD, DynamicExHII PCD 和DynamicExVpd PCD——專門應用在編譯好的二進制組件發布中的三種PCD。
2.1 PCD的分類和區別
從大面上,全局配置數據庫中存放的PCD被分為兩個大類Dynamic和DynamicEx,每個大類又各分三個小類Default PCD, HII PCD和VPD PCD。
Dynamic和DynamicEx的作用局域完全一樣,唯一的區別就是源代碼級別的發布還是編譯好的代碼發布。如果上層開發者給二級開發者提供的是所有驅動的源代碼,那么二級開發者可以直接修改源代碼來改變某個參數的值,此時只要把該配置參數設置為Dynamic形式的即可滿足要求。否則,必須用DynamicEx的。DynamicEx的PCD在保護上層開發者的版權和代碼發布權限提供了更多層次的選擇空間。
Default PCD:在初始化過程中,可以被PEI,DXE和RT階段的幾乎所有驅動所使用,一般是前面的驅動修改,后面的驅動讀取。這是不同的驅動,不同的階段之間有效信息交互和傳遞的一種方法。該PCD的作用空間是一次加電過程,所修改的數值在系統斷電后會自動回復到默認初始狀態。
HII PCD:作用空間和Default PCD一樣,主要的區別是HII的PCD可以把修改的數值直接保存到BIOS NOR Flash芯片的NVRAM區域。這樣一旦修改,再計算機下次啟動的時候,訪問的就是上次修改的新數值。
VPD PCD:作用空間和上面兩種相同,主要區別是VPD PCD是只讀的不能修改,但是它也有自己的優勢。因為VPD PCD是的初始值是保存在BIOS固件的一段二進制數據空間上的所以在固件編譯完成后,可以在不依賴編譯器重新編譯情況下,對該PCD的數值進行直接的重復設置。
2.2 設計原理分析
在EDKII源代碼編譯中,編譯工具集的AutoGen會遍歷整個平臺所有驅動和頂層結構文件生成AutoGen.h和AutoGen.c兩個關鍵文件。這兩個文件將作為后面C編譯器的自動包換的頭文件輸入,參與C語言的系統級編譯過程,最終生成這個平臺的全局配置數據庫。
下面通過一個NT32模擬平臺中的例子來進行過程說明。
首先在NT32的頂層平臺文件DEC, DSC和INF文件中依次做如下聲明。
MdeModulePkg.dec
[PcdsFixedAtBuild, PcdsDynamic, PcdsDynamicEx]
gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase|0x0|UINT32|0x30000001
Nt32Pkg.dsc
[PcdsDynamicExDefault.common.DEFAULT]
gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase|0xf000
WinNtFlashMapPei.inf
[Pcd]
gEfiNt32PkgTokenSpaceGuid.PcdWinNtFlashNvStorageVariableBase
通過該聲明,定義了一個DynamicExDefault類型的PCD,其類型為UINT32,初始默認數值為0xf000,并且驅動模塊WinNtFlashMapPei要使用該配置數據。
接著用EDKII的BaseTools對該源代碼架構進行編譯,AutoGen工具會在遍歷完整個代碼之后,在相應的PCD驅動編譯目錄下面自動生成AutoGen.h和AutoGen.c兩個文件,如下所示:
AutoGen.h (Build\NT32\DEBUG_MYTOOLS\IA32\MdeModulePkg\Universal\PCD\Pei\Pcd\DEBUG)
#define PEI_LOCAL_TOKEN_NUMBER_TABLE_SIZE 3
#define PEI_LOCAL_TOKEN_NUMBER 3
#define PEI_EXMAPPING_TABLE_SIZE 1U
#define PEI_EX_TOKEN_NUMBER 1U
#define PEI_SIZE_TABLE_SIZE 2U
typedef struct {
UINT32 PcdFlashNvStorageVariableBase_a1aff049_fdeb_442a_b320_13ab4cb72bbc[1];
DYNAMICEX_MAPPING ExMapTable[PEI_EXMAPPING_TABLE_SIZE];
UINT32 LocalTokenNumberTable[PEI_LOCAL_TOKEN_NUMBER_TABLE_SIZE];
GUID GuidTable[PEI_GUID_TABLE_SIZE];
UINT8 StringTable[1]; /* _ */
SIZE_INFO SizeTable[PEI_SIZE_TABLE_SIZE];
UINT8 SkuIdTable[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 = {
{ 0xf000U }, /* 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, 0xFDEB, 0x442a, { 0xB3, 0x20, 0x13, 0xAB, 0x4C, 0xB7, 0x2B, 0xBC }},},
//gEfiMdeModulePkgTokenSpaceGuid
/* StringTable */ /* SizeTable *//* SkuIdTable */
};
AutoGen.h自動生成的是該數據庫的結構定義文件,它定義了各個PCD在該數據庫中存放的數據位置、類型、偏移量等信息。AutoGen.c則配合AutoGen.h詳細列出了各個比特位置存放的具體數值。
當WinNtFlashMapPei驅動模塊中想要訪問該PCD數值的時候,只需要在C語言中引用PcdGet32Ex(gEfiMdeModulePkgTokenSpaceGuid, 0x30000001)。這時就會自動掃描Init.ExMapTable 和Init.GuidTable兩張數據庫表取得該PCD對應的LocalTokenNumber數值 “2U”。
而后根據映射LocalTokenNumber的數值找到“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在數據庫中的偏移量、PCD類型和數據類型信息。
其過程如圖2所示:
圖2 PCD訪問過程
3 設計局限性和改進方法
在該數據庫生成過程中,離不開對MS, ICC或者GCC編譯器的支持,這樣DynamicEx所宣稱的二進制固件發布模式受到約束。換言之,想要完全的二進制驅動組件的發布,必須讓EDKII整個平臺PCD的生成過程脫離對任何編譯器的依賴性。
針對這個設計要求,提出了新的設計架構,其流程圖如圖3所示:
圖3 PCD數據庫生成流程改進
在新的架構中,主要改變的是AutoGen的組件,EDKII的編譯工具集依然會遍歷整個架構的所有驅動和上層配置文件,但它會直接生成PCD數據庫,同時生成一份包含改數據庫結構的AutoGen.h文件和一份空的只包含注釋信息AutoGen.c文件。AutoGen.h和AutoGen.c依然采用PEI/DXE驅動的源代碼編譯,只不過PCD數據庫不在依賴該過程產生,因此稍加改動,就可使DynamicEx真正發揮其所宣稱的作用。
4 結 語
EDKII的PCB數據庫目前在國內沒有任何論文研究發表過,本文主要針對這個空白領域,分析和研究了EDKII 最核心、最關鍵的全局數據設置數據庫PCD的設計和實現,并指出了其設計的不足。隨著UEFI BIOS的廣泛應用,越來越多的軍用板卡、通信主板、嵌入式設備和服務器也會轉移到這個架構上。如果用一個穩定不變的核心代碼來支持不同的設備,必然會減少維護成本,提高開發效率,以及提高設備的質量,這就是本文所研究的PCD技術的意義所在。
參考文獻
[1] UEFI Forum. UEFI Specification. Version 2.3[EB/OL]. http://www.uefi.org/specs,2010
[2] UEFI Forum. UEFI Platform Initialization Specification. Version 1.2. [EB/OL]. http://www.uefi.org/specs,2010
[3] Vincent Zimmer. Beyond BIOS[M]. Intel corporation,2006.
[4] Framework Open Source Community. Pre_EFI Initialization Core Interface [EB/OL].http://www.uefi.org/specs,2008
[5] Intel Corporation.EDK II C Coding Standard[S]. 2006
[6] 倪光南. UEFI BIOS是軟件業的藍海[EB/OL]. http://soft.chinabyte.com/90/3382590_1.shtml,2007
[7] Gaurav Banga. EFI/UEFI 將帶領PC產業進入下一世代[EB/OL].
offsetof(PEI_PCD_DATABASE, Init.PcdFlashNvStorageVariableBase_a1aff049_fdeb_442a_b320_13ab4cb72bbc) | PCD_TYPE_DATA | PCD_DATUM_TYPE_UINT32,
},
/* GuidTable */
{{ 0xA1AFF049, 0xFDEB, 0x442a, { 0xB3, 0x20, 0x13, 0xAB, 0x4C, 0xB7, 0x2B, 0xBC }},},
//gEfiMdeModulePkgTokenSpaceGuid
/* StringTable */ /* SizeTable *//* SkuIdTable */
};
AutoGen.h自動生成的是該數據庫的結構定義文件,它定義了各個PCD在該數據庫中存放的數據位置、類型、偏移量等信息。AutoGen.c則配合AutoGen.h詳細列出了各個比特位置存放的具體數值。
當WinNtFlashMapPei驅動模塊中想要訪問該PCD數值的時候,只需要在C語言中引用PcdGet32Ex(gEfiMdeModulePkgTokenSpaceGuid, 0x30000001)。這時就會自動掃描Init.ExMapTable 和Init.GuidTable兩張數據庫表取得該PCD對應的LocalTokenNumber數值 “2U”。
而后根據映射LocalTokenNumber的數值找到“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在數據庫中的偏移量、PCD類型和數據類型信息。
其過程如圖2所示:
圖2 PCD訪問過程
3 設計局限性和改進方法
在該數據庫生成過程中,離不開對MS, ICC或者GCC編譯器的支持,這樣DynamicEx所宣稱的二進制固件發布模式受到約束。換言之,想要完全的二進制驅動組件的發布,必須讓EDKII整個平臺PCD的生成過程脫離對任何編譯器的依賴性。
針對這個設計要求,提出了新的設計架構,其流程圖如圖3所示:
圖3 PCD數據庫生成流程改進
在新的架構中,主要改變的是AutoGen的組件,EDKII的編譯工具集依然會遍歷整個架構的所有驅動和上層配置文件,但它會直接生成PCD數據庫,同時生成一份包含改數據庫結構的AutoGen.h文件和一份空的只包含注釋信息AutoGen.c文件。AutoGen.h和AutoGen.c依然采用PEI/DXE驅動的源代碼編譯,只不過PCD數據庫不在依賴該過程產生,因此稍加改動,就可使DynamicEx真正發揮其所宣稱的作用。
4 結 語
EDKII的PCB數據庫目前在國內沒有任何論文研究發表過,本文主要針對這個空白領域,分析和研究了EDKII 最核心、最關鍵的全局數據設置數據庫PCD的設計和實現,并指出了其設計的不足。隨著UEFI BIOS的廣泛應用,越來越多的軍用板卡、通信主板、嵌入式設備和服務器也會轉移到這個架構上。如果用一個穩定不變的核心代碼來支持不同的設備,必然會減少維護成本,提高開發效率,以及提高設備的質量,這就是本文所研究的PCD技術的意義所在。
參考文獻
[1] UEFI Forum. UEFI Specification. Version 2.3[EB/OL]. http://www.uefi.org/specs,2010
[2] UEFI Forum. UEFI Platform Initialization Specification. Version 1.2. [EB/OL]. http://www.uefi.org/specs,2010
[3] Vincent Zimmer. Beyond BIOS[M]. Intel corporation,2006.
[4] Framework Open Source Community. Pre_EFI Initialization Core Interface [EB/OL].http://www.uefi.org/specs,2008
[5] Intel Corporation.EDK II C Coding Standard[S]. 2006
[6] 倪光南. UEFI BIOS是軟件業的藍海[EB/OL]. http://soft.chinabyte.com/90/3382590_1.shtml,2007
[7] Gaurav Banga. EFI/UEFI 將帶領PC產業進入下一世代[EB/OL].
offsetof(PEI_PCD_DATABASE, Init.PcdFlashNvStorageVariableBase_a1aff049_fdeb_442a_b320_13ab4cb72bbc) | PCD_TYPE_DATA | PCD_DATUM_TYPE_UINT32,
},
/* GuidTable */
{{ 0xA1AFF049, 0xFDEB, 0x442a, { 0xB3, 0x20, 0x13, 0xAB, 0x4C, 0xB7, 0x2B, 0xBC }},},
//gEfiMdeModulePkgTokenSpaceGuid
/* StringTable */ /* SizeTable *//* SkuIdTable */
};
AutoGen.h自動生成的是該數據庫的結構定義文件,它定義了各個PCD在該數據庫中存放的數據位置、類型、偏移量等信息。AutoGen.c則配合AutoGen.h詳細列出了各個比特位置存放的具體數值。
當WinNtFlashMapPei驅動模塊中想要訪問該PCD數值的時候,只需要在C語言中引用PcdGet32Ex(gEfiMdeModulePkgTokenSpaceGuid, 0x30000001)。這時就會自動掃描Init.ExMapTable 和Init.GuidTable兩張數據庫表取得該PCD對應的LocalTokenNumber數值 “2U”。
而后根據映射LocalTokenNumber的數值找到“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在數據庫中的偏移量、PCD類型和數據類型信息。
其過程如圖2所示:
圖2 PCD訪問過程
3 設計局限性和改進方法
在該數據庫生成過程中,離不開對MS, ICC或者GCC編譯器的支持,這樣DynamicEx所宣稱的二進制固件發布模式受到約束。換言之,想要完全的二進制驅動組件的發布,必須讓EDKII整個平臺PCD的生成過程脫離對任何編譯器的依賴性。
針對這個設計要求,提出了新的設計架構,其流程圖如圖3所示:
圖3 PCD數據庫生成流程改進
在新的架構中,主要改變的是AutoGen的組件,EDKII的編譯工具集依然會遍歷整個架構的所有驅動和上層配置文件,但它會直接生成PCD數據庫,同時生成一份包含改數據庫結構的AutoGen.h文件和一份空的只包含注釋信息AutoGen.c文件。AutoGen.h和AutoGen.c依然采用PEI/DXE驅動的源代碼編譯,只不過PCD數據庫不在依賴該過程產生,因此稍加改動,就可使DynamicEx真正發揮其所宣稱的作用。
4 結 語
EDKII的PCB數據庫目前在國內沒有任何論文研究發表過,本文主要針對這個空白領域,分析和研究了EDKII 最核心、最關鍵的全局數據設置數據庫PCD的設計和實現,并指出了其設計的不足。隨著UEFI BIOS的廣泛應用,越來越多的軍用板卡、通信主板、嵌入式設備和服務器也會轉移到這個架構上。如果用一個穩定不變的核心代碼來支持不同的設備,必然會減少維護成本,提高開發效率,以及提高設備的質量,這就是本文所研究的PCD技術的意義所在。
參考文獻
[1] UEFI Forum. UEFI Specification. Version 2.3[EB/OL]. http://www.uefi.org/specs,2010
[2] UEFI Forum. UEFI Platform Initialization Specification. Version 1.2. [EB/OL]. http://www.uefi.org/specs,2010
[3] Vincent Zimmer. Beyond BIOS[M]. Intel corporation,2006.
[4] Framework Open Source Community. Pre_EFI Initialization Core Interface [EB/OL].http://www.uefi.org/specs,2008
[5] Intel Corporation.EDK II C Coding Standard[S]. 2006
[6] 倪光南. UEFI BIOS是軟件業的藍海[EB/OL]. http://soft.chinabyte.com/90/3382590_1.shtml,2007
[7] Gaurav Banga. EFI/UEFI 將帶領PC產業進入下一世代[EB/OL].