UEFI—hello world

UEFI——hello world

    包(以pkg结尾的文件夹)即package为包。是由一组模块(.工程文件.inf和源文件.c)和一个平台描述文件(.dsc)和包声明文件(.dec)组成的集合。inf文件用于自动编译源代码。
   模块的可执行文件(.efi)可以像插件一样动态加载到UEFI内核中,本文主要讲述uefi编程常用的几种模块。

标准应用程序模块(DXE阶段或者shell阶段运行的应用程程序)

#include <Uefi.h>            //头文件。Uefi定义了UEFI基本数据类型和核心数据结构。
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;
}

1.入口函数UefiMain,作为入口函数名,可以在改变它的函数名,但是相应的也要在inf工程文件中改变入口函数的名字,而且他的函数签名(参数类型和返回值类型)不能改变。
    -返回值类型 EFI_STATUS,本质为无符号长整数。
    -最高位为1时其值为错误代码,为0时表示非错误值。通过宏EFI_ERROR(Status)可以判断返回值Status时候为错误代码。若Status为错误代码EFI_ERROR(Status)返回值为真,否则为假。
   -EFI_SUCCESS为预定义常量,其值为0,表示没有错误的状态值和返回值。

2.入口函数参数 ImageHandle和SystenTable
   efi文件(UEFI应用程序或UEFI驱动程序)加载到内存后生成的对象成为Image(映像)。
  ImageHandle是 Image的句柄,作为模块入口函数的参数,它表示模块自身加载到内存后生成的Image对象 。
   句柄(handle)作为对象的唯一标识,和对象唯一对应的,以此来寻找和操作对象。handle实现id的一些功能,但是权限比id少,代码暴露较少。
    SystemTable是程序同UEFI内核交互的桥梁,通过它可以获得UEFI提供的各种服务(BT/RT),SystemTable是UEFI内核的一个全局结构体。

工程文件(.inf)

[Defines]                                                       //定义本模块的属性变量及其他变量,这些变量可以在工程文件其他块中引用
 INF_VERSION = 0x00010005                                  //INF版本号
 BASE_NAME = HelloWorld    //模块名字
 FILE_GUID = 6987936E-ED34-ffdb-AE97-1FA5E4ED2117 //GUID生产固件库
 MODULE_TYPE = UEFI_APPLICATION                                       //模块类型   此为标准应用程序模块
 VERSION_STRING = 1.01    //模块版本号
 ENTRY_POINT = UefiMain                                         //入口函数 UfeiMain
 
[Sources]       //所有源文件和资源文件
 HelloWorld.c
//  a.c   |   MSFT    //VS编译器有效
//  b.c   |   GCC     //gcc编译器有效
    //  INTEL     IC编译器有效
    //  RVCT      arm编译器
//[Sources.IA32]      //32位模块
// cpu32.c
//[Sources.X64]      //64位模块
// cpu64.c

[Packages]                     //本模块所有引用到的包的包声明模块
  MdePkg/MdePkg.dec            //modelpackage.dec对应Uefi.h
  MyPkg/MyPkg.dec

[LibraryClasses]               //本模块要链接的库模板
  UefiApplicationEntryPoint    //应用工程模块
  UefiLib
//UefiDriverEntryPoint          //驱动工程模块

//[Protrcols]                 //列出使用的prorocol的GUID
//[BuildOptions]              //本模块的编译和链接选项

程序流程:StartImage - ModuleEntryPoint - ProcessModuleEntryPointList-Main

ShellAppMain应用程序模块(shell环境运行的应用程序)

  1. c文件
      方便shell环境执行,以ShellAppMain作为函数入口,可以传参数,以全局变量gST操纵系统表。第一个参数是命令行个数,第二个是命令行列表。
      ENTRY_POINT必须为ShellCEntryLib,入口函数不支持自定义,标准应用程序UefiMain支持自定义修改可以换成别的名字,源程序中要提供ShellAppMain。

  2. inf文件

    1. [Defines]块
        基本与标准应用程序工程模块相同,除了EntryPoint。在标准应用程序工程模块中,入口函数名,需要开发者自己定义,需要保持工程文件与源文件一致,一般设置为UefiMain。但是在Shell应用程序工程模块中,它必须设置为ShellAppMain。
    2. [Package]块
        MdePkg/MdePkg.dec和ShellPkg/ShellPkg.dec。
    3. [LibraryClasses]块
        必须列出ShellCEntryLib,通常还要列出 UefiBootServicesTableLib和UefiLib。

  Shell应用程序工程模块是在标准应用程序模块的基础之上利用Protocol做了封装,使我们可以很好地编写带命令行参数的UEFI程序。
  Shell应用程序的入口函数是ShellCEntryLib,它的入参和标准应用程序的入参是一样的,它会去打开EFI_SHELL_PAEAMETERS_PROTOCOL,通过这个protocol获得ShellAppMain的入参,就是首先获取命令行参数,然后再调用用户的入口函数ShellAppMain去打开Shell。

main应用程序工程模块(shell环境,且程序连接了StdLib库)

  使用main函数的应用程序工程模块会使用StdLib,在StdLib中提供了ShellAppMain函数,我们自己实现main函数作为程序的入口函数供ShellAppMain去调用,真正的模块入口函数是ShellCEntryLib,调用过程是:ShellCEntryLib———>ShellAppMain——>main

  使用main函数的应用程序工程模块要在AppPkg环境下才能编译成功,所以需要将main.inf添加到AppPkg.dsc文件的[Components]块下。

库模块(作为静态库被其他模块调用)

  在开发uefi工程过程中,会使用到大量的库。库也有源文件、工程文件,其他模块要使用库,要将这个库添加到包的dsc声明文件中。
  可以看到库的工程文件和其他应用程序有很大的区别。没有ENTRY_POINT;它会指定 MODULE_TYPE是BASE函数DRIVER等类型;通过LIBRARY_CLASS设定库名,指定库的适用范围,让它仅能被特定的模块调用

其他模块要使用这个库,就将库添加到自己的dsc文件中:

[LibraryClasses]

UefiLib|MdePkg/Library/UefiLib/UefiLib.inf

然后在自己的inf中添加这个库:

[LibraryClasses]

UefiLib

然后在源文件中就可以使用这个库了

  库如果要在使用之前需要初始化,那要在库的工程文件中指定CONSTRUCTOR和DESTRUCTOR

驱动模块

驱动和应用程序的最大区别就是驱动会常驻内存,而应用程序在执行完毕之后就会从内存中清除。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值