总述

DXE(Driver Execution Environment)阶段,是执行大部分系统初始化的阶段,也就是说是BIOS发挥作用,初始化整个主板的主战场。在这个阶段我们可以进行大量的驱动工作。

PEI 是 DXE 之前的阶段,负责初始化平台中的永久内存(相对于Cache来说的内存,并非ROM),以便可以加载和执行 DXE 阶段。

PEI 阶段结束时的系统状态通过称为 Hand-Off Blocks (HOB) 的与位置无关的数据结构列表传递到 DXE 阶段。

There are several components in the DXE phase:

DXE 阶段有几个组件:

DXE Foundation

DXE 基础核心

DXE Dispatcher

DXE 调度器

A set of DXE Drivers

一组 DXE 驱动程序

从中可以看到,和 PEI 阶段的构成十分相似,这也印证了之前说的PEI 其实可以看作是 DXE 阶段的一个特殊微型版本。

DXE Foundation 生成一组 Boot ServicesRuntime Services 以及 DXE Services.

DXE Dispatcher 负责按正确的顺序发现和执行 DXE Drivers

DXE Drivers 负责 初始化处理器、芯片组和平台组件,以及为系统服务、控制台设备和启动设备提供软件。

DXE 阶段和 引导设备选择 (BDS) 阶段协同工作,以建立控制台并尝试引导 OS。成功启动 OS 后,DXE 阶段将终止。

DXE Foundation 由启动服务代码组成,因此不允许将 DXE Foundation 本身的代码保留在 OS 运行时环境中。

仅允许 DXE Foundation 分配的运行时数据结构以及 驱动程序生成的服务和数据结构 保留在 OS 运行时环境中。

下面介绍一下DXE,本人初学者,一家之言,如有错误请留言指正。

DXE Foundation

DXE Foundation,在代码中的实际表现为 DxeMain 函数,路径为edk2\MdeModulePkg\Core\Dxe\DxeMain\DxeMain.c

在DXE阶段,最重要的资源是 System Table,如下 DxeMain.c中初始化的 mEfiSystemTableTemplate,这个变量将在随后被执行的代码中逐步完善此table。

EFI_SYSTEM_TABLE  mEfiSystemTableTemplate = {
{
EFI_SYSTEM_TABLE_SIGNATURE, // Signature
EFI_SYSTEM_TABLE_REVISION, // Revision
sizeof (EFI_SYSTEM_TABLE), // HeaderSize
0, // CRC32
0 // Reserved
},
NULL, // FirmwareVendor
0, // FirmwareRevision
NULL, // ConsoleInHandle
NULL, // ConIn
NULL, // ConsoleOutHandle
NULL, // ConOut
NULL, // StandardErrorHandle
NULL, // StdErr
NULL, // RuntimeServices
&mBootServices, // BootServices
0, // NumberOfConfigurationTableEntries
NULL // ConfigurationTable
};

DXE 阶段提供的所有服务都可以通过 System Table 的指针进行访问。

这个变量如此重要,因而 UEFI 专门将这个 mEfiSystemTableTemplate赋给一个全局变量gST,方便我们调用。

具体的赋值逻辑如下:

DxeMain.c 中
gDxeCoreST = AllocateRuntimeCopyPool (sizeof (EFI_SYSTEM_TABLE), &mEfiSystemTableTemplate);
...
ProcessLibraryConstructorList (gDxeCoreImageHandle, gDxeCoreST);
...
||
||
\/
MdePkg\Library\UefiBootServicesTableLib\UefiBootServicesTableLib.c 中
....
gST = SystemTable;
....

System Table 中,有两个重要的 Service:BootServices 以及 RuntimeServices

这两个 ServiceOS Loader 提供了接口,用于访问硬件和软件资源。

同样地,UEFI 也分配了两个全局变量,gBSgRT来指代这两个Service。

在编写其他驱动或应用程序的时候,System Table指针作为 Image(就是其他的 UEFI 应用或 UEFI 驱动编译形成 .efi 文件被加载到内存后形成的东西) 的Entry Point的参数传递进来,类似于 Main 函数的参数一样,因此,我们可以直接使用它。

每一个 .efi 文件加载到内存中,会变成Image,UEFI 会创建ImageHandle,我们可以用这个ImageHandle来调用或做相关操作。

Image的入口函数有统一的格式,可以在很多地方找到,可以查看 EDK2 中的例程学习。

例如,HelloWorld 应用:MdeModulePkg\Application\HelloWorld\HelloWorld.c 或者 I2C 驱动MdeModulePkg\Bus\I2c\I2cDxe\I2cDxe.c,其函数原型如下:

typedef
EFI_STATUS
(EFIAPI *EFI_IMAGE_ENTRY_POINT)(
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
);

BootServices

首先介绍 SystemTable 中最重要的 BootServices

BootService 是 UEFI 的核心 API,可以做很多事情,例如内存分配释放、驱动管理、Protocol 的管理以及使用、UEFI 应用程序或驱动程序的加载、卸载、启动和退出等。

其中最重要的,也是我们接触最多的便是 Protocol,其不仅是 DXE 阶段,也是我们整个 BIOS 的核心工作。

什么是Protocol

Protocol

UEFI 使用 Handle 来指代着我们需要初始化的诸多设备对象(例如PCIe设备),而 设备的驱动以 Protocol 的形式安装到这个 Handle上。

Protocol的本质是一个结构体,这个结构体内存了很多的函数来实现不同的功能。其实Protocol如同PEIM中的PPI,是一套功能的集合,里面就是一套函数集合+一个Guid

Protocol需要等到 DXE 阶段才可以使用(不需要特别在意 DXE 阶段的哪个点开始,基本上我们开发时写的 DXE 模块都可以使用)。

EDK2框架下,提供了现有的API函数来Install(安装)Open(打开)、使用Protocol等。

比如使用Protocol内的功能前需要先打开Protocol,有三个API可以打开,OpenProtocol()HandleProtocol()LocateProtocol().使用完毕要关闭Protocol,使用CloseProtocol().

PPI一样,Protocol必须先Install才能使用。

Protocol的作用跟普通的结构体没有区别,存放的是函数指针,可以调用来让特定功能代码执行。

UEFI下将大部分的设备初始化流程和其它功能都包装成了一个个的Protocol,所以要学习UEFI,Protocol是必经之路。

Protocol在哪里?

具象到代码中,在MdeModulePkg\Core\Dxe\Hand\Handle.h中定义了PROTOCOL_ENTRY

///
/// PROTOCOL_ENTRY - each different protocol has 1 entry in the protocol
/// database. Each handler that supports this protocol is listed, along
/// with a list of registered notifies.
///
typedef struct {
UINTN Signature;
/// Link Entry inserted to mProtocolDatabase
LIST_ENTRY AllEntries;
/// ID of the protocol
EFI_GUID ProtocolID;
/// All protocol interfaces
LIST_ENTRY Protocols;
/// Registerd notification handlers
LIST_ENTRY Notify;
} PROTOCOL_ENTRY;

其他成员先不管,可以看到有一个EFI_GUID ProtocolID以及LIST_ENTRY Protocols,不难猜出,Protocol 被和Guid 以及其他一些信息一起封装,封装成为了PROTOCOL_ENTRY

实际上,ProtocolHandle中有很多双向链表,比较复杂,当然,不了解这一点也没问题。因为我们创建或者使用 Protocol 时使用 BootService(gBS 或者 gST->BootServices)的 API 函数来做。

回顾并总结一下。从具象的角度来说,Protocol是 一个个的结构体,包含了一些属性(成员变量)和函数指针(功能)。Protocol 是一个 DXE 驱动暴露给外界的服务,是提供者和使用者的一个约定,这个约定规范了提供服务或者使用服务所必须的一些流程和方式(例如要通过Guid来使用Protocol)。

代码

代码之前的一些概念

Protocol 可以被翻译为"服务",是用于向外界提供功能或者数据的接口。和驱动Driver的概念非常类似,但是在 UEFI 中,服务 Protocol 和驱动 Driver 是两个独立的概念,该如何理解?这涉及到了 UEFI 的驱动模型。

《UEFI 原理与编程》这本书中写:

服务与驱动不同,驱动需要特定的硬件的支持,而服务则不需要。

通常服务要能够常驻内存,而应用程序是不可常驻内存的,只有驱动可以。

所以,我们需要用驱动的形式来提供服务,这种被称作“服务型驱动”

在 UEFI 的标准中,驱动被分为两类:

一类是符合 UEFI 驱动模型的驱动,称为“ UEFI 驱动”;包括总线驱动、设备驱动和混合驱动。通过实现 Driver Binding Protocol 来控制设备。这些驱动程序可以动态地启动、停止和管理设备。

另一类是不遵循 UEFI 驱动模型的驱动,称为“ DXE 驱动”;有这些[1]

(1)服务型驱动 (Protocol)

不管理任何设备,不需要硬件支持,用来产生protocol提供功能服务。

一般来说,服务是可以常驻内存的,应用程序不能常驻内存,只有驱动可以,所以用驱动的形式来提供服务,称之为服务型驱动。

(2)初始化驱动

不产生任何句柄,用来做一些初始化操作,执行完后就会从系统中卸载。

(3)根桥型驱动

用来初始化平台上的根桥控制器,并产生一个设备地址 Protocol,以及访问总线设备的 Protocol。

一般用来通过总线驱动访问设备。比如,使用的支持访问 PCIe/PCI 设备的 EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL

UEFI Driver 主要用于管理 PCI 设备,采用分层架构,具有良好的模块化特性,层次结构清晰。

相较之下,DXE Driver 主要负责平台的初始化工作以及一些功能服务。

有一个感性认识:

UEFI 驱动的执行流程为:

-> UEFI 驱动被加载到内存中

-> EntryPoint 入口函数

-> 执行 gBS->InstallProtocolInterface()

-> 通过 Driver Binding Protocol (struct EFI_DRIVER_BINDING_PROTOCOL) 以及 Component Name Protocol 这两个服务,安装驱动到自身的 Handle 或其他 Handle 上

-> 使用 Driver Binding Protocol 给的三个API来管理 驱动以及其 Protocol

服务型驱动则很简单,具体流程为:

-> EntryPoint 入口函数

-> 将Protocol安装到自身的Handle

“服务型驱动”并不遵循 UEFI 驱动模型,因此是属于 DXE 驱动。

有以下几个特点:

  • 在 Image 的入口函数中执行安装,因此也无法进行多次安装(无法卸载再安装,必须卸载整个驱动文件重新执行 loadImage 命令,即再次进入驱动文件的入口函数)
  • 不需要驱动特定的硬件,可以单纯的是软件功能,所以可以安装到任意的控制器(设备)上
  • 没有提供卸载函数

所以服务型驱动(DXE驱动),可以看作是一种简易版本的 UEFI 驱动。

因此,下面以 DXE 驱动为例子,进行代码实践。

Install一个自己的Protocol

与 PEI 阶段中的 PPI 类似,Protocol 在使用之前也需要安装。

与 PPI 不同的是,Protocol 需要安装在 Image 对象的句柄(Handle)上。

BootService 提供了一个 API,InstallProtocolInterface,可以通过gBS->InstallProtocolInterface 来安装 Protocol。其定义如下:MdePkg\Include\Uefi\UefiSpec.h

/**
Installs a protocol interface on a device handle. If the handle does not exist, it is created and added
to the list of handles in the system. InstallMultipleProtocolInterfaces() performs
more error checking than InstallProtocolInterface(), so it is recommended that
InstallMultipleProtocolInterfaces() be used in place of
InstallProtocolInterface() @param[in, out] Handle A pointer to the EFI_HANDLE on which the interface is to be installed.
@param[in] Protocol The numeric ID of the protocol interface.
@param[in] InterfaceType Indicates whether Interface is supplied in native form.
@param[in] Interface A pointer to the protocol interface. @retval EFI_SUCCESS The protocol interface was installed.
@retval EFI_OUT_OF_RESOURCES Space for a new handle could not be allocated.
@retval EFI_INVALID_PARAMETER Handle is NULL.
@retval EFI_INVALID_PARAMETER Protocol is NULL.
@retval EFI_INVALID_PARAMETER InterfaceType is not EFI_NATIVE_INTERFACE.
@retval EFI_INVALID_PARAMETER Protocol is already installed on the handle specified by Handle. **/
typedef
EFI_STATUS
(EFIAPI *EFI_INSTALL_PROTOCOL_INTERFACE)(
IN OUT EFI_HANDLE *Handle,
IN EFI_GUID *Protocol,
IN EFI_INTERFACE_TYPE InterfaceType,
IN VOID *Interface
);

步骤

Protocol 是一套功能函数和数据的集合,所以 Protocol 是一个结构体。

我们需要自己定义这个结构体的原型,然后实例化这个结构体。

紧接着,再将这个 Protocol 实例和一个 Guid 绑定,即 完成安装。

我们以一个打印 Hello Protocol 字符串的例子,来 Install 一个 名为EFI_HELLO_PROTOCOL的 Protocol。

  1. 在目录edk2\OvmfPkg\Include\Protocol\新建一个文件HelloProtocol.h,用于定义 EFI_HELLO_PROTOCOL 的原型和功能函数的原型。内容如下:
// edk2\OvmfPkg\Include\Protocol\HelloProtocol.h
#ifndef __HELLO_PROTOCOL_H
#define __HELLO_PROTOCOL_H EFI_GUID gEfiHelloProtocolGuid= {0x2b35952b, 0xa6dc, 0x4181, {0xa2, 0xab, 0x95, 0x89, 0xbe, 0xcf, 0x4c, 0xb3}}; typedef struct _EFI_HELLO_PROTOCOL EFI_HELLO_PROTOCOL; // Protocol功能函数的定义
typedef
EFI_STATUS
(EFIAPI *PRINT_HELLO)(
IN EFI_HELLO_PROTOCOL *This
// 按照 UEFI 驱动模型,第一个参数需要是指向
// 这个函数所属的 Protocol的This指针,虽然我们是
// DXE 驱动,所撰写的 Protocol 也并无意和任何硬件绑定
// 但是我们为保证一致性仍然遵循这个规范
); // HelloProtocol结构体定义
struct _EFI_HELLO_PROTOCOL{
UINTN Data;
PRINT_HELLO Hello;
}; #endif // !__HELLO_PROTOCOL_H
  1. 在目录edk2\OvmfPkg\下新建目录MyHelloProtocolInstall :即edk2\OvmfPkg\MyHelloProtocolInstall,并创建两个文件

    MyHelloProtocolInstall.c 以及 MyHelloProtocolInstall.inf
// MyHelloProtocolInstall.c 文件内容
#include <Uefi.h> #include <Library/UefiDriverEntryPoint.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/MemoryAllocationLib.h>
#include <Library/DebugLib.h> #include <Protocol/HelloProtocol.h> // 1、实现Protocol的功能函数
EFI_STATUS
EFIAPI
PrintHello(
IN EFI_HELLO_PROTOCOL *This
)
{
DEBUG((EFI_D_ERROR, "[MyHelloProtocol] Hello Protocol!\r\n")); return EFI_SUCCESS;
} // 入口函数
EFI_STATUS
EFIAPI
ProtocolServerEntry (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
EFI_HELLO_PROTOCOL *Protocol; Status = EFI_SUCCESS; // 2、实例化Protocol,分配相应的内存空间
Protocol = AllocatePool(sizeof(EFI_HELLO_PROTOCOL));
if (NULL == Protocol)
{
DEBUG((EFI_D_ERROR, "[MyHelloProtocol] Protocol Memory Allocate Failed!\r\n"));
return EFI_OUT_OF_RESOURCES;
}
// 为Protocol的成员赋值
Protocol->Data = 0x01;
Protocol->Hello = PrintHello; // 3、Install 这个 Protocol
Status = gBS->InstallProtocolInterface(
&ImageHandle,
&gEfiHelloProtocolGuid,
EFI_NATIVE_INTERFACE,
Protocol
);
// 安装失败的处理
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "[MyHelloProtocol] Install EFI_HELLO_PROTOCOL Failed! Code - %r\n", Status));
FreePool (Protocol);
Protocol = NULL;
return Status;
} return Status;
}
// MyHelloProtocolInstall.inf 文件内容
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = MyHelloProtocolInstall
FILE_GUID = b885710c-40f9-4a92-a5ce-022829746c5e
MODULE_TYPE = UEFI_DRIVER
VERSION_STRING = 1.0
ENTRY_POINT = ProtocolServerEntry [Sources.common]
MyHelloProtocolInstall.c [Packages]
MdePkg/MdePkg.dec
OvmfPkg/OvmfPkg.dec # 如果不包含自己的这个包,那么头文件就
# 需要写为 #include "../Include/Protocol/HelloProtocol.h" [LibraryClasses]
UefiDriverEntryPoint
UefiBootServicesTableLib
MemoryAllocationLib
DebugLib [Protocols] [Depex]
TRUE

安装一个 Protocol 就是实现一个 Protocol ,因此需要

1、 实例化 Protocol 结构体(在这之前需要实现 Protocol 内的函数)

2、 调用 gBS->InstallProtocolInterface()GuidProtocol 实例绑定。

另外,不要忘记,在OvmfPkg\OvmfPkgX64.dsc[Components]中添加我们的.inf文件,这样才会被编译。

以及 OvmfPkg\OvmfPkgX64.fdf中的[FV.DXEFV],增加如下:

使用Protocol

使用 Protocol 的方式有很多,主要是 BS 中的 OpenProtocol()HandleProtocol() 以及 LocateProtocol() 函数。

gBS->OpenProtocol()gBS->HandleProtocol() 的功能主要是打开指定设备(入参 Handle)中安装的某个Protocol

由于我们期望调用的我们自己的 HelloProtocol 是属于服务型 Protocol,因此我们并不关心这个 Protocol 具体在哪个设备上。

另外,系统中仅仅只有一个我们的 HelloProtocol 的实例,所以,我们使用 gBS->LocateProtocol() 来找到我们安装好的 HelloProtocol

回顾一下,在 DXE 阶段中,Protocol 是 被DXE Foundation 自动调度到我们的 MyHelloProtocolInstall 后,进行安装的。

如果要使用这个 Protocol,可以写一个名为MyHelloProtocolLocate的应用程序,即类型为UEFI Application来调用。

具体步骤

1、在目录OvmfPkg\MyHelloProtocolLocate\ 下分别创建MyHelloProtocolLocate.c以及MyHelloProtocolLocate.inf

2、编写这两文件,内容如下:

# MyHelloProtocolLocate.inf
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = MyHelloProtocolLocate
FILE_GUID = 554b3cbf-af08-44c7-829f-13a59ee0bf21
MODULE_TYPE = UEFI_APPLICATION
VERSION_STRING = 1.0
ENTRY_POINT = ProtocolConsumerEntry [Sources]
MyHelloProtocolLocate.c [Packages]
MdePkg/MdePkg.dec
OvmfPkg/OvmfPkg.dec # 如果不包含这个包,那么头文件就需要写为 #include "../Include/Protocol/HelloProtocol.h" [LibraryClasses]
UefiApplicationEntryPoint
UefiBootServicesTableLib
MemoryAllocationLib
DebugLib
UefiLib
// MyHelloProtocolLocate.c
#include <Uefi.h> #include <Library/UefiLib.h>
#include <Library/BaseLib.h>
#include <Library/DebugLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/UefiBootServicesTableLib.h> #include "Protocol/HelloProtocol.h" EFI_STATUS
EFIAPI
ProtocolConsumerEntry(
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
EFI_STATUS Status;
EFI_HELLO_PROTOCOL *Protocol; Status = EFI_SUCCESS; DEBUG ((EFI_D_ERROR , "[MyHelloProtocol] MyHelloProtocol App ProtocolEntry Start..\n"));
Print (L"[MyHelloProtocol] MyHelloProtocol App ProtocolConsumerEntry Has Started..\n"); // 1、根据Guid, Locate Protocol,LocateProtocol()会自动将其装填进 第三个参数 Protocol这个变量里
Status = gBS->LocateProtocol(
&gEfiHelloProtocolGuid,
NULL,
(VOID **)&Protocol
);
// locate失败的操作
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "[MyHelloProtocol] Locate EFI_HELLO_PROTOCOL Failed! - %r\n", Status));
Print(L"[MyHelloProtocol] Locate Protocol gEfiHelloProtocolGuid Failed - Code: %r \n",Status);
return Status;
} // 2、使用 Protocol
// 拿Protocol内的数据
DEBUG ((EFI_D_ERROR, "[MyHelloProtocol] Protocol Version: 0x%08x\n", Protocol->Data)); // 调Protocol内的功能 ---- Hello
Status = Protocol->Hello (Protocol);
if (EFI_ERROR (Status)) {
DEBUG ((EFI_D_ERROR, "[MyHelloProtocol] Protocol->Hello Failed! - %r\n", Status));
return Status;
} DEBUG ((EFI_D_ERROR, "[MyHelloProtocol] MyHelloProtocol End..\n"));
Print (L"[MyHelloProtocol] MyHelloProtocol End ... \n"); return Status;
}

.c 文件大概的逻辑如下:

  • 根据 guid,找到 MyHelloProtocol,并将其装填进名为 Protocol 的局部变量中。
  • 使用 Protocol,根据函数指针调用功能或者直接拿取数据。

3、在edk目录下,先执行 ./edksetup.bat ,再 编译

build -a X64 -p OvmfPkg\OvmfPkgX64.dsc -D DEBUG_ON_SERIAL_PORT

4、在edk同级目录下创建ovmf文件夹

再创建 D:\edk2\ovmf\esp 文件夹,并且将D:\edk2\edk2\Build\OvmfX64\DEBUG_VS2019\X64\MyHelloProtocolLocate.efi复制到上面的目录里D:\edk2\ovmf\esp\MyHelloProtocolLocate.efi

这一步是为了创建了一个分区,等会进 UEFI Shell中,挂载磁盘,方便我们执行UEFI App

5、进入qemu的文件夹,并且进入终端执行qemu-system-x86_64.exe -bios D:\edk2\edk2\Build\OvmfX64\DEBUG_VS2019\FV\OVMF.fd -hda fat:rw:D:\edk2\ovmf\esp -net none

如图:

6、运行App

进入shell后,输入fs0:,在ls命令查看文件,找到我们的MyHelloProtocolLocate.efi并执行。

7、查看运行结果,符合预期。


  1. UEFI学习笔记(十四):UEFI驱动的分类与UEFI驱动模型

【UEFI】DXE阶段从概念到代码的更多相关文章

  1. 第三章--Win32程序的执行单元(部分概念及代码讲解)(上 -- 多线程)

    学习<Windows程序设计>记录 概念贴士: 1. 线程描述了进程内代码的执行路径. 2. _stdcall是新标准C/C++函数的调用方法.从底层来说,使用这种调用方法参数的进栈顺序和 ...

  2. 第二章--Win32程序运行原理 (部分概念及代码讲解)

    学习<Windows程序设计>记录 概念贴士: 1. 每个进程都有赋予它自己的私有地址空间.当进程内的线程运行时,该线程仅仅能够访问属于它的进程的内存,而属于其他进程的内存被屏蔽了起来,不 ...

  3. OpenResty 执行阶段的概念和用途

    主要还是 Nginx 的执行阶段知识了,都是因为 OR 才会那么深刻, 它有些自己的阶段. 主要还是参照 春哥的 Nginx 教程 请多读几遍,如果不清楚nginx的执行阶段就无法充分利用 openr ...

  4. bluetooth(蓝牙) AVRCP协议概念及代码流程解析

    一 概念 AVRCP全称:The Audio/Video Remote Control Profile (AVRCP) 翻译成中文就是:音视频远程控制协议.概念:AVRCP定义了蓝牙设备之间的音视频传 ...

  5. 基于ARMv8的固件系统体系结构

    基于ARMv8的固件系统体系结构 The architecture of ARMv8-based firmware systems 自2011年发布以来,ARMv8处理器架构在移动设备市场上已经相当普 ...

  6. EDK II之DXE Core框架简介

    本文旨在简单的介绍一下DXE阶段的工作原理: UDK2015的开源代码下载:https://github.com/tianocore/tianocore.github.io/wiki/EDK-II D ...

  7. (译)UEFI 启动:实际工作原理

    本文是我翻译自国外技术博客的一篇文章,其中讲述了 UEFI 的一些基本概念和细节. 本文的原始链接位于: https://www.happyassassin.net/2014/01/25/uefi-b ...

  8. UEFI EVENT 全解

    Event和Timer在UEFI当中是怎么实现的以及原理,我们先从Timer开始,然后细细的拨开隐藏在底层的实现. 先说Timer,那什么是Timer呢?其实在中文里面我们把它叫做定时/计数器,但是我 ...

  9. 笔记三(UEFI详解)

    1.SEC 安全验证 SEC(Security Phase)阶段是平台初始化的第一个阶段,计算机系统加电后进入这个阶段. 1)接收并处理系统启动和重启信号:系统加点信号.系统重启信号.系统运行过程中的 ...

  10. UEFI启动(翻译)

    本文是我翻译自国外技术博客的一篇文章,其中讲述了 UEFI 的一些基本概念和细节. 本文的原始链接位于: https://www.happyassassin.net/2014/01/25/uefi-b ...

随机推荐

  1. 使用vscode开发微信小程序

    1. 安装插件 2. 文件-打开文件夹-将新建的微信小程序导入,代码会有高亮的效果 3. 编辑内容,查看效果,如果有就说明插件引入成功.

  2. kalibr标定单相机,自用指南,防忘记

    1. 标定环境 1.1 从源码编译(linux环境,建议ubuntu 18或20) 步骤见 kalibr wiki 1.2 Docker 如果实体机为Ubuntu,则见official docker ...

  3. QT5笔记:34. 视口和窗口

    ![image-20220504160327597](QT5 使用.assets/image-20220504160327597.png) 例子: void Widget::paintEvent(QP ...

  4. 附039.Kubernetes_v1.32.2高可用部署架构二

    部署组件 该 Kubernetes 部署过程中,对于部署环节,涉及多个组件,主要有 kubeadm .kubelet .kubectl. kubeadm介绍 Kubeadm 为构建 Kubernete ...

  5. Swagger OpenAPI Schema 为空时 Example Value 显示 "string" 的原因及解决方案

    解决Swagger UI示例值显示"string"的问题 最近在使用ObjectScript生成JSON接口文档时,遇到了一个奇怪的问题: 生成的JSON数据是正常的. 但Swag ...

  6. Forest v1.5.13 发布,声明式 HTTP 框架,已超 1.8k star

    Forest介绍 Forest 是一个开源的 Java HTTP 客户端框架,它能够将 HTTP 的所有请求信息(包括 URL.Header 以及 Body 等信息)绑定到您自定义的 Interfac ...

  7. 【计算力学】CST单元格式推导

    CST单元格式推导

  8. [第一章]ABAQUS CM插件中文手册

    ABAQUS Composite Modeler User Manual(zh-CN) Dassault Systèmes, 2018 注: 源文档的交叉引用链接,本文无效 有些语句英文表达更易理解, ...

  9. pytest 框架使用规则

    使用pytest 注意 有时候常常会调用时文件未执行,就是没注意命名规范 如何调用-命令行调用 pytest 批量运行测试用例 单个用例调试成功后,接下来我们要进行所有脚本统一执行 我要执行testc ...

  10. docker mysql SQLSTATE[HY000] [2002] Connection refused

    使用docker搭建lnmp环境,使用的是分容器的搭建方案 框架使用thinkphp,想要连接数据MySQL,一直显示"SQLSTATE[HY000] [2002] Connection r ...