# 模块

模块与包概念

  • 包:是一组 模块平台描述文件 ( .dsc 文件),包声明文件 ( .dec 文件) 组成的集合。
  • 模块可执行 文件,即 .efi 文件) 像 插件一样 可以 动态地 加载到 UEFI内核 中。
  • 每个成功模块由 元数据文件 ( .inf ) 和 源文件 (有些情况包含 .efi 文件) 组成。 .inf 类似与 Linux 下得 Makefile.dsc 文件则相当于 VS 项目中的 .sln文件 ;模块相当于 VS 项目中的工程, .inf 文件则相当于 VS 工程中的 .proj文件

# UEFI 主要模块

UEFI模块

# DSC 文件

DSC 文件描述了 模块 ,库和组件如何编译,其中还包含很多 的节section )标志,包含必要的 [Defines] , [Components] , 和可选的 [LibraryClasses][Libraries][SkuIds][BuildOptions][PCD][UserExtensions][DefaultStores] 。所有节标志,都内置与中括号中,且 大小写敏感 。在同一个括号中,可以包含复数的节标志字符串,他们之间使用 逗号 隔开,注释使用 #

# 使用逗号隔开
[Library.X64,LibraryClasses.IPF]
# 其制定CPU架构的节,通常的节([LibraryClasses]有更高的优先级优先使用高优先级编辑)
# 在DSC文件中,使用!include来包含其他的文件,!include可以在任何节中出现
[components]
......
!include StdLib/StdLib.inc  #包含StdLib库

# [Defines]

此节定义 各种变量 ,以供 后续编译 使用,必须在 DEC中第一个 定义,

通过 DEFINE 定义的 都是 全局的 ,都可以使用 $(MACRO) 来访问

语法如下

[Defines] 中可配置 PCD 信息, PCD : Platform Configuration Database , 数据库,类似 window的注册表 。PCD 除了 SEC早期PEI阶段DXE早期阶段外 ,都可以访问。

[Defines]
	Name = Value
    DEFINE MACRO = Value

DSC文件变量

# 示例

# 定义的全局宏,
[Defines]
  PLATFORM_NAME                  = AppPkg
  PLATFORM_GUID                  = 0458dade-8b6e-4e45-b773-1b27cbda3e06
  PLATFORM_VERSION               = 0.01
  DSC_SPECIFICATION              = 0x00010006
  OUTPUT_DIRECTORY               = Build/AppPkg
  SUPPORTED_ARCHITECTURES        = IA32|IPF|X64
  BUILD_TARGETS                  = DEBUG|RELEASE
  SKUID_IDENTIFIER               = DEFAULT
#
#  Debug output control
#
  DEFINE DEBUG_ENABLE_OUTPUT      = FALSE       # Set to TRUE to enable debug output
  DEFINE DEBUG_PRINT_ERROR_LEVEL  = 0x80000040  # Flags to control amount of debug output
  DEFINE DEBUG_PROPERTY_MASK      = 0
  DEFINE UEFI_BOOK_DIR            = uefi\book

# [ LibraryClasses ]

用来 提供模块 所使用的 库入口 ,而且它允许将模块编译成 ,这些库可以被 [ Components ] 中的 模块使用 ,当 DSC 文件中的模块不需要 使用库 时,这个节也可以不设置,可选的。

# 语法格式

$(Arch)$(MODULE_TYPE) 是可选的,节内的库对指定的 结构模块 都有效。

[LibraryClasses.$(Arch).$(MODULE_TYPE),LiBraryClasses.$(Arch).$(MODULE_TYPE)]
	LibraryName | Path/LibraryName.inf

LibraryClasses六种 表示方法,按照模块 优先搜 索的顺序,从 高到低

<LibraryClasses>
[LibraryClasses.$(Arch).$(MODULE_TYPE),LibraryClasses.$(Arch).$(MoDULE_TYPE)]
[LibraryClasses.$(Arch).$(MODULE_TYPE)]
[LibraryClasses.common.$(MODULE_TYPE)]
[LibraryClasses.$(Arch)]
[LibraryClasses.common]
MdeModulePkg/Universal/PCD/Pei/Pcd.inf {
    <LibraryClasses>
        PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
}
# 直接制定目前编译模块所需要的库,此方法优先级最高

[ Components ] 中的模块在寻找所需要的库时,将按照上面 优先级依次 寻找

# [ Components ]

用来定义模块编译的 ,通过制定模块的 INF文件 所在的位置, Build 工具可以编译生成 .efi 文件。

[Components.$(Arch)]
	Path/and/Filename.inf
# 语法格式
[Components.$(Arch)]{
        Path/and/Filename.inf{
<LibraryClasses> # 嵌套节
    LibraryName | Path/LibraryName.inf
 # 还可以嵌套<Defines>,<PCD*><BuildOptions>
        }
    }

# [ BuildOptions ]

给出编译器和相关的 编译参数 ,它会覆盖为编译模块准备的默认参数。如果是为了替换编译参数,则可以使用 == 。如果是为了添加编译参数,则可以使用 =

# 语法格式

[BuildOptions]
${FAMILY}:${TARGET}_${TAGNAME}_{ARCH}_${TOOLCODE}——FLAGS[= | == ] 编译参数

# 示例

编译参数定义宏 DISABLE_NEW_DEPRECATED_INTERFACES , 作为 源代码编译开关 。两个参数分别 禁用优化启用框架指针 省略功能。

[BuildOptions]
	*_*_*_CC_FLAGS = -D DISABLE_NEW_DEPRECATED_INTEREACES
    MSFT:DEBUG_*_*_CC_FLAGS = /Od / Oy-

# 语法格式

BuildOptions语法格式

FAMILY 是指 编译 时使用的 编译器

语法字段解释

语法字段

# 标准引用程序工程模块

工程模块的基础,

每个工程模块至少需要分为

  • 工程 文件 : .inf文件
  • 源文件C/C++ 文件, .asm 汇编文件,也包含 .uni ( 字符串资 源文件) 和 .vfr ( 窗口资源 文件)

# INF 文件

INF 是模块的 工程文件 ,描述了模块的属性,包含模块由那些 代码组成提供什么 ,依赖什么 ,支持什么 CPU架构 等信息。对 ODM 厂商 (第三方开发者而言),可以针对自家设备发布 二进制形式的模块 ,不必提供源代码。

一般来说,如果是提供 库的模块 ,则其位于 包的Library 子目录下,并且会针对不同的架构再创建子目录划分;如果是 UEFI_APPLICATION 一般位于子目录 Applications 下。

INF文件的节标志

# [Defines]

Define变量
Define变量

如果编译的模块为 库模块 ,则 LIBRARY_CLASS 变量 必须制定 ,生成的库模块在指定运行哪些 类型 的模块时使用

LIBRARY_CLASS = FOO | PEI_CORE PEIM
LIBRARY_CLASS = BAR | DXE_CORE DXE_DRIVER DXE_SMM_DRIVER
# 如果只想在UEFI应用中使用,则可以如下设置
LIBRARY_CLASS = FOO | UEFI_APPLICATION

# [Sources]

列出模块中所有的 源文件资源文件 ,这些文件位于 INF文件 所在的目录或者子目录。这个节可以针对不同的架构指定文件.

$(Arch) 可以是 COMMON , IA32 , X64IPF , EBC , ARMAARCH64 中任何 一个 。如果需要对 所有架构 适用,可以 使用COMMON 或者 不指定任何架构

[Sources.$(Arch)]
	SourceCode.c

同时可以 对源文件 制定 编译的工具链 ,即只有在使用指定的工具链时,此源文件才会被编译,目前常用的 4种工具 分别是 MSFT (微软的 Visual Studio编 译器), GCC ( GNU GCC编译 器), INTEL (Intel C 编译器和 ntel EFI 字节码编译器) 和 RVCT ( ARM RealVIew 工具链)

[Sources.ARM]
	GicV3/Arm/ArmGicV3.S  | GCC
    GicV3/Arm/ArmGicV3.asm  | RVCT

# [ BuildOptions ]

INF 中的与 DSC文件 中的语法 格式基本相同 ,区别在与 INF文件 只对 本模块有效 。而 DSC所有模块 都有效。

日常开发中,通过 INF 文件修改编译选项以解决一些 特别问题 。比如在解决 汉字字符串 显示问题时,强制要求编译器把源文件按 UTF-8编码 进行识别

[BuildOptions]
	MSFT:*_*_*_CC_FLAGS = /utf-8

# [Protocols]

列出 模块 使用的 协议 ,在 INF文件 中列出的是协议的 GUID ,通过 EDK2 的分析工具, GUID输出 到模块的 AUtoGen.c ,如果模块 没有使用任何协议 ,则这个 节为空

[Protocols.$(Arch)]#COMMON,IA32,X64,IPF,EBC或者不指定
    gEfiProtocolGuid [ | FeatureFlagExpression ]
    
# 当FeatureFlagExpression为true时所添加的Protocol Guid是有效的,当为FALSE是,会忽略Protocol Guid

# [ LibraryClasses ]

列出 本模块 需要 链接的库

[LibraryClasses.$(Arch)] #COMMON,IA32,X64,IPF,EBC或者不指定
    LibraryClassNamel [ | FeatureFlagExpression ]

在日常开发中,模块如果要 添加 库,一般需要进行两个步骤,

  • INF 文件下的 [LibraryClasses] 中添加 库名
  • DSC 文件的 [LibraryClasses] 中寻找 词库 ,如果有,则需要添加 编译此库INF文件
[LibraryClasses]
	UefiApplicationEntryPoint
    UefiLib

# [Packages]

列出 本模块 引用的 所有包DEC文件

[Packages.$(Arch)]  # COMMON,IA32,X64,IPF,EBC或者不指定,针对不同的平台架构
    MdePkg/MdePkg.dec

EDC文件 的目录使用的是 相对路径 ,其 根位 置( $(WORKSPACE )(通过 edksetup.bat/edksetup.sh 指定的 工作目录 ))。 DEC文件 的指定是 有顺序的 ,比如 MdePkg/MdePkg.dec 必须在 MdeModulePkg/MdeModulePkg.dec .

[Packages]
	MdePkg/MdePkg.dec
	MdeModulePkg/MdeModulePkg.dec
[Package.IA32]
    DEFINE CPUS = IA32FamilyCpuPkg
    $(CPUS)/DualCore/DualCore.dec

# DEC 文件

每个 只有 一个DEC 文件, DEC文件 用来 配合DSC文 件,描述了 公开数据接口

# [Defines]

必须的节 ,用来提供 包的GUID , 版本名称等信息DSC相同

# [Includes]

列出本包提供的 头文件 所在 目录 ,此节 DSC文件没有对应语法 结构

[Includes.$(Arch)] # COMMON,IA32,X64,IPF,EBC或者不指定,可添加Private
    Path

头文件的路径是 相对路径 ,其根目录为 DEC所在的目录

指定框架的时候,可以添加 Private 限定符,用来 规定 所包含的 头文件 只能在 本包 中的 模块中 使用

[Include.common]
[Include.common.Private]
[Include.IA32.Private]
  • 不带Private标志 的项, 严禁带Private标志 的项结合
  • 同一文件目录不能 同时指定带 Private标志 的项和 不带Private标志 的项

# [ LibraryClasses ]

对外提供 中都会 提供头文件 ,这些头文件位于包下的 ``Include\Library 录下,用来明确 库 和头文件 的对应关系

[LibraryClasses.$(Arch)] # COMMON,IA32,X64,IPF,EBC或者不指定
	LibraryClassesName | PAth/LibraryHeader.h

# [ Guids ]

这个 用于定义 Guid变量 ,对于 Private标志 的要求 [Includes] 相同

[Guids.$(Arch)] # COMMON,IA32,X64,IPF,EBC或者不指定,可添加Private
    GUIDName = GUID

# 举例

## Include/Guid/GlobalVariable.h
  gEfiGlobalVariableGuid         = { 0x8BE4DF61, 0x93CA, 0x11D2, { 0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C }}
  ## Include/Guid/PcAnsi.h
  gEfiVT100PlusGuid              = { 0x7BAEC70B, 0x57E0, 0x4C76, { 0x8E, 0x87, 0x2F, 0x9E, 0x28, 0x08, 0x83, 0x43 }}

# [Protocols]

定义 ProtocolGUID ,其规则与 [Guids] 是一样的。

[Protocols.(Arch)]  # common,IA32,X64,IPF,EBC或者不指定,可添加Private
    ProtocolName = GUID

# 其余节

PPIPI 阶段 PEIM和PEIM之间 的沟通 桥梁 ,类似 Dxe阶段Protocol 。一个 PEIMInstal l 一个 PPI 后,另一个 PEIM 通过 Locate 获取该 PPI

  • [Ppis] : 用于 源文件 用到的 PPI , 语法与 [Guids] 类似
  • [PCD] :是对 DSC 文件 [PCD] 的补充
  • [UserExtensions] :可以 定制用户 的命令

# FDF 文件

Flash Description File 用于描述 固件Flash 中的 布局位置 ,这些 固件 是与 UEFI/PI 兼容的 二进制镜像 。一般生成 固件 的源码只有一个 FDF文件 ,其作用是规定把那些 包编入Flash 中,并 确定编入的位置

FDF文件 用于生成 Option ROM镜像固件镜像可启动镜像 ,它与 DSC文件二进制文件 配合,在 GenFW工具 的协助下生成 镜像

# [Defines]

可选的节,用来个 跟踪FDF 文件的版本,定义 全局宏 以及 设定PCD 的值

[Defines]
	Name=Value
    DEFINE MACRO = Value

其中 set语句 专门用来对 PCD变量 进行赋值的

# [FD]

FD (Firmware Device) 即 固件设备 ,一个 BIOS ROM 就是一个 FD , 这个节在开发平台 Flash 时是必须得,开发 Option ROM 时不需要此项。FD 由各类声明和 FD 区域布局组成,它可以构成一个完整的 Flash设备 镜像。Flash 设备可以是移动式 可启动镜像 (比如可启动的 U 盘), 系统Flash镜像 (如 BIOS ROM) 或 更新镜像 (UEFI 中称为 Capsule 镜像),用来 升级系统Flash

# 令牌声明 (TOKEN Statements) :

Token = Value [| PcdName]
  • BaseAddress : FD 的基址,设备开机后 BIOS 被加载到 系统中 的位置
  • Size : FD的大小 ,单位为 字节
  • BlockSizeFlash 中一个 Block 的大小
  • ErasePolarity : 表示 用1或者0 擦除 Flash, 一般为 1
  • NumBlocks : Flash 中 Block 的个数

# 定义声明

DEFINE Statements : 用来定义 宏的声明 ,所定义的 整个FDF 文件中都有效,使用的时候,可以通过 $(MACRO) 来引用

DEFINE MACRO = PATH

# 设置声明

设置 声明 用来 设置PCD变量 的值

语法格式

SET PcdName = VALUE
SET gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase = $(MEMFD_BASE_ADDRESS) +  gUefiOvmfPkgTokenSpaceGuid.PcdOvmfWorkAreaBase + gUefiOvmfPkgTokenSpaceGuid.PcdOvmfConfidentialComputingWorkAreaHeader
SET gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaSize = gUefiOvmfPkgTokenSpaceGuid.PcdOvmfWorkAreaSize - gUefiOvmfPkgTokenSpaceGuid.PcdOvmfConfidentialComputingWorkAreaHeader

类声明 外, [FD] 的另外一个组成部分是 区域布局 ( Region Layout ),它用来指明各种 区域类型 的数据在 FD中 的布局

offset|Size
    [TokenSpaceGuidCName.PcdOffsetCname | TokenSpaceGuidCName.PcdSizeCName] ?
    	[RegopmType] ?

上诉代码的含义为 FD开辟 一段空间,用来放置区域类型 ( RegionType ) 所指明的内容,其中 offsetSize 表示其后的内容 处于FD 中的 偏移内容的大小RegionType 可以是 FV ( Firmware Volume , 固件区块 ), DATA (数据), FILE (文件), INF (INF 文件) 和 CAPSULE (更新固件的镜像) 也可以不指定

0x000000|0x006000
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfSecPageTablesSize
0x006000|0x001000
gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageBase|gUefiOvmfPkgTokenSpaceGuid.PcdOvmfLockBoxStorageSize

# [ FV ]

FV ( Firmware Volume ) 是 固件逻辑区块 ,相当于 FD上的分区 ,此节 定义镜像包含的组件模块 ,对于 平台镜像是必要 的,但 Option ROM镜像不需要 此节

[FV.UiFvName]

# [ OptionRom ]

此节 用来编译 独立的 Legacy PCI Option ROM 或者 UEFI PCI Option ROM .

# 资源文件

IDFUNI 文件 VFR文件 可算做 资源文件 ,用于 描述图像文字框架资源 ,在 Build工具协助 下,生成 二进制 文件 (如 .efi 文件, .lib 文件)

IDF ( Image Description File图像描述 文件), UNI ( Unicode String File宽字节字符串 文件) 和 VFR ( Visual Forms Representation可视化窗体 描述) 都是 资源文件 ,同属于 用户接口组件

IDF 文件用来 描述图像资源UNI文件 用来描述 字符串资源VFR 文件用来描述 窗体资源 ,类似与 Windows 操作系统下的窗口。

用户接口组件结构

# IDF 文件

IDF文件 中,可通过 #image标识符 指定 图像文件 ,所给出的 资源文件 一般与 IDF文 件在同一个目录下。

使用 TRANSPARENT 用来指定是否 使用透明 显示。

#image IMG_LOGO TRANSPARENT Logo.bmp
#image IMG_FULL_LOGO Logo.jpg
#image IMG_OEM_LOGO Logo.png

# UNI 文件

同一个字符串 变量,可针对 不同的语言 定义不同的 内容

#langdef en-US "English"
#langdef zh-Hans "简体中文"
#string STR_LANGUAGE_SELECT #language en-US "Select Language"
							#language zh-Hans "选择语言"

在 UNI 文件中,可以使用的标识符有 #langdef , #string , #language

  • #langdef 用于声明 本字符串 资源文件所支持的语言
  • #string 用于定义字符串
  • #language 用于标注所用的语言

#langdef#language 标识符在使用时,需要指定语言代码 ( Language Code ), en-US 代表的是英文

# VFR 文件

VFR文件 用来描述 窗体框架文件 ,它可以使用 #define#include 来定义 变量包含的头文件

  • formset (窗体集合):用来 标志 整个 窗体的结构
    • form :窗体,标志整个窗体的结构
    • checkbox : 复选框 ,可通过 空格键 或者 回车键 进行选择
  • 关键字 formsetendformset 成对出现,他们之间所包含的 内容定义 了整个 formset
    • guid : 标志本 formsetGUID值
    • title : 在界面中标志 本formset 的字符串标题
    • help : 在界面上显示本 formset 的帮助信息
    • classguid : 本 formset挂载界面GUID值
    • varstore : 变量所用 数据结构 类型
    • form窗体 关键字,与 endform成对 出现,定义 窗体的结构
    • checkbox复选框关键字 ,与 endcheckbox 成对出现,定义 复选框用户使用
///** @file
//
//    File Explorer Formset
//
//  Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
//  SPDX-License-Identifier: BSD-2-Clause-Patent
//
//**/
#include "FormGuid.h"
formset
  guid = EFI_FILE_EXPLORE_FORMSET_GUID,
  title = STRING_TOKEN(STR_FILE_EXPLORER_TITLE),
  help = STRING_TOKEN(STR_NULL_STRING),
  classguid = EFI_FILE_EXPLORE_FORMSET_GUID,
  form formid = FORM_FILE_EXPLORER_ID,
       title = STRING_TOKEN(STR_FILE_EXPLORER_TITLE);
       label FORM_FILE_EXPLORER_ID;
       label LABEL_END;
  endform;
  form formid = FORM_ADD_NEW_FILE_ID,
       title = STRING_TOKEN(STR_ADD_NEW_FILE_TITLE);
      string
          prompt   = STRING_TOKEN(STR_NEW_FILE_NAME_PROMPT),
          help     = STRING_TOKEN(STR_NEW_FILE_NAME_HELP),
          flags    = INTERACTIVE,
          key      = NEW_FILE_NAME_ID,
          minsize  = 2,
          maxsize  = 20,
      endstring;
      subtitle text = STRING_TOKEN(STR_NULL_STRING);
       text
         help   = STRING_TOKEN(STR_CREATE_FILE_AND_EXIT),
         text   = STRING_TOKEN(STR_CREATE_FILE_AND_EXIT),
         flags  = INTERACTIVE,
         key    = KEY_VALUE_CREATE_FILE_AND_EXIT;
       text
         help   = STRING_TOKEN(STR_NO_CREATE_FILE_AND_EXIT),
         text   = STRING_TOKEN(STR_NO_CREATE_FILE_AND_EXIT),
         flags  = INTERACTIVE,
         key    = KEY_VALUE_NO_CREATE_FILE_AND_EXIT;
  endform;
  form formid = FORM_ADD_NEW_FOLDER_ID,
      title = STRING_TOKEN(STR_ADD_NEW_FOLDER_TITLE);
      string
          prompt   = STRING_TOKEN(STR_NEW_FOLDER_NAME_PROMPT),
          help     = STRING_TOKEN(STR_NEW_FOLDER_NAME_HELP),
          flags    = INTERACTIVE,
          key      = NEW_FOLDER_NAME_ID,
          minsize  = 2,
          maxsize  = 20,
      endstring;
      subtitle text = STRING_TOKEN(STR_NULL_STRING);
      text
        help   = STRING_TOKEN(STR_CREATE_FOLDER_AND_EXIT),
        text   = STRING_TOKEN(STR_CREATE_FOLDER_AND_EXIT),
        flags  = INTERACTIVE,
        key    = KEY_VALUE_CREATE_FOLDER_AND_EXIT;
      text
        help   = STRING_TOKEN(STR_NO_CREATE_FOLDER_AND_EXIT),
        text   = STRING_TOKEN(STR_NO_CREATE_FOLDER_AND_EXIT),
        flags  = INTERACTIVE,
        key    = KEY_VALUE_NO_CREATE_FOLDER_AND_EXIT;
  endform;
endformset;

# EDK2 目录介绍

  • AppPkg : UEFI Application Development Kit 是一系列用来开发 UEFI APP 开发的套件, 标准依赖库 ,工具以及 demo ,目标是 降低UEFI app 的开发框架
  • ArmPkg : 提供 ARM框架 相关的 Protocols, 属于 ARM平台上 的通用代码
  • ArmPlatformPkg : ARM开发板 相关的 UEFI代码 ,包 含ARM平台上通用 的一些 组件重复利用 这些组件会令 ARM 平台不用的版型之间的移植变得更加容易
  • BaseTools : 提供了编译 EDK2的相关工具 :AutoGen,Build,GenSec,GenFV,GenFW,GenRds 工具。
  • Conf :
  • CryptoPkg : UEFI 定义了 HLOS(high level OS)平台固件之间 的接口,多个安全特性也再去其中,用来提供加密支持
  • EmbeddedPkg : 为 memory mapped controllers 提供 protocol实现 ,是一个简单的 EFI shell(EBL)
  • EmulatorPkg : Emulator虚拟环境 ,用来替代 Nt32Pkg 和 UnixPkg,k 可以跨平台编译
  • FatPkg : FAT支持包
  • MdeModulePkg : 此包提供符合 UEEI/PI 工业标准的模版,也提供标准相关的开发环境, PPIs/PROTOCOLs/GUIDS依赖库
  • MdePkg : 全程 Module Development Environment Package , 此为特殊的 Package ,包含了用于 开发module 所需要的最小环境。一个 module可 能也会依赖于其他的 Package ,但是所有 modules 必须依赖于 MdePkg .
  • NetworkPkg : 提供 网络支持的包 ,比如:IPV6 网络协议栈 / IPsec 驱动 / ISCSI 驱动 / 网络配置 先关的shell app
  • OvmfPkg : OVM F 是用来给虚拟机 提供UEFI支持的包 ,可以使用 QEMUKVM 来引导 OVMF固件 ,并进一步引导 HLOS
  • PcAtChipsetPkg : 此包提供了 符合PcAt标准器件 的接口和实现
  • StdLib : 提供了 标准库UDK 实现, StdLibPrivateInternalFiles 包时用来 给StdLib 使用的,不能用作其他引用
  • UefiCpuPkg : 提供 兼容UEFICPU模版

# 参考资料

  • UEFI 原理与编程 - 第三章节内容整理
  • 《UEFI 编程实战》
此文章已被阅读次数:正在加载...更新于

请我喝[茶]~( ̄▽ ̄)~*

YuHeShui 微信支付

微信支付

YuHeShui 支付宝

支付宝

YuHeShui 贝宝

贝宝