本文主要介绍UEFI的发展历史,以及对UEFI在ARM嵌入式领域的生态状况做了简单的调研。下一篇会对UEFI和PI规范做一些简单介绍。
本篇参考内容主要来源于以下3方面:
(1) 微信公众号“ Wolf UEFI社区 ”系列文章。
(2) 《UEFI原理与编程》—戴正华。
(3) UEFI Spec和PI Spec官方文档。
UEFI最初是为BIOS所设计的,由于Legacy BIOS(存在近40年)历史局限性,一直无法跟上硬件的发展,并且在可编程、可维护性、安全性方面表现很差。
考虑到传统BIOS的诸多问题,前辈们迫切希望降低这些底层固件代码的复杂性,并希望对操作系统提供尽可能少的平台硬件细节。做法是:在平台固件和OS加载器\OS之间设计一套基于高级C语言(当时固件用汇编写的,相对来说C算高级语言)的接口。基于这个想法,最初的EFI(Extensible Firmware Interface)诞生,其定义了启动过程中底层固件和操作系统之间的接口,该接口和CPU架构无关。
EFI诞生:
1999年,IBI计划制定了新接口的首版规范。开发者们将新规范命名为EFI(Extensible Firmware Interface),同时呼吁使之成为未来成长的Base。EFI规范对任何特定类型的电脑保持中立性,旨在仅仅描述接口。
2000年12月,英特尔发布了EFI规范1.02初始版本。规范约定的范围涵盖了系统从平台固件运行至控制权转移到操作系统的过程。
2002年,在早期版本的基础上发布了EFI规范1.10版本。这次更新主要在规范中添加了一个固件驱动模型,该模型解决了在引导过程中使用扩展卡设备的问题。本质上,这提供了一种替代最先应用在ISA总线设备上的脆弱的16位可选ROM的可行性,并很快也用于PCI引导设备。
UEFI诞生:
2005年年中,行业大会召开。包括BIOS供应商,OS供应商,系统制造商以及芯片生产公司在内的行业参与者建立了统一的EFI论坛(UEFI,Unified Extensible Firmware Interface),并声明长期共同管理这项技术。
作为行业执牛角者,Intel贡献了EFI规范,作为新论坛的开端。创始成员们以真正统一的方式工作,制定了受到行业广泛支持和认可的新规范。这份由论坛所制定的首版规范——UEFI规范2.0,于2006年一月发行。
除了制定固件与操作系统间接口外,论坛同意为固件内部制定符合UEFI规范的标准化接口。这项工作产生了PI规范(Platform Initialization)。PI规范1.0于2016年10月发布。这份规范旨在使芯片驱动程序可以在各种固件厂商开发的平台上直接运行而无需修改,从而简化和缩短新产品的部署。
2007年1月,发布UEFI 2.1版本。这种基础设施的引入,使得固件的用户界面更加图形化,本地化。
2008年9月,推出UEFI 2.2版本。加入了对IPv6的支持,同时改进了平台安全策略。2.2版本曾在很短的段时间内是最大/最完善的版本,很大一部分原因在于实施在规范之后。
对于ARM生态的支持方面:
2009 年,UEFI 联盟公布UEFI 2.3 规范,将对ARM 平台的支持纳入规范。
2013 年,发布UEFI 2.4 规范,包含了对ARM 64 位架构处理器的支持。ARM-UEFI 已经成为了规范的一部分。
UEFI和PI还在继续演进中,最新的规范是UEFI 2.5和PI 1.4
开源:
Intel提供了首版EFI规范的最初的开源示例实现。随着UEFI和PI规范的更新,这项工作还在进行中。
UEFI项目目标比较远大,希望支持所有类型的CPU,并成为事实上的BIOS标准。为此,Intel成立了开源组织TianoCore,其目标就是提供UEFI标准的实现,以及各类工具和开源代码,促进UEFI的健康发展。
开源社区“tianocore.org”于2004年开始,采用BSD许可证。TianoCore的代码最早落户于www.tianocore.org。在开源大潮的带领下,先扎根于SourceForge,后随着Github火遍全球,也移步于Github。可以在https://github.com/tianocore下找到许多相关的项目。其中,最核心的项目就是EDK2。EDK2项目是TianoCore为实现UEFI标准和PI标准(平台初始化标准)而开发的,支持多种CPU架构的固件和程序。包括ARM、X86、RISC-V等。
对于ARM生态的支持方面:
随着ARM平台纳入UEFI规范,苹果和惠普向tianocore.org贡献了UEFI的参考实现(其中对Beagle Board的一个实现)。使供应商可为他们的硬件提供UEFI的驱动程序。 ARM公司也贡献了使用Cortex A9 多核处理器的Versatile Express参考平台的核心代码。
现在已经过去十多年,越来越多的ARM玩家已经加入到了UEFI大家庭。下一章对UEFI + ARM 平台生态进行更详细介绍。
前面我们介绍了UEFI的诞生主要是为了解决传统BIOS的痼疾,UEFI一开始就是作为Legacy BIOS的替代品使用的。So, UEFI主要是X86的开发者在玩吗?答案当然是:NO!
ARM生态越来越需要通用性和标准。
ARM生态一直以来缺乏统一的标准。随着ARM进入到x86的传统领域—PC和服务器市场,他们一样也要面临碎片化的生态系统的问题。于是接受UEFI和ACPI变成了必然的选择。
** UEFI在ARM生态中越来越成熟。**
就UEFI对ARM的支持来讲, UEFI 2.3 规范,将对ARM 平台的支持纳入规范。UEFI 2.4 规范,包含了对ARM 64 位架构处理器的支持。ARM-UEFI 已经成为了规范的一部分。
UEFI在ARM生态中越来越成熟。这也从EDK2社区最活跃的用户在近几年已经不是x86的开发者,而是ARM相关开发者(最近一年多换成了RISC-V)可以看出。于此同时EDK2开源平台仓库EDK2_Platforms下面也涌入了大量ARM平台,如海思、NXP、树莓派等等。
当前现状是,所有成熟的ARM服务器产品都采用UEFI+ACPI方案;很多ARM移动和桌面产品也已经采用UEFI+ACPI方案;大量ARM产品在赶来的路上。
前面我们介绍了,UEFI 起初主要是作为BIOS的替代品,也就是说起初主要玩家在PC领域。那么UEFI在嵌入式产品中的情况是什么样的呢?
在大多数人心目中,ARM 嵌入式世界的BootLoader还被Uboot+DeviceTree统治。但是只要查看EDK2代码,就会发现Hisilicon、NXP、RaspberryPi等好多大厂都upstream了他们的ARM嵌入式平台代码。可见UEFI在ARM 嵌入式中的生态也已经非常成熟。以手机芯片大厂高通为例,其从MSM8998开始使用UEFI替代LK(Little Kernel)作为手机的Bootloader。
除了很多ARM芯片厂商都在其自己的芯片上使用UEFI固件之外,嵌入式Bootloader(Uboot等)也在向UEFI靠拢。具体表现为,部分bootloader也在基于UEFI标准定义自己的接口,比如U-boot20号称实现了40%的UEFI接口。
作为嵌入式开发者我们知道,嵌入式领域的Bootloader(u-boot、LK等)大都是基于C语言开发的,并没有之前所说的传统BIOS那样的问题。
为什么大厂他们的嵌入式产品也开始向UEFI 转移阵地呢?UEFI相对当前的嵌入式Bootloader有什么优势呢?下一节展开描述。
为何大家都开始玩UEFI呢?
我们先从PC中的BIOS、嵌入式系统Bootloader、以及UEFI固件EDK2三者的功能做一个对比。
EDK2在兼具Legacy BIOS和传统嵌入式Bootloader功能之外,同时符合UEFI标准和PI规范的操作系统启动固件。它即可以支持不同架构的硬件平台,也可以支持启动不同的操作系统。它相对前二者最大的不同就是标准化和通用性。
通过对比我们可知,无论BIOS,还是嵌入式领域各种类型Bootloader,他们都具有两个最重要使命是:初始化硬件平台和引导操作系统。
UEFI很好的解决了传统BIOS的移植性差、碎片化等问题,是否也可以作为嵌入式Bootloader的标准呢?答案自然是:Sure。
其实,Bootloader之于嵌入式平台,比BIOS之于PC要好太多。Bootloader(u-boot、LK等)简单快捷,移植容易。那它有什么不足吗?
当然有,至少体现在两点:缺乏标准和互操作性。
这种问题是从娘胎里带来的。嵌入式设备往往是垂直定制开发的,从硬件、固件、BSP和操作系统,都深度定制,没有问题是定制修改程序所不能解决的。这导致Bootloader 更合适专用系统,而不是通用系统。
不同芯片厂商的Bootloader也是五花八门。对下游玩家来说想像X86 PC那样,使用不同厂商的组件规划自己的产品很难实现。
随着ARM生态的发展,尤其进入PC市场后,对通用性的需求越烈越强烈。作为ARM世界的灵魂,ARM公司也意识到了生态碎片化的问题,因此推出了大量规范和标准,来规范ARM产品的行为。如针对服务器的服务器的SBSA和SBBR规范,最新的基本系统架构(BSA)、基本启动要求(BBR),以及针对安全的基本启动安全要求(BBSR)等等。
ARM的这些规范多而杂,后面又演化为Arm SystemReady。分别对服务器系统、物联网边缘设备、嵌入式系统等ARM产品的架构和启动等内容进行规范。
前面已经提到,ARM嵌入式Bootloader有缺乏标准和互操作性的问题。自然UEFI 系统能解决这两个问题,所以才选择UEFI。
那么ARM SystemReady 能解决上述问题吗,它会是UEFI之外的另一个选择吗?
其实,ARM SystemReady 和UEFI并不冲突。其中ARM针对嵌入式设备的EBBR标准,旨在嵌入式系统生态系统中缺乏引导时序标准化的问题。下面是摘自EBBR规范的一段话,大家自行阅读。
EBBR was written as a response to the lack of boot sequence standardization in the embedded system ecosystem.As embedded systems are becoming more sophisticated and connected, it is becoming increasingly important forembedded systems to run standard OS distributions and software stacks, or to have consistent behaviour across alarge deployment of heterogeneous platforms. However, the lack of consistency between platforms often requiresper-platform customization to get an OS image to boot on multiple platforms.
A large part of this ecosystem is based on U-Boot and Linux. Vendors have heavy investments in both projects and are not interested in large scale changes to their firmware architecture. The challenge for EBBR is to define a set of boot standards that reduce the amount of custom engineering required, make it possible for OS distributions to support embedded platforms, while still preserving the firmware stack product vendors are comfortable with. Or in simpler terms, EBBR is designed to solve the embedded boot mess by adding a defined standard (UEFI) to the existing firmware projects (U-Boot).
However, EBBR is a specification, not an implementation. The goal of EBBR is not to mandate U-Boot and
Linux. Rather, it is to mandate interfaces that can be implemented by any firmware or OS project, while at the
same time work with both Tianocore/EDK2 and U-Boot to ensure that the EBBR requirements are implemented
by both projects.1
从这两段话,我们提取出的有用信息是:
由此可见EBBR 还是比较开放了,它的主旨和UEFI一致,就是为了使嵌入式系统启动时序标准化,在平台固件和操作系统之间提供标准接口。
EBBR并没有说必需以什么方式实现。而是提供了两个思路:
个人觉得,第一种方案虽然限定了接口标准,但是实现方式可能依然五花八门,不能确保启动时序的标准化。第二种方案,还不如直接使用EDK2一种。仅代表个人观点。
总结:
由此可见,ARM 嵌入式实现UEFI,是ARM SystemReady 所要求的。
前面已经介绍了既有ARM 嵌入式Bootloader 在通用性方面的不足,UEFI可以弥补这些不足。UEFI带来的收益自然也体现在互操作性和标准化两个方面。
最直观的收益就是降低 OEM / ODM厂商开发成本。对于 OEM / ODM厂商来说,使用UEFI系统带来的收益:
就技术来看带来的收益: