目录
2.1.2 UEFI Applications(UEFI 应用)
2.1.3 UEFI OS Loaders(UEFI OS 加载器)
2.2.2 Runtime Services(Runtime 服务)
2.3.2 IA-32 Platforms(IA-32架构平台)
2.3.3 Intel® Itanium®-Based Platforms(Intel® Itanium®-Based架构平台)
2.3.5 AArch32 Platforms(AArch32架构平台)
2.3.5 AArch64 Platforms(AArch64架构平台)
2.3.7 RISC-V Platforms(RISC-V架构平台)
2.5 UEFI Driver Model(UEFI 驱动模型)
2.5.1 Legacy Option ROM Issues(遗留选项ROM问题)
2.5.2 Driver Initialization(驱动程序初始化)
2.5.3 Host Bus Controllers(主机总线控制器)
2.5.6 Platform Components(平台组件)
2.5.8 EFI Services Binding(EFI服务绑定)
2.6.2 Platform-Specific Elements(特定于平台的元素)
2.6.3 Driver-Specific Elements(驱动特定元素)
2.6.4 Extensions to this Specification published elsewhere(规范的扩展已在其他地方发布)
2 Overview(概述)
- UEFI允许通过加载UEFI驱动程序和UEFI应用程序映像来扩展平台固件。当加载UEFI驱动程序和UEFI应用程序时,它们可以访问所有UEFI定义的运行时和引导服务。参见图2。
- UEFI允许将OS加载程序和平台固件的引导菜单合并到一个平台固件菜单中。这些平台固件菜单将允许从UEFI引导服务支持的任何引导介质上的任何分区中选择任何UEFI OS加载器。UEFI OS加载器可以支持用户界面上出现的多个选项。还可以在平台固件引导菜单中包含遗留的引导选项,比如从A:或C:驱动器引导。
- UEFI支持从包含UEFI OS加载器或UEFI定义的系统分区的媒体引导。UEFI需要一个UEFI定义的系统分区来从块设备引导。UEFI不需要对分区的第一个扇区进行任何更改,因此可以构建同时在遗留体系结构和UEFI平台上引导的媒体。
2.1 Boot Manager(启动管理器)
- UEFI包含一个引导管理器,允许从UEFI定义的文件系统上的任何文件或通过使用UEFI定义的图像加载服务加载按此规范编写的应用程序(包括OS 1阶段加载器)或UEFI驱动程序。
- UEFI定义了NVRAM变量,用于指向要加载的文件。这些变量还包含直接传递给UEFI应用程序的特定于应用程序的数据。这些变量还包含一个人类可读的字符串,可以在菜单中显示给用户。
- UEFI定义的变量允许系统固件包含一个引导菜单,该菜单可以指向所有操作系统,甚至同一个操作系统的多个版本。UEFI的设计目标是拥有一组可以驻留在平台固件中的引导菜单。UEFI只指定用于选择引导选项的NVRAM变量。UEFI将菜单系统的实现留作增值实现空间。
- UEFI极大地扩展了系统的引导灵活性,超过了PC-AT-class系统的当前状态。今天的PC-AT-class系统只能从附加到系统上的第一个软盘、硬盘、CD-ROM、USB密钥或网卡引导。从公共硬盘驱动器引导可能会导致操作系统之间的互操作性问题,以及来自同一供应商的不同版本的操作系统之间的互操作性问题。
2.1.1 UEFI Images(UEFI 镜像)
- UEFI映像是由包含可执行代码的UEFI定义的一类文件。UEFI图像最显著的特征是,UEFI图像文件中的第一组字节包含一个Images头,它定义了可执行Images的编码。
- UEFI使用PE32+Images格式的一个子集,带有修改的头签名。修改PE32+Images中的签名值是为了将UEFI Images与普通PE32可执行文件区分开来。PE32的“+”添加提供了标准PE32格式的64位重新定位修复扩展。
- 对于具有UEFI Images签名的Images,PE Images头部中的子系统值定义如下。映像类型之间的主要区别是固件将加载映像的内存类型,以及映像的入口点退出或返回时所采取的操作。当从Images的入口点返回控件时,总是卸载UEFI应用程序Images。只有在使用UEFI错误代码将控件传回时,才会卸载UEFI驱动程序映像。
// PE32+ Subsystem type for EFI images
#define EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION 10
#define EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11
#define EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12
// PE32+ Machine type for EFI images
#define EFI_IMAGE_MACHINE_IA32 0x014c
#define EFI_IMAGE_MACHINE_IA64 0x0200
#define EFI_IMAGE_MACHINE_EBC 0x0EBC
#define EFI_IMAGE_MACHINE_x64 0x8664
#define EFI_IMAGE_MACHINE_ARMTHUMB_MIXED 0x01C2
#define EFI_IMAGE_MACHINE_AARCH64 0xAA64
#define EFI_IMAGE_MACHINE_RISCV32 0x5032
#define EFI_IMAGE_MACHINE_RISCV64 0x5064
#define EFI_IMAGE_MACHINE_RISCV128 0x5128注意:选择此Images类型是为了使UEFI Images能够包含Thumb和Thumb2指令,同时将EFI接口本身定义为ARM模式。
Table 3. UEFI Image Memory Types
Subsystem Type | Code Memory Type | Data Memory Type |
EFI_IMAGE_SUSBSYTEM_EFI_APPLICATION | EfiLoaderData | EfiLoaderData |
EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER | EfiBootServicesCode | EfiBootServicesData |
EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER | EfiRuntimeServicesCode | EfiRuntimeServicesData |
- 在PE Images文件头中找到的Machine值用于指示Images的机器码类型。下面定义了具有UEFI Images签名的图像的机器码类型。给定的平台必须实现该平台本机的Images类型和EFI字节码(EBC)的Images类型。平台可选支持其他机器代码类型。
- UEFI映像通过EFI_BOOT_SERVICES.LoadImage()引导服务加载到内存中。该服务将一个PE32+格式的Images加载到内存中。需要使用这个PE32+加载器将PE32+ Images的所有部分加载到内存中。一旦将映像加载到内存中,并执行了适当的修复,控制就会根据应用程序基于支持的32位、64位或128位处理器的正常间接调用约定,在AddressOfEntryPoint引用处转移到已加载的映像。与UEFI映像的所有其他链接都是通过编程实现的。
2.1.2 UEFI Applications(UEFI 应用)
- 按照此规范编写的应用程序由引导管理器或其他UEFI应用程序加载。为了加载UEFI应用程序,固件分配足够的内存来保存映像,将UEFI应用程序映像中的部分复制到分配的内存中,并应用所需的重新定位修复。一旦完成,分配的内存就被设置为代码和图像数据的正确类型。然后控制被转移到UEFI应用程序的入口点。当应用程序从其入口点返回时,或者当它调用引导服务EFI_BOOT_SERVICES.Exit()时,将从内存中卸载UEFI应用程序,并将控件返回到加载UEFI应用程序的UEFI组件。当引导管理器加载UEFI应用程序时,映像句柄可用于定位UEFI应用程序的“加载选项”。load选项存储在非易失性存储中,并与引导管理器加载和执行的UEFI应用程序相关联。
2.1.3 UEFI OS Loaders(UEFI OS 加载器)
- UEFI OS加载程序是一种特殊类型的UEFI应用程序,它通常从符合该规范的固件接管对系统的控制。加载时,UEFI OS加载程序的行为与任何其他UEFI应用程序一样,它必须只使用从固件分配的内存,并且只能使用UEFI服务和协议访问固件公开的设备。如果UEFI OS加载器包含任何引导服务风格的驱动程序函数,那么它必须使用适当的UEFI接口来获得对总线特定资源的访问。也就是说,I/O和内存映射设备寄存器必须通过正确的总线特定的I/O调用来访问,就像UEFI驱动程序将要执行的那样。
- 如果UEFI OS加载器遇到问题,无法正确加载操作系统,它可以释放所有分配的资源,并通过Boot Service Exit()调用将控制权返回固件。Exit()调用允许返回错误代码和ExitData。ExitData包含要返回的字符串和特定于OS加载器的数据。如果UEFI OS加载器成功地加载了它的操作系统,它可以通过使用引导服务EFI_BOOT_SERVICES.ExitBootServices()来控制系统。成功调用ExitBootServices()后,系统中的所有引导服务都被终止,包括内存管理,UEFI OS加载器负责系统的继续操作。
2.1.4 UEFI Drivers(UEFI 驱动)
- UEFI驱动程序由引导管理器、符合此规范的固件或其他UEFI应用程序加载。为了加载UEFI驱动程序,固件分配足够的内存来保存映像,将UEFI驱动程序映像中的部分复制到分配的内存中,并应用所需的重新定位修复程序。一旦完成,分配的内存就被设置为代码和图像数据的正确类型。然后控制被转移到UEFI驱动程序的入口点。当UEFI驱动程序从其入口点返回时,或者当它调用引导服务EFI_BOOT_SERVICES.Exit()时,UEFI驱动程序可选地从内存中卸载,控件返回到加载UEFI驱动程序的组件。如果UEFI驱动程序返回EFI_SUCCESS状态代码,则不会从内存中卸载它。如果UEFI驱动程序的返回代码是错误状态代码,则从内存中卸载驱动程序。
- UEFI驱动程序有两种类型:引导服务驱动程序和运行时驱动程序。这两种驱动程序类型之间的唯一区别是,UEFI OS加载程序使用引导服务EFI_BOOT_SERVICES.ExitBootServices()控制平台之后,UEFI运行时驱动程序就可用了。
- 当调用ExitBootServices()时,UEFI引导服务驱动程序将被终止,UEFI引导服务驱动程序消耗的所有内存资源将被释放,以便在操作系统环境中使用。当操作系统调用SetVirtualAddressMap()时,EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER类型的运行时驱动程序使用虚拟映射修复。
2.2 Firmware Core(固件的核心)
- 本节概述UEFI定义的服务。这些服务包括引导服务和运行时服务。
2.2.1 UEFI Services(UEFI 服务)
- UEFI接口的目的是定义一个通用的引导环境抽象,供已加载的UEFI映像使用,其中包括UEFI驱动程序、UEFI应用程序和UEFI OS加载器。这些调用是用一个完整的64位接口定义的,因此未来还有增长的空间。这组抽象平台调用的目标是允许平台和操作系统彼此独立地发展和创新。此外,操作系统可以使用一组标准的基本运行时服务。
- 本节定义的平台接口允许使用标准即插即用选项Rom作为引导服务的底层实现方法。这些接口的设计方式类似于映射回遗留接口。这些接口没有受到遗留选项Rom固有的任何限制。
- UEFI平台接口旨在提供平台与要在平台上引导的操作系统之间的抽象。UEFI规范还提供了诊断程序或实用程序与平台之间的抽象;但是,它并不尝试实现一个完整的诊断OS环境。我们设想可以在UEFI系统上轻松构建一个小型的类似于os的诊断环境。本规范没有描述这样的诊断环境。
本规范所添加的接口分为以下几类,在本文档后面将详细介绍:
•Runtime services
•Boot services interfaces, with the following subcategories:
— Global boot service interfaces
— Device handle-based boot service interfaces
— Device protocols
— Protocol services
2.2.2 Runtime Services(Runtime 服务)
- 本节描述UEFI运行时服务函数。运行时服务的主要目的是从操作系统中抽象平台硬件实现的次要部分。运行时服务函数在引导过程中可用,并且在运行时提供操作系统切换到平面物理寻址模式以进行运行时调用。但是,如果OS加载器或OS使用运行时服务SetVirtualAddressMap()服务,则OS只能以虚拟寻址模式调用运行时服务。所有运行时接口都是非阻塞接口,如果需要,可以在禁用中断的情况下调用它们。为了确保与现有平台的最大兼容性,建议将组成运行时服务的所有UEFI模块在MemoryMap中表示为EfiRuntimeServicesCode类型的单个EFI_MEMORY_DESCRIPTOR。
- 在所有情况下,运行时服务使用的内存必须被保留,而不是由OS使用。运行时服务内存始终对UEFI函数可用,并且不会被操作系统或其组件直接操作。UEFI负责定义运行时服务使用的硬件资源,以便在运行时服务调用时操作系统可以与这些资源同步,或者确保操作系统从不使用这些资源。
表4列出了运行时服务函数。
Name | Description |
GetTime() | 返回当前时间、时间上下文和时间保持功能。 |
SetTime() | 设置当前时间和时间上下文。 |
GetWakeupTime () | 返回当前的唤醒警报设置。 |
SetWakeupTime () | 设置当前唤醒报警设置。 |
GetVariable () | 返回指定变量的值。 |
GetNextVariableName () | 枚举变量名。 |
SetVariable () | 置一个变量,如果需要,创建一个变量。 |
SetVirtualAddressMap () | 将所有运行时函数从物理寻址切换到虚拟寻址。 |
ConvertPointer () | 用于将指针从物理地址转换为虚拟地址。 |
GetNextHighMonotonicCount () | 包含平台的单调计数器功能。 |
ResetSystem () | 重置所有处理器和设备并重新启动系统。 |
UpdateCapsule () | 通过虚拟和物理映射将胶囊传递到固件。 |
QueryCapsuleCapabilities () | 返回是否可以通过updatecap()支持胶囊。 |
QueryVariableInfo () | 返回关于EFI变量存储的信息。 |
2.3 Calling Conventions(调用约定)
- 除非另有说明,否则在UEFI规范中定义的所有函数都是通过指针调用的,这些指针使用C编译器中常见的、体系结构定义的调用约定。
- 指向各种全局UEFI函数的指针可以在通过系统表定位的EFI_RUNTIME_SERVICES和EFI_BOOT_SERVICES表中找到。指向此规范中定义的其他函数的指针通过设备句柄动态定位。在所有情况下,所有指向UEFI函数的指针都使用EFIAPI这个单词进行转换。这允许每个体系结构的编译器提供适当的编译器关键字,以实现所需的调用约定。当将指针参数传递给引导服务、运行时服务和协议接口时,调用者有以下职责:
- 调用者的职责是传递引用物理内存位置的指针参数。如果传递的指针不指向物理内存位置(即,内存映射I/O区域),结果是不可预测的,系统可能会停止。
- 调用者的职责是传递具有正确对齐的指针参数。如果将未对齐指针传递给函数,结果是不可预测的,系统可能会停止。
- 调用者的责任是,除非显式允许,否则不将NULL参数传递给函数。如果一个空指针被传递给一个函数,结果是不可预测的,系统可能会挂起。
- 除非另有说明,否则如果函数返回一个错误,调用者不应该对指针参数的状态做出任何假设。
- 调用者不能传递按值大于本机大小的结构,这些结构必须由调用者通过引用(通过指针)传递。传递大于本机宽度的结构(在支持的32位处理器上传递4个字节;栈上的8个字节(支持64位处理器指令)将产生未定义的结果。
- 下面将更详细地描述支持32位和支持64位应用程序的调用约定。任何函数或协议都可以返回任何有效的返回代码。
- UEFI模块的所有公共接口都必须遵循UEFI调用约定。公共接口包括图像入口点、UEFI事件处理程序和协议成员函数。类型EFIAPI用于指示与本节定义的调用约定的一致性。非公共接口(如私有函数和静态库调用)不需要遵循UEFI调用约定,编译器可以对其进行优化。
2.3.1 Data Types(数据类型)
2.3.2 IA-32 Platforms(IA-32架构平台)
2.3.3 Intel® Itanium®-Based Platforms(Intel® Itanium®-Based架构平台)
2.3.4 x64 Platforms(x64架构平台)
2.3.5 AArch32 Platforms(AArch32架构平台)
2.3.5 AArch64 Platforms(AArch64架构平台)
2.3.7 RISC-V Platforms(RISC-V架构平台)
2.4 Protocols(协定)
- 设备句柄支持的协议是通过EFI_BOOT_SERVICES.HandleProtocol()引导服务或EFI_BOOT_SERVICES.OpenProtocol()引导服务发现的。每个协议都有一个规范,包括以下内容:
- 协议的全局惟一ID (GUID)
- 协议接口结构
- 协议服务
- 除非另有规定,否则不从运行时内存分配协议的接口结构,并且不应在运行时调用协议成员函数。如果没有显式指定,可以在小于或等于TPL_NOTIFY的TPL级别调用协议成员函数(请参见第7.1节)。除非另有规定,否则协议的成员函数不是可重入的或MP安全的。
- 任何状态码协议定义的成员函数定义是需要实现的,额外的就会返回一个错误代码,但他们不会被测试通过标准遵从性测试,和任何软件使用过程不能依靠任何扩展的错误代码,可以提供一个实现。
- 为了确定句柄是否支持任何给定的协议,协议的GUID被传递给HandleProtocol()或OpenProtocol()。如果设备支持请求的协议,则返回一个指向已定义协议接口结构的指针。协议接口结构将调用方链接到此设备使用的特定于协议的服务。
- 图5显示了协议的构造。UEFI驱动程序包含特定于一个或多个协议实现的函数,并将它们注册到引导服务EFI_BOOT_SERVICES.InstallProtocolInterface()。固件返回协议的协议接口,然后用于调用特定于协议的服务。UEFI驱动程序使用协议接口保持私有的、特定于设备的上下文。
- 下面的C代码片段说明了协议的使用:
// There is a global “EffectsDevice” structure. This
// structure contains information pertinent to the device.
// Connect to the ILLUSTRATION_PROTOCOL on the EffectsDevice,
// by calling HandleProtocol with the device’s EFI device handle
// and the ILLUSTRATION_PROTOCOL GUID.
EffectsDevice.Handle = DeviceHandle;
Status = HandleProtocol (
EffectsDevice.EFIHandle,
&IllustrationProtocolGuid,
&EffectsDevice.IllustrationProtocol
);
// Use the EffectsDevice illustration protocol’s “MakeEffects”
// service to make flashy and noisy effects.
Status = EffectsDevice.IllustrationProtocol->MakeEffects (
EffectsDevice.IllustrationProtocol,
TheFlashyAndNoisyEffect
);
- 表8列出了此规范定义的UEFI协议。
2.5 UEFI Driver Model(UEFI 驱动模型)
- UEFI驱动程序模型旨在简化设备驱动程序的设计和实现,并生成较小的可执行映像大小。因此,一些复杂性已经转移到总线驱动程序中,并且在很大程度上转移到了公共固件服务中。
- 设备驱动程序需要在加载驱动程序的同一映像句柄上生成驱动程序绑定协议。然后等待系统固件将驱动程序连接到控制器。当发生这种情况时,设备驱动程序负责在控制器的设备句柄上生成一个协议,该协议抽象控制器支持的I/O操作。总线驱动程序执行完全相同的任务。此外,总线驱动程序还负责发现总线上的任何子控制器,并为找到的每个子控制器创建设备句柄。
- 一个假设是,系统的体系结构可以看作是连接到一个或多个核心芯片组的一个或多个处理器的集合。核心芯片组负责生产一个或多个I/O总线。UEFI驱动程序模型不试图描述处理器或核心芯片组。相反,UEFI驱动程序模型描述由核心芯片组生成的I/O总线集,以及这些I/O总线的任何子节点。这些子节点可以是设备,也可以是额外的I/O总线。这可以看作是总线和设备的树,树的根上有核心芯片组。
- 这个树结构中的叶子节点是执行某种类型的I/O的外围设备。这可能包括键盘、显示器、磁盘、网络等等。非叶节点是在设备和总线之间或不同总线类型之间移动数据的总线。图6显示了一个包含4个总线和6个设备的示例桌面系统。
- 图7是一个更复杂的服务器系统的示例。其思想是使UEFI驱动程序模型简单且可扩展,这样就可以在预引导环境中描述和管理更复杂的系统,如下所示。该系统包括6个总线和8个设备。
- 任何给定平台上的固件服务、总线驱动程序和设备驱动程序的组合都可能由各种供应商(包括oem、ibv和ihv)生产。来自不同供应商的这些不同组件需要一起工作,为I/O设备生成一个协议,用于引导符合UEFI的操作系统。因此,为了提高这些组件的互操作性,对UEFI驱动程序模型进行了非常详细的描述。
- 本节的其余部分是UEFI驱动程序模型的简要概述。它描述了UEFI驱动程序模型设计用来解决的遗留选项ROM问题、驱动程序的入口点、主机总线控制器、设备驱动程序的属性、总线驱动程序的属性,以及UEFI驱动程序模型如何适应热插拔事件。
2.5.1 Legacy Option ROM Issues(遗留选项ROM问题)
2.5.2 Driver Initialization(驱动程序初始化)
- 驱动程序映像的文件必须从某种类型的媒体加载。这可能包括ROM、闪存、硬盘、软盘驱动器、CD-ROM,甚至网络连接。一旦找到驱动程序映像,就可以使用引导服务EFI_BOOT_SERVICES.LoadImage()将其加载到系统内存中。LoadImage()将一个PE/COFF格式的Image加载到系统内存中。为驱动程序创建一个句柄,并将加载的映像协议实例放在该句柄上。包含加载的映像协议实例的句柄称为映像句柄。此时,驱动程序还没有启动。它只是坐在记忆里等待着被启动。图8显示了调用LoadImage()之后驱动程序的Image句柄的状态。
- 在用引导服务LoadImage()加载驱动程序之后,必须用引导服务EFI_BOOT_SERVICES.StartImage()启动驱动程序。这适用于所有类型的UEFI应用程序和UEFI驱动程序,它们可以在符合UEFI的系统上加载和启动。遵循UEFI驱动程序模型的驱动程序的入口点必须遵循一些严格的规则。首先,它不允许接触任何硬件。相反,驱动程序只允许将协议实例安装到它自己的映像句柄上。遵循UEFI驱动程序模型的驱动程序需要将驱动程序绑定协议的实例安装到自己的映像句柄上。它可以选择安装驱动程序配置协议、驱动程序诊断协议或组件名称协议。此外,如果驱动程序希望可卸载,它可以选择更新已加载的映像协议(参见第9节),以提供自己的Unload()函数。最后,如果驱动程序需要在调用引导服务EFI_BOOT_SERVICES.ExitBootServices()时执行任何特殊操作,它可以选择创建一个带有通知函数的事件,该函数在调用引导服务ExitBootServices()时触发。包含驱动程序绑定协议实例的映像句柄称为驱动程序映像句柄。图9显示了在调用引导服务StartImage()之后,图8中的映像句柄的可能配置。
2.5.3 Host Bus Controllers(主机总线控制器)
- 驱动程序不允许触摸驱动程序入口点中的任何硬件。因此,驱动程序将被加载并启动,但它们都将等待被告知管理系统中的一个或多个控制器。平台组件(如引导管理器)负责管理驱动程序到控制器的连接。然而,在建立第一个连接之前,必须有一些控制器的初始集合供驱动程序管理。这个控制器的初始集合称为主机总线控制器。主机总线控制器提供的I/O抽象由不在UEFI驱动程序模型范围内的固件组件生成。主机总线控制器的设备句柄和每个控制器的I/O抽象必须由平台上的核心固件或不遵循UEFI驱动程序模型的驱动程序生成。有关PCI总线的I/O抽象示例,请参阅PCI根桥接I/O协议规范。
- 平台可以看作是一组处理器和一组核心芯片组组件,它们可以生成一个或多个主机总线。图10显示了一个拥有n个处理器(cpu)和一组核心芯片组组件的平台,这些核心芯片组组件生成m个主机桥接。
- 在UEFI中,每个主机桥接都表示为一个设备句柄,该句柄包含一个设备路径协议实例和一个协议实例,该协议实例抽象主机总线可以执行的I/O操作。例如,PCI主机总线控制器支持一个或多个由PCI根桥接I/O协议抽象的PCI根桥接。图11显示了一个PCI根桥接器的设备句柄示例。
- PCI总线驱动程序可以连接到这个PCI根桥,并为系统中的每个PCI设备创建子句柄。然后应该将PCI设备驱动程序连接到这些子句柄,并生成I/O抽象,这些抽象可用于引导符合UEFI的OS。下一节描述可以在UEFI驱动程序模型中实现的不同类型的驱动程序。UEFI驱动程序模型非常灵活,因此这里不讨论所有可能的驱动程序类型。相反,本文将介绍主要类型,这些类型可作为设计和实现其他驱动程序类型的起点。
2.5.4 Device Drivers(设备驱动程序)
- 设备驱动程序不允许创建任何新设备句柄。相反,它在现有设备句柄上安装额外的协议接口。最常见的设备驱动程序类型将把I/O抽象附加到由总线驱动程序创建的设备句柄上。这个I/O抽象可以用来引导符合UEFI的操作系统。一些示例I/O抽象包括简单的文本输出、简单的输入、块I/O和简单的网络协议。图12显示了连接到设备驱动程序之前和之后的设备句柄。在本例中,设备句柄是XYZ总线的子句柄,因此它包含XYZ总线支持的I/O服务的XYZ I/O协议。它还包含一个由XYZ总线驱动程序放置在那里的设备路径协议。并非所有设备句柄都需要设备路径协议。它只适用于表示系统中物理设备的设备句柄。虚拟设备句柄不包含设备路径协议。
- 连接到图12中的设备句柄的设备驱动程序必须在其自己的映像句柄上安装了驱动程序绑定协议。驱动程序绑定协议(参见11.1节)包含三个函数,分别称为Supported()、Start()和Stop()。函数的作用是:测试驱动程序是否支持给定的控制器。在本例中,驱动程序将检查设备句柄是否支持设备路径协议和XYZ I/O协议。如果驱动程序所支持的()函数通过,则可以通过调用驱动程序的Start()函数将驱动程序连接到控制器。函数的作用是:向设备句柄添加额外的I/O协议。在本例中,正在安装块I/O协议。为了提供对称性,驱动程序绑定协议还有一个Stop()函数,该函数强制驱动程序停止管理设备句柄。这将导致设备驱动程序卸载在Start()中安装的任何协议接口。
- EFI驱动程序绑定协议支持的()、Start()和Stop()函数需要使用引导服务EFI_BOOT_SERVICES.OpenProtocol()来获得协议接口,引导服务EFI_BOOT_SERVICES.CloseProtocol()来释放协议接口。OpenProtocol()和CloseProtocol()更新系统固件维护的句柄数据库,以跟踪哪些驱动程序正在使用协议接口。句柄数据库中的信息可用于检索有关驱动程序和控制器的信息。新的引导服务EFI_BOOT_SERVICES.OpenProtocolInformation()可用于获取当前正在使用特定协议接口的组件列表。
2.5.5 Bus Drivers(总线驱动程序)
- 从UEFI驱动程序模型的角度来看,总线驱动程序和设备驱动程序实际上是相同的。唯一的区别是总线驱动程序为总线驱动程序在其总线上发现的子控制器创建新的设备句柄。因此,总线驱动程序比设备驱动程序稍微复杂一些,但这反过来又简化了设备驱动程序的设计和实现。巴士司机主要有两种类型。第一个函数在第一次调用Start()时为所有子控制器创建句柄。另一种类型允许在多个Start()调用之间创建子控制器句柄。第二种类型的总线驱动程序在支持快速引导功能方面非常有用。它允许创建几个子句柄,甚至一个子句柄。在需要很长时间枚举所有子节点(例如SCSI)的总线上,这可能导致在启动平台时节省大量时间。图13显示了调用Start()前后总线控制器的树结构。进入总线控制器节点的虚线表示到总线控制器父控制器的链接。如果总线控制器是主机总线控制器,那么它将没有父控制器。节点A、B、C、D和E表示总线控制器的子控制器。
- 一个公交车司机,支持在每次调用Start()创建一个孩子可能会选择先创建子C,然后孩子E,然后剩下的孩子,B和d所支持的(),()开始,停止()函数驱动程序绑定协议的足够灵活,允许这种类型的行为。
- 总线驱动程序必须在创建的每个子句柄上安装协议接口。至少,它必须安装一个协议接口,该接口为子控制器提供总线服务的I/O抽象。如果总线驱动程序创建表示物理设备的子句柄,则总线驱动程序还必须在子句柄上安装设备路径协议实例。总线驱动程序可以选择在每个子句柄上安装总线特定的驱动程序覆盖协议。当驱动程序连接到子控制器时,使用该协议。引导服务EFI_BOOT_SERVICES.ConnectController()使用体系结构定义的优先规则来为给定的控制器选择最佳驱动程序集。总线特定的驱动程序覆盖协议具有比一般驱动程序搜索算法更高的优先级,比平台覆盖的优先级更低。一个总线特定驱动程序选择的例子发生在PCI上。PCI总线驱动程序使存储在PCI控制器的选项ROM中的驱动程序具有比存储在平台其他位置的驱动程序更高的优先级。图14显示了一个由XYZ总线驱动程序创建的子设备句柄示例,该驱动程序支持特定于总线的驱动程序覆盖机制。
2.5.6 Platform Components(平台组件)
- 在UEFI驱动程序模型下,在平台固件控制下连接和断开驱动程序与控制器的操作。这通常将作为UEFI引导管理器的一部分实现,但也可以实现其他实现。
- 平台固件可以使用引导服务EFI_BOOT_SERVICES.ConnectController()和EFI_BOOT_SERVICES.DisconnectController()来确定哪些控制器启动了,哪些没有启动。如果平台希望执行系统诊断或安装操作系统,则可以选择将驱动程序连接到所有可能的引导设备。如果平台希望引导预安装的操作系统,它可以选择只将驱动程序连接到引导所选操作系统所需的设备。UEFI驱动程序模型通过引导服务ConnectController()和DisconnectController()支持这两种操作模式。此外,由于负责引导平台的平台组件必须使用控制台设备的设备路径和引导选项,所以UEFI驱动程序模型中涉及的所有服务和协议都在考虑到设备路径的情况下进行了优化。
- 由于平台固件可能选择只连接生产控制台所需的设备并获得对引导设备的访问权限,所以OS当前的设备驱动程序不能假定已经执行了设备的UEFI驱动程序。在系统固件或选项ROM中存在UEFI驱动程序并不保证将加载、执行或允许管理平台中的任何设备。所有OS现有的设备驱动程序必须能够处理由UEFI驱动程序管理的设备和未由UEFI驱动程序管理的设备。
- 平台还可以选择生成一个名为平台驱动程序覆盖协议的协议。这类似于总线特定的驱动程序覆盖协议,但是它具有更高的优先级。这使得平台固件在决定哪些驱动程序连接到哪些控制器时具有最高优先级。平台驱动程序覆盖协议附加到系统中的句柄上。如果系统中存在引导服务ConnectController(),它将使用该协议。
2.5.7 Hot-Plug Events(热插拔事件)
2.5.8 EFI Services Binding(EFI服务绑定)
2.6 Requirements(需求)
- 这个文档是一个架构规范。因此,已经谨慎地指定了允许实现最大灵活性的体系结构。但是,必须实现此规范的某些元素,以确保操作系统加载器和其他设计为使用UEFI引导服务运行的代码可以依赖于一致的环境。
- 为了描述这些需求,规范被分解为必需的和可选的元素。通常,可选元素完全在匹配元素名称的部分中定义。但是,对于必需的元素,在某些情况下,定义可能不是完全包含在以特定元素命名的部分中。在实现所需的元素时,应该注意涵盖本规范中定义的与特定元素相关的所有语义。
2.6.1 Required Elements(所需元素)
2.6.2 Platform-Specific Elements(特定于平台的元素)
2.6.3 Driver-Specific Elements(驱动特定元素)
2.6.4 Extensions to this Specification published elsewhere(规范的扩展已在其他地方发布)