嗨我是k66,久等了終於可以進到UEFI程式碼階段~今天實作Day3的No Pig Killing,這次不用asm而用efi。如Day5提的UEFI開機流程,除Security部分,其餘皆使用C語言,故以下開發我們皆使用C語言。我們會在EDK2上開發UEFI Application,故會與標準C寫法不同。不知道EDK2的人請看[註1]。要輸出No Pig Killing,標準C寫法是:
#include <stdio.h>
int main{
printf("No Pig Killing!\n");
return 0;
}
UEFI APPICATION分3類:UefiMain
、main
、ShellAppMain
,此三種皆能在UEFI Shell上運行。本篇會以第一類UefiMain
實作,然而此類做法的C語言是不支援標準函數庫stdio.h
的,支援的做法是第二類main
,將在Day10實作。繼續回到本日主題,EDK2程式碼龐大,重點不外乎:
1. 先建立一資料夾: XXPkg // 沒硬性規定,以此命名的好處是未來看到Pkg字樣就知道是個資料夾
2. 在資料夾內建立: XX.c
3. 在資料夾內建立: XX.inf // 注意: inf檔名需與c檔名相同
4. 在資料夾內建立: XXPkg.dsc // 注意: dsc檔名需與資料夾檔名相同,故要有*Pkg*
5. 開始寫第二步到第四步的檔案內容。
6. 修改Conf\target.txt
7. 執行
1. 建一資料夾: NoPigKillPkg
2. 建: NoPigKill.c
3. 建: NoPigKill.inf
4. 建: NoPigKillPkg.dsc // 注意要有*Pkg*
#include<Uefi.h> // Uefi所需最基本庫
#include<Library/UefiLib.h> // Print庫
EFI_STATUS // 宣告函數的型別,實作UEFI APPICATION使用EFI_STATUS是硬性規定。
UefiMain(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) // 宣告UefiMain()函式,名稱要與INF檔的ENTRY_POINT名稱一致。
{
Print(L"No pig killing!\n"); // 輸出字串,L: Long
return 0; // C語言函數一定得有返回值
}
[Defines]
INF_VERSION = 0x00010006 // 建議此版本
BASE_NAME = NoPigKill // c的檔名
FILE_GUID = 812f9633-219f-4e1e-b665-a1252870bfad // 需一GUID,請去guidgen.com生成一組
MODULE_TYPE = UEFI_APPLICATION // 使我們能在UEFI shell執行之
ENTRY_POINT = UefiMain // 填NoPigKill.c的進入點函數名稱
[Sources]
NoPigKill.c // 請Compiler執行NoPigKill.c
[Packages]
MdePkg/MdePkg.dec // 使用到的Library來自MdePkg
[LibraryClasses]
UefiApplicationEntryPoint // 使用到的Library
UefiLib // 使用到的Library,Print()
[LibraryClasses]就是要寫這麼多...
[Defines]
PLATFORM_NAME = NoPigKillPkg // 資料夾名稱
PLATFORM_GUID = f2b2247d-b9ce-4ced-a58c-a534925ab4e3 // 需一GUID,需與inf的不同
PLATFORM_VERSION = 0.1 // 需給一版本號,自訂
DSC_SPECIFICATION = 0x00010005 // 建議此版本
SUPPORTED_ARCHITECTURES = X64 // X64表示x86的64位元
BUILD_TARGETS = DEBUG|RELEASE // DEBUG或RELEASE
// [LibraryClasses]寫所有需要用到的inf,通常先填UefiLib和UefiApplicationEntryPoint,
// 及c有用到的函式如Print()的BasePrintLib,其他就看報錯缺什麼填什麼。寫UEFI APPLICATION最痛苦之處~
[LibraryClasses]
UefiLib|MdePkg/Library/UefiLib/UefiLib.inf
UefiApplicationEntryPoint|MdePkg/Library/UefiApplicationEntryPoint/UefiApplicationEntryPoint.inf
PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
DebugLib|MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.inf
BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
BaseLib|MdePkg/Library/BaseLib/BaseLib.inf
UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf
DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf
UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf
RegisterFilterLib|MdePkg/Library/RegisterFilterLibNull/RegisterFilterLibNull.inf
DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf
[Components]
NoPigKillPkg/NoPigKill.inf // NoPigKill.inf位置
ACTIVE_PLATFORM = NoPigKillPkg/NoPigKillPkg.dsc
k66run1.bat
edk2setup.bat Rebuild
build // 看到Done表示編譯成功,後續可將efi[註2]放至QEMU執行(Day7有完整做法)
畫面如下:
恭喜完成!我們明天見!
[註1] EDK2是現代實現UEFI的跨平台開發環境,前兩篇文下載工具列表就有EDK2。
[註2] C:\edk2space\edk2\Build\NoPigKillPkg\DEBUG_VS2019\X64\NoPigKill.efi
Day3實作OinkBootloader.asm時,豬油博士說x86與ARM的組合語言差異非常大。
想想看本日Day8實作NoPigKill.efi時,用的是C語言,
在x86和ARM下efi,程式碼差異大嗎?為什麼?