1. 程式人生 > 其它 >UEFI開發探索36 – UEFI Option ROM

UEFI開發探索36 – UEFI Option ROM

圖1 UEFI Option ROM結構(From UEFI Spec 2.8 page 723)

畢竟都是脫胎於PCI/PCIE規範,和Legacy Option ROM的結構是相同的。UEFI Option ROM利用了之前保留的位元組(偏移0x04處),用來表明自己的身份。

1 UEFI Option ROM的載入過程

在MdeModulePkg的原始檔MdeModulePkg\Bus\Pci\PciBusDxe\PciOptionRomSupport.c中,可以窺見UEFI Option ROM的處理過程。原始檔中包含了處理Option ROM的8個函式:

圖2 UDK2018 MdeModulePkg中處理UEFI Option ROM的程式碼

Option ROM的執行檔案不是在Flash上執行的,它會被拷貝到記憶體中,然後在記憶體中執行。Legacy BIOS的Option ROM一般載入到0xC0000~0xE0000(即0xC000段至0xE000段),而UEFI Option ROM並沒有這樣的約定。

仔細讀讀ProcessOpRomImage()的程式碼,可以窺見處理Option Rom的過程。

ProcessOpRomImage()的入口引數只有一個:PCI_IO_DEVICE *PciDevice。這是一個指向PCI裝置的指標,包含了裝置的所有屬性以及其兄弟裝置、父裝置的資訊。資料結構PCI_IO_DEVICE定義在PciBus.h中,可以對照PCI協議去理解。

函式中用do-while迴圈對裝置進行迴圈處理,尋找到Option ROM的ROM signature(也即0xAA55)。而後對ROM結構進行分析,包括是否為EFI image、機器型別是否支援等,並建立其裝置路徑(DevicePath)。

在UEFI中,使用Device Path去描述一個裝置的位置資訊,匯流排、啟動項等也常用它來描述。進入UEFI shell的時候,出現的各裝置的字串描述,就是Device Path:

圖3 TianoCore模擬環境中的啟動資訊

Device Path共有六種,在Uefi Spec中有詳細的描述:

圖4 Device Path 分類(UEFI Spec 2.8 page 285)

函式中建立的Option ROM device path型別為MEDIA_DEVICE_PATH,這是一種能夠作為啟動項裝置的Device Path。

建立完成後,呼叫LoadImage()和StartImage(),執行Option ROM程式碼。

圖5 PciOptionRomSupport.c的ProcessOptionRomImage()

2 如何生成UEFI Option ROM

UEFI Option ROM實際上是UEFI driver的一種,EDKII提供了相應的工具,將生成檔案轉換為Option ROM。前面已經說過了,我們現在所開發的option ROM,主要是PCI Option ROM。關於PCI Option ROM的內容可以參考《EDKII Driver Writer’s Guide for UEFI 2.3.1》,以下的介紹也主要來自於這個文件。

有兩種方法可以生成PCI Option ROM映象,使用工具EfiRom轉換或直接使用EDKII的INF/FDF檔案編譯生成。

EfiRom提供了原始碼,允許使用者在任何支援EDKII的作業系統上編譯。原始碼位於\BaseTools\Source\C\EfiRom下,在我開發用的機器上(Win10),編譯後的執行檔案位於\BaseTools\Bin\Win32。

它提供的功能如下:

圖6 EfiRom功能列表

UEFI Option ROM是通過UEFI Driver轉換而來的,至於如何編寫UEFI driver,那是另外一個議題,這裡不展開。

EfiRom會對傳入的efi檔案(UEFI Driver)進行驗證,比如Rom頭是不是0xAA55、PCI資料結構標識是不是“PCIR”等。任何一項檢查不通過,則EfiRom會退出,建立Option ROM的過程將被終止。

生成命令如下:

EfiRom -f 0x9999 -i 0x8000 -e pcidriver.efi

其中,-f後指定Verdor ID,-i後指定 Device ID,-e之後給定需要轉換的檔案。更多的轉換方法,包括如何與Legacy Option ROM一起打包轉換、如何壓縮等,請參考之前提到的手冊《EDKII Driver Writer’s Guide for UEFI 2.3.1》第18章第7節。

另一種轉換方法是使用INF/FDF,在build命令執行的時候,自動呼叫efirom將其轉換為指定的Option ROM。這是我常用的方法,編譯的同時就完成了轉換過程,一個典型的INF例子如下:

圖7 INF例子

Vendor ID和Device ID可以在Inf檔案中指定,其他包括PCI類碼、PCI版本、是否對Option ROM進行壓縮(PCI_COMPRESS)都可以指定。

不管是採用EfiRom工具直接轉換,還是使用Inf檔案,都只能對一個UEFI Driver進行處理。如果需要同時管理多個UEFI Driver,以及生成多種型別的Option ROM(IA32、X64等),可以使用FDF檔案進行處理。具體的內容就不一一討論了,同樣可以參考上述的程式設計手冊。

3 軟體結構

UEFI Option ROM實質上是UEFI Driver,因此最好找一個比較“純潔”的Driver例子開始。在github的EDKII部分找了很久,始終沒有找到合適的。EDKII現在提供了開發驅動的工具 UEFI Driver Wizard,我沒有去使用過,也許很多示例都整合到這裡面去了。

最終還是使用了我以前使用的BlankDrv,我一向以這個為基礎構建UEFI Option ROM。它目前還可以在這個地方下載:

https://sourceforge.net/projects/edk2/files/EDK%20II%20Releases/Demo%20apps/

對於Driver的開發,《UEFI原理與程式設計》中說得很詳細,值得好好研究一下。不過,我的目標是開發出UEFI Option ROM,很多細節不需要深究。

所開發的Option ROM是遵循UEFI driver module的,實際上也算是PCI Driver,所以它必須實現EFI_DRIVER_BINDING_PROTOCOL,並例項化Supported(), Start(), and Stop() 這三個服務。

前面已經探討過如何啟動Option ROM了,目前我們主要關心在哪裡加上實際執行的程式碼。

大部分執行程式碼是在Start()中新增的,Start()主要的任務是啟動硬體裝置,在函式中最重要的事情是呼叫InstallProtocolInterface()或者InstallMultipleProtocolInterfaces()在ControllerHandle上安裝驅動Protocol。

而Stop()函式用來解除安裝驅動,並停止硬體裝置,基本上不需要修改BlankDrv提供的原始程式碼。

Supported()用來評估傳遞給Driver的device handle所指明的pci controller是否能被driver所驅動,主要通過Vendor ID、Device ID、Class code判定。

如前所述,具體的驅動細節可以參考其他的文件,架構搭建完後,就可以專注在Option ROM的功能實現上了。之前35篇部落格中所討論的議題,所編寫的程式碼,完全可以移植到Option ROM中,只要硬體裝置的擴充套件ROM大小足夠。

圖8 UEFI Option ROM code

4 編譯及演示

因為涉及到公司商業上的原因,原始程式碼不能貼出。我正在考慮使用另外一種PCI-E晶片做測試卡,ROM空間大些,做一些相對複雜的功能,到時再將程式碼公開。

編譯和寫入到測試卡的過程,可以參考部落格:“UEFI開發探索12 – Oprom測試板”。

這裡把測試的結果再貼一次:

圖9 UEFI Option ROM演示

至此,UEFI探索系列的主線-UEFI Option ROM的開發就完成了。

對我來說,真是個不錯的經歷。從決定寫這個系列部落格,到現在已經半年多了。每週都強迫自己坐到書桌旁開始敲字,從不習慣到成自然,現在都成為我每週必做的功課了。

在這個過程中,我完成了很多知識的補全。不過,感覺上了解越多,不理解的也越來越多。

計劃中還有14篇,將針對各個我感興趣的議題再進行整理。這個探索的旅程還遠到沒結束的時候。
————————————————
版權宣告:本文為CSDN博主「luobing4365」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處連結及本宣告。
原文連結:https://blog.csdn.net/luobing4365/article/details/102597109

參考---->

https://blog.csdn.net/luobing4365/article/details/102597109