UEFI+BIOS全局配置数据库的设计与实现
2014-10-30高云岭庄克良丁守芳
高云岭 庄克良 丁守芳
摘 要:EDKII是目前最流行的一个高度分层和抽象化UEFI BIOS的开发架构,它针对不同平台硬件参数设置引入了新的设计概念PCD。PCD就是在计算机系统初始化过程中建立起来的一个全局平台配置数据库,它为整个平台的驱动,函数库和模块组提供了有效的信息共享和设置机制。研究了数据库建立和使用的流程和方法,同时指出该数据库平台在非源代码发布中的一些设计弊端。
关键词:EDKII;UEFI;BIOS;PCD
中图分类号:TP393 文献标志码:A 文章编号:2095-1302(2014)10-00-03
0 引 言
BIOS是一组固化到计算机主板上一个ROM芯片中的程序,它保存着计算机最重要的基本输入输出的程序、系统设计信息、开机后自检程序和系统自启动程序。人们经常需要重新对FLASH芯片进行编程以便升级BIOS,以便获得新的功能。
UEFI BIOS是目前最主流的一个BIOS架构,约占超过70%的计算机,服务器和嵌入式市场。它是对老的BIOS开发模式的一种彻底的革新,打破了BIOS只能用汇编语言开发和只能应用在计算机和服务器市场的局限性,当前越来越多的嵌入式设备、平板、手持设备、工控设备、通信设备等都在它的应用行列。
采用UEFI BIOS开发架构EDKII的架构,可保证同一份核心代码运行在不同的硬件平台之上,仅仅需要针对平台的特定性来设置一些特定的参数,这是EDKII架构中最难也是最核心的一个设计部分,也就是要研究全局配置数据库PCD。
1 UEFI和EDKII简介
2000年,Intel向业界展示了BIOS的新一代接口程序EFI (Extensible Firmware Interface),并将此技术应用于其安腾服务器平台上。EFI是由Intel推出的一种在未来的电脑系统中用来替代BIOS的升级方案。2005年,在工业界达成共识的基础上,Intel将EFI规范交给了一个由微软、AMD、惠普等公司共同参与的工业联盟进行管理,并将实现该规范的核心代码开源于网站上。与此同时,EFI也正式更名为UEFI(Unified Extensible Firmware Interface)。UEFI联盟将负责开发、管理和推广UEFI规范。
UEFI定义了操作系统与系统硬件平台固件之间的开放接口。该规范定义的接口包括平台相关信息、启动服务例程以及操作系统运行时服务例程。操作系统装载器与操作系统可通过接口调用这些服务例程。UEFI规范是一个公开的纯接口定义,它不依赖于某个特定的BIOS制造商或某个特定的BIOS的实现,它仅仅定义了平台固件必须实现的接口,以及操作系统可能使用的一系列接口与数据结构,其实现的方式与细节均取决于该规范的实现者。UEFI规范还定义了固件驱动程序模型,使得所有遵循此模型开发的固件驱动程序能够互相协作。
不同于传统的BIOS实现,EDKII基于现代软件体系设计的思想,对UEFI Framework采用模块化设计,并根据其执行流程主要划分为:SEC、PEI、DXE、BDS、TSL、RT和AL等7个阶段,其运行机理如图1所示。
SEC(Security)是平台上电后最先执行的步骤。这个阶段的主要目的是对平台固件进行验证,确保选择的平台固件映像没有被破坏。主要工作是初始化临时内存区并对平台早期初始化代码进行验证。
PEI(Pre-EFI Initialization)阶段有两个主要任务:确定重新启动的来源和做尽可能少的工作以便寻找和初始化内存,为DXE阶段提供少量的固定内存。
DXE(Driver Execution Environment)被设计来处理与外围设备的通信,它通过加载驱动的方式(轮询检测)来为操作系统的启动管理构建环境。
BDS(Boot Device Selection)是UEFI拥有平台控制权的最后一个阶段。BDS与DXE阶段一起工作,为启动操作系统建立控制台。
TSL(Transient System Load)即操作系统启动管理器尝试引导操作系统的阶段。
RT(Run Time)是操作系统启动运行后,UEFI提供的一组运行时服务。
AL(After Life)阶段,即最后一个阶段,其提供一种机制来保证用户在有意或者无意的情况下终止操作系统后,让UEFI重新获得系统控制权。
2 全局配置数据库PCD的设计实现
EDKII中PCD根据其作用的时间,分两大类,一类是在编译过程中起作用,这类PCD等同于C语言中的全局静态变量,包含FeatureFlag PCD, FixedAtBuild PCD以及PatchableInModule PCD三种。这类PCD跟全局配置数据库没有关系,所以本文不做过多介绍。另一类是平台初始化过程中起作用,包括DynamicDefault PCD, DynamicHII PCD, 和DynamicVpd PC三种应用在源代码组件发布的PCD,以及与之对应的DynamicExDefault PCD, DynamicExHII PCD 和DynamicExVpd PCD——专门应用在编译好的二进制组件发布中的三种PCD。
2.1 PCD的分类和区别
从大面上,全局配置数据库中存放的PCD被分为两个大类Dynamic和DynamicEx,每个大类又各分三个小类Default PCD, HII PCD和VPD PCD。
Dynamic和DynamicEx的作用局域完全一样,唯一的区别就是源代码级别的发布还是编译好的代码发布。如果上层开发者给二级开发者提供的是所有驱动的源代码,那么二级开发者可以直接修改源代码来改变某个参数的值,此时只要把该配置参数设置为Dynamic形式的即可满足要求。否则,必须用DynamicEx的。DynamicEx的PCD在保护上层开发者的版权和代码发布权限提供了更多层次的选择空间。
Default PCD:在初始化过程中,可以被PEI,DXE和RT阶段的几乎所有驱动所使用,一般是前面的驱动修改,后面的驱动读取。这是不同的驱动,不同的阶段之间有效信息交互和传递的一种方法。该PCD的作用空间是一次加电过程,所修改的数值在系统断电后会自动回复到默认初始状态。
HII PCD:作用空间和Default PCD一样,主要的区别是HII的PCD可以把修改的数值直接保存到BIOS NOR Flash芯片的NVRAM区域。这样一旦修改,再计算机下次启动的时候,访问的就是上次修改的新数值。
VPD PCD:作用空间和上面两种相同,主要区别是VPD PCD是只读的不能修改,但是它也有自己的优势。因为VPD PCD是的初始值是保存在BIOS固件的一段二进制数据空间上的所以在固件编译完成后,可以在不依赖编译器重新编译情况下,对该PCD的数值进行直接的重复设置。
2.2 设计原理分析
在EDKII源代码编译中,编译工具集的AutoGen会遍历整个平台所有驱动和顶层结构文件生成AutoGen.h和AutoGen.c两个关键文件。这两个文件将作为后面C编译器的自动包换的头文件输入,参与C语言的系统级编译过程,最终生成这个平台的全局配置数据库。
下面通过一个NT32模拟平台中的例子来进行过程说明。
首先在NT32的顶层平台文件DEC, DSC和INF文件中依次做如下声明。
MdeModulePkg.dec
[PcdsFixedAtBuild, PcdsDynamic, PcdsDynamicEx]
gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase|0x0|UINT32|0x30000001
Nt32Pkg.dsc
[PcdsDynamicExDefault.common.DEFAULT]
gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase|0xf000
WinNtFlashMapPei.inf
[Pcd]
gEfiNt32PkgTokenSpaceGuid.PcdWinNtFlashNvStorageVariableBase
通过该声明,定义了一个DynamicExDefault类型的PCD,其类型为UINT32,初始默认数值为0xf000,并且驱动模块WinNtFlashMapPei要使用该配置数据。
接着用EDKII的BaseTools对该源代码架构进行编译,AutoGen工具会在遍历完整个代码之后,在相应的PCD驱动编译目录下面自动生成AutoGen.h和AutoGen.c两个文件,如下所示:
AutoGen.h (Build\NT32\DEBUG_MYTOOLS\IA32\MdeModulePkg\Universal\PCD\Pei\Pcd\DEBUG)
#define PEI_LOCAL_TOKEN_NUMBER_TABLE_SIZE 3
#define PEI_LOCAL_TOKEN_NUMBER 3
#define PEI_EXMAPPING_TABLE_SIZE 1U
#define PEI_EX_TOKEN_NUMBER 1U
#define PEI_SIZE_TABLE_SIZE 2U
typedef struct {
UINT32 PcdFlashNvStorageVariableBase_a1aff049_fdeb_442a_b320_13ab4cb72bbc[1];
DYNAMICEX_MAPPING ExMapTable[PEI_EXMAPPING_TABLE_SIZE];
UINT32 LocalTokenNumberTable[PEI_LOCAL_TOKEN_NUMBER_TABLE_SIZE];
GUID GuidTable[PEI_GUID_TABLE_SIZE];
UINT8 StringTable[1]; /* _ */
SIZE_INFO SizeTable[PEI_SIZE_TABLE_SIZE];
UINT8 SkuIdTable[PEI_SKUID_TABLE_SIZE];
SKU_ID SystemSkuId;
} PEI_PCD_DATABASE_INIT;
AutoGen.c (Build\NT32\DEBUG_MYTOOLS\IA32\MdeModulePkg\Universal\PCD\Pei\Pcd\DEBUG)
PEI_PCD_DATABASE_INIT gPEIPcdDbInit = {
{ 0xf000U }, /* PcdFlashNvStorageVariableBase_a1aff049_fdeb_442a_b320_13ab4cb72bbc[1] */
/* ExMapTable */ {{ 0x30000001U, 2U, 0U },},
/* LocalTokenNumberTable */
{
offsetof(PEI_PCD_DATABASE, Uninit.PcdFlashNvStorageFtwSpareBase_a1aff049_fdeb_442a_b320_13ab4cb72bbc) | PCD_TYPE_DATA | PCD_DATUM_TYPE_UINT32,
offsetof(PEI_PCD_DATABASE, Init.PcdFlashNvStorageVariableBase_a1aff049_fdeb_442a_b320_13ab4cb72bbc) | PCD_TYPE_DATA | PCD_DATUM_TYPE_UINT32,
},
/* GuidTable */
{{ 0xA1AFF049, 0xFDEB, 0x442a, { 0xB3, 0x20, 0x13, 0xAB, 0x4C, 0xB7, 0x2B, 0xBC }},},
//gEfiMdeModulePkgTokenSpaceGuid
/* StringTable */ /* SizeTable *//* SkuIdTable */
};
AutoGen.h自动生成的是该数据库的结构定义文件,它定义了各个PCD在该数据库中存放的数据位置、类型、偏移量等信息。AutoGen.c则配合AutoGen.h详细列出了各个比特位置存放的具体数值。
当WinNtFlashMapPei驱动模块中想要访问该PCD数值的时候,只需要在C语言中引用PcdGet32Ex(gEfiMdeModulePkgTokenSpaceGuid, 0x30000001)。这时就会自动扫描Init.ExMapTable 和Init.GuidTable两张数据库表取得该PCD对应的LocalTokenNumber数值 “2U”。
而后根据映射LocalTokenNumber的数值找到“offsetof(PEI_PCD_DATABASE, Init.PcdFlashNvStorageVariableBase_a1aff049_fdeb_442a_b320_13ab4cb72bbc) | PCD_TYPE_DATA | PCD_DATUM_TYPE_UINT32”。
通过在C语言中解析“offsetof(PEI_PCD_DATABASE, Init.PcdFlashNvStorageVariableBase_a1aff049_fdeb_442a_b320_13ab4cb72bbc) | PCD_TYPE_DATA | PCD_DATUM_TYPE_UINT32”的定义,就可以得到该PCD在数据库中的偏移量、PCD类型和数据类型信息。
其过程如图2所示:
图2 PCD访问过程
3 设计局限性和改进方法
在该数据库生成过程中,离不开对MS, ICC或者GCC编译器的支持,这样DynamicEx所宣称的二进制固件发布模式受到约束。换言之,想要完全的二进制驱动组件的发布,必须让EDKII整个平台PCD的生成过程脱离对任何编译器的依赖性。
针对这个设计要求,提出了新的设计架构,其流程图如图3所示:
图3 PCD数据库生成流程改进
在新的架构中,主要改变的是AutoGen的组件,EDKII的编译工具集依然会遍历整个架构的所有驱动和上层配置文件,但它会直接生成PCD数据库,同时生成一份包含改数据库结构的AutoGen.h文件和一份空的只包含注释信息AutoGen.c文件。AutoGen.h和AutoGen.c依然采用PEI/DXE驱动的源代码编译,只不过PCD数据库不在依赖该过程产生,因此稍加改动,就可使DynamicEx真正发挥其所宣称的作用。
4 结 语
EDKII的PCB数据库目前在国内没有任何论文研究发表过,本文主要针对这个空白领域,分析和研究了EDKII 最核心、最关键的全局数据设置数据库PCD的设计和实现,并指出了其设计的不足。随着UEFI BIOS的广泛应用,越来越多的军用板卡、通信主板、嵌入式设备和服务器也会转移到这个架构上。如果用一个稳定不变的核心代码来支持不同的设备,必然会减少维护成本,提高开发效率,以及提高设备的质量,这就是本文所研究的PCD技术的意义所在。
参考文献
[1] UEFI Forum. UEFI Specification. Version 2.3[EB/OL]. http://www.uefi.org/specs,2010
[2] UEFI Forum. UEFI Platform Initialization Specification. Version 1.2. [EB/OL]. http://www.uefi.org/specs,2010
[3] Vincent Zimmer. Beyond BIOS[M]. Intel corporation,2006.
[4] Framework Open Source Community. Pre_EFI Initialization Core Interface [EB/OL].http://www.uefi.org/specs,2008
[5] Intel Corporation.EDK II C Coding Standard[S]. 2006
[6] 倪光南. UEFI BIOS是软件业的蓝海[EB/OL]. http://soft.chinabyte.com/90/3382590_1.shtml,2007
[7] Gaurav Banga. EFI/UEFI 将带领PC产业进入下一世代[EB/OL].
offsetof(PEI_PCD_DATABASE, Init.PcdFlashNvStorageVariableBase_a1aff049_fdeb_442a_b320_13ab4cb72bbc) | PCD_TYPE_DATA | PCD_DATUM_TYPE_UINT32,
},
/* GuidTable */
{{ 0xA1AFF049, 0xFDEB, 0x442a, { 0xB3, 0x20, 0x13, 0xAB, 0x4C, 0xB7, 0x2B, 0xBC }},},
//gEfiMdeModulePkgTokenSpaceGuid
/* StringTable */ /* SizeTable *//* SkuIdTable */
};
AutoGen.h自动生成的是该数据库的结构定义文件,它定义了各个PCD在该数据库中存放的数据位置、类型、偏移量等信息。AutoGen.c则配合AutoGen.h详细列出了各个比特位置存放的具体数值。
当WinNtFlashMapPei驱动模块中想要访问该PCD数值的时候,只需要在C语言中引用PcdGet32Ex(gEfiMdeModulePkgTokenSpaceGuid, 0x30000001)。这时就会自动扫描Init.ExMapTable 和Init.GuidTable两张数据库表取得该PCD对应的LocalTokenNumber数值 “2U”。
而后根据映射LocalTokenNumber的数值找到“offsetof(PEI_PCD_DATABASE, Init.PcdFlashNvStorageVariableBase_a1aff049_fdeb_442a_b320_13ab4cb72bbc) | PCD_TYPE_DATA | PCD_DATUM_TYPE_UINT32”。
通过在C语言中解析“offsetof(PEI_PCD_DATABASE, Init.PcdFlashNvStorageVariableBase_a1aff049_fdeb_442a_b320_13ab4cb72bbc) | PCD_TYPE_DATA | PCD_DATUM_TYPE_UINT32”的定义,就可以得到该PCD在数据库中的偏移量、PCD类型和数据类型信息。
其过程如图2所示:
图2 PCD访问过程
3 设计局限性和改进方法
在该数据库生成过程中,离不开对MS, ICC或者GCC编译器的支持,这样DynamicEx所宣称的二进制固件发布模式受到约束。换言之,想要完全的二进制驱动组件的发布,必须让EDKII整个平台PCD的生成过程脱离对任何编译器的依赖性。
针对这个设计要求,提出了新的设计架构,其流程图如图3所示:
图3 PCD数据库生成流程改进
在新的架构中,主要改变的是AutoGen的组件,EDKII的编译工具集依然会遍历整个架构的所有驱动和上层配置文件,但它会直接生成PCD数据库,同时生成一份包含改数据库结构的AutoGen.h文件和一份空的只包含注释信息AutoGen.c文件。AutoGen.h和AutoGen.c依然采用PEI/DXE驱动的源代码编译,只不过PCD数据库不在依赖该过程产生,因此稍加改动,就可使DynamicEx真正发挥其所宣称的作用。
4 结 语
EDKII的PCB数据库目前在国内没有任何论文研究发表过,本文主要针对这个空白领域,分析和研究了EDKII 最核心、最关键的全局数据设置数据库PCD的设计和实现,并指出了其设计的不足。随着UEFI BIOS的广泛应用,越来越多的军用板卡、通信主板、嵌入式设备和服务器也会转移到这个架构上。如果用一个稳定不变的核心代码来支持不同的设备,必然会减少维护成本,提高开发效率,以及提高设备的质量,这就是本文所研究的PCD技术的意义所在。
参考文献
[1] UEFI Forum. UEFI Specification. Version 2.3[EB/OL]. http://www.uefi.org/specs,2010
[2] UEFI Forum. UEFI Platform Initialization Specification. Version 1.2. [EB/OL]. http://www.uefi.org/specs,2010
[3] Vincent Zimmer. Beyond BIOS[M]. Intel corporation,2006.
[4] Framework Open Source Community. Pre_EFI Initialization Core Interface [EB/OL].http://www.uefi.org/specs,2008
[5] Intel Corporation.EDK II C Coding Standard[S]. 2006
[6] 倪光南. UEFI BIOS是软件业的蓝海[EB/OL]. http://soft.chinabyte.com/90/3382590_1.shtml,2007
[7] Gaurav Banga. EFI/UEFI 将带领PC产业进入下一世代[EB/OL].
offsetof(PEI_PCD_DATABASE, Init.PcdFlashNvStorageVariableBase_a1aff049_fdeb_442a_b320_13ab4cb72bbc) | PCD_TYPE_DATA | PCD_DATUM_TYPE_UINT32,
},
/* GuidTable */
{{ 0xA1AFF049, 0xFDEB, 0x442a, { 0xB3, 0x20, 0x13, 0xAB, 0x4C, 0xB7, 0x2B, 0xBC }},},
//gEfiMdeModulePkgTokenSpaceGuid
/* StringTable */ /* SizeTable *//* SkuIdTable */
};
AutoGen.h自动生成的是该数据库的结构定义文件,它定义了各个PCD在该数据库中存放的数据位置、类型、偏移量等信息。AutoGen.c则配合AutoGen.h详细列出了各个比特位置存放的具体数值。
当WinNtFlashMapPei驱动模块中想要访问该PCD数值的时候,只需要在C语言中引用PcdGet32Ex(gEfiMdeModulePkgTokenSpaceGuid, 0x30000001)。这时就会自动扫描Init.ExMapTable 和Init.GuidTable两张数据库表取得该PCD对应的LocalTokenNumber数值 “2U”。
而后根据映射LocalTokenNumber的数值找到“offsetof(PEI_PCD_DATABASE, Init.PcdFlashNvStorageVariableBase_a1aff049_fdeb_442a_b320_13ab4cb72bbc) | PCD_TYPE_DATA | PCD_DATUM_TYPE_UINT32”。
通过在C语言中解析“offsetof(PEI_PCD_DATABASE, Init.PcdFlashNvStorageVariableBase_a1aff049_fdeb_442a_b320_13ab4cb72bbc) | PCD_TYPE_DATA | PCD_DATUM_TYPE_UINT32”的定义,就可以得到该PCD在数据库中的偏移量、PCD类型和数据类型信息。
其过程如图2所示:
图2 PCD访问过程
3 设计局限性和改进方法
在该数据库生成过程中,离不开对MS, ICC或者GCC编译器的支持,这样DynamicEx所宣称的二进制固件发布模式受到约束。换言之,想要完全的二进制驱动组件的发布,必须让EDKII整个平台PCD的生成过程脱离对任何编译器的依赖性。
针对这个设计要求,提出了新的设计架构,其流程图如图3所示:
图3 PCD数据库生成流程改进
在新的架构中,主要改变的是AutoGen的组件,EDKII的编译工具集依然会遍历整个架构的所有驱动和上层配置文件,但它会直接生成PCD数据库,同时生成一份包含改数据库结构的AutoGen.h文件和一份空的只包含注释信息AutoGen.c文件。AutoGen.h和AutoGen.c依然采用PEI/DXE驱动的源代码编译,只不过PCD数据库不在依赖该过程产生,因此稍加改动,就可使DynamicEx真正发挥其所宣称的作用。
4 结 语
EDKII的PCB数据库目前在国内没有任何论文研究发表过,本文主要针对这个空白领域,分析和研究了EDKII 最核心、最关键的全局数据设置数据库PCD的设计和实现,并指出了其设计的不足。随着UEFI BIOS的广泛应用,越来越多的军用板卡、通信主板、嵌入式设备和服务器也会转移到这个架构上。如果用一个稳定不变的核心代码来支持不同的设备,必然会减少维护成本,提高开发效率,以及提高设备的质量,这就是本文所研究的PCD技术的意义所在。
参考文献
[1] UEFI Forum. UEFI Specification. Version 2.3[EB/OL]. http://www.uefi.org/specs,2010
[2] UEFI Forum. UEFI Platform Initialization Specification. Version 1.2. [EB/OL]. http://www.uefi.org/specs,2010
[3] Vincent Zimmer. Beyond BIOS[M]. Intel corporation,2006.
[4] Framework Open Source Community. Pre_EFI Initialization Core Interface [EB/OL].http://www.uefi.org/specs,2008
[5] Intel Corporation.EDK II C Coding Standard[S]. 2006
[6] 倪光南. UEFI BIOS是软件业的蓝海[EB/OL]. http://soft.chinabyte.com/90/3382590_1.shtml,2007
[7] Gaurav Banga. EFI/UEFI 将带领PC产业进入下一世代[EB/OL].