UEFI 實戰(2) HelloWorld 之一 helloworld及.inf文件
Posted on 2012-03-13 09:50 djx_zh 閱讀(26889) 評論(47) 編輯 收藏 引用初識UEFI
按慣例,首先讓我們用HelloWorld跟UEFI打個招呼吧
標準application
1。 頭文件, 所有的UEFI程序都有include <Uefi.h>
2。 main函數, UEFI 基本Application的main函數是UefiMain
3。 main函數的返回值類型 EFI_STATUS。 在UEFI中基本上所有的返回值類型都是EFI_STATUS。
4。 main函數的參數。.efi 文件加載到內存后稱為Image, ImageHandle 用來描述、訪問、控制此Image。 第二個參數是SystemTable,它是我們的程序同UEFI內核打交道的橋梁,通過它我們可以使用UEFI提供的各種服務,如Boot Services和 Runtime Services。 SystemTable是UEFI內核中的一個全局結構體。
5。 輸出是通過EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL的OutputString服務完成的。 服務(函數)的第一個參數是This指針,指向Protocol本身。 OutputString()的第二個參數是Unicode字符串。
要想編譯main.c,我們還需要.inf文件, 在main.c所在的目錄下編輯main.inf文件
然后將 main.inf 添加到 Nt32Pkg.dsc 或UnixPkg.dsc 的[Components]部分, 例如添加下面一行(example目錄在EDK2下)
其他類型的inf文件
(1) 可以看出標準的application處理命令行參數不方便,UEFI提供了幫我們處理命令行參數的入口函數ShellCEntryLib。 我們要實現INTN ShellAppMain(UINTN Argc, CHAR16** Argv) 作為(開發者視角的)入口函數。
(2)使用main函數的application。如果你想像C一樣使用main函數,那么你需要用到LibC。 LibC 中提供了ShellAppMain函數,我們要提供 int main(int Argc, char** Argv) 供其調用。
EFIAPI
main (
IN int Argc,
IN char **Argv
)
{
}
真正的入口函數是
ShellCEntryLib, 調用過程為
ShellCEntryLib -> ShellAppMain -> main.
inf 文件: 我們需要連接 ShellCEntryLib 和LibC庫。
(3)Lib 模塊的inf文件。開發大型工程的時候我們會用到lib,例如我們要開發視頻解碼程序,會用到zlib庫,
中添加 zlib即可。
(4)driver模塊的inf文件。例如DiskIo的inf()
現在我們已經掃除了編譯UEFI應用的所有障礙。 在下一部分,我們將了解開發UEFI一定用到的系統服務。
按慣例,首先讓我們用HelloWorld跟UEFI打個招呼吧
標準application
/*main.c */
#include <Uefi.h>
EFI_STATUS
UefiMain (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
SystemTable -> ConOut-> OutputString(SystemTable -> ConOut, L"HelloWorld\n");
return EFI_SUCCESS;
}
有以下幾點需要注意:#include <Uefi.h>
EFI_STATUS
UefiMain (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
SystemTable -> ConOut-> OutputString(SystemTable -> ConOut, L"HelloWorld\n");
return EFI_SUCCESS;
}
1。 頭文件, 所有的UEFI程序都有include <Uefi.h>
2。 main函數, UEFI 基本Application的main函數是UefiMain
3。 main函數的返回值類型 EFI_STATUS。 在UEFI中基本上所有的返回值類型都是EFI_STATUS。
它本質上是UINTN。
4。 main函數的參數。.efi 文件加載到內存后稱為Image, ImageHandle 用來描述、訪問、控制此Image。 第二個參數是SystemTable,它是我們的程序同UEFI內核打交道的橋梁,通過它我們可以使用UEFI提供的各種服務,如Boot Services和 Runtime Services。 SystemTable是UEFI內核中的一個全局結構體。
5。 輸出是通過EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL的OutputString服務完成的。 服務(函數)的第一個參數是This指針,指向Protocol本身。 OutputString()的第二個參數是Unicode字符串。
要想編譯main.c,我們還需要.inf文件, 在main.c所在的目錄下編輯main.inf文件
##
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = main #輸出文件的名字為 main.efi
FILE_GUID = 6987936E-ED34-ffdb-AE97-1FA5E4ED2117
MODULE_TYPE = UEFI_APPLICATION #模塊類型:, , ,,BASE,等
VERSION_STRING = 1.0
ENTRY_POINT = UefiMain #入口函數
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64 IPF EBC
#
# 源文件
[Sources]
main.c
# .dec里面定義 include的路徑
[Packages]
MdePkg/MdePkg.dec
#要鏈接的庫
[LibraryClasses]
UefiApplicationEntryPoint
UefiLib
[Protocols]
[FeaturePcd]
[Pcd.common]
[Guids]
#編譯選項, = 表示選項附加到默認選項后面。 == 表示僅使用所定義的選項,棄用默認選項。
[BuildOptions]
#MSFT:*_*_*_CC_FLAGS == /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1ib2 /GL /EHs-c- /GR- /GF /Gy /Zi /Gm /D EFI_SPECIFICATION_VERSION=0x0002000A /D TIANO_RELEASE_VERSION=0x00080006 /FAs /Oi-
#MSFT:*_*_*_CC_FLAGS = /wd4804
#MSFT:Debug_*_IA32_CC_FLAGS =
#MSFT:Debug_*_X64_CC_FLAGS =
#MSFT:Release_*_IA32_CC_FLAGS =
#MSFT:Release_*_IA32_CC_FLAGS =
#MSFT:Release_*_IA32_DLINK_FLAGS =
#GCC:Release_*_IA32_CC_FLAGS =
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = main #輸出文件的名字為 main.efi
FILE_GUID = 6987936E-ED34-ffdb-AE97-1FA5E4ED2117
MODULE_TYPE = UEFI_APPLICATION #模塊類型:
UEFI_DRIVER
DXE_DRIVER
DXE_RUNTIME_DRIVER
UEFI_APPLICATION
VERSION_STRING = 1.0
ENTRY_POINT = UefiMain #入口函數
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64 IPF EBC
#
# 源文件
[Sources]
main.c
# .dec里面定義 include的路徑
[Packages]
MdePkg/MdePkg.dec
#要鏈接的庫
[LibraryClasses]
UefiApplicationEntryPoint
UefiLib
[Protocols]
[FeaturePcd]
[Pcd.common]
[Guids]
#編譯選項, = 表示選項附加到默認選項后面。 == 表示僅使用所定義的選項,棄用默認選項。
[BuildOptions]
#MSFT:*_*_*_CC_FLAGS == /nologo /c /WX /GS- /W4 /Gs32768 /D UNICODE /O1ib2 /GL /EHs-c- /GR- /GF /Gy /Zi /Gm /D EFI_SPECIFICATION_VERSION=0x0002000A /D TIANO_RELEASE_VERSION=0x00080006 /FAs /Oi-
#MSFT:*_*_*_CC_FLAGS = /wd4804
#MSFT:Debug_*_IA32_CC_FLAGS =
#MSFT:Debug_*_X64_CC_FLAGS =
#MSFT:Release_*_IA32_CC_FLAGS =
#MSFT:Release_*_IA32_CC_FLAGS =
#MSFT:Release_*_IA32_DLINK_FLAGS =
#GCC:Release_*_IA32_CC_FLAGS =
然后將 main.inf 添加到 Nt32Pkg.dsc 或UnixPkg.dsc 的[Components]部分, 例如添加下面一行(example目錄在EDK2下)
example/main/main.inf
然后就可以使用BaseTools下的build進行編譯了。Windows下執行
edksetup.bat
build -p Nt32Pkg\t32Pkg.dsc -a IA32
Linux 執行
source ./edksetup.sh BaseTools
build -p UnixPkg/UnixPkg.dsc -a IA32
edksetup.bat
build -p Nt32Pkg\t32Pkg.dsc -a IA32
Linux 執行
source ./edksetup.sh BaseTools
build -p UnixPkg/UnixPkg.dsc -a IA32
其他類型的inf文件
(1) 可以看出標準的application處理命令行參數不方便,UEFI提供了幫我們處理命令行參數的入口函數ShellCEntryLib。 我們要實現INTN ShellAppMain(UINTN Argc, CHAR16** Argv) 作為(開發者視角的)入口函數。
/*Main.c */
#include <Uefi.h>
INTN
EFIAPI
ShellAppMain (
IN UINTN Argc,
IN CHAR16 **Argv
)
{
gST -> ConOut-> OutputString(gST -> ConOut, L"HelloWorld\n");
return 0;
}
inf文件。 我們需要連接ShellCEntryLib 庫。#include <Uefi.h>
INTN
EFIAPI
ShellAppMain (
IN UINTN Argc,
IN CHAR16 **Argv
)
{
gST -> ConOut-> OutputString(gST -> ConOut, L"HelloWorld\n");
return 0;
}
[Defines]
INF_VERSION = 0x00010006
BASE_NAME = Main
FILE_GUID = 4ea97c46-7491-4dfd-b442-747010f3ce5f
MODULE_TYPE = UEFI_APPLICATION
VERSION_STRING = 0.1
ENTRY_POINT = ShellCEntryLib
#
# VALID_ARCHITECTURES = IA32 X64 IPF
#
[Sources]
Main.c
[Packages]
MdePkg/MdePkg.dec
ShellPkg/ShellPkg.dec
[LibraryClasses]
ShellCEntryLib
UefiLib
[BuildOptions]
INF_VERSION = 0x00010006
BASE_NAME = Main
FILE_GUID = 4ea97c46-7491-4dfd-b442-747010f3ce5f
MODULE_TYPE = UEFI_APPLICATION
VERSION_STRING = 0.1
ENTRY_POINT = ShellCEntryLib
#
# VALID_ARCHITECTURES = IA32 X64 IPF
#
[Sources]
Main.c
[Packages]
MdePkg/MdePkg.dec
ShellPkg/ShellPkg.dec
[LibraryClasses]
ShellCEntryLib
UefiLib
[BuildOptions]
(2)使用main函數的application。如果你想像C一樣使用main函數,那么你需要用到LibC。 LibC 中提供了ShellAppMain函數,我們要提供 int main(int Argc, char** Argv) 供其調用。
/*Main.c */
#include <Uefi.h>
int#include <Uefi.h>
EFIAPI
main (
IN int Argc,
IN char **Argv
)
{
gST -> ConOut-> OutputString(gST -> ConOut, L"HelloWorld\n");
return 0;}
inf 文件: 我們需要連接 ShellCEntryLib 和LibC庫。
[Defines]
INF_VERSION = 0x00010006
BASE_NAME = Main
FILE_GUID = 4ea97c46-7491-4dfd-b442-747010f3ce5f
MODULE_TYPE = UEFI_APPLICATION
VERSION_STRING = 0.1
ENTRY_POINT = ShellCEntryLib
#
# VALID_ARCHITECTURES = IA32 X64 IPF
#
[Sources]
Main.c
[Packages]
MdePkg/MdePkg.dec
ShellPkg/ShellPkg.dec
[LibraryClasses]
LibC
ShellCEntryLib
[BuildOptions]
MSFT:*_*_IA32_CC_FLAGS = /Oi-
還要再說明一點,如果你的程序中用到了printf(...)等等標準C的庫函數,那么一定要使用此種類型的application。 因為
ShellCEntryLib 函數中會調用ShellAppMain(...), StdLib的ShellAppMain(...) 會對stdlib 進行初始化。 然后才可以調用stdlib的函數。 (當然,如果你已經清楚地了解了入口函數的處理流程,你也可以手工調用StdLib的ShellAppMain進行出事后).INF_VERSION = 0x00010006
BASE_NAME = Main
FILE_GUID = 4ea97c46-7491-4dfd-b442-747010f3ce5f
MODULE_TYPE = UEFI_APPLICATION
VERSION_STRING = 0.1
ENTRY_POINT = ShellCEntryLib
#
# VALID_ARCHITECTURES = IA32 X64 IPF
#
[Sources]
Main.c
[Packages]
MdePkg/MdePkg.dec
ShellPkg/ShellPkg.dec
[LibraryClasses]
LibC
ShellCEntryLib
UefiLib
[BuildOptions]
MSFT:*_*_IA32_CC_FLAGS = /Oi-
(3)Lib 模塊的inf文件。開發大型工程的時候我們會用到lib,例如我們要開發視頻解碼程序,會用到zlib庫,
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = zlib
FILE_GUID = 348aaa62-BFBD-4882-9ECE-C80BBbbbb736
VERSION_STRING = 1.0
MODULE_TYPE = BASE #Base 表示此模塊編譯為library
LIBRARY_CLASS = zlib
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64 IPF EBC
#
[Sources]
adler32.c
crc32.c
deflate.c
infback.c
inffast.c
inflate.c
inftrees.c
trees.c
zutil.c
compress.c
uncompr.c
gzclose.c
gzlib.c
gzread.c
gzwrite.c
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
StdLib/StdLib.dec
[LibraryClasses]
MemoryAllocationLib
BaseLib
UefiBootServicesTableLib
BaseMemoryLib
UefiLib
UefiRuntimeServicesTableLib
[Protocols]
[FeaturePcd]
[Pcd]
[Guids]
[BuildOptions]
GCC:*_*_IA32_CC_FLAGS = -D__UEFI__ -DLARGEFILE64_SOURCE=1 -w
然后將 INF_VERSION = 0x00010005
BASE_NAME = zlib
FILE_GUID = 348aaa62-BFBD-4882-9ECE-C80BBbbbb736
VERSION_STRING = 1.0
MODULE_TYPE = BASE #Base 表示此模塊編譯為library
LIBRARY_CLASS = zlib
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64 IPF EBC
#
[Sources]
adler32.c
crc32.c
deflate.c
infback.c
inffast.c
inflate.c
inftrees.c
trees.c
zutil.c
compress.c
uncompr.c
gzclose.c
gzlib.c
gzread.c
gzwrite.c
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
StdLib/StdLib.dec
[LibraryClasses]
MemoryAllocationLib
BaseLib
UefiBootServicesTableLib
BaseMemoryLib
UefiLib
UefiRuntimeServicesTableLib
[Protocols]
[FeaturePcd]
[Pcd]
[Guids]
[BuildOptions]
GCC:*_*_IA32_CC_FLAGS = -D__UEFI__ -DLARGEFILE64_SOURCE=1 -w
zlib|zlib-1.2.6/zlib.inf # zlib-1.2.6 在EKD2的根目錄下
放到.dsc 文件 [LibraryClasses]中。 需要鏈接zlib的時候,在.inf文件的[LibraryClasses]
(4)driver模塊的inf文件。例如DiskIo的inf(
MdeModulePkg/Universal/Disk/DiskIoDxe/DiskIoDxe.inf
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = DiskIoDxe
FILE_GUID = 6B38F7B4-AD98-40e9-9093-ACA2B5A253C4
MODULE_TYPE = UEFI_DRIVER
VERSION_STRING = 1.0
ENTRY_POINT = InitializeDiskIo
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64 IPF EBC
#
# DRIVER_BINDING = gDiskIoDriverBinding
# COMPONENT_NAME = gDiskIoComponentName
# COMPONENT_NAME2 = gDiskIoComponentName2
#
[Sources]
ComponentName.c
DiskIo.h
DiskIo.c
[Packages]
MdePkg/MdePkg.dec
[LibraryClasses]
UefiBootServicesTableLib
MemoryAllocationLib
BaseMemoryLib
BaseLib
UefiLib
UefiDriverEntryPoint
DebugLib
[Protocols]
gEfiDiskIoProtocolGuid ## BY_START
gEfiBlockIoProtocolGuid ## TO_START
INF_VERSION = 0x00010005
BASE_NAME = DiskIoDxe
FILE_GUID = 6B38F7B4-AD98-40e9-9093-ACA2B5A253C4
MODULE_TYPE = UEFI_DRIVER
VERSION_STRING = 1.0
ENTRY_POINT = InitializeDiskIo
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64 IPF EBC
#
# DRIVER_BINDING = gDiskIoDriverBinding
# COMPONENT_NAME = gDiskIoComponentName
# COMPONENT_NAME2 = gDiskIoComponentName2
#
[Sources]
ComponentName.c
DiskIo.h
DiskIo.c
[Packages]
MdePkg/MdePkg.dec
[LibraryClasses]
UefiBootServicesTableLib
MemoryAllocationLib
BaseMemoryLib
BaseLib
UefiLib
UefiDriverEntryPoint
DebugLib
[Protocols]
gEfiDiskIoProtocolGuid ## BY_START
gEfiBlockIoProtocolGuid ## TO_START
現在我們已經掃除了編譯UEFI應用的所有障礙。 在下一部分,我們將了解開發UEFI一定用到的系統服務。