传统BIOS有着诸多的弊端,使得系统维护代价大,阻碍了国内计算机技术的发展。UEFI提供了标准化的BIOS规范,为计算机系统的扩展和升级提供了方便,同时也使得系统引导更为迅速、对操作系统引导器以及操作系统本身的限制大大减少。随着龙芯等国产高性能处理器芯片的研发成功及稳定性增强,国内陆续展开了许多基于国产CPU的计算机系统研究开发工作。计算机系统中BIOS是连接硬件和软件的关键组件,也是系统安全性验证的重要环节,然而长期以来,BIOS技术基本被国外几家厂商掌控,给计算机系统的安全埋下了安全隐患。UEFI已经在国外诸多知名计算机厂商中得到广泛的认可和使用,它的推广和应用也使得国产BIOS的研究和开发成为可能,国产计算机平台上的UEFIBIOS研究是国产BIOS发展的要求,也是提高计算机系统安全性的需要,基于国产计算机平台的UEFIBIOS研究具有十分重要的意义。基于此,本文研究基于UEFI的国产计算机平台BIOS。
本文的硬件平台是一款自主研发的龙芯2F处理器计算机平台,其逻辑结构如图1所示。龙芯处理器自带内存控制器,支持最高容量2GB的DDR2内存,处理器通过PCI总线与南桥、以太网控制器、显卡相连,向外提供最多3个PCI设备扩展。通过南桥向外提供2路RS232接口、4路USB接口、1路数字音频接口、1路IDE接口和1路LPC接口;通过以太网控制器向外提供两路千兆以太网口;通过显卡提供LVDS和VGA2种显示接口。Flash通过LocalBUS与CPU连接。该平台原先使用PMON作为BIOS。PMON是MIPS处理器最常使用的BIOS,最新版本为PMON2000,支持MIPS、ARM、PPC和X86体系结构,可以从Flash、IDE、网络以及USB启动操作系统,包含调试系统,支持多种调试命令,使用串口作为输出。
可扩展固件接口(ExtensibleFirmwareInterface,EFI)首先由Intel为解除传统BIOS对安腾处理器体系结构性能的限制而提出,后交由国际标准化组织UEFI管理,改名为统一可扩展固件接口(UnifiedExtensibleFirmwareInterface,UEFI)。UEFIBIOS的执行流程如图2所示,它一般包括SEC(security)、PEI(pre-EFIInitialization)、DXE(DriverExecutionEnvironment)、BDS(BootDeviceSelect)4个阶段,SEC执行系统基本初始化,准备C语言执行环境;PEI阶段进入C代码环境,描述系统资源和初始化信息,结束后传递给DXE阶段;DXE阶段对计算机系统设备进行初始化和配置,构建系统表,提供对资源的访问接口;BDS阶段为BIOS引导的最后阶段,完成进入操作系统引导前的准备工作,最终加载OSLoader,系统控制权交给OSLoader,仅保留运行时服务可为系统使用[1-2]。至此,UEFIBIOS对系统的控制结束。
UEFI具有模块化结构、C语言风格、EFI驱动模型硬件操作方式等优点。下面分别从可移植性、开机速度、可扩展性、操作界面4个方面对PMON和龙芯国产计算机平台的UEFI固件两者进行比较:
(1)开机速度PMON会对它发现的所有挂到主板上的设备进行驱动加载和执行,因此挂载设备的多少直接影响到系统的引导启动速度;UEFI设备驱动遵循UEFI驱动模型,DXE阶段不会对该类型的驱动进行更多的初始化工作,直到BDS中调用EFI_DRIVER_BINDING_PROTOCOL中的start()将该驱动与设备控制器连接并初始化设备[3],在BDS阶段设置界面中可对这些设备进行选择以及调整启动顺序,某些启动时不需要的设备可以推迟到后阶段进行初始化和配置,从而提高系统引导速度。
(2)可移植性PMON与UEFIBIOS一样由C语言编写,使用轮询方式发现设备驱动。PMON中与平台硬件相关的部分分布不规则,移植工作量较大,且要求开发者对代码结构了解程度高;UEFI的模块化结构以及标准的硬件操作接口使得驱动与核心控制代码之间耦合度低,移植时只需修改这些标准接口的实现,而不影响其上层或者其他平行模块,所以,UEFI可移植性要远优于PMON。UEFI的标准硬件操作接口即一组DXEArchitecturalProtocols[2],它们屏蔽底层硬件细节,使得UEFIBIOS具有高可移植性。
(3)可扩展性PMON中添加驱动或者功能时需在初始化流程中添加对相应设备或者功能的调用,编程者需要十分熟悉整个代码的结构和调用位置;UEFIBIOS中设备驱动符合EFIDriverModel,BIOS核心代码会发现并加载驱动,不需要编程者关注核心代码。同时UEFI对PCI总线体系结构的支持也体现了其良好的可扩展特性。UEFIPCI总线驱动采用分层结构,从下至上包括PCIRootBridge、PCIBUS和PCI设备驱动三层[1],关于总线的大部分初始化和配置工作在硬件相关的HostBridge驱动中实现,PCI设备驱动程序的实现与平台PCI体系结构无关,总线结构发生改变时,也仅需对PciHostBridge进行改变。
(4)操作界面PMON通过shell命令行提供大量的命令和功能使系统与用户进行交互,包括网络通信、读写内存、在线烧写Flash等存储设备等等;UEFIBIOS在BDS阶段可进入shell界面,与PMON不同的是,用户能自定义UEFI应用程序,它们不影响固件核心程序,在shell中加载运行,图形界面中还可选择加载UEFI应用程序对系统进行检测或者修复工作,或者管理系统信息、配置启动选项,UEFIshell是一种应用程序。国产计算机平台的UEFIBIOS是国产化BIOS发展的需要,针对国产计算机平台的不同结构和应用场合,其BIOS的实现和维护也更加方便。固件运行阶段可使用外部设备,并拥有图形化设置界面,支持从除Flash之外的位置加载固件模块,同时操作系统的启动位置和方式的选择也更加灵活。还可以开发功能丰富的UEFI应用程序,操作系统中某些功能或者机制的实现可以在固件中实现,例如固件层电源管理功能[4]、固件层数据备份和恢复[5]等,解决了这些关键机制过分依赖于操作系统的问题,使得国产计算机系统更为可靠。
本文BIOS的实现以EDKII框架为基础,EDKII是遵循UEFI规范的开源框架,它包含了大量开发示例和基本的底层库函数,这些代码中一部分与平台体系结构无关,另一部分则与硬件结构关系密切。实现BIOS首先分析出必须实现的模块,属于EDKII通用部分的模块则直接使用,平台相关部分的则必须针对硬件细节进行修改,最后添加EDKII中没有提供参考实现或者实例的功能模块,组成一个能在平台上运行并且使平台能正常工作的代码集合。遵循UEFI模块化的特点,除EDKII中直接被使用的通用代码外,其余修改或者自定义编写模块包含在一个独立的包(package)中,它与ArmPkg、BeaglePkg等目录平行,并按照执行流程进行划分。BIOS的实现内容如图3所示,可以大致划分为3大部分,如图中虚线框所示,在包中体现为3个子目录。图3BIOS实现内容
EDKII中各基本模块的依赖关系如图4所示,其主要模块的功能如下:(1)BaseTools:包含代码编译所需的二进制编译工具集和编译环境配置文件。(2)MdePkg:包含各个平台通用的基本的底层库函数、协议和工业标准,各种平台架构的UEFIBIOS都可以在模块中引用这些库函数,有效减少了开发工作量。(3)MdeModulePkg:包含一系列各平台通用的模块,其中包括MdePkg中公共库的应用模块示例。(4)Conf:保存编译环境信息、编译目标路径以及编译器参数,工具将在该路径下产生3个配置文件。(5)EdkShellPkg、ShellPkg:提供一个平台通用的UEFIShell应用程序开发环境。(6)EdkFatBinPkg:包含针对不同CPU架构的原始FAT驱动。(7)Nt32Pkg:一个在Windows操作系统下可加载32位模拟器,提供UEFI运行环境的平台。UnixPkg是Linux操作系统下的模拟环境。(8)ArmPkg、ArmPlatformPkg:针对ARM平台的实现,与具体平台硬件相关。相应的ArmRealViewPkg、EmbeddedPkg、Omap35xxPkg分别是在ArmRealView、嵌入式、Omap35xx平台上的参考实现。(9)NetWorkPkg、UefiCpuPkg:网络、CPU驱动参考实现。(10)DuetPkg:提供基于传统BIOS运行环境的支持库。(11)OptionRomPkg:提供针对不同CPU架构编译PCI兼容映像的示例。
固件以模块为单位,每个模块实现若干功能的集合。各模块之间的依赖关系在模块的配置文件(.inf)中进行定义,并通过包中的配置文件DEC(packagedeclarationfile)、DSC(builddescriptionfile)和FDF(FlashDescriptionFile)选择需要编译到BIOS中的代码、对PCD和变量赋值描述内存空间等资源的分配以及描述二进制代码在Flash上的布局。本文使用0x80000000~0x90000000的一段空间作为系统内存,其分配情况如图5所示。代码编译时,编译器解析配置文件将指定的代码按照指定的结构生成二进制可执行文件。
SEC和PEI是UEFIBIOS中最先执行的2个阶段,UEFI中关于PEI的设计类似于一个微型DXE,它执行的操作应该尽量的少。本文中将SEC和PEI的功能作为一个模块实现,不采用规范中的PEI的(加载器-PEI模块)结构,该模块分为2个部分。(1)系统上电后的执行起点,负责对系统硬件进行检测以及系统内存、cache、堆栈空间的基本初始化,为之后C语言代码准备执行环境。调试时通常要使用串口输出信息,龙芯国产计算机平台通过南桥向外提供串口,因此该阶段还需初始化北桥、南桥、串口。这部分采用MIPS汇编语言实现,完成基本的初始化之后调用第2阶段的C语言部分入口函数。(2)使用C语言实现,其任务包括将BIOS拷贝到内存以加快执行速度(shadowFlash),硬件的复杂初始化,PCI地址空间映射,构建HOBList并将其交给DXE。本文不实现标准PEI结构,而是使用EDKII中MdePkg/Library/BasePeCoffLib以及EmbeddedPkg/Library/PrePiLib中提供的关于二进制映像、HOBList、内存的操作来完成PEI的主要功能。最后,通过过渡函数查找并调用DXE入口函数。
DXE阶段负责系统引导中主要初始化工作,分为核心和驱动两部分。核心创建各种服务和接口供其他模块使用,驱动则提供对硬件的操作、初始化设备以及实现对各种机制的支持。(1)核心DXE核心建立在一系列对硬件的抽象接口之上,不依赖于CPU、芯片组等特定平台相关细节,其实现没有平台差异。EDKII/MdeModulePkg/Core/Dxe是DXE核心模块,包括DXEDispatcher和DXEFoundation,分别负责按顺序加载驱动和创建各种服务。在保证DXE核心所必须的功能完整的情况下,根据需求对其中某些部分进行增、删、改,如添加debug代码,即可作为固件的DXE核心部分。(2)驱动DXE驱动是固件实现的重要部分,它可以是平台硬件和外部设备的驱动程序,或者支持特定功能和机制的模块。它分为两种类型:早期DXE驱动和UEFI驱动模型驱动[2]。对于不同的平台,驱动的类型、数量均有差异,可以由程序员重新编写,也可以通过修改EDKII中包含的大量驱动的参考实来获得需要的设备驱动,从而节省编码时间,规范代码风格使其便于阅读。首先分析平台体系结构,实现对CPU、芯片组、计时器等板级设备以及总线等平台底层硬件操作的驱动,添加固件内部实现机制支持的驱动,这些驱动将创建DXE架构协议,提供抽象接口。这部分驱动属于早期DXE驱动,它们最终产生出所有的DXE服务、启动服务、运行时服务,后续执行的程序使用这些服务进行平台底层操作,不直接与硬件交互。其次根据需要连接的外部设备确定要添加的设备驱动程序,这些模块遵循UEFI驱动模型。键盘、鼠标、显卡、网卡以及其他PCI设备驱动都通过这种方式加载。本文硬件平台总线包括PCI、USB、IDE。遵循UEFI总线驱动的风格,它们的驱动都分为3个层次,包括控制器驱动、BUS驱动以及设备驱动,当总线体系结构发生改变时,只需对控制器驱动层进行适配。PCI驱动主要实现PCIHostBridge、PCIBUS驱动。EDKII的PcatChipsetPkg/PciHostBridgeDxe下是PC-AT结构的PciHostBridge驱动的参考实现,不同的PCI架构扫描PCI总线时是不一样的,需针对平台具体PCI架构进行适当修改。MdeModulePkg/Bus/PciBusDxe是PCIBUS驱动的实现,通常来说该驱动程序所做的工作与平台无关,不需要修改,除非是要对设备的配置空间做一些修正。USB驱动包括控制器和USBBUS,IDE驱动包括IDE控制器和IDEBUS驱动,控制器与硬件相关,USB控制器需针对平台细节编写,PcAtChipsetPkg/Bus/Pci/IdeControllerDxe是IDE控制器的驱动实现,MdeModulePkg/Bus/Usb是关于USBBUS的驱动实现,IntelFramework/Bus/Pci/IdeBusDxe是IDEBUS的驱动实现。该硬件平台板级设备包括龙芯CPU、芯片组、计时器、定时器、Flash等,固件内部支持PCD机制、容错写机制、HII(HumanInterfaceInfrastructure)以及GPT分区格式,DXE驱动包含对以上内容支持以及产生架构协议的驱动。EDKII/MdeModulePkg/Universal包含一组平台通用的驱动,包括WatchdogTimerDxe、Metronome、Variable等,同时EmbeddedPkg中包含对RealTimeClock和Reset驱动的实现,它们与硬件关系密切,针对平台硬件进行修改后即可加入该固件中。EDKII/MdeModulePkg/Universal/Disk下的模块提供对GPT的支持,同时参考FatBinPkg的代码实现Fat文件系统驱动,或者实现其他文件系统驱动,如NTFS[6]等。MdeModulePkg/Universal/PCD实现PCD机制的功能和操作,MdeModulePkg/Universal/下HiiDatabaseDxe和SetupBrowserDxe对Hii进行支持。除此之外,其余驱动则需要根据主板硬件编写,如Flash、南桥等,实现对这些硬件操作的抽象接口即协议。外部设备驱动程序由平台上连接的外部设备数量和种类决定。控制台提供给用户基本的系统输入输出信息,MdeModulePkg/Universal/Console中包含提供控制台服务的UEFI驱动。若目标平台要求支持网络引导或者要求图形显示,固件还应该分别实现该平台所使用网卡和显示芯片的驱动程序。如果平台使用了PCI、USB或者其它类型的设备,并且要在BIOS环境中使用这些设备,也必须实现相应的设备驱动程序。
BDS架构协议是引导进入BDS阶段的标准接口,由BdsDxe驱动模块产生。该阶段代码参考EDKII/IntelFrameworkModulePkg/Universal/BdsDxe实现,它在DXE阶段被发现并加载,DXE结束时将调用其入口函数。BDS阶段可进入图形界面进行系统管理或者配置启动选项,用户还可以创建UEFI应用程序对系统进行安全检测、诊断系统问题或者提供其他安全保障方案。
EDKII的MdePkg/Libarary中提供了Debug库用于BIOS开发调试,它们可以格式化打印输出代码的调试信息,便于对代码中的错误进行定位和分析。通过串口输出调试信息,还需根据平台串口配置编写相应的Debug库方法。代码编译得到二进制FD文件之后,烧写到IO地址空间0xBFC00000所对应的Flash地址(在龙芯平台上,系统上电时从该地址寻找第一条执行指令)。系统上电后,BIOS引导至所有初始化工作完毕,可选择直接进入OSLoader引导操作系统或者进入系统设置界面,在系统设置界面中,可以对系统进行诊断、启动设置、参数查看、日期设置等,或者进入shell界面,通过shell命令查看系统信息、设置参数、从指定路径手动安装新的设备驱动、应用程序或者从选择的启动设备引导操作系统。
本文分析对比了PMON与UEFIBIOS,简单介绍UEFIBIOS的引导过程,以开源框架EDKII为基础,描述了龙芯国产计算平台的UEFIBIOS实现内容和方法。随着国产处理器技术和基于国产处理器的计算机研究及应用的发展,UEFI的开放性、可扩展性、可移植性、标准接口编程以及快速开机等优点使其在国产计算机平台上具有广阔的应用前景。固件技术的发展将提高和促进计算机技术水平及其安全性,UEFIBIOS在国产计算平台上的应用有着重大的意义。该BIOS实现了UEFI固件的基本功能和操作,运行良好,在之后的研究中其功能还有待进一步的完善。同时,UEFI的特点也给BIOS带来了新的安全问题,这些工作将在今后的工作中得到改进,比如在其中加入可信支持[7]等。