当前位置: 首页 > news >正文

如何使用 UEFI Shell 执行 Hello World 程序

如何创建一个 UEFI 应用程序

在之前的文章中曾详细介绍了 EDKII 开发环境的搭建以及 OVMF 固件的编译过程。并且使用 QEMU 虚拟机来执行编译好的 OVMF 固件。我们知道在 Linux 终端中可以在命令行中执行编译好的应用程序,UEFI 也有 shell,如下图所示。我们能够在 shell 中执行编译好的 UEFI Application。本文以简单的 Hello World 程序为例来介绍 UEFI 应用程序的编译执行过程和各个文件的作用。

1. 编译并执行一个 Hello World 程序

  • 在 EDKII 目录下创建文件 HelloWorldPkg

  • 创建文件 HelloWorld.c

    #include <Uefi.h>
    #include <Library/UefiLib.h>
    EFI_STATUS
    EFIAPI
    UefiMain (
    IN EFI_HANDLE ImageHandle,
    IN EFI_SYSTEM_TABLE *SystemTable
    ) {
    Print(L"Hello, World!\n");
    return EFI_SUCCESS;
    }
  • 创建文件 HelloWorld.inf

    GUID 可通过网站产生:https://guidgen.com/

    [Defines]
    INF_VERSION = 0x00010006
    BASE_NAME = HelloWorld
    FILE_GUID = 69ea2943-dbdd-404c-a3bf-6ef3fdfdf0a1
    MODULE_TYPE = UEFI_APPLICATION
    VERSION_STRING = 1.0
    ENTRY_POINT = UefiMain
    [Sources]
    HelloWorld.c
    [Packages]
    MdePkg/MdePkg.dec
    [LibraryClasses]
    UefiApplicationEntryPoint
    UefiLib
  • 创建文件 HelloWorldPkg.dsc

    [Defines]
    PLATFORM_NAME = HelloWorldPkg
    PLATFORM_GUID = 0adf0da5-100e-49a9-9f87-76215486216d
    PLATFORM_VERSION = 0.1
    DSC_SPECIFICATION = 0x00010005
    SUPPORTED_ARCHITECTURES = X64
    BUILD_TARGETS = DEBUG|RELEASE
    [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]
    HelloWorldPkg/HelloWorld.inf
  • 编译为.efi文件

    打开终端

    cd /home/ayuan/src/edk2
    source edksetup.sh

    编译 HelloWorldPkg

    打开文件./Conf/target.txt,修改如下项

    ACTIVE_PLATFORM = HelloWorldPkg/HelloWorldPkg.dsc
    TARGET = DEBUG
    TARGET_ARCH = X64
    TOOL_CHAIN_TAG = GCC5

    回到终端执行命令build,生成的 efi 文件的路径如下:

    /home/ayuan/src/edk2/Build/HelloWorldPkg/DEBUG_GCC5/X64/HelloWorld.efi
  • 在 QEMU 中打开 OVMF 固件,然后在 UEFI Shell 中执行刚才编译的 HelloWorld.efi 文件

    qemu-system-x86_64 -bios /home/ayuan/run-ovmf/OVMF.fd -drive format=raw,file=fat:rw:/home/ayuan/run-ovmf/hda-contents -m 512M
    # 或者
    qemu-system-x86_64 -m 512M -drive if=pflash,format=raw,readonly=on,file=/home/ayuan/run-ovmf/OVMF.fd -drive format=raw,file=fat:rw:/home/ayuan/run-ovmf/hda-contents

除了.c源文件之外,我们还涉及到INF, DSC, DEC三个重要的文件。三个文件分别用于描述“模块”,“平台”,和“包”。他们的关系如下所示:

平台 (Platform)
└── 由多个 模块 (Module) 组成
├── 来自 包A (Package A)
├── 来自 包B (Package B)
└── 来自 包C (Package C)

1. 包(Package)是“资源提供者”一个包就是一个功能或主题相关的“大仓库”。 例如:

  • MdePkg:最基础的库、头文件、通用协议
  • MdeModulePkg:通用驱动(如控制台、文件系统、USB 等)
  • OvmfPkg:专用于 QEMU/Ovmf 虚拟机的平台包
  • ShellPkg:UEFI Shell 相关模块

包通过 .DEC 文件对外声明:我提供了哪些头文件、哪些库、哪些 GUID、哪些 PCD。

2. 模块(Module)是“可构建单元”模块是真正会被编译的东西(.efi、.lib)。 每个模块必须属于某个包,它的 .INF 文件第一件事就是通过 [Packages] 节声明自己属于哪些包,从而获得头文件和定义。 一个 ConOutDxe.inf(控制台输出驱动)属于 MdeModulePkg 这个包。

3. 平台(Platform)是“最终产品组装者”平台负责决定:“我这个主板/产品要用哪些模块?” 它通过 .DSC 文件的 [Components] 节,把来自不同包的各种模块“挑选”进来,并配置 PCD 值、库映射关系等。 最终通过构建命令生成完整的固件映像。

三个文件的相互引用关系如下:

在 .INF 文件中必须说明引用包,就是当前模块的源码使用了哪些包定义的函数或者接口:

[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec

在 .DSC 文件中需要引用模块,就是需要将那些模块编译进该平台,如:

[Components]
MdeModulePkg/Universal/Console/ConOutDxe/ConOutDxe.inf
OvmfPkg/QemuVideoDxe/QemuVideoDxe.inf

读者可能注意到我们在 HelloWorldPkg 中并没有创建 DEC 文件,这是因为没有其他模块使用到我们自定义的这个包,所以不创建也没什么问题。

2. INF 文件说明

INF 文件是单个模块(Module)的“身份证”。一个模块可以是驱动(Driver)、库(Library)、应用(Application)或 PEI/DXE 模块等。它告诉构建系统这个模块由哪些源文件组成,依赖哪些包、库、协议、GUID,模块的类型、入口点、输出文件名是什么,编译时需要哪些特殊选项等。没有 INF 文件,模块就无法被构建。每个 .inf 文件对应一个独立的、可独立构建的单元(最终生成 .efi 或 .lib)。INF 通常放在模块目录下(如 MdeModulePkg/Universal/Console/ConOutDxe/ConOutDxe.inf)。

INF 文件的常用组成:

  • [Defines]:模块基本信息(版本、GUID、类型、入口点等)。
  • [Packages]:依赖哪些包(提供头文件和 PCD)。
  • [Sources]:源代码文件列表。
  • [LibraryClasses]:需要链接哪些库类。
  • [Protocols] / [Guids] / [Ppis]:使用的协议/GUID/PPI 及使用方式(BY_START、PRODUCES 等)。
  • [BuildOptions]:特定编译器选项。
  • [Depex](可选):DXE 依赖表达式。

例如:

[Defines]
INF_VERSION = 1.27
BASE_NAME = HelloWorld
FILE_GUID = 12345678-ABCD-1234-ABCD-123456789ABC
MODULE_TYPE = UEFI_APPLICATION # 或 DXE_DRIVER、BASE 等
VERSION_STRING = 1.0
ENTRY_POINT = UefiMain # 入口函数名
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
[Sources]
HelloWorld.c
HelloWorld.h
[LibraryClasses]
UefiLib
UefiApplicationEntryPoint
DebugLib
[Protocols]
gEfiShellProtocolGuid ## CONSUMES
[Guids]
gEfiMdeModulePkgTokenSpaceGuid ## SOMETIMES_PRODUCES

3. DSC 文件说明

DSC 为平台描述文件,是整个平台(Platform)的“构建蓝图”。它定义了这个平台要包含哪些模块(INF 文件),库类(LibraryClass)如何映射到具体实现,PCD(Platform Configuration Database)值如何覆盖,平台整体的架构、构建目标、输出目录等。一个平台通常只有一个主 DSC 文件(如 OvmfPkg/OvmfPkgX64.dsc 或 PlatformPkg/Platform.dsc)。DSC 不负责包的内容声明(那是 DEC),也不负责 Flash 布局(那是 FDF),但会引用 FDF 来生成最终固件映像。

DSC 文件常用组成:

[Defines]:平台名称、GUID、支持架构、构建目标等。

[LibraryClasses]:库类 → 具体 INF 的映射(全局生效)。

[Pcds]:覆盖包中声明的 PCD 默认值(FixedAtBuild、Dynamic 等)。

[Components]:列出所有要构建的模块 INF 文件(支持条件编译)。

[Components.IA32]/[Components.X64]等架构特定节。

例如:

[Defines]
PLATFORM_NAME = MyPlatform
PLATFORM_GUID = 87654321-ABCD-1234-ABCD-123456789ABC
PLATFORM_VERSION = 1.0
DSC_SPECIFICATION = 1.28
OUTPUT_DIRECTORY = Build/MyPlatform
SUPPORTED_ARCHITECTURES = IA32|X64
BUILD_TARGETS = DEBUG|RELEASE
SKUID_IDENTIFIER = DEFAULT
[LibraryClasses]
DebugLib| MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.inf
UefiLib| MdePkg/Library/UefiLib/UefiLib.inf
# ... 其他库映射
[PcdsFixedAtBuild]
gEfiMdeModulePkgTokenSpaceGuid.PcdHelloWorldPrintTimes| 5 | UINT32 | 0x40000005
[Components]
# 核心模块
MdeModulePkg/Universal/Console/ConOutDxe/ConOutDxe.inf
MyPkg/HelloWorld/HelloWorld.inf # 引用上面的 INF
[Components.X64]
# 只在 X64 下构建的模块
OvmfPkg/QemuVideoDxe/QemuVideoDxe.inf

4. DEC 文件说明

DEC 是包(Package)的“目录索引”。一个包是一组相关模块、库、头文件、GUID、协议、PCD 的集合(如 MdePkg、MdeModulePkg、OvmfPkg)。DEC 文件的作用是声明包对外提供什么(GUID、Protocol、PPI、LibraryClass、PCD),指定头文件包含路径([Includes]),让其他模块的 INF 文件可以通过 [Packages] 引用这个包,从而获得头文件和 PCD 定义。

没有 DEC,模块就无法知道这个包里有哪些可用的接口和配置。

DEC 文件常用组成:

[Defines]:包名称、GUID、版本。

[Includes]:头文件目录(支持架构特定)。

[LibraryClasses]:包提供的库类及其头文件路径。

[Guids]/[Protocols]/[Ppis]:声明 GUID/协议/PPI(带注释说明用途)。

[Pcds]:声明所有 PCD(FeatureFlag、FixedAtBuild、Dynamic 等)及其默认值、类型、Token。

例如:

[Defines]
DEC_SPECIFICATION = 1.27
PACKAGE_NAME = MdePkg
PACKAGE_GUID = 1E0A9C1A-5A9C-4C9A-9B7A-5A9C1E0A9C1A
PACKAGE_VERSION = 1.05
[Includes]
Include
Include/Ia32 # 架构特定
[LibraryClasses]
## @libraryclass 基础内存操作库
BaseMemoryLib| Include/Library/BaseMemoryLib.h
[Guids]
## Include/Guid/MdePkgTokenSpace.h
gEfiMdePkgTokenSpaceGuid = { 0x1E0A9C1A, 0x5A9C, 0x4C9A, {0x9B, 0x7A, 0x5A, 0x9C, 0x1E, 0x0A, 0x9C, 0x1A} }
[PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamic, PcdsDynamicEx]
http://www.jsqmd.com/news/588191/

相关文章:

  • 漏洞挖掘变现指南:合法渠道\+赏金技巧,新手也能月入过万
  • 干货:企业知识库是AI落地的核心,别让大模型“失忆”!
  • 实战指南:基于快马平台为openclaw社区开发精华帖子系统
  • NoSleep防休眠工具:彻底解决Windows系统意外休眠的终极方案
  • Lambda 表达式 —— Java 8 的函数式编程利器
  • 2026年远程真机测试平台选型对比与体验解析
  • 2026届毕业生推荐的六大降AI率神器实测分析
  • 高效Agent系统:大模型进阶指南,小白程序员必备收藏!
  • 嘉为蓝鲸应用发布中心V6.3发布:流自融合、安全提效,全方位护航企业级应用发布
  • 3步实现跨平台文献管理效率跃升:WPS-Zotero开源工具深度应用指南
  • 十年磨一剑:DirectX Repair如何成为最受欢迎的DLL修复工具
  • 2026届最火的六大降重复率平台实际效果
  • 数据分析与可视化:班级学生与微信好友分析
  • 终极抖音批量下载指南:5分钟搞定无水印视频批量采集
  • OneDrive顽固残留?高效彻底卸载指南:释放系统资源的实用方案
  • MouseClick:解放双手的跨平台鼠标自动化神器,告别重复点击的烦恼
  • ai一键生成node.js环境配置教程,快马平台助你跳过繁琐安装步骤
  • 【架构实战】海量数据存储:分库分表中间件实战
  • 2026年6款AI驱动的人力系统测评:谁更适合科技企业
  • 开源游戏串流新标杆:Sunshine如何实现跨设备游戏自由
  • AI辅助开发:利用快马多模型能力为红目香薰设计智能场景联动规则
  • 小白程序员必收藏!Agent工程入门指南:轻松上手大模型,抓住AI时代红利
  • DirectX Repair:从Windows XP到Windows 11的全平台DLL修复专家
  • 光伏618政策松绑!安科瑞分布式光伏监控系统解锁电站收益新高度
  • Gemma 4 现已发布: 同等规模下性能最强的开放模型
  • 直线导轨的精度对设备运行稳定性与寿命的影响
  • 3步解锁音乐宝库:qmcdump助你轻松转换QQ音乐加密文件
  • Flux Sea Studio 架构解析:理解其底层扩散模型与注意力机制设计
  • 基于stm32的心率血氧检测仪[单片机]-计算机毕业设计源码+LW文档
  • 改进二进制粒子群算法在配电网重构中的应用:基于IEEE33节点系统的功率损耗优化与动态重构程序