UEFI與inf文件


UEFI與inf文件

背景

學習高通UEFI中的LCD顯示框架,看到有些博客對inf文件進行了介紹,因此整理了這方面的一些入門知識。

參考:

inf文件的構成

Defines

INF_VERSION:Inf版本號,用於編譯時解釋inf文件,通常設置為0x00010005,INF_VERSION版本號便於EDKII系統升級。

BASE_NAME:用於設置編譯輸出的文件名稱,根據文件功能設置,不能包含空格。它通常也是輸出文件名字。

FILE_GUID:文件的全局唯一標識符,格式:8-4-4-4-12,用於生成固件。例如: 4ea97c46-7491-4dfd-b442-747010f3ce5f

可以通過 http://www.guidgen.com/獲得GUID。

VERSION_STRING:文件版本字符串,用於標注文件的版本號

MODUL_TYPE:用於標識模塊的類型、應用工程文件設置為:UEF工_APPLICATION

定義模塊的模塊類型,可以是SEC/PEI_CORE/PEIM/DXE_CORE/DXE_SAL_DRIVER/DXE_SMM_DRIVER/UEFI_DRIVER/DXE_DRIVER/DXE_RUNTIME_DRIVER/UEFI_APPLICATION/BASE中的一個。對於標准應用程序工程模塊來說,為UEFI_APPLICATION類。

ENTRY POINT:模塊的入口函數

Sources

列出文件內所有的源文件和資源文件

Packages

列出文件使用的包的描述文件,即.dec文件,如果source塊內包含了源文件,必須將MdePkg/MdePkg.dec放在首行

LibraryClasses

列出文件內所使用的庫文件,應用工程文件必須包含UefiApplicationEntryPoint,驅動文件必須包含UEFIDriverEntryPoint

Protocols

列出文件內使用的Protocol的GUID

BuildOptions

編譯配置。

  • = 表示選項附加到默認選項后面。
  • == 表示僅使用所定義的選項,棄用默認選項。

附錄

初識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;
}

有以下幾點需要注意:

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字符串。

對應的inf文件

要想編譯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 #模塊類型: UEFI_DRIVER, DXE_DRIVER, DXE_RUNTIME_DRIVER,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 = 

然后將 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

其他類型的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 庫。

[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]

(2)使用main函數的application。如果你想像C一樣使用main函數,那么你需要用到LibC。 LibC 中提供了ShellAppMain函數,我們要提供int main(int Argc, char** Argv)供其調用。

/*Main.c */
#include <Uefi.h>
int
EFIAPI
main (
  IN int Argc,
  IN char **Argv
  )
{
 gST -> ConOut-> OutputString(gST -> ConOut, L"HelloWorld\n"); 
  return 0;
}

真正的入口函數是ShellCEntryLib, 調用過程為 ShellCEntryLib -> ShellAppMain -> main.

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
  UefiLib

[BuildOptions]
  MSFT:*_*_IA32_CC_FLAGS  = /Oi-

還要再說明一點,如果你的程序中用到了printf(...)等等標准C的庫函數,那么一定要使用此種類型的application。 因為ShellCEntryLib 函數中會調用ShellAppMain(...), StdLib的ShellAppMain(...) 會對stdlib 進行初始化。 然后才可以調用stdlib的函數。 (當然,如果你已經清楚地了解了入口函數的處理流程,你也可以手工調用StdLib的ShellAppMain進行出事后).

(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

然后將 zlib|zlib-1.2.6/zlib.inf # zlib-1.2.6 在EKD2的根目錄下放到.dsc 文件 [LibraryClasses]中。

需要鏈接zlib的時候,在.inf文件的[LibraryClasses]中添加 zlib即可。

(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

現在我們已經掃除了編譯UEFI應用的所有障礙。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM