BIOS
BIOS功能:
- 加电自检程序,用于开机时对硬件的检测。
- 系统初始化代码,包括硬件设备的初始化,创建 BIOS 中断向量等。
- 基本的外围I/O处理的子程序代码。
- CMOS程序设置。
BIOS工作流程:
- 加电自检(Power On Self Test,POST):检测关机设备是否正常工作,设备设置是否与CMOS(CMOS是是电脑主板上的一块可读写的RAM芯片,常用来保存BIOS设置完电脑硬件参数后的数据)中的设置一致。如果出现硬件错误则发出警报(鸣笛)。POST检测通过后进行初始化
- 初始化:初始化显示设备、显示显卡信息,然后初始化其他设备。
- 检查CPU和内存并显示检测结果。进行标准设备检测(如:硬盘、光驱、串口设备等)。结束标准设备检测后进行即插即用设备,并为其分配中断号、I/O端口号和DMA通道等资源。硬件设备发生改变时将变化记录到CMOS中。
- 根据配置的启动顺序从设备启动,将启动设备主引导记录的启动代码通过BIOS终端读入内存,然后将控制权交至引导程序,最终引导进入操作系统。
BIOS缺点:
- 开发效率较低:大部分BIOS使用汇编语言开发,使用汇编语言开发与硬件的耦合度过高,使得开发出来的BIOS严重受硬件影响。
- 性能差:BIOS基本输入/输出服务需要依靠中断来完成,而且BIOS没有异步工作模式,有大量的时间被消耗在等待。
- 不易进行功能扩展:在添加硬件功能时,必须将16位的代码放置在0x0C0000~0x0DFFFF间,初始化时才能将其设置为约定的中断处理程序。而且BIOS不能动态的加载设备驱动方案。
- 安全性较差:BIOS没有考虑运行过程中执行代码的安全性。
- 不支持从硬盘2 TB及以上的地址进行引导:BIOS硬盘采用32位地址,因此引导扇区的最大逻辑块地址是232(字节地址为:(232)*512=2 TB)
UEFI(Unified Extensible Firmware Interface)
UEFI简介:
- UEFI是统一可扩展固件接口,定义了操作系统和平台固件之间交互的接口,它是UEFI Forum发布的一种标准,并没有提供实现。
- UEFI的实现可以分为两部分:
- 平台初始化。
- 固件-操作系统接口。
UEFI系统组成:
-
UEFI供系统调用的接口:
-
启动时服务(Boot Service,BS)
-
运行时服务(Runtime Service,RT)
-
-
隐藏在BS后的Protocol
其中BS和RT以表的形式(C语言中的结构体)存在,UEFI驱动和服务以Protocol的形式通过BS提供给操作系统。
UEFI模式的启动的几个阶段:
-
操作系统加载器(OS Loader)被加载。
-
OS Loader执行ExitBootServices()。
从1->2的过程是从UEFI环境向操作系统过渡的过程,在该过程中,OS Loader可以通过BS和RT使用UEFI提供的服务,将计算机资源逐渐从UEFI转至操作系统。该过程被称为TSL(Transient System Load)
当OS Loader完全掌握计算机系统资源是,BS便完成了其使命。OS Loader调用ExitBootServices()结束BS并回收BS占用的资源。计算机系统进入UEFI Runtime阶段。在Runtime阶段中只有RT继续为OS提供服务,BS已经被计算机系统销毁。
TSL阶段系统通过BS管理系统资源,此时BS提供的服务有:
- 事件服务:事件是异步操作的基础。有了事件的支持,才可以在UEFI系统内执行并发操作。
- 内存管理:主要提供内存的分配与释放,管理系统的内存映射。
- Protocol管理:提供了安装Protocol与卸载Protocol的服务,以及注册Protocol通知函数(该函数会在Protocol安装时调用)的服务。【UEFI驱动和服务通过Protocol的形式通过BS提供给系统】
- Protocol的实用类服务:包括Protocol的打开与关闭,查找支持Protocol的控制器。(比如:需要读写某个PCI设备的寄存器,可以通过OpenProtocol服务打开这个设备上的PciIo Protocol,用PciIo->Io.Read()服务读取这个设备上的寄存器。
- 驱动管理:包括用于将驱动安装到控制器的connect服务,及将驱动从控制器上卸载的disconnect服务。(例如:如果我们启动时需要网络支持,则可以通过loadImage将驱动加载到内存,然后通过connect服务将驱动安装到设备)。
- Image管理:此类服务包括加载、卸载、启动和推出UEFI应用程序或驱动。
- ExitBootServices:用于结束启动服务,注销BS。
RT主要提供以下几个方面的业务:
- 时间服务:读取/设置系统时间
- 读写UEFI系统变量:读取/设置系统变量。(例如:BootOrder用于指定启动项顺序)更改这些系统变量可以改变系统配置。
- 虚拟内存服务:将物理地址转换为虚拟地址。
- 其它服务:重启系统、获取系统提供的下一个单调单增值等。
UEFI的优点
- UEFI具有较高的开发效率:BIOS一般采用汇编语言,代码多是与硬件相关的代码。而UEFI中大部分的代码可以用C语言进行编写,UEFI的应用程序和驱动也可以用C++编写。UEFI通过固件-操作系统接口(BS和RT服务)为OS和OS Loader屏蔽了底层硬件细节,使UEFI的上层应用可以重用。
- UEFI系统的可扩展性:UEFI系统的可扩展性主要体现在 驱动的模块化设计以及软硬件升级的兼容性。UEFI模式中驱动的模块化设计在于,大部分硬件的初始化通过UEFI驱动实现。每个驱动都是一个独立的模块,可以包含在固件中,也可以放在设备上,运行时根据需要来动态加载。软硬件升级的兼容性体现在,UEFI中每个表、每个Protocol(包括驱动)都有版本号,这使得系统可以很方便的进行平滑升级。
- UEFI系统的性能较高:相比于BIOS,UEFI有很大的性能提升,从启动到进入操作系统的事件大大缩短。原因主要有一下几点
- 1、UEFI支持基于事件的异步操作,提高了CPU的效率,减少了总的等待时间;
- 2、关于中断,UEFI仅保留了时钟中断,舍弃了其余的中断操作外部设备的方式,改为“事件+异步操作”;
- 3、高效遍历设备的方式,启动时可以仅遍历启动所需的设备,从而加速系统启动;
- 4、UEFI具有更高的安全性:相比于BIOS,UEFI的一个重要突破就是其在安全性方面的考虑。在系统的安全启动模式下UEFI在执行应用程序和驱动前会先检测程序和驱动的证书,仅当证书被信任时才会执行该程序或驱动。(UEFI的应用程序和驱动采用PE/COFF格式,其签名放在签名块中)
UEFI系统的启动过程
UEFI系统从加电到关机可分为以下七个阶段:
SEC(安全验证)->PEI(EFI前期初始化)->DXE(驱动执行环境)
->BDS(BS?)(启动设备选择)->TSL(操作系统加载前期)
->RT(Run Time)
->AL(系统灾难恢复期)
其中,前三个阶段为UEFI初始化加载阶段,DXE阶段结束后UEFI环境已经准备完毕。
BDS和TSL是UEFI运行OS Loader的阶段。
OS Loader调用ExitBootServices()服务后系统启动进入RT阶段,操作系统加载后期和操作系统运行期均属于RT阶段。
硬件系统或操作系统出现严重错误不能继续正常运行时,固件会尝试进行修复,此时系统进入AL期。但是PI规范和UEFI规范都没有规定AL期的行为。AL期的系统行为由系统供应商自行定义。
上述过程可见下图:
每个阶段具体的功能和流程:
-
SEC(Security Phase,安全阶段)阶段
SEC阶段是平台初始话的第一个阶段,计算机系统加电后首先进入这个阶段。
-
SEC阶段的功能:UEFI系统开机或重启后首先进入SEC阶段,SEC阶段系统执行以下四种任务:
- 接收并处理系统启动和重启信号,系统加电信号、系统重启信号、系统运行过程中的异常信号。
- 初始化临时存储区域:系统运行在SEC阶段时,仅CPU和CPU内部资源被初始化,而各种外部设备和内存都没有被初始化。因此系统需要一部分临时内存用于代码和数据的存储,一般称为临时RAM,临时RAM只能位于CPU内部(CPU和CPU内部的资源最先被初始化)。最常用的临时RAM是Cache,通过将Cache设置为no-eviction模式,来把其当成内存使用(此时读取命中则返回Cache中的数据,读取缺失并不会向主存发出缺失事件;写命中时写入Cache,写缺失时也不会向主存发出缺失事件),这种技术称为CAR(Cache As RAM)。
- SEC阶段是可信系统的根:作为系统启动的第一部分,只有SEC能被系统信任,以后的各个阶段才有被信任的基础。因此,大部分情况下SEC再转交控制权给PEI前可以验证PEI是否可信。
- 传递系统参数给下一阶段:SEC阶段的一切工作都是为PEI阶段做准备的,最重要把系统的控制权转交给PEI,并将SEC阶段的运行信息汇报给PEI。SEC通过将以下信息作为参数传递给PEI的入口程序来向PEI汇报信息:
- 系统当前状态,PEI根据状态值判断系统当前的健康情况。
- 可启动固件(Boot Firmware Volume)的地址和大小,PEI据此判断可用硬件。
- 临时RAM区域的地址和大小。
- 栈的地址和大小。
-
SEC阶段执行流程:
根据临时RAM是否初始化为界限,SEC阶段分为两部分:临时RAM初始化前称为Reset Vector阶段;临时RAM初始化后调用SEC入口函数从而进入SEC功能区。其流程如下图:
其中Reset Vector的执行流程如下:
- 进入固件接口。
- 从实模式转换到32位平坦模式。
- 定位固件中的BFV(Boot Firmware Volume)。
- 定位BFV中的SEC影响。
- 如果是64位系统,则从32位模式转换至64位模式。
- 调用SEC入口函数。
- 在SEC功能区中初始化 临时RAM ,完成其功能后找到PEI的入口函数(PEI Image?)
-
-
PEI(Pre-EFI Initialization,预先EFI初始化)阶段
虽然SEC阶段对CPU和CPU内的资源进行了初始化,但是PEI阶段可用的资源依旧十分有限,该阶段对内存进行初始化,主要功能是为DXE阶段准备执行环境,将所需要传递给DXE的信息组成HOB(Hand Off Block)列表,最终将控制权转交到DXE。
UEFI具有模块化设计的特点,PEI就是一个模块。PEI Image的入口函数调用PEI模块的入口函数PEICore。
-
PEI阶段的功能:
- 初始化内存。
- 为DXE阶段准备执行环境。
-
PEI划分:
-
PEI内核(PEI Foundation):负责PEI基础服务和流程。
-
PEIM(PEI Module)派遣器:找出系统中的所有PEIM,并根据PEIM之间的依赖关系按顺序执行PEIM。PEI阶段对系统的初始化主要由PEIM完成。
每个PEIM都是一个独立的模块。通过PEIServices,PEIM可以调用PEI阶段(UEFI?)提供的系统服务。通过调用这些服务,PEIM可以访问PEI内核。PEIM之间的的通信通过PPI(PEIM-to-PEIM Interfaces)完成。
-
-
PEI阶段执行流程:
-
进入PEI入口。
-
根据SEC阶段传入的信息初始化PS(PEI Core Service)。
-
调度系统中的PEIM(PEI Module),准备HOB列表。
具体调用的系统中的PEIM有:CPU PEIM(提供CPU相关功能,如进行Cache设置、主频设置等);平台相关PEIM(初始化内存控制器、I/O控制器等);内存初始化PEIM(对内存进行初始化,此时内存才可用,之前使用的CPU模拟的临时内存)。
-
调用PEIServices得到DEX IPL PPI的Entry服务(即DEXLoadCore)。
注:PPI与DEX阶段的Protocol类似,每个PPI都是一个结构体,包含有函数指针和变量。每个PPI都有一个GUID。通过PEIServices的LocatePPI服务可以找到GUID对应的PPI实例。
-
DXELoadCore服务找出并运行DXEImage的入口函数,将HOB列表传递给DXE。
PEI阶段执行流程完整描述:SEC模块找到PEI Image的入口函数 _ModuleEntryPoint(该函数位于MdePkg/Library/PeimEntryPoint/PeimEntryPoint.c), _ModuleEntryPoint函数最终调用PEI模块的入口函数PEICore(该函数位于MdeModulePkg/Core/Pei/PeiMain/PeiMain.c),进入PEICore后,首先根据从SEC阶段出入的信息设置PEI Core Services,然后调用PEIDispatcher执行系统总的PEIM,在内存初始化完成后,系统切换栈并重新进入PEICore。重新进入PEICore后使用的不再是 临时RAM 而是真正的内存。在所有PEIM执行完成后,调用PEIServices的LocatePPI服务得到DXE IPL PPI,并调用DXE IPL PPI的Entry服务(即DEXLoadCore),找出DEX Image的入口函数,执行DXE Image函数并将HOB列表传递给DXE。
PEI阶段执行流程如下图:
-
-
-
DXE(Driver Execution Environment,执行驱动配置环境)阶段
DXE阶段执行系统大部分的初始化工作。由于此阶段内存已经可以被正常使用,因此该阶段可以执行大量复杂的工作。从程序设计角度DXE阶段与PEI阶段相似。
-
DXE阶段的功能:
- 执行系统大部分的初始化工作
- 提供系统表、启动服务以及Run Time Services。
-
DXE划分:
- DXE内核:负责DXE的基础服务和执行流程
- DXE派遣器:负责调度执行DXE驱动,初始化系统设备。
-
DXE执行流程:
-
从DXE入口进入DXE阶段。
-
根据HOB列表初始化系统服务。
-
调度系统中的Driver。
详:遍历固件中所有的Driver,当Driver所依赖的资源得到满足时,调度Driver到执行队列执行,直到所有满足条件的Driver都被执行。
-
打开EFI_BDS_ARCH_PROTOCOL。
-
EFI_BDS_ARCH_PROTOCOL->Entry。
DXE驱动之间通过Protocol通信。Protocol是一种特殊的结构体,每个Protocol都有一个GUID,通过系统BootServices的OpenProtocol,可以根据GUID调用对应的Protocol,从而使用这个Protocol提供的服务。
在所有的Driver都执行完成后,系统完成初始化,DEX通过EFI_BDS_ARCH_PROTOCOL找到BDS并屌用BDS的入口函数,从而进入BDS阶段(从本质上讲BDS是一种贴无数的DXE)。
DXE的执行流程如下图所示:
-
-
-
BDS(Boot Device Selection,选择boot设备)阶段
-
BDS阶段的功能有:
- 执行启动策略(主要功能)。
- 初始化控制台设备。
- 加载必要的设备驱动。
- 根据系统设置加载和执行启动项。
当加载项其启动失败时,系统将重新执行DXE dispatcher以加载更多的驱动,然后重新尝试加载驱动项。BDS策略通过全局NVRAM变量配置,这些变量可以被运行时服务的GetVariable()读取,通过SetVariable()设置(如BootOrder定义了启动顺序,Boot####对应不同的启动项,#为十六进制数)。当用户选中某个启动项(或进入系统默认启动项)后,OS Loader启动,系统进入TSL阶段。
-
-
TSL(Transient System Load)阶段
TSL阶段是OS Loader(操作系统加载器)执行的第一阶段,这一阶段的OS Loader作为一个UEFI应用程序运行,系统资源有UEFI内核控制。但是当ExitBootServices()服务被调用后,系统将进入Run Time阶段。
TSL阶段被称为临时系统的原因在于,其存在的目的就是为操作系统加载器准备执行环境。虽然是临时系统,但已经具备操作系统的雏形,UEFI Shell是这个临时系统的人机交互界面。正常运行中,系统不会进入UEFI Shell,而是直接执行OS Loader,只有在用户干预或是操作系统加载器出现严重问题时才会进入UEFI Shell。
-
RT(Run Time,运行)阶段
系统进入RT阶段后系统控制权从UEFI内核转交至OS Loader,UEFI占用的各种资源被OS Loader接管。随着OS Loader的继续执行,操作系统将完全取得对电脑的控制权。
-
AL(After Life)阶段
在RT阶段如果系统(硬件或是软件)遇到灾难性错误,系统固件需要提供错误处理以及灾难恢复机制,这种机制运行在AL阶段。UEFI和UEFI PI均未对AL阶段的行为和规范进行定义。
总结
与BIOS相比,UEFI具有更好的可编程性(PPI、Protocol)、更高的安全性(SEC)、更强的可扩展性,并且其设计相比BIOS能更好的适应64位平台,这使得UEFI能迅速的取代BIOS。
UEFI定义了操作系统和平台间的接口。UEFI接口可以分为以下两个部分:
- 启动服务:启动时服务的主要对象是操作系统(OS)、操作系统加载器(OS Loader)以及其他UEFI应用程序和UEFI驱动。操作系统加载器(OS Loader)通过启动服务逐步取得对整个计算机资源的控制。当加载器完全控制计算机软硬件资源后,系统会结束启动服务,进入运行时服务。启动服务主要包括有:时间服务、内存管理、Protocol管理、Protocol使用类服务、驱动管理、Image管理及ExitBootServices服务。
- 运行时服务:运行时服务主要的服务对象是操作系统、操作系统加载器以及UEFI应用和UEFI驱动。运行时服务主要包括:时间服务、读写UEFI系统变量服务、虚拟内存服务以及重启系统服务。