UEFI與硬體初始化

UEFI論壇的PI 規範允許使用模塊化的方法支持晶元和硬體平台的初始化。這其中包括:系統初始化,引導,以及引導前的特殊配置需求。

在BIOS領域採用UEFI規範後的巨大影響是有目共睹的。如今,UEFI已是固件,操作系統,附加設備和其他行業標準的必備組件。基於Intel架構的PC生態系統中的大多數產品都是基於原先的EFI規範或其繼任者:UEFI規範,或是PI規範。這些規範已成為X86架構的PC生態系統中硬體初始化的基石。

本文將探討如何應用UEFI平台初始化(PI)規範作為使能晶元和硬體平台的框架。我們將學習和了解規範提供的構建塊元素,還會對平台啟動過程,獨特模式和常見用途做一些介紹。此外,我們還將檢視各類處理器,內存和圖形控制器以及支持晶元的驅動程序。

介紹與回顧

在過去的十年中,PC悄然經歷了一場由晶元使能化推動的革命。行業從單一的PC演化成為採用多種架構的不同產品線,引入了可擴展的和面向組件的工業標準固件架構 ,同時BIOS環境採納了這些架構和規範。這場革命的開始有很多原因,但最主要的是由於需要以具有成本效益的方式初始化和使用日益複雜的晶元和產品。

定義:何謂晶元使能化?實則英文原詞為silicon enabling,硅使能?如何理解呢?其實不複雜,首先強調一點,公司的存在當然是為了盈利的。又有個比方說,假如你買了一堆積木,先想了下要搭個什麼東西,然後你就通過各種方法把他搭成了你預想的樣子。晶元(Silicon)製造商做的事情其實差不多,首先,他要購入硅,塑料,各種金屬(買積木),通過技術把這些東西有機組合在一起,使其「變廢為寶「(按自己想法搭建),變成了具有各種用途的晶元,然後宣傳其特點,試圖賣出這些商品來獲利(展示給別人看)。這些商品也和其他常見商品一樣,具有性狀,使用方法等特點,也隨商品附贈使用手冊,只不過這裡的使用手冊的內容包括的是:晶元規範,參考代碼,二進位模塊,默認設置等較專業內容。而OEM的責任就是使用這些晶元搭建出終端用戶使用的產品。概括的說:silicon enabling指代的是OEM如何使用晶元,從無到有製造產品,開發/使用/配套驅動到整個產品可用的過程。讀者應理解,本文譯作晶元使能化並不完整,但可用來強調文章解釋的重點在於晶元的軟硬體初始化實現,而不包括原意中晶元的硬體製造階段。

不同的需求催生了行業標準的制定。但即便在有明確需求的情況下,行業標準也不僅僅是寫入文件就算制定成功的。UEFI論壇所制定的PI架構之所以成為「廣泛接受和認可的可擴展工業標準架構」並作為一種標準,基於以下五個原因:

? 它被寫入UEFI平台初始化規範中。提供了二進位可互操作組件架構,其主要作用是在載入OS之前進行晶元初始化。它通常被認為是一個BIOS架構規範。

?它在兩個開源軟體開發環境(EFI開發套件(EDK)和EDK II)中得到實現; 這些工具都可在Build software better, together上找到。這些工具包提供了可用性強,易重複使用的實現方式,模塊開發商可以作為參考,來構建各種符合UEFI和PI規範的產品。

?它在BIOS產品中被實例化為事實上的標準實現,通過被稱為Intel Green H的概念(包含工業標準介面的頭文件等)。 只需要最小程度的移植,就可以在多個多個BIOS代碼庫中的使用。

?它可以使用UEFI發布的自認證測試(Self-Certification Test,簡稱SCT)進行測試。 SCT會檢查各種UEFI規範中定義的介面的實現是否符合標準。

?他被行業領先的硬體,軟體,系統生產商應用,因而市場需求量很高。

?提供了大量的平台和晶元參考代碼實現,譬如CPU,SIO,開放硬體平台(Minnow系列和Galilo)。

作為一個BIOS軟體標準,必須要符合這樣一個特殊要求:必須能支持多種不同活動。我們在此重點討論其中兩個:硬體初始化和系統調試。它涉及到源代碼和二進位模塊的兼容性和互操作性。 通過符合該要求以便有效地實現面向組件的架構,該架構由整個行業中支持Intel架構的PC生態系統的眾多公司使用。以我們之前講過的PI為例,二進位的兼容性由規範文檔和測試(SCT)保證,源代碼兼容性通過EDK和Intel Green H實現。靠著全行業內BIOS,硬體,和軟體供應商的支持,PI得到了全面普及。

為了更好地探究如今的晶元Enabling支持環境,有必要重溫PI定義本身,和基於它的可擴展的晶元初始化模型,以及可能的機遇。

PI的架構

什麼是BIOS?名字是basic input/output system的縮寫。BIOS的終極目標是初始化硬體平台並引導操作系統。

最早的PC/XT系統的BIOS只有8KB,也能啟動DOS。那是在1982年,IBM發明了它。從那以後在經歷了一段平靜期後,BIOS得到了飛速進化,尤其在UEFI誕生後。

我們把最初的BIOS稱為傳統BIOS,稱UEFI類引導代碼為UEFI,不論是哪一樣,一些重要的職責都是不變的:首先,二者都有平台初始化的重要使命。這一過程其實是在平台重啟(s3,s5及其他)之後立即執行的一段代碼。傳統BIOS中,這是供應商特定的流程和結構,但很多時候只是些不需要堆棧的彙編代碼和啟動塊,不同的BIOS廠商(IBV)直接的代碼差距很大,不具備互操作性,規範性很低。而在UEFI中,針對這一過程,提出了專門的平台初始化標準(UEFI PI Spec)。在基於PI的平台初始化中,SEC和PEI階段肩負前期初始化的責任。基於UEFI PI的引導的時序關係如下圖所示:

之後,每個硬體平台都需要發現I / O匯流排,從主機匯流排適配器調度opROM(option ROM)等等。 在傳統BIOS中,此I / O枚舉發生在上電自檢(Power On Self Test,簡稱POST)階段。在常規BIOS上沒有POST的真正標準。 但是,對於基於UEFI PI的固件,此階段的執行發生在驅動程序執行環境(DXE)中。DXE還可以作為UEFI核心,用於支持基於UEFI的操作系統。

在BIOS POST和DXE之後,就到了標準描述的平台介面部分。對於PC / AT BIOS,該標準包括在x86架構上以16位實模式執行的事實上的中斷可調用介面(例如,磁碟的Int13h,視頻的Int10h)。對於UEFI,則是UEFI引導服務和協議protocol(例如,EFI_BLOCK_IO_PROTOCOL與BIOS int13h類似),由UEFI規範對此進行詳細說明。在該階段執行期間,第三方驅動可以從磁碟或外置適配器中讀取而未必由平台製造商(PM)系統板提供。

上文所述的二者區別至關重要,因為從一個抽象的,由PM提供的執行規則轉變成為具體的,第三方代碼可以運行的空間,這一實現的質量對構建可信平台有很大的影響。

下圖展示了通用BIOS初始化流程。 此流程包括在POST期間平台CPU,內存和I / O設備的初始化。 POST流程類似於前圖中的DXE流程。

UEFI固件

在硬體層之上,OS之下的安全架構就是固件,如下圖:

由於目前和將來可能有平台固件的若干種代碼的實現,因此本文將對平台初始化(PI)標準及其一些代表性的代碼庫進行討論。

作為背景,UEFI論壇的PI工作組——PIWG提供基於英特爾PEI和DXE規範的PI架構規範。PI體系結構規範於UEFI 2.0規範中獨立出來。PI架構平台仍然可以啟動現今的操作系統。AMD, AMI, Apple, Dell, HP, IBM, Insyde, Intel, Lenovo, Microsoft, and Phoenix共同擁有這一規範。PIWG的任務是允許當前創建了「參考代碼」的晶元供應商將此參考代碼打包為嵌入PI架構固件實現的模塊。下圖說明了PI範圍。

UEFI和PI規範僅作為闡述關於介面定義和機制的規範材料,但是沒有諸如為什麼這麼做和如何做的具體內容。 後者(PI)僅作為設計指南。

與傳統BIOS的單一目的性相反,UEFI PI通過闡釋驅動程序模型(例如基於依賴性表達式的PEI模塊(PEIM)和DXE驅動程序)所帶來的軟體可擴展性來實現硬體敏捷性。 可擴展性點也可能被作為惡意軟體的攻擊點。這類惡意軟體基本上不能被OS所擁有的防護技術(例如殺毒軟體)檢測到,因為惡意軟體可以在OS之前就被完整執行。因此,基於UEFI的pre-OS引導環境以及其他的pre-OS可擴展性的安全完整性基礎必須確保穩固,同時還要提供足夠的靈活性來支持硬體敏捷性。

PI階段旨在僅由平台製造商(PM)而不是第三方(與UEFI及其選項ROM /載入程序/驅動程序模型相反)可擴展。 在這個PI過程中,代碼的安裝和其行為是在平台製造商的授權下進行的; 下文中簡稱為「PM_AUTH」。讓PM才能擴展PI,保證了系統的安全性。

下圖描述了UEFI PI引導流程,包括僅PM可擴展的PI代碼和第三方可擴展UEFI。

晶元初始化

UEFI PI提供了一個軟體環境,允許晶元供應商提供幾乎所有必需的核心晶元初始化。為了本討論的目的,我們不區分UEFI和PI這兩組規範,因為二者的應用範圍中有太多類似的用於組件開發及其互操作性的基礎架構。

對於硬體自我初始化,軟體初始化硬體相對而言成本更低和靈活性更好,所以仍然是必要的。 在過去20年中,我們看到處理器從10萬晶體管增長到1000萬個以上。這種增長,帶來了一系列愈發複雜的特徵和能力。 而軟體仍然是初始化和支持這種越來越複雜的硬體的最有效的方法。

出於本文的主題考慮,我們關注的是構建X86架構系統的關鍵組件(核心晶元):處理器,內存控制器,圖形控制器,存儲控制器,系統匯流排控制器,IO控制器等。PC中當然還有許多額外的設備,但他們也可以從本文中類推而得,不在詳述。此外,這些設備往往在引導過程中的稍後時間被初始化,更多地依賴於其他工業標準,如USB,PCIE和ACPI。在某些情況下,BIOS在其初始化他們中起到的作用並不顯著。

1。晶元初始化發生在哪?

核心晶元初始化依賴於分階段的方法。在初始系統複位時,僅有部分非常有限的硬體資源可用;不能訪問設備,不能訪問存儲器等等限制。這才導致了隨著硬體的初始化以及可用資源的增加,BIOS為軟體的正常運行不斷地改變操作環境。在PI中:

? 在SEC階段,系統從複位開始運行(由主機引導處理器取回的第一指令),通過初始化處理器高速緩存(Cache)來作為臨時內存使用,我們有了堆棧,從而可以執行c程序,然後轉到PEI階段。

? 在PEI最開始階段,僅少量棧和堆可用,我們需要找到並使能足夠我們使用的永久內存,通常是內存顆粒或內存條(DIMM),然後轉入DXE。

? DXE階段有了永久存儲空間,真正開始負責初始化核心晶元,然後轉換到BDS階段。

? 核心晶元初始化完成後BDS階段開始,並繼續初始化引導操作系統(輸入,輸出和存儲設備)所需的硬體。 縱觀PI的整個階段,BDS對應的是「執行UEFI驅動程序模型」來引導OS這一過程。

流程中有幾個特殊的子階段:

? PEI pre-mem

? PEI post-mem

? SMM

? CSM

如上表所示,晶元初始化遍布整個引導過程。之所以這樣設計,而不將初始化內容放在一起完成,主要是基於成本和複雜性的考慮:隨著引導的進行,有更多的基礎架構可用,初始化一組晶元功能模塊的成本和複雜性下降。這不是說SMM初始化過程不複雜,而是說,在永久內存和DXE服務可用後,其後階段的複雜性雖仍然維持在「複雜」一級,但的確不如之前過程複雜。這裡所說的「成本」,說的是要在存儲器可用前,從未壓縮的FLASH存儲器直接執行程序(XIP)。最終結果就是,在表中列舉的大多數核心晶元初始化活動可以由PI模塊合理且廉價地實現,完成度通常能佔到全部任務的90%以上。

2。晶元初始化如何實現?

我們以Intel的方案為例,晶元初始化代碼以晶元對應的程序包(Package)的形式提供。這些封裝包可以支持單個產品,多個產品,與單個產品相關聯的類似產品,甚至可能支持跨越多種產品。樣例包括平台電源管理(platform power mamagement,簡稱PPM)參考包(其通常支持多代晶元),南橋晶元(platform controller hub,簡稱PCH)參考包(通常只支持對應一代的晶元)和集成時鐘控制器(integrated clock controller,簡稱ICC)參考包 ,ICC僅在PCH用於特定配置時才適用。對象模型的複雜性源於整個平台的複雜性以及參考包使用的靈活性。PPM參考包通常在產品開發周期的後期啟用,因此,將其與「總是必需的」處理器代碼分開封裝,為客戶提供了產品開發的靈活性。

每個包含有各種階段的驅動程序,例如memory之前的PEIM(pre-memory,PEIM),UEFI引導服務以及運行時服務(DXE),系統管理模式(system management mode,簡稱SMM)驅動以及其他。這些DLL文件通常以源形式,在常規晶元參考包中遞送,一般包含:

1.源代碼

2.自定義介面及其文檔

3.用於在開源EDK/EDKII中使用的構造文件。

4.示例代碼

5.靜態庫(static libraries)

6.設計和移植文檔

為了減少支持的配置數量,針對特定版本的工業標準介面和實用庫,開發對應的晶元參考包並通過測驗,即Intel的Green H計劃。該計劃的意義在於,通過封裝特定的一組文件,使得提供具有易集成和可重用性的源代碼而不無需修改變得可行。而經過業內討論,一致同意在頭文件中包含服務協議調用表(services tables)及公共協議(Common protocol)定義,如此一來就避免了大量的源代碼可移植性問題。

儘管PI提供了豐富的基礎服務類型,甚至有時候,他的能力顯得有些多餘,但是,用工業標準介面來覆蓋所有可能的晶元特性或許仍力有不逮。因此,參考包還提供了自定義介面。這些介面通常採取變數、HOB、PPI、Protocl,以及依賴關係(dependency)、回調和其他UEFI和PI類型的服務。利用這個「工具箱」,晶元廠家可以為「難搞」的晶元初始化提供豐富的「服務」。在當前的晶元參考封裝包中,通常還有提供一組設置介面「Policy」,允許使用者根據主板或者設計的不同來定製某些參數。所有這些既保證了晶元包的獨立性,又提供了很高的靈活性,方便OEM使用。

總的來說,使用提供代碼的晶元參考包並採用Intel Green H,OEM等使用者可以應用廣泛可用的EDK/EDKII構建模塊,他們只需關注如何將這些模塊集成到他們的BIOS構建環境並在其BIOS中發揮晶元參考封裝包的各種特性。如此一來,晶元供應商便可以提供在碎片化的環境中也能重複使用的晶元初始化實現代碼,而OEM等也可以專註於自己的核心業務。

BIOS角色的轉變

UEFI PI標準的出現成為了行業的分水嶺,從此BIOS相關各方的角色也發生了不可逆轉的變化。

1。實現一次即可

PI允許晶元供應商開發晶元初始化代碼,並使其用在各種場合下可用。以前,諸多公司各自基於所用晶元(said silicon,簡稱SI)的有限文檔來進行核心晶元初始化工作。這樣做的明顯缺點就是SI消費者在晶元上實現的初始化可能與晶元製造商的原本意圖大相徑庭。此外,SI生產商雖負責初始化代碼的實現和驗證,但對SI消費者而言它卻要自己開發,其中出現了嚴重的脫節。顯然由PI帶來的晶元初始化代碼包可以一次開發,各處使用,保證了信息的連貫和準確。

2。部署

為避免干擾敏感的模擬信號量,也出於總體布局的考慮,越來越多的SI消費者將系統板設計和SI生產商緊密聯繫起來,更多地考慮在SI初始代碼上做文章。正如上文提到的,SI生產商生產SI初始化代碼以在內部驗證SI。如果SI生產方和使用方都為其系統板固件支持了UEFI PI規範,SI生產方可發布其SI初始化模塊,同時發布SI物理器件。這樣,就可以在採用的部署模型中實現「硬體和固件」的無延時。

3。集成

支持UEFI和UEFI PI規範的系統的出現亦改變了PC固件生態系統中各個玩家的關係和責任。

在以前(UEFI和PI出現之前),晶元供應商提供參考源代碼來描述用於初始化其特定晶元或晶元組的重要初始化和配置步驟。BIOS供應商使用該代碼,對其進行修改後用到他們的代碼庫中,並將每個參考代碼段鏈接到它們的程序中。為所有客戶提供BUG修復服務費時費力費資本,因為每個客戶都經歷了鬼才知道的步驟形成了自己獨特的目標代碼庫,旁人維護何其艱難(這正是沒有規範的時候的行業困境)。BIOS的質量保證依賴於功能測試或自主開發的API測試,因為(當時)很少有明確定義的API。擴展BIOS的唯一標準方法是可選ROM,20多年來基本沒有什麼變化(從BIOS的誕生到UEFI誕生之間的時間,相較於PC性能的日新月異,這個東西一成不變顯得多麼不合群)。

隨時間的推移,許多晶元供應商開始為他們的產品研發「核心」源代碼包,並為每個他們支持的BIOS代碼庫研發「插件」層。這種方案在當時確實緩解了晶元供應商面臨的一些問題。因為現在,他們只需要鑽研一個問題,做出一點改變:就是使「核心」可以工作在所有的目標代碼庫。但也對BIOS供應商提出一個新的難題。因為每個晶元供應商都在各自研發這樣一個「插件層」,每家公司都有自己的BIOS代碼庫,有不同的晶元供應渠道。代碼的通用性其實還是沒有得到根本改善。

隨著UEFI和後來PI的推行,行業整體前進了一大步。現在每一個晶元供應商可以封裝支持他們的晶元驅動程序。規範定義了它們是如何啟動的,如何發布介面,以及如何發現介面的。因為標準化,不同的BIOS廠商代碼庫不再有千差萬別的「插件」層。使其再也不必被每個客戶(BIOS供應商或OEM)「奴役」(一家一本天書,說奴役還真不是誇張)。

這種新模式產生了一系列影響:

1. 一旦寫成,隨處可用。如果BIOS環境符合規範,符合規範的驅動可以插入到任何BIOS和他應該發揮作用的地方。

2. 晶元供應商生產驅動,隨著UEFI應用時間愈久,與晶元支持相關的所有源代碼的任何問題都會由晶元供應商負責。

3. 可測試性的提高。UEFI為啟動系統所需的一切服務都提供了明確定義的API,這些API實現的魯棒性(rubustness,來源於rubust,強壯,健壯的意思,計算機的魯棒性一般指可觀察性,可恢復性,響應性,任務規範性)對於確保互操作性至關重要。為了能充分發揮這些API的優點,UTWG(UEFI測試工作組)為每一版的規範制定了SCT。

4. 孤立到模塊化BIOS。BIOS已越來越多地作為一個平台,使眾多驅動和應用得以良好運行,而不再是一堆代碼體的雜亂堆放。

5. 驅動提供內置的可定製化。在以前的模型中,為特定平台或產品的定製化是由OEM或BIOS供應商在開發周期的後期進行處理,而且經常涉及直接修改供應商所提供代碼的操作。如今晶元供應商通過採用PI 標準的平台配置資料庫(Platform Configuration Database,簡稱PCD),策略協議以及EFI變數,在驅動中直接實現可定製化。

BIOS世界的內部工作原理一經公共規範揭露和闡釋,許多新的靈感就會紛至沓來。UEFI使得有一定代碼基礎的人都有可能進行底層的開發,相較於老舊的BIOS的晦澀,複雜,UEFI著實簡單了太多,何況還有規範的EDK供你使用,任何有想法的人都可以在自己的PC上進行驗證,正所謂眾人拾柴火焰高,UEFI BIOS功能增長之快似乎也不那麼讓人驚訝了。

互操作性例子

UEFI PI規範並沒有給你構建一個PC平台所需的一切,許多小型晶元組件——嵌入式控制器,超級I/O控制器(super I/O,也叫做I/O晶元,從486以後的主板開始採用,在南橋這樣的高速設備和串列、並行介面、軟盤驅動器及鍵盤滑鼠等大量低速設備之間必定存在資源的不匹配,而需要經過轉換和管理。Super I/O晶元則完成了該功能),OTG設備等等需要自己開發。然而,PI規範提供了可以構建質量可靠的固件的堅實基礎(雖然沒有給你磚瓦,但卻給了你土,水,和火)。

我們以PI規範中對系統管理匯流排(System Management Bus,簡稱SMBus)的支持為例,做一個比較詳細的表述。這東西本來是為支持電池管理子系統而開發的,這種雙線多主式匯流排介面已發展成用於感測器和平台管理的標準主板邊帶匯流排。自1995年推出以來,它已成為其他行業標準的一個組成部分,包括PCI,IPMI,DASH以及ASF。

規範中描述了兩個描述SMBus 主控制器的低級特性的API:EFI_PEI_SMBUS2_PPI (用於PEI階段)和 EFI_SMBUS_HC_PROTOCOL (用於DXE階段)。這些API允許在SMBus地址上發送和接收命令,而無需對硬體介面進行專門的學習:

typedef struct _EFI_SMBUS_HC_PROTOCOL {EFI_SMBUS_HC_EXECUTE_OPERATION Execute;EFI_SMBUS_HC_PROTOCOL_ARP_DEVICE ArpDevice;EFI_SMBUS_HC_PROTOCOL_GET_ARP_MAP GetArpMap;EFI_SMBUS_HC_PROTOCOL_NOTIFY Notify;} EFI_SMBUS_HC_PROTOCOL;

這個協議介面結構具有到不同抽象函數的函數指針。Execute 會通過SMBus向目標SMBus設備發送指令。ArpDevice和GetArpMap將處理SMBus地址解析協議,為SMBus設備分配唯一的地址並報告結果。當SMBus設備發送事件通知時,Notify允許其他驅動程序註冊回調。

操作者無需了解SMBus主控制器在硬體中如何實現,實際上,他都不需要知道硬體是不是真的存在。就這樣,只要Green H中定義了介面規範,晶元供應商在晶元參考代碼包中包含了其實現,OEM或IBV即可直接調用而不必考慮過多細節,互操作性得到極大提高。

後記

UEFI PI的出現,使得固件開發也可以像點菜一樣,規劃好菜式,根據口味,一項一項組合,再配上一些自己的秘方即可。從此,BIOS工程師過上了幸福的生活(不可能。。)。

UEFI的拼圖中有一塊重要的部分:UEFI驅動模型(UEFI driver model),我們會在有機會的單獨介紹。

UEFI歷史和架構其他文章:

UEFI和UEFI論壇 - 知乎專欄

UEFI背後的歷史 - 知乎專欄

ACPI與UEFI - 知乎專欄

UEFI安全啟動 - 知乎專欄

UEFI與硬體初始化 - 知乎專欄

UEFI架構 - 知乎專欄

歡迎大家關注本專欄和用微信掃描下方二維碼加入微信公眾號"UEFIBlog",在那裡有最新的文章。同時歡迎大家給本專欄和公眾號投稿!

用微信掃描二維碼加入UEFIBlog公眾號


推薦閱讀:

英特爾放話:酷睿「i9」真的要來了!

TAG:UEFI | 电脑硬件 | BIOS |