UEFI 基础教程 (二):UEFI工程模块文件

1.概述

  介绍EDK2的两个概念模块(Module)和包(Package)。

  • “包”是一组模块及平台描述文件(.dsc文件)、包声明文件(.dec文件)组成的集合,多在以*pkg命名的文件夹中,一般也称这样的文件夹为一个包。

  • 模块是UEFI系统的一个特色。模块(可执行文件,即.efi文件)像插件一样可以动态地加载到UEFI内核中。对应到源文件,EDK2中的每个工程模块由元数据文件(.inf)和源文件(有些情况也可以包含.efi文件)组成。

  主要介绍3种应用程序模块、UEFI驱动模块和库模块。

1.1.标准应用程序工程模块

  标准引用程序工程模块是其它应用程序模块的基础,也是UEFI中常见的一种应用程序模块。每个工程模块由两部分组成:工程文件和源文件。源文件包括C/C++文件、.asm汇编文件,也可以包括.uni(字符串资源文件)和.vrf(窗体资源文件)等资源文件。

示例程序:

//hello.c
#include<Uefi.h>
EFI_STATUS UefiMain(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable)
{
    
    
    SystemTable->ConOut->OutputString(SystemTable->ConOut,L"Hello man,\n welcome to UEFI world\n");
    return EFI_SUCCESS;
}
  • 头文件:所有的标准应用程序工程模块的源文件的头文件都要包含Uefi.h。Uefi 定义了UEFI基本数据类型和核心数据结构。
  • 入口函数:UEFI标准应用程序的入口函数通常是UefiMain,它是约定成俗的函数,它是可以在.inf文件中指定。它的函数签名(返回值类型和参数列表类型)是不能变化的。
    • 入口函数的返回值类型是EFI_STATUS。
      • 在UEFI程序中基本所有的返回值类型都是EFI_STATUS。它的本质是无符号长整数
      • 最高位为1时其值为错误代码,为0时表示非错误值。通过宏EFI_ERROR(Status)可以判断返回值Status时候为错误代码。若Status为错误代码EFI_ERROR(Status)返回值为真,否则为假。
      • EFI_SUCCESS为预定义常量,其值为0,表示没有错误的状态值和返回值。
  • 入口函数参数 ImageHandle和SystenTable
    • .efi文件(UEFI应用程序或UEFI驱动程序)加载到内存后生成的对象成为Image(映像)。ImageHandle是 Image的句柄,作为模块入口函数的参数,它表示模块自身加载到内存后生成的Image对象 。
    • SystemTable是程序同UEFI内核交互的桥梁,通过它可以获得UEFI提供的各种服务(BT/RT),SystemTable是UEFI内核的一个全局结构体。

  向标准输出设备打印字符串是通过SystemTable的ConOut提供的OutputString服务完成的。ConOut是EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL的一个实例,而EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL主要功能是控制字符输出设备。OutputString服务的第一个参数是指向EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL的一个实例即:ConOut。第二个参数是Unicode字符串。简单讲就是SystemTable->ConOut->OutputString服务将字符串L”Hello World”打印到SystemTable->ConOut所控制的字符串输出设备。

1.2.工程文件
  
  工程模块分为很多块,每个块以“[快名]”开头,它必须单独占一行。有些块是所有工程文件都必需的块,这些块包括[Defines]、[Sources]、[Packages]和[LibraryClass]。
在这里插入图片描述

  • [Defines]块:用于定义模块的属性和其它变量,块内定义的变量可以被其它块引用。
属性定义的语法:
属性名 = 属性值
块内必须属性
INF_VERSION:INF标准版本号。EDK2的build会检查INF_VERSION 的值并根据这个值解释.inf文件。设置为0x000100060x00010005。
BASE_NAME:模块名字符串,不能包含空格。它通常也是输出文件的名字。
FILE_GUID:每个工程文件必须有一个 8-4-4-4-12格式的GUID用于生成固件。(每一位数十六进制 0-F)
VERSION_STRING:模块的版本号,一般设置为1.0,根据自己写的模块版本设定即可。
MODULE_TYPE:定义模块的模块类型,对于标准应用模块,设为UEFI_APPLICATION.
ENTRY_POINT:定义模块的入口函数,根据在源文件中的入口函数填写。一般是UefiMain。
  • [Sources]块 用于列出模块的所有源文件和资源文件。
语法:
块内每一行表示一个文件,文件使用相对工程文件的路径。

体系结构相关块:
可以在使用Sources.$(Arch),其中$(Arch)是表示本块的体系结构,可以是IA32, X64, IPF, EBC, ARM中一个。这个的作用是不同的体系结构可能包含的源文件或资源文件不同,如果都写进[Sources]可能有问题,但是可以列出对应的[Sources.$(Arch)],然后根据编译时标识设置,[Sources]都会被编译,[Sources.$(Arch)]中和标识相符的才会被编译。

编译工具链相关的源文件:
有是文件后跟工具链的符号表示只有在该工具链编译器编译时有效。
MSFT : Visual Stdio
INTEL : ICC编译器
RVCT : ARM编译器
  • [Packages]块 :列出本模块引用到的所有包的声明(.dec)文件。
语法:
[Packages]块内每一行列出一个文件,文件使用相对于EDK2根目录的路径。若[Sources]列出了源文件,则[Packages]块必须列出MdePkg/MdePkg.dec,并将其放在本块首行。
  • [LibraryClasses] :列出本模块要连接的库模块。
语法:
块内每一行声明一个要连接的库(库的定义在.dsc文件中)
常用库:
应用程序工程模块必须连接UefiApplicationEntryPoint库,驱动模块必须连接UefiDriverEntryPoint库。

refer to

  • https://blog.csdn.net/sevensevensevenday/article/details/70789517

猜你喜欢

转载自blog.csdn.net/weixin_41028621/article/details/112553276
今日推荐