BIOS实现和带内交互
BIOS实现和带内交互
BIOS模块代码路径是:BIOS
功能介绍
BIOS本来是系统侧启动过程中引导OS启动的部分,此处介绍的是BMC侧的BIOS组件,功能主要是和带内的BIOS进行系统交互,内容主要分为: 1、给带内的BIOS版本升级固件; 2、BMC设置和获取带内BIOS的属性;
整体设计实现
学习这个模块之前,请先关注这个帖子: bios地址是:https://www.openubmc.cn/docs/zh/development/api/app_api/bios.html,里面对bios功能做了非常详细且高效的介绍。
写的非常好,可以反复阅读,本组件实现非常复杂,不是非常必要,建议只关注遇到的问题,系统完整学习很耗精力。此篇介绍只是在代码实现方面做部分补充,引导学习;
给带内的bios版本升级固件
升级模式分为装备升级、非装备升级、无感升级,对于装备升级则会执行强制上下电,而非装备包不会。
升级的逻辑相对很复杂,上面帖子bios已经很详细的介绍,这里从代码流程分析一下,普通BIOS升级的主要过程如下:
升级任务启动后,会调用到upgrade_hpm函数,里面会调用HpmUpgrade的prepare,process,finish函数,在process时,调用build_upgrade_mode确定升级模式(热/冷/强制/在线强制),然后构建升级信息,构建升级信息的结果upgrade_info,传入到Package:process中,然后调用Package:_start()。此处正常情况下升级回在app.log里面有打印Start the bios upgrade prepare phase,最终升级结束后有hpm upgrade: bios package upgrade successfully打印,最终升级结束。;
以上是流程中的核心部分,执行Package:_start()的时候,生成了executor执行链的上下文对象,scenarios:execute(ctx)函数根据场景来确定执行哪些步骤,此时是热升级还是冷升级,生成执行链。全部执行链包含如下步骤:拷贝包、缓存包、强制下电操作(仅装备模式)、上电锁、加载驱动、解析包(按header解析)、选择升级区域、选择升级通道(SPI或IPMB)、开始升级。不同的场景会执行不同的执行链;
正常升级过程的执行链有打印供参考:upgrade chain: parse_bin (executor) start,执行链结束时有打印upgrade chain: spi_driver (executor) end;
升级BIOS的实质是将升级包的内容刷新到flash里面,对于无感升级底层是IPMB通道、而非无感升级底层是spi链路。
IPMB通道的实现参考IpmbChannel:upgrade函数 IPMB总线发送命令和数据,并不直接操作Flash,由接收方IMU来处理升级。具体参考ComponentUpgrade的write_firmware_data。
其他情况的BIOS的升级最终调用的是:SpiFlashChannel:upgrade SPI通道:直接操作硬件,需要切换SPI总线、加载驱动、直接读写Flash,调用的spi_flash.spi_flash_copy。
BMC页面上修改BIOS属性
比如设置启动项命令,对应redfish接口是https://$ip/UI/Rest/System/BootOptions 接口内容是:
{"PreferredBootMedium":{"Target":"BiosSetup","EffectivePeriod":"Continuous"}}调用到接口映射模块rack_mount中,通过rpc接口,调用到BIOS模块的函数SetStartOption,SetStartOptionFlag,实现具体功能,这两个函数同样也可以通过ipmi命令,rpc命令调用过来,能看到如下打印auto clear valid is false, set start option,设置属性成功后等待BIOS启动后读取;
BIOS固件导出功能
export_bios_firmware创建一个新的协程来执行实际的导出工作,调用process_download_action开始下载bios固件的动作,实际调用download_one_bios切換SPI通道,调用download_bios函数从SPI闪存中读取BIOS固件,并写入到导出路径。 核心动作是write_data_from_flash,就是从SPI Flash中读取 BIOS 固件数据,并写入到本地文件中保存,这是“导出”过程的关键一步。 导出后会打印export bios firmware finished,导出的是bios.tar.gz文件。
BIOS与BMC交互流程
BIOS启动流程说明:
1、首先是执行上电操作,bios模块接收到上电信号之后会对Bios Flash进行安全校验,如果校验失败则不允许启动,如果校验成功则允许启动。
2、对于Bios启动过程,会通过ipmi命令与BMC的bios模块进行信息交互,主要包含两部分,如下图所示:
- a、Bios将版本号、生效的启动项与配置、BDF等信息上报给BMC,详情见 “Bios信息上报”;
- b、Bios从BMC获取待生效的启动项与配置、内存与PCIE的丝印等信息,详情见 “Bios配置读取”。
图片说明:绿色字体表示场景a、蓝色字体表示场景b
Bios信息上报
| 编号(时序图编号) | 命令 | 功能 |
|---|---|---|
| 1 | ReportAlarm | 上报PowerLink、VRAbnormal、MemoryLink等告警 |
| 2 | SetBiosVersion | 上报Bios Version版本号 |
| 5 | WriteSmbiosData | 上报Smbios文件,包含内存、CPU的厂商等静态信息 |
| 7 | WriteFileToBmc | 上报生效的Bios配置(FileSelector是0x1a);上报生效的证书文件(FileSelector为0x2c) |
| 9 | SetBootOption | 上报生效的Bios启动项、启动项生效次数 |
| 10 | UpdatePostStatus | 上报Bios启动完成标记 |
Bios配置读取
| 编号(时序图编号) | 命令 | 功能 |
|---|---|---|
| 3 | ReadFileFromBmc | 从BMC获取丝印(FileSelector是0x2a);从BMC读取Bios配置信息(FileSelector是0x1b) |
| 4 | UpdateBiosPassword | 从BMC获取设置的Bios密码,并上报设置结果到BMC |
| 6 | ReadFileFromBmc | 从BMC获取bios配置生效流程书文件(FileSelector是0x2b) |
| 8 | GetBootOption | 从BMC获取设置的启动项、启动项生效次数配置 |
Bios配置生效详解
1、用户通过redfish或者Web接口导入Bios配置,配置写入到setting.json文件;
2、带内Bios在启动过程中,通过ReadFileFromBmc命令从BMC读取setting.json文件,获取到Bios配置;
3、带内Bios获取配置并进行生效,生效的配置通过WriteFileToBmc命令把currentValue.json文件上报给BMC,内容是生效的Bios配置。
ReadFile举例
BIOS和BMC沟通信息主要是通过ipmi命令,比如ReadFileFromBmc命令是bios从bmc获取文件的函数,每次开机过程中会调用bios_read_file_from_bmc,会有如下打印Disk PCIeAddrInfo:,get_mem_silk_array,get_pcie_silk_config等从bmc获取信息; 代码bios_read_file_from_bmc作为入口,BIOS传入不同的参数,分别调用bios_read_prepare准备,bios_read_data组装数据,bios_read_finish计算校验和,根据命令参数不同,在bios_read_prepare,根据FileSelector命令字不同,区分需要返回的信息是silkconfig.json文件或者new_secureboot.json,psu_info.json等内容给BIOS。
交互时的数据可能是超过IPMI命令的长度的,具体处理流程如下:
BIOS侧 BMC侧
| |
|--- BIOS_READ_PREPARE ------------>|
| (请求准备) |
| |-- 读取整个文件到内存
| |-- 返回文件总大小
|<--- 响应(文件长度) --------------- |
| |
|--- BIOS_READ_DATA --------------->|
| (偏移=0, 长度=248) |
| |-- 截取0-247字节
| |-- 计算校验和
|<--- 响应(数据块1 + 标志位) --------|
| |
|--- BIOS_READ_DATA --------------->|
| (偏移=248, 长度=248) |
| |-- 截取248-495字节
| |-- 计算校验和
|<--- 响应(数据块2 + 标志位) --------|
| |
| ... (循环直到读完) |
| |
|--- BIOS_READ_DATA --------------->|
| (最后一块) |
| |-- 截取最后部分
| |-- 标志位设为NO_MORE_DATA
|<--- 响应(最后数据块 + 结束标志) ----|
| |
|--- BIOS_READ_FINISH ------------->|
| (请求结束) |
| |-- 验证整体校验和
|<--- 响应(完成) -------------------|
| |这套机制通过分块传输 + 状态机控制 + 偏移量管理,在IPMI消息大小限制下实现了大文件的可靠传输。
WriteFile举例
BIOS会通过WriteSmbiosData的IPMI命令发送SMBIOS数据给BMC,write_smbios和上面的Read类似,也是经过三个阶段,把数据写入到本地文件,在开机时调用,会打印update_smbios_file: write file len执行结束的时候有打印smbios_write_finish;
开机也会调用bios_write_bdf_to_bmc,会打印write_one_frame: pcie bdf reported和bios_write_bdf_to_bmc: sht bios_write_bdf_data_to_bmc max_frame,还有类似的WritePcieCardBdfToBmc接口把pciecard的BDF信息写入到bmc等等。
其他情况Bios和BMC通信
BMC和BIOS通信还有很多其他的接口,具体可以在BiosIpmiCmdsMsg中查找,或者在mds\ipmi.json中查找,具体实现比较复杂,此处不再介绍;