【UEFI基础】BIOS模块执行的优先级

news2024/11/14 18:47:08

综述

BIOS下主要通过两种方式来确定一般模块的优先级,一种是fdf文件中指定的优先级,另一种是inf文件中指定的优先级。需要注意这里使用了“一般模块”的说法,因为有些模块(尤其是PEI_CORE,DXE_CORE类型的模块)总是会先执行的,事实上就是因为这些优先执行的模块在控制一般模块的优先级。

fdf中的优先级

APRIORI

fdf中的优先级通过特殊的标识来说明,下面是一个例子:

[FV.DXEFV]
# 中间略

APRIORI DXE {
  INF  MdeModulePkg/Universal/DevicePathDxe/DevicePathDxe.inf
  INF  MdeModulePkg/Universal/PCD/Dxe/Pcd.inf
  # AmdSevDxe must be loaded before TdxDxe. Because in SEV guest AmdSevDxe
  # driver performs a MemEncryptSevClearMmioPageEncMask() call against the
  # PcdPciExpressBaseAddress range to mark it shared/unencrypted.
  # Otherwise #VC handler terminates the guest for trying to do MMIO to an
  # encrypted region (Since the range has not been marked shared/unencrypted).
  INF  OvmfPkg/AmdSevDxe/AmdSevDxe.inf
  INF  OvmfPkg/TdxDxe/TdxDxe.inf
!if $(SMM_REQUIRE) == FALSE
  INF  OvmfPkg/QemuFlashFvbServicesRuntimeDxe/FvbServicesRuntimeDxe.inf
!endif
}

这里的APRIORI就指定了需要优先执行的模块。

在编译时这个部分会被组成一个Firmware File,上例中可以从DXEFV中找到这个Firmware File,下面是该文件中的实际数据:

在这里插入图片描述

这些数据实际上是一个个的GUID,来自包含模块中的inf文件中的FILE_GUID

[Defines]
  INF_VERSION                    = 0x00010005
  BASE_NAME                      = DevicePathDxe
  MODULE_UNI_FILE                = DevicePathDxe.uni
  FILE_GUID                      = 9B680FCE-AD6B-4F3A-B60B-F59899003443 # Firmware File中包含的GUID
  MODULE_TYPE                    = DXE_DRIVER
  VERSION_STRING                 = 1.0
  ENTRY_POINT                    = DevicePathEntryPoint

而这个Firmware File本身也有一个GUID:

在这里插入图片描述

这个GUID实际上是固定的,定义在MdePkg\Include\Guid\Apriori.h中:

#define EFI_APRIORI_GUID \
  { \
    0xfc510ee7, 0xffdc, 0x11d4, {0xbd, 0x41, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 } \
  }
extern EFI_GUID gAprioriGuid;

这个gAprioriGuid将会在代码中进一步使用,来获取上面提到的APRIORI文件中的GUID,以确定哪些模块需要优先执行。

代码处理gAprioriGuid

相关代码可以在edk2\MdeModulePkg\Core\Dxe\DxeMain.inf中的CoreDispatcher()找到:

    //
    // Read the array of GUIDs from the Apriori file if it is present in the firmware volume
    //
    AprioriFile = NULL;
    Status      = Fv->ReadSection (
                        Fv,
                        &gAprioriGuid,
                        EFI_SECTION_RAW,
                        0,
                        (VOID **)&AprioriFile,
                        &SizeOfBuffer,
                        &AuthenticationStatus
                        );
    if (!EFI_ERROR (Status)) {
      AprioriEntryCount = SizeOfBuffer / sizeof (EFI_GUID);
    } else {
      AprioriEntryCount = 0;
    }

    //
    // Put drivers on Apriori List on the Scheduled queue. The Discovered List includes
    // drivers not in the current FV and these must be skipped since the a priori list
    // is only valid for the FV that it resided in.
    //

    for (Index = 0; Index < AprioriEntryCount; Index++) {
      for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
        DriverEntry = CR (Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);
        if (CompareGuid (&DriverEntry->FileName, &AprioriFile[Index]) &&
            (FvHandle == DriverEntry->FvHandle))
        {
          CoreAcquireDispatcherLock ();
          DriverEntry->Dependent = FALSE;
          DriverEntry->Scheduled = TRUE;
          InsertTailList (&mScheduledQueue, &DriverEntry->ScheduledLink);
          CoreReleaseDispatcherLock ();
          DEBUG ((DEBUG_DISPATCH, "Evaluate DXE DEPEX for FFS(%g)\n", &DriverEntry->FileName));
          DEBUG ((DEBUG_DISPATCH, "  RESULT = TRUE (Apriori)\n"));
          break;
        }
      }
    }

代码也非常的简单:

  • 获取GUID。
  • 遍历GUID。
  • 遍历找到的所有模块,与指定的GUID匹配,如果匹配到了就放到mScheduledQueue

以上只是第一步,即存放优先模块,在edk2\MdeModulePkg\Core\Dxe\Dispatcher\Dispatcher.c文件的头部对应如下的说明:

Step #1 - When a FV protocol is added to the system every driver in the FV
is added to the mDiscoveredList. The SOR, Before, and After Depex are
pre-processed as drivers are added to the mDiscoveredList. If an Apriori
file exists in the FV those drivers are addeded to the
mScheduledQueue. The mFvHandleList is used to make sure a
FV is only processed once.

主要是这一句:

If an Apriori file exists in the FV those drivers are addeded to the mScheduledQueue.

在执行时:

EFI_STATUS
EFIAPI
CoreDispatcher (
  VOID
  )
{
  // 其它次要代码已经略去
  do {
    //
    // Drain the Scheduled Queue
    //
    while (!IsListEmpty (&mScheduledQueue)) {
      // 获取模块
      DriverEntry = CR (
                      mScheduledQueue.ForwardLink,
                      EFI_CORE_DRIVER_ENTRY,
                      ScheduledLink,
                      EFI_CORE_DRIVER_ENTRY_SIGNATURE
                      );
      // 加载模块
      Status = CoreLoadImage (
                  FALSE,
                  gDxeCoreImageHandle,
                  DriverEntry->FvFileDevicePath,
                  NULL,
                  0,
                  &DriverEntry->ImageHandle
                  );
      // 执行之后移除魔魁啊
      DriverEntry->Scheduled   = FALSE;
      DriverEntry->Initialized = TRUE;
      RemoveEntryList (&DriverEntry->ScheduledLink);
      if (DriverEntry->IsFvImage) {
        //
        // Produce a firmware volume block protocol for FvImage so it gets dispatched from.
        //
        Status = CoreProcessFvImageFile (DriverEntry->Fv, DriverEntry->FvHandle, &DriverEntry->FileName);
      } else {
        // 执行模块
        Status = CoreStartImage (DriverEntry->ImageHandle, NULL, NULL);
      }

      ReturnStatus = EFI_SUCCESS;
    }
  } while (ReadyToRun);

这里有两个循环,第二个while循环中就是先执行mScheduledQueue中的模块。对应edk2\MdeModulePkg\Core\Dxe\Dispatcher\Dispatcher.c文件的头部的说明:

Step #2 - Dispatch. Remove driver from the mScheduledQueue and load and
start it. After mScheduledQueue is drained check the
mDiscoveredList to see if any item has a Depex that is ready to
be placed on the mScheduledQueue.

主要对应第一句:

Dispatch. Remove driver from the mScheduledQueue and load and start it.

inf中的优先级

并不是所有的模块都可以包含依赖关系,有些模块的依赖关系即使写了也会被忽略,在《edk-ii-inf-specification.pdf》中有如下的说明:

  • If the Module is a Library, then a [Depex] section is optional.
    If the Module is a Library with a MODULE_TYPE of BASE, the generic (i.e., [Depex]) and generic with only architectural modifier entries (i.e., [Depex.IA32]) are not permitted. It is permitted to have a Depex section if one ModuleType modifier is specified (i.e., [Depex.common.PEIM).
  • If the ModuleType is USER_DEFINED , then a [Depex] section is optional. If a PEI, SMM or DXE DEPEX section is required, the user must specify a ModuleType of PEIM to generate a PEI_DEPEX section, a ModuleType of DXE_DRIVER to generate a DXE_DEPEX section, or a ModuleType of DXE_SMM_DRIVER to generate an SMM_DEPEX section.
  • If the ModuleType is SEC, UEFI_APPLICATION, UEFI_DRIVER, PEI_CORE, SMM_CORE or DXE_CORE, no [Depex] sections are permitted and all library class [Depex] sections are ignored.
  • Module types PEIM, DXE_DRIVER, DXE_RUNTIME_DRIVER, DXE_SMM_DRIVER require a DXE_SAL_DRIVER and [Depex] section unless the dependencies are specified by a PEI_DEPEX , DXE_DEPEX or SMM_DEPEX in the [Binaries] section.

生成depex文件

inf中有一个Section包含了依赖关系,下面是一个例子(来自beni\BeniPkg\Dxe\DxeDriverInBds\DxeDriverInBds.inf):

[Depex]
  gEfiPciIoProtocolGuid

也就是说要执行本模块,前提是gEfiPciIoProtocolGuid这个GUID已经安装。

在编译模块时,会生成一个特定的文件(通过edk2\BaseTools\Source\Python\AutoGen\GenDepex.py执行相关操作,它也是AutoGen的一部分),名称格式是“模块名.depex”,本例就是DxeDriverInBds.depex:

在这里插入图片描述

上图高亮的就是gEfiPciIoProtocolGuid这个GUID。不过这里还是有几点需要说明:

  • 首先GUID前面有一个02,它表示的是OPCODE,在edk2\BaseTools\Source\Python\AutoGen\GenDepex.py可以看到更多的OPCODE:
    Opcode = {
        "PEI"   : {
            DEPEX_OPCODE_PUSH  :   0x02,
            DEPEX_OPCODE_AND   :   0x03,
            DEPEX_OPCODE_OR    :   0x04,
            DEPEX_OPCODE_NOT   :   0x05,
            DEPEX_OPCODE_TRUE  :   0x06,
            DEPEX_OPCODE_FALSE :   0x07,
            DEPEX_OPCODE_END   :   0x08
        },

        "DXE"   : {
            DEPEX_OPCODE_BEFORE:   0x00,
            DEPEX_OPCODE_AFTER :   0x01,
            DEPEX_OPCODE_PUSH  :   0x02,
            DEPEX_OPCODE_AND   :   0x03,
            DEPEX_OPCODE_OR    :   0x04,
            DEPEX_OPCODE_NOT   :   0x05,
            DEPEX_OPCODE_TRUE  :   0x06,
            DEPEX_OPCODE_FALSE :   0x07,
            DEPEX_OPCODE_END   :   0x08,
            DEPEX_OPCODE_SOR   :   0x09
        },

02表示的是DEPEX_OPCODE_PUSH,03表示的是DEPEX_OPCODE_AND,08表示的是DEPEX_OPCODE_END

  • 这里还有第二个GUID,对应gEfiPcdProtocolGuid
  ## Include/Protocol/PiPcd.h
  gEfiPcdProtocolGuid = { 0x13a3f0f6, 0x264a, 0x3ef0, { 0xf2, 0xe0, 0xde, 0xc5, 0x12, 0x34, 0x2f, 0x34 } }

不确定为什么要包含这个GUID,并且当[Depex]下只有TRUE的时候,也有这个GUID:

在这里插入图片描述

另外值得注意的一点是,在fdf文件中,也会将这个PCD模块包含在APRIORI中,因为PCD是一种基本的模式,为了所有的模块都能够支持PCD,有这样的依赖也是可以理解的。

将depex文件包含到BIOS二进制中

通过查看fdf可以知道depex是如何被包含的,主要是通过Rules这种[Section],比如一个DXE_DRIVER,它生成的ffs文件结构遵循的Rule如下:

[Rule.Common.DXE_DRIVER]
  FILE DRIVER = $(NAMED_GUID) {
    DXE_DEPEX    DXE_DEPEX Optional      $(INF_OUTPUT)/$(MODULE_NAME).depex
    PE32     PE32                    $(INF_OUTPUT)/$(MODULE_NAME).efi
    UI       STRING="$(MODULE_NAME)" Optional
    VERSION  STRING="$(INF_VERSION)" Optional BUILD_NUM=$(BUILD_NUMBER)
    RAW ACPI  Optional               |.acpi
    RAW ASL   Optional               |.aml
  }

即首先是一个depex文件,然后是一个efi文件,如下所示:

在这里插入图片描述

代码处理

模块中没有一个特定的GUID(像gAprioriGuid)来指定依赖,不过depex本来就是ffs中的一部分,所以是可以读出来的,在一个描述模块的结构体中有成员来表示这个depex(以DXE为例):

typedef struct {
  // 其它略
  VOID                             *Depex;		// 描述依赖关系
  UINTN                            DepexSize;	// depex的大小
} EFI_CORE_DRIVER_ENTRY;

所以在得到模块的时候我们就已经能够知道它依赖的GUID了,而这些模块通过一个全局变量mDiscoveredList构成了一个链表,后续会通过遍历这个链表来进行各种操作。

真正处理依赖关系的代码同样在CoreDispatcher()

EFI_STATUS
EFIAPI
CoreDispatcher (
  VOID
  )
{
  // 其它次要代码已经略去
  do {
    //
    // Drain the Scheduled Queue
    //
    while (!IsListEmpty (&mScheduledQueue)) {
      // 首次执行的时候,执行fdf中的优先模块
      // 后面的操作又会往mScheduledQueue里面放更多的模块,又会继续执行
    }
    //
    // Search DriverList for items to place on Scheduled Queue
    //
    ReadyToRun = FALSE;
    for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
      DriverEntry = CR (Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);

      if (DriverEntry->DepexProtocolError) {
        //
        // If Section Extraction Protocol did not let the Depex be read before retry the read
        //
        // 会将满足依赖的模块继续放入mScheduledQueue
        Status = CoreGetDepexSectionAndPreProccess (DriverEntry);
      }

      if (DriverEntry->Dependent) {
        if (CoreIsSchedulable (DriverEntry)) {
          CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);
          ReadyToRun = TRUE;
        }
      }
    }
  } while (ReadyToRun);

总体来说,对于依赖关系的处理如下:

在这里插入图片描述

其它

开始的时候说过依赖关系主要有两种,实际上还是有一些衍生的方式。比如在inf中的优先级中有提到depex文件,它可以有不同的用法,在inf中包含[Depex]可以生成depex文件,也可以手动生成(通过edk2\BaseTools\Source\Python\AutoGen\GenDepex.py),然后直接放到fdf中来为某个文件指定依赖,这种情况对于在fdf中直接包含efi文件时时很有用的,下面是一个例子:

FILE DRIVER = 5BBA83E5-F027-4ca7-BFD0-16358CC9E123 {
    SECTION PE32 = $(PLATFORM_FEATURES_PATH)/Icc/IccOverClocking/IccOverClocking.efi
    SECTION DXE_DEPEX = $(PLATFORM_FEATURES_PATH)/Icc/IccOverClocking/IccOverClocking.depex
    SECTION UI = "IccOverClocking"
  }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2139170.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Codeforces Round 972(Div.2)A+B

Codeforces Round 972&#xff08;Div.2&#xff09;ABC 昨天晚上做了Codeforces Round 972&#xff08;Div.2&#xff09;的A、B两道题&#xff0c;今天补一下思路。 题目来源&#xff1a;https://codeforces.com/contest/2005 A. Simple Palindrome 题目描述 输入输出样例…

linux---压缩打包

linux打包和压缩文件和目录&#xff1a; 归档(打包)命令&#xff1a;tar 归档就是将多个文件或者目录打包成为一个文件&#xff0c;存放再磁盘中&#xff0c;方便文件或者目录丢失时&#xff0c;可以恢复。 归档文件名使用相对路径 &#xff08;注意区分归档文件和被归档文…

Go 注册Nacos

根据需要GO 项目也接入Nacos 系统版本&#xff1a;Linux 5.4.18-87.76-generic KYLINOS SMP Thu Aug 31 09:05:44 UTC 2023 aarch64 aarch64 aarch64 GNU/Linux Go:1.19.4 1.查看Nacos-sdk-go 官方适配自己的工程 github.com/nacos-group/nacos-sdk-go NacosManager.go p…

【自动化测试】UI自动化的分类、如何选择合适的自动化测试工具以及其中appium的设计理念、引擎和引擎如何工作

引言 UI自动化测试主要针对软件的用户界面进行测试&#xff0c;以确保用户界面元素的交互和功能符合预期 文章目录 引言一、UI自动化的分类1.1 基于代码的自动化测试1.2 基于录制/回放的自动化测试1.3 基于框架的自动化测试1.4 按测试对象分类1.5 按测试层次分类1.6 按测试执行…

[产品管理-21]:NPDP新产品开发 - 19 - 产品设计与开发工具 - 详细设计与规格定义

目录 前言&#xff1a; 一、详细设计与规格定义概述 1、产品详细设计 2、规格定义 3、详细设计与规格定义的关系 4、实际应用中的注意事项 二、详细设计与规格定义主要工具 2.1 质量功能展开QFD - 需求跟踪矩阵 1、QFD的基本原理 2、QFD的实施步骤 3、QFD的优势与应…

智能赋能,Vatee万腾平台助力企业升级新高度

在当今这个日新月异的数字时代&#xff0c;智能技术的飞速发展正以前所未有的力量重塑着各行各业的面貌。作为这一变革浪潮中的佼佼者&#xff0c;Vatee万腾平台凭借其卓越的智能赋能能力&#xff0c;正引领众多企业迈向转型升级的新高度&#xff0c;开启了智能化发展的新篇章。…

【性能优化】分块

性能优化-tiling过程 这张图展示了在硬件和软件两个层面上执行矩阵乘法 C + = A B C += AB C+

560 和为k的子数组

解题思路&#xff1a; \qquad 一开始看到连续非空序列&#xff0c;会想到是不是可以用双指针表示一个区间&#xff0c;然后通过一次遍历找出所有可能的区间&#xff0c;但看到元素的取值区间就知道行不通&#xff0c;这个方法仅适用于数组元素大于等于0的情况。若数字是负数&a…

【Java面试】第十天

&#x1f31f;个人主页&#xff1a;时间会证明一切. 目录 Spring 中的 Bean 是线程安全的吗&#xff1f;有状态的Bean如何解决线程安全问题 SpringBoot和Spring的区别是什么&#xff1f;SpringBoot的启动流程是怎么样的&#xff1f;new SpringApplication()SpringApplication.r…

【Android 13源码分析】WindowContainer窗口层级-2-构建流程

在安卓源码的设计中&#xff0c;将将屏幕分为了37层&#xff0c;不同的窗口将在不同的层级中显示。 对这一块的概念以及相关源码做了详细分析&#xff0c;整理出以下几篇。 【Android 13源码分析】WindowContainer窗口层级-1-初识窗口层级树 【Android 13源码分析】WindowCon…

ArrayList 源码解析

ArrayList是Java集合框架中的一个动态数组实现&#xff0c;提供了可变大小的数组功能。它继承自AbstractList并实现了List接口&#xff0c;是顺序容器&#xff0c;即元素存放的数据与放进去的顺序相同&#xff0c;允许放入null元素&#xff0c;底层通过数组实现。除该类未实现同…

模板替换引擎(支持富文本动态表格)

模板替换引擎&#xff08;支持富文本动态表格&#xff09; 前言功能介绍example&#xff1a; 使用方法函数扩展系统函数自定义函数 前言 分享一下自己开源的工具——模板替换引擎 https://github.com/RwTo/template-engine 可以拿来学习设计模式或使用 感兴趣的话&#xff…

网络编程基础概述

文章目录 协议网络协议栈(osi)局域网IPIP和Mac地址端口号TCP和UDP网络字节序 协议 (网络协议的)意义:为了让计算机传输之间将信息正确传输给目标机器 不同系统之间能接入网络是因为定制了一套通用的协议以便支持不同系统间的网络通信 1.网络通信的问题: 将数据可靠的从A传给B a…

AtCoder ABC369 A-D题解

比赛链接:ABC369 省流&#xff1a;A<B<D<C&#xff08;题解是按照该顺序写的&#xff09; Problem A: #include <bist/stdc.h> using namespace std; int main(){int A,B;cin>>A>>B;if(AB)cout<<1<<endl;else if(abs(A-B)%20)cout&l…

织物缺陷检测系统源码分享

织物缺陷检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer Vis…

1405 问题 E: 世界杯

废话 这个题&#xff0c;我估计 22 22 22 年的时候写过一次&#xff0c;当时应该是搞明白了&#xff0c;现在重新写还是不会写&#xff0c;有点无奈 题目 问题 E: 世界杯&#xff1a;现在的 OJ 把题目加到一个活动里面去之后&#xff0c;感觉之后这个链接就访问不了了。题目…

伙房食堂电气安全新挑战:油烟潮湿环境下,如何筑起电气火灾“防火墙”?

近几年&#xff0c;随着我国经济的飞速发展&#xff0c;食堂餐饮也经历了一场变革&#xff0c;越来越多的电器走进了伙房食堂中&#xff0c;实现了电气化&#xff0c;为人们提供了高效便利的饮食服务&#xff0c;但同时也增加了火灾负荷。目前我国非常严重的电气火灾危害&#…

【STM32】DAC数字模拟转换

本篇博客重点在于标准库函数的理解与使用&#xff0c;搭建一个框架便于快速开发 目录 前言 DAC简介 DAC配置 DAC时钟使能 GPIO初始化 DAC配置 DAC使能 读写DAC值 驱动代码 MyDAC.h MyDAC.c main.c 前言 大容量的STM32F101xx和STM32F103xx产品才有DAC外设 大容量…

几种mfc140u.dll常见错误情况,以及mfc140u.dll文件修复的方法

如果你遇到与mfc140u.dll 文件相关的错误&#xff0c;这通常指的是该mfc140u.dll文件可能丢失、损坏或与您的应用程序不兼容。详细分析关于mfc140u.dll文件错误会对系统有什么影响&#xff0c;mfc140u.dll文件处于什么样的位置&#xff1f;以下是几种常见的错误情况及其修复方法…

R语言统计分析——功效分析(作图)

参考资料&#xff1a;R语言实验【第2版】 假设对于相关系数统计显著性检验&#xff0c;我们想计算一系列效应值和功效水平下所需的样本量&#xff0c;此时可用pwr.r.test()函数和for循环来完成任务。 # 加载pwr包 library(pwr) # 设置各效应值 r<-seq(0.1,0.5,0.01) # 计算…