上一章把UEFI的編譯開發和模擬器環境都搭建好了,這裏開始寫第一個應用。寫之前先簡單介紹下UEFI-edk2的源碼目錄結構,源碼目錄下主要有以下這些子目錄:
目錄名 | 說明 |
---|---|
BaseTools | 包含代碼編譯所需的二進制編譯工具集和編譯環境配置文件。 |
MdePkg | 包含各個平臺通用的基本的底層庫函數、協議和工業標準。 |
MdeModulePkg | 包含一系列各平臺通用的模塊,其中包括MdePkg中公共庫的應用模塊示例。 |
Conf | 保存編譯環境信息、編譯目標路徑以及編譯器參數,工具將在該路徑下產生3個配置文件。 |
EdkShellPkg、ShellPkg | 提供一個平臺通用的UEFIShell應用程序開發環境。 |
EdkFatBinPkg | 包含針對不同CPU架構的原始FAT驅動。 |
EmulatorPkg | 一個在Windows操作系統下可加載32/64位模擬器,提供UEFI運行環境的平臺。 |
ArmPkg、ArmPlatformPkg | 針對ARM平臺的實現,與具體平臺硬件相關。 |
NetWorkPkg、UefiCpuPkg | 網絡、CPU驅動參考實現。 |
DuetPkg | 提供基於傳統BIOS運行環境的支持庫。 |
OptionRomPkg | 提供針對不同CPU架構編譯PCI兼容映像的示例。 |
每個以Pkg結尾的目錄都是一個工程包,編譯時可以通過"build -p *Pkg*Pkg.dsc"命令編譯對應的工程包,比如編譯模擬器的工程包就可以用"build -p EmulatorPkg\Emulator\Pkg.dsc"命令。
每個工程包可以通過更改配置 *Pkg*Pkg.inf 文件來引用其他工程包中的應用和庫以及驅動模塊,部分可生成UEFI啓動固件的工程包可以通過更改配置 *Pkg*Pkg.fdf 文件來把自身或者其他工程包中的應用/庫/驅動模塊添加到目標UEFI固件中。
一、應用代碼編寫
寫應用模塊的話首先要新建一個模塊目錄,如前言的表格所述,我們這裏要創建的是一個簡單的測試程序,並不針對特定的平臺,新建的應用模塊放在MdeModulePkg\Application目錄下還是比較合適一些。這個應用模塊暫取名爲TestoneApp,同時在這個目錄下新建兩個文件TestoneApp.c和TestoneApp.inf,如下圖所示。
TestoneApp.inf是模塊的工程描述文件,有點類似Linux系統下的Makefile。TestoneApp.inf文件的內容如下:
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = TestoneApp
FILE_GUID = 12345678-ABCD-EF01-2345-123456789012
MODULE_TYPE = UEFI_APPLICATION
VERSION_STRING = 1.0
ENTRY_POINT = UefiMain
[Sources]
TestoneApp.c
[Packages]
MdePkg/MdePkg.dec
[LibraryClasses]
UefiApplicationEntryPoint
UefiLib
TestoneApp.inf文件中有着一些定義塊,各個定義塊功能如下。
[Defines] : 用於定義模塊的屬性和一些自定義變量,BASE_NAME配置的是改應用編譯後生成的EFI模塊文件名,MODULE_TYPE指定了這是一個UEFI應用模塊,ENTRY_POINT制定了該模塊的入口函數名,FILE_GUID是模塊的唯一編碼,這個可以隨便寫,只要不與其他模塊一樣就行。
[Sources] :
[Packages] : 列出本模塊引用到的包的包聲明文件。
[LibraryClasses] : 需要列出本模塊使用到的庫。
接着看TestoneApp.c源碼文件,源碼功能很簡單,就是打印一個"Hello, world!"的字符串。注意字符串前面需要加L字母,表面該字符串是一Unicode的字符串。
#include <Uefi.h>
#include <Library/UefiLib.h>
EFI_STATUS EFIAPI UefiMain(
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable){
Print(L"Hello, world!\r\n");
return EFI_SUCCESS;
}
二、編譯自定義應用
編譯測試應用模塊的話,把模塊的配置文件路徑添加到EmulatorPkg包的工程配置文件即可。打開EmulatorPkg\EmulatorPkg.dsc文件,在其[Components]塊下面添加"MdeModulePkg/Application/TestoneApp/TestoneApp.inf"。
現在就可編譯EmulatorPkg工程包了,在cmd命令行裏面執行build命令或者通過visual stdio編譯EmulatorPkg工程。編譯完成後除了生成默認的WinHost.exe(虛擬機程序)和FV_RECOVERY.fd(UEFI固件)之外,也生成了我們添加的應用模塊TestoneApp.efi,如下圖所示。
通過visual studio編譯EmulatorPkg工程的時候,這裏會遇到報"‘gbk’ codec can’t encode character ‘\u2cbf’ in position"錯誤的情況,因爲TestoneApp.c文件中L"Hello, world!"字符串是Unicode編碼,gdk解析不了,這個錯誤可以通過更改源碼文件或者配置系統編碼解決,我建議是將直接windows系統的默認編碼改成UTF-8,這樣方便代碼在windows和Linux平臺下遷移。
三、運行應用
啓動模擬器,等到固件運行到UEFI shell後,通過ls命令可以查看生成的efi模塊文件位置,然後直接執行該模塊文件即可,如下圖所示。
四、調試應用
同樣通過visual studio軟件打開 $(edk2-base)\EmulatorPkg\Win\VS2017\Win.sln 工程文件,然後在visual studio工程中打開 $(edk2-base)\MdeModulePkg\Application\TestoneApp\TestoneApp.c 文件,在"Print(L"Hello, world!\r\n"); " 這一行代碼打上斷點,以調試模式編譯運行工程,即可調試該應用了。