综述
SBL的一个特性是Customizable,它分为构建前和构建后的定制化。
SBL有两种配置数据,分别是内部配置数据和外部配置数据。内部配置数据是代码写死的默认数据,当获取不到外部数据的时候就使用这个默认数据;外部配置数据通过预定义文件和配置工具生成。
SBL中的预定义文件和配置工具包括:
- YAML文件:它定义配置;
- DLT(delta,表示的其实是变量数据)文件:Override数据,用来覆盖YAML文件中的配置;
- 配置操作工具:通常是Python脚本。
YAML文件
YAML文件中包含了内存、Silicon、GPIO、启动策略、安全配置等等。
YAML文件通常包含在特定单板目录下,比如ApolloLake平台:
还有一些通用的YAML文件在Platform\CommonBoardPkg\CfgData目录中:
其中平台需要的配置文件入口是CfgDataDef.yaml
,其它的配置文件都作为它的子文件包含在CfgDataDef.yaml
中。比如Platform\ApollolakeBoardPkg\CfgData\CfgDataDef.yaml:
## @file
#
# Slim Bootloader CFGDATA Default File.
#
# Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
##
variable:
COND_GPIO_SKIP : ($GPIO_CFG_DATA.$(1)_Half0.GpioSkip == 0)
COND_GPIO_PID_ENABLE : ($PID_GPIO_CFG_DATA.$(1).Enable==1) and ($PLATFORMID_CFG_DATA.PlatformId==0)
COND_PCIE_RP_PWR_PIN_SKIP : ($PCIE_RP_CFG_DATA.PcieRpPower$(1).Skip == 0)
COND_PCIE_RP_RST_PIN_SKIP : ($PCIE_RP_CFG_DATA.PcieRpReset$(1).Skip == 0)
COND_PCIE_RP_EN : ($PCIE_RP_CFG_DATA.PcieRpFeatures$(1).En == 1)
COND_PCIE_RP_CLK_REQ_SUP : (($PCIE_RP_CFG_DATA.PcieRpFeatures$(1).ClkReqSup == 1) and ($PCIE_RP_CFG_DATA.PcieRpFeatures$(1).En == 1))
COND_HDA_EN : ($HDA_CFG_DATA.HdaEnable == 1)
COND_HDA_DSP_EN : (($HDA_CFG_DATA.HdaEnable == 1) and ($HDA_CFG_DATA.DspEnable == 1))
template:
- !include Template_CfgData.yaml
configs:
- $ACTION :
page : PLT::"Platform", MEM::"Memory Settings", SIL::"Silicon Settings", GEN::"General Settings", GIO::"Gpio Settings", OS::"OS Boot Options"
- Signature :
length : 0x04
value : {'CFGD'}
- HeaderLength :
length : 0x01
value : 0x10
- Reserved :
length : 0x03
value : {0,0,0}
- UsedLength :
length : 0x04
value : _LENGTH_
- TotalLength :
length : 0x04
value : 0x2000
- !include Platform/CommonBoardPkg/CfgData/CfgData_Platform.yaml
- $ACTION :
page : IOCUART:PLT:"IOC Uart Settings"
- $ACTION :
page : IOCUART
- IOC_UART_CFG_DATA :
- !expand { CFGHDR_TMPL : [ IOC_UART_CFG_DATA, 0x120, 0, 0 ] }
- DeviceIndex :
name : Device Index
type : Combo
option : 0:UART0, 1:UART1, 2:UART2, 3:UART3, 0xF:Disable
help : >
UART device index for IOC interface (0..3 or Disable)
length : 0x01
value : 0xF
- BaudRate :
name : Baud Rate
type : Combo
option : 0:9600, 1:19200, 2:38400, 3:57600, 4:115200, 5:921600, 6:1.5M
help : >
UART Baud Rate
length : 0x01
value : 0
- Retries :
name : Retries
type : EditNum, HEX, (0x00,0xFF)
help : >
specify retry count
length : 0x01
value : 0
- TimeoutInitial :
name : TimeoutInitial
type : EditNum, HEX, (0x00,0xFF)
help : >
initial/setup time-out (in milliseconds)
length : 0x01
value : 0
- TimeoutXmit :
name : TimeoutXmit
type : EditNum, HEX, (0x00,0xFF)
help : >
transmission time-out
length : 0x01
value : 0
- Rsvd :
length : 0x03
value : 0
- $ACTION :
page : PSEL:PLT:"Payload Selection GPIO"
- $ACTION :
page : PSEL
- PLATFORM_CFG_DATA :
- !expand { CFGHDR_TMPL : [ PLATFORM_CFG_DATA, 0x280, 0, 0 ] }
- PayloadSelGpio :
- $STRUCT :
name : GPIO pin for switching payload
struct : PAYLOAD_SEL_GPIO_PIN
length : 0x04
value : 0x000000c5
- PadInfo :
name : Pin Number
type : Combo
option : !include CfgData_GpioPinOption.yaml
condition : ($PLATFORM_CFG_DATA.PayloadSelGpio.Enable > 0)
help : >
Specify GPIO Pin Number
length : 24b
- Rsvd1 :
name : Reserved
type : Reserved
length : 7b
- Enable :
name : Payload Selection Pin Enable
type : Combo
option : $EN_DIS
help : >
Enable/Disable this pin for payload selection.
order : 0000.0000
length : 1b
- !include CfgData_Memory.yaml
- !include CfgData_Silicon.yaml
- !include CfgData_Usb.yaml
- !include CfgData_Gpio.yaml
- !include Platform/CommonBoardPkg/CfgData/CfgData_Common.yaml
- !include CfgData_BootOption.yaml
- !include CfgData_PidGpioPins.yaml
- !include CfgData_PcieRp.yaml
- !include CfgData_GpuConfig.yaml
- !include CfgData_Features.yaml
- !include CfgData_DeviceEnable.yaml
- !include CfgData_Hda.yaml
- !include CfgData_CapsuleInformation.yaml
可以看到包含很多的include
命令,指定了内存、Silicon、USB、GPIO等等YAML文件。
DLT文件
DLT文件中的数据是用来覆盖YAML文件中的配置的。
DLT文件包含一个PlatformId
,比如Platform\ApollolakeBoardPkg\CfgData\CfgData_Ext_Up2.dlt中:
#
# Delta configuration values for platform ID 0x000E
#
PLATFORMID_CFG_DATA.PlatformId | 0x000E
一个平台中的DLT文件可以有多个,每个都对应一个PlatformId
,并最终和一个特定的单板匹配。如果PlatformId
等于0,表示对于所有的单板都适用,相当于改了YAML文件本身。这些DLT文件对应到BoardConfig.py中:
self._CFGDATA_EXT_FILE = ['CfgData_Ext_Gpmrb.dlt', 'CfgData_Ext_Up2.dlt','CfgData_Ext_OxbHill.dlt','CfgData_Ext_MB3.dlt','CfgData_Ext_JuniperHill.dlt']
如果需要增加单板,通常不会直接修改YAML文件,而是增加DLT文件并修改配置来覆盖原有配置,并将DLT文件增加到上述的列表中。
顺便再说明下PlatformId
,Intel的CRB单板中指定了若干个GPIO管脚,通过硬件配置死的方式来指定特定单板,这样代码中就可以通过读取GPIO的值来确定PlatformId
。对应ApolloLake平台,相关的代码可以在Platform\ApollolakeBoardPkg\Library\Stage1BBoardInitLib\Stage1BBoardInitLib.c中看到:
/**
Detect board and configure PlatformID.
@retval EFI_SUCCESS Configuration data was loaded successfully.
@retval Others Failed to get configuration data blob.
**/
EFI_STATUS
EFIAPI
PlatformIdInitialize (
IN VOID
)
{
UINT16 PlatformId;
PlatformId = (UINT16)GetBoardIdFromGpioPins ();
if (PlatformId != 0xFF) {
PlatformId += 0x10; // Customer board identified, assign Platform Ids from 16 to 31
} else {
PlatformId = (UINT16)GetEmbeddedBoardId ();
//Platform ID from GPIOs are read as 0 for Juniper hills due to GPIO pins
//on the board reduced from 4 to 3 (hardware change) hence translating here
//in the code.
if (PlatformId == 0){
DEBUG ((DEBUG_INFO, "GPIO returned platformID 0 translating to 8(JNH)\n"));
PlatformId = 0x8;
}
if ((PlatformId != PLATFORM_ID_OXH) && (PlatformId != PLATFORM_ID_LFH) && (PlatformId != PLATFORM_ID_JNH)) {
PlatformId = (UINT16)GetIVIBoardId ();
if (PlatformId != PLATFORM_ID_GPMRB) {
DEBUG ((DEBUG_ERROR, "BOARD NOT SUPPORTED: 0x%04X\n", PlatformId));
CpuDeadLoop ();
}
}
}
SetPlatformId (PlatformId);
return EFI_SUCCESS;
}
配置工具
配置工具处理YAML和DLT文件的方式大致就是下面这个样子(注意二进制本身同时可以作为输入和输出):
所以本节就介绍配置工具,它位于BootloaderCorePkg/Tools目录下。最重要的是ConfigEditor.py,它是一个图形工具,打开之后如下所示:
点击“File”,第一次只能选择“Open Config YAML file…“:
这里可以选择前面提到的CfgDataDef.yaml,即基础配置文件。在这之后就可以选择“Load Config Changes from Delta File”,这样新加入的DLT文件会覆盖原本的显示,之后可以继续修改,并最终保存修改之后的数据,这样的数据可以是只包含修改部分的DLT文件,也可以是覆盖所有配置的DLT文件,或者直接生成二进制文件。
除了ConfigEditor.py,还有配置工具是用来将YAML文件转换成头文件Platform\XXXPkg\Include\ConfigDataStruct.h的,它会被包含到SBL代码中,通过代码来最终获取配置并使用。
最终配置工具的使用流程就像如下图所示的一样:
总的来说,SBL的配置就是YAML文件定义基础配置,DLT文件根据实际单板修改配置,最终生成二进制配置文件,这个二进制配置文件会被放到SBL二进制*后续获取。在SBL代码中,会判断当前的PlatformId
,并加载需要的二进制配置文件,来完成最终的配置。
最后,即使生成了SBL二进制,也还是可以通过工具修改其参数,这就是构建后自定义。