OpenUBMC QEMU打包完整技术文档
文档版本:v2.0
文档日期:2026年5月
适用范围:OpenUBMC开发与维护人员
目录
一、QEMU打包完整流程
1.1 打包脚本与入口
核心脚本:build/works/packet/work_build_qemu_rootfs.py
打包入口:TaskClass.run() → qemu_rootfs_deploy()
1.2 打包流程七步骤
步骤1:源文件准备
源rootfs路径:
rtos_with_driver/rootfs(真机rootfs)
内容包含:
| 目录 | 内容说明 |
|---|---|
/bin, /sbin, /usr/bin |
系统命令 |
/lib, /lib64 |
系统库 |
/etc |
配置文件(rc.sysinit, systemd服务) |
/opt/bmc/apps |
BMC应用程序 |
/boot |
内核镜像 |
步骤2:复制到临时打包目录
# 691-698行
src_rootfs_path = "rtos_with_driver/rootfs"
qemu_rootfs_path = "temp_path/qemu/qemu_rootfs"
操作:cp -a src_rootfs_path → qemu_rootfs_path
目的:创建临时打包目录,避免破坏源rootfs
步骤3:QEMU定制化处理(核心)
处理类:QemuCi.qemu_action()(374-416行)
处理对象:qemu_rootfs_path目录
关键操作:
虚拟化驱动注入
启动脚本修改
硬件密钥禁用
Mock数据注入
服务降级处理
健康检查禁用
初始化脚本裁剪
步骤4:清理虚拟化临时文件
# 424-461行
QemuCi.rm_ve_libs()
删除目录:
| 目录 | 说明 |
|---|---|
virtio/ |
虚拟化临时文件 |
lua_code/ |
Lua临时文件 |
scripts/ |
脚本临时文件 |
qemu/ |
QEMU临时文件 |
qemu_luas/ |
QEMU Lua临时文件 |
sr/ |
SR临时文件 |
目的:清理打包过程中产生的临时文件,避免污染最终镜像
步骤5:编译数据脚本
# 707-708行
chdir("qemu_rootfs_path/data/script")
make # 编译/data/script目录下的脚本
目的:确保数据脚本可执行
步骤6:CPIO打包压缩
# 712-729行
chdir("qemu_rootfs_path")
find . | cpio -H newc --quiet -o > qemu.cpio
gzip -k qemu.cpio → qemu.cpio.gz
打包格式:newc格式(标准CPIO格式)
压缩方式:gzip压缩
步骤7:组装最终发布包
# 733-738行
产物组成:
1. qemu.cpio.gz(根文件系统镜像)
2. zImage_openUBMC(内核镜像,从uImage提取)
3. hi1711_9p8c.dtb(设备树文件,从qemu_mockup复制)
打包:
tar -czf board_qemu_default.data.gz(包含上述3个文件)
最终路径:output/packet/board_qemu_default.data.gz
1.3 打包流程图
┌────────────────────────────────────────────┐
│ 源rootfs: rtos_with_driver/rootfs │
│ (真机rootfs,包含完整系统文件) │
└────────────────────────────────────────────┘
↓ 复制
┌────────────────────────────────────────────┐
│ 临时目录: temp_path/qemu/qemu_rootfs │
│ (临时打包目录,所有定制化操作在此执行) │
└────────────────────────────────────────────┘
↓ QEMU定制化处理(核心步骤)
┌────────────────────────────────────────────┐
│ QemuCi.qemu_action() │
│ ├─ 虚拟化驱动注入 │
│ ├─ 启动脚本修改 │
│ ├─ 硬件密钥禁用 │
│ ├─ Mock数据注入 │
│ ├─ 服务降级处理 │
│ ├─ 健康检查禁用 │
│ └─ 初始化脚本裁剪 │
└────────────────────────────────────────────┘
↓ 清理临时文件
┌────────────────────────────────────────────┐
│ QemuCi.rm_ve_libs() │
│ 删除:virtio, lua_code, scripts, qemu等 │
└────────────────────────────────────────────┘
↓ 编译脚本
┌────────────────────────────────────────────┐
│ make data/script │
└────────────────────────────────────────────┘
↓ CPIO打包
┌────────────────────────────────────────────┐
│ find . | cpio -H newc -o > qemu.cpio │
└────────────────────────────────────────────┘
↓ GZIP压缩
┌────────────────────────────────────────────┐
│ gzip qemu.cpio → qemu.cpio.gz │
└────────────────────────────────────────────┘
↓ 提取内核镜像
┌────────────────────────────────────────────┐
│ dd if=uImage of=zImage bs=1 skip=64 │
│ (跳过64字节uImage头) │
└────────────────────────────────────────────┘
↓ 组装发布包
┌────────────────────────────────────────────┐
│ 最终产物: │
│ ├─ qemu.cpio.gz(根文件系统) │
│ ├─ zImage_openUBMC(内核镜像) │
│ ├─ hi1711_9p8c.dtb(设备树) │
│ └─ board_qemu_default.data.gz(发布包) │
└────────────────────────────────────────────┘
二、真机与QEMU的核心差异
2.1 差异总览对比表
| 维度 | 真机 | QEMU虚拟化环境 | 差异说明 |
|---|---|---|---|
| 硬件访问 | 直接访问物理寄存器(I2C/GPIO/SPI) | 通过virtio读取宿主机文件(9p文件系统) | 核心差异:物理硬件 vs 虚拟化文件 |
| 数据来源 | 真实传感器/EEPROM硬件数据 | Mock数据文件(JSON/二进制) | 核心差异:真实数据 vs 模拟数据 |
| 驱动类型 | I2C/GPIO/SPI/UART物理驱动 | Virtio虚拟化驱动(virtio_pci/9pnet) | 核心差异:物理驱动 vs 虚拟驱动 |
| 数据挂载 | 物理分区挂载(mtdblock/mmcblk) | 9p虚拟文件系统挂载(hostshare/pramshare) | 核心差异:物理分区 vs 虚拟挂载 |
| 启动流程 | 完整硬件检查和初始化 | 跳过硬件检查,裁剪初始化脚本 | 核心差异:完整流程 vs 裁剪流程 |
| 服务安全 | secbox用户 + 沙箱隔离 + 最小权限 | root用户 + 无沙箱 + 扩展权限 | 核心差异:安全隔离 vs 开放环境 |
| 健康检查 | MACA重启机制 + 健康监控 + 离线阈值 | 全部禁用(避免反复重启) | 核心差异:严格监控 vs 放宽限制 |
| 密钥验证 | 硬件根密钥验证(EFUSE芯片) | 软件模拟(禁用硬件验证) | 核心差异:硬件验证 vs 软件模拟 |
| 调试方式 | 串口/JTAG硬件调试 | telnet + 虚拟串口(远程调试) | 核心差异:硬件调试 vs 软件调试 |
| 网络配置 | 真实物理网络接口(eth0物理MAC) | 虚拟网络接口(eth0: 10.0.2.15虚拟MAC) | 核心差异:物理网络 vs 虚拟网络 |
2.2 启动流程差异详解
真机启动流程
Bootloader(U-Boot)
↓ 加载uImage + rootfs
内核启动
↓ 加载物理驱动
├─ i2c_drv.ko(I2C总线驱动)
├─ gpio_drv.ko(GPIO驱动)
├─ uart_drv.ko(UART驱动)
├─ spi_drv.ko(SPI驱动)
├─ watchdog_drv.ko(硬件看门狗)
└─ mctp_drv.ko(MCTP协议驱动)
↓
rc.sysinit初始化
├─ 硬件检查(cooling.sh散热检查)
├─ 分区挂载(mount /dev/mmcblk0p1 /data)
├─ 设备树解析(读取真实硬件信息)
├─ RTOS快照加载(rtos_snapshot.ko)
└─ 物理设备初始化(读取硬件寄存器)
↓
systemd服务启动
├─ 以secbox用户运行(安全隔离)
├─ 通过secbox沙箱启动(ExecStart=secbox -f ...)
├─ 最小权限集(CAP_DAC_OVERRIDE, CAP_NET_BIND_SERVICE)
├─ MACA异常重启机制(健康检查失败 → 重启)
└─ 硬件根密钥验证(HARDWARE_ROOTKEY_ENABLE=true)
↓
rc.start脚本执行
├─ S11EventInit.sh(读取真实Event传感器)
├─ S11FrudataInit.sh(读取真实FRU EEPROM)
├─ S11SensorInit.sh(读取真实Sensor数据)
├─ S12BiosInit.sh(初始化真实BIOS硬件)
├─ S12PCIeInit.sh(扫描真实PCIe设备)
└─ S12StorageInit.sh(初始化真实存储设备)
↓
应用程序运行
├─ 健康检查机制(启动失败 → MACA重启)
├─ 真实硬件访问(i2c_read → 物理寄存器)
├─ Watchdog监控(硬件看门狗触发)
└─ 物理传感器数据上报
QEMU启动流程
QEMU虚拟化层启动
↓ 配置虚拟化参数
├─ 加载zImage_openUBMC(内核镜像)
├─ 加载qemu.cpio.gz(根文件系统)
├─ 加载hi1711_9p8c.dtb(设备树)
├─ 配置virtfs共享(hostshare, pramshare, mockshare)
└─ 配置虚拟网络(eth0: 10.0.2.15)
↓
内核启动 + virtio驱动加载
├─ insmod_9p_vfs.sh(第179行执行)
├─ 加载virtio驱动(virtio_pci, virtio_net, 9pnet)
├─ 配置虚拟网络(ifconfig eth0 10.0.2.15)
└─ 挂载9p文件系统
├─ mount hostshare → /data(宿主机数据共享)
├─ mount pramshare → /opt/bmc/pram(宿主机PRAM共享)
└─ mount mockshare → /mockdata(宿主机Mock数据共享)
↓
rc.sysinit初始化(修改版)
├─ 跳过硬件检查(注释cooling.sh)
├─ 注释RTOS快照(rtos_snapshot.ko)
├─ 启动telnetd服务(调试入口)
├─ 创建虚拟设备标志(touch /dev/uart_connect)
├─ 软链接shadow文件(ln -s /data/trust/shadow)
└─ 调整分区参数(logpart_sectors_num=0)
↓
systemd服务启动(修改版)
├─ 以root用户运行(User=root,原secbox)
├─ 直接bash启动(ExecStart=bash -c,跳过secbox沙箱)
├─ 扩展权限集(增加CAP_SYS_MODULE等10个权限)
├─ 禁用健康检查(IGNORE_HEALTH_CHECK_RESULT=true)
├─ 禁用MACA机制(mc_control.json: true → false)
└─ 禁用硬件密钥(HARDWARE_ROOTKEY_ENABLE=false)
↓
rc.start脚本执行(裁剪版)
├─ S11EventInit.sh(删除硬件检查,保留脚本)
├─ S11FrudataInit.sh(删除硬件读取,保留脚本)
├─ S11SensorInit.sh(删除传感器读取,保留脚本)
├─ S12BiosInit.sh(删除BIOS检查,保留脚本)
├─ S12PCIeInit.sh(删除PCIe扫描,保留脚本)
└─ S12StorageInit.sh(删除存储检查,保留脚本)
↓
应用程序运行
├─ 禁用健康检查(启动失败不重启)
├─ 读取mock数据(/mockdata/i2c/1/0x60_smc.json)
├─ 无Watchdog监控(虚拟环境)
└─ 模拟传感器数据上报(从mockdata读取)
2.3 关键差异点详解
差异点1:硬件访问方式
真机:
应用层调用:i2c_read(bus=1, addr=0x60)
↓
驱动层执行:ioctl(/dev/i2c-1, I2C_SLAVE, 0x60)
↓
硬件层读取:读取I2C总线物理寄存器
↓
返回真实数据:温度35.5°C(从物理传感器读取)
QEMU:
应用层调用:i2c_read(bus=1, addr=0x60)
↓
驱动层拦截:检测到QEMU环境
↓
文件读取:读取/mockdata/i2c/1/0x60_smc.json
↓
返回mock数据:温度35.5°C(从JSON文件读取)
应用层无感知:接口相同,底层实现不同
差异点2:数据挂载机制
真机:
# 物理分区挂载
mount /dev/mmcblk0p1 /data # 物理SD卡分区
mount /dev/mtdblock7 /opt/bmc # 物理Flash分区
特点:
- 数据持久化在物理存储介质
- 分区大小固定(硬件限制)
- I/O性能取决于硬件速度
QEMU:
# 9p虚拟文件系统挂载
mount -t 9p hostshare /data # 宿主机目录共享
mount -t 9p pramshare /opt/bmc/pram # 宿主机PRAM共享
mount -t 9p mockshare /mockdata # 宿主机Mock数据共享
特点:
- 数据持久化在宿主机目录
- 分区大小由宿主机决定(无限制)
- I/O性能取决于virtio传输速度
- 实时同步(宿主机修改立即生效)
差异点3:服务安全机制
真机(严格安全隔离):
[Service]
User=secbox # 非root用户运行
Group=secbox # 专用安全组
AmbientCapabilities=CAP_DAC_OVERRIDE CAP_NET_BIND_SERVICE # 最小权限集
ExecStart=secbox -f secbox.cfg -c skynet config.cfg # 通过secbox沙箱启动
安全机制:
| 机制 | 说明 |
|---|---|
| 沙箱隔离 | secbox容器隔离应用 |
| 用户隔离 | secbox用户(UID=104) |
| 权限限制 | 仅2个权限(最小原则) |
| 进程审计 | 所有操作被审计记录 |
QEMU(开放环境):
[Service]
User=root # root用户运行(无隔离)
AmbientCapabilities=CAP_SYS_ADMIN CAP_FOWNER CAP_SYS_MODULE ... # 扩展权限集(10个权限)
ExecStart=bash -c 'exec -a om skynet config.cfg' # 直接bash启动(无沙箱)
开放原因:
| 原因 | 说明 |
|---|---|
| 虚拟化环境无需安全隔离 | 测试环境,不涉及生产数据 |
| root简化权限管理 | 无需复杂的用户权限配置 |
| 扩展权限访问虚拟硬件 | 需要加载virtio驱动等操作 |
| 无审计需求 | 测试环境不需要审计 |
差异点4:健康检查机制
真机(严格监控):
{
"maca_enable": true, // 启用MACA机制
"health_monitor_enable": true, // 启用健康监控
"restart_on_failure": true, // 失败自动重启
"timeout_mins": 2, // 超时2分钟
"max_restart_count": 5 // 最大重启5次
}
检查机制:
| 检查类型 | 触发条件 | 执行动作 |
|---|---|---|
| 启动检查 | 服务启动失败 | 记录日志 → MACA重启 |
| 健康检查 | 健康异常 | 告警 → MACA重启 |
| 离线计数 | 离线次数 > 3 | 服务重启 |
QEMU(放宽限制):
{
"maca_enable": false, // 禁用MACA机制
"health_monitor_enable": false, // 禁用健康监控
"restart_on_failure": false, // 禁用失败重启
"timeout_mins": 99, // 超时99分钟(放宽)
"max_restart_count": 99 // 最大重启99次(放宽)
}
放宽原因:
| 原因 | 说明 |
|---|---|
| QEMU性能可能受限 | 虚拟化开销可能导致响应慢 |
| 避免反复重启导致不稳定 | 性能限制下可能频繁触发重启 |
| 测试环境允许失败 | 不影响生产,允许服务失败 |
差异点5:启动脚本差异
真机(完整硬件初始化):
#!/bin/bash
# 硬件设备检查
BIOS_DEV="/dev/bios_spi"
if [ ! -e $BIOS_DEV ]; then
log_error "BIOS device not exist"
exit 1
fi
# BIOS寄存器读取
BIOS_VERSION=$(hexdump -C $BIOS_DEV | head -1)
if [ -z "$BIOS_VERSION" ]; then
log_error "Read BIOS version failed"
exit 1
fi
# 硬件初始化
init_bios_registers $BIOS_DEV
# 目录创建和权限设置
mkdir -p /data/backup/bios
chown -R secbox:secbox /data/backup/bios
QEMU(裁剪版):
#!/bin/bash
# 硬件检查代码已删除(第4-12行被删除)
# 保留:目录创建和权限设置
mkdir -p /data/backup/bios
mkdir -p /data/opt/bmc/conf/bios
mkdir -p /dev/shm/bios
chown -R secbox:secbox /data/backup/bios
裁剪原则:
| 操作 | 是否执行 | 原因 |
|---|---|---|
| 保留脚本文件 | 维护启动依赖链 | |
| 删除硬件检查 | 无真实硬件 | |
| 删除寄存器读取 | 使用mock数据 | |
| 保留目录创建 | 业务功能需要 |
三、QEMU打包详细机制
3.1 打包定制化处理七大步骤详解
步骤详解1:虚拟化驱动注入
处理目的:为QEMU提供虚拟化硬件访问能力
关键操作:
操作1:复制virtio驱动模块
| 源路径 | 目标路径 | 文件列表 |
|---|---|---|
qemu_mockup/src/lualib/mock/kernel/ |
qemu_rootfs/lib/modules/qemu/ |
virtio.ko, virtio_pci.ko, virtio_net.ko, virtio_blk.ko, 9pnet.ko, 9pnet_virtio.ko, 9p.ko, sys_info.ko, dfx.ko |
操作2:复制关键脚本
| 源路径 | 目标路径 | 文件列表 |
|---|---|---|
qemu_mockup/src/lualib/mock/script/ |
qemu_rootfs/opt/bmc/ |
insmod_9p_vfs.sh(核心), insmod_drv.sh |
操作3:复制专用驱动
| 源路径 | 目标路径 | 文件列表 |
|---|---|---|
qemu_mockup/src/lualib/mock/kernel/ |
qemu_rootfs/lib/modules/ko/ |
bmc_hisport_drv.ko, mctp_drv.ko |
步骤详解2:启动脚本修改
修改对象:/etc/rc.d/rc.sysinit(584行)
关键修改位置:
修改1:注释硬件检查(289行)
# 修改前:
insmod /lib/modules/${KERNEL_NAME}/rtos_snapshot.ko
# 修改后:
#insmod /lib/modules/${KERNEL_NAME}/rtos_snapshot.ko # QEMU不支持RTOS快照
原因:QEMU无RTOS快照功能
修改2:注释散热检查(292-297行)
# 修改前:
if [ -x /opt/bmc/script/cooling.sh ]; then
sh /opt/bmc/script/cooling.sh &
fi
# 修改后:
#if [ -x /opt/bmc/script/cooling.sh ]; then
# sh /opt/bmc/script/cooling.sh &
#fi
原因:QEMU无真实散热系统
修改3:插入9p挂载脚本(324行,关键)
# 插入位置:在"rm -rf /var/lib"之前(第179行)
# 插入内容:
sh /opt/bmc/insmod_9p_vfs.sh
原因:
- 确保/data在访问前已挂载
- 避免软链接失效(ln -s /data/var/lib)
修改4:添加QEMU定制命令(末尾追加)
# 新增内容:
chmod 755 /data/home/busybox_x
/data/home/busybox_x telnetd & # 启动telnet服务(调试)
touch /dev/uart_connect # 创建虚拟串口标志
rm /etc/shadow
ln -s /data/trust/shadow /etc/shadow # shadow文件软链接
步骤详解3:硬件密钥禁用
修改对象:各应用配置文件
影响组件:
| 组件 | 说明 |
|---|---|
iam |
身份认证管理 |
event_policy |
事件策略 |
firmware_mgmt |
固件管理 |
key_mgmt |
密钥管理 |
hica各子系统 |
bmc_core, security, framework, om, hardware等 |
修改内容:
# 修改前:
HARDWARE_ROOTKEY_ENABLE = true # 真机:启用硬件根密钥验证
KEY_STORAGE = hardware # 真机:密钥存储在硬件EFUSE
# 修改后:
HARDWARE_ROOTKEY_ENABLE = false # QEMU:禁用硬件根密钥验证
KEY_STORAGE = hardware # QEMU:实际使用mock数据
禁用原因:
QEMU无硬件EFUSE芯片
无法进行硬件根密钥验证
key_mgmt服务启动会失败
步骤详解4:Mock数据注入
数据源:qemu_mockup/src/lualib/mock/data/
映射配置:mockdata_mapping.json
注入流程:
流程1:解析映射配置
{
"i2c": {
"1": {
"Data": {
"0x60_smc.json": "BCU/00000001020302031825/0x60_smc.json",
"0xae_eeprom.bin": "BCU/00000001020302031825/0xae_eeprom.bin"
}
}
}
}
流程2:递归创建目录层级
def parse_node(node, des_dir):
# 处理Data节点:复制数据文件
if 'Data' in node:
for filename, source_file in node['Data'].items():
cp -a {source_file} {des_dir}/{filename}
# 处理Address节点:递归创建地址层级
if 'Address' in node:
for address, address_node in node['Address'].items():
parse_node(address_node, {des_dir}/{address})
# 处理Channel节点:递归创建通道层级
if 'Channel' in node:
for channel, channel_node in node['Channel'].items():
parse_node(channel_node, {des_dir}/{channel})
流程3:最终目录结构
/mockdata/
├── i2c/ # I2C设备模拟数据
│ ├── 1/ # I2C总线1
│ │ ├── 0x60_smc.json # SMC设备信息(JSON)
│ │ └── 0xae_eeprom.bin # EEPROM数据(二进制)
│ ├── 7/ # I2C总线7
│ │ └── 0xe0/ # 地址0xe0(Mux)
│ │ └── 0/ # 通道0
│ │ └── 0x42_pca9555.json
│ └── 12/ # Hisport总线0(编号+12)
│ ├── 0xD8_atlas300ipro.json # PCIe卡
│ └── 0x02_lsi.json # LSI RAID卡
├── IMU/ # IMU传感器数据
│ ├── imu_info.json
│ └── pcie_card.json
├── pciecard/ # PCIe卡数据
│ └── 0x02_0x9700_mctp.bin
└── nvme/ # NVMe设备数据
├── pcie_nvme.json
└── 0x04_0x9500_mctp.bin
步骤详解5:服务降级处理
修改对象:systemd业务服务
影响服务:alarm, energy, hardware, interface, om, ras
关键修改:
修改1:运行用户降级
# 修改前:
User=secbox
# 修改后:
User=root
原因:QEMU无需安全隔离
修改2:启动命令简化
# 修改前:
ExecStart=secbox -f /opt/bmc/apps/om/secbox.cfg -c /opt/bmc/skynet/skynet config.cfg
# 修改后:
ExecStart=bash -c 'exec -a om /opt/bmc/skynet/skynet config.cfg'
原因:跳过secbox沙箱,直接启动
修改3:权限集扩展
# 修改前:
AmbientCapabilities=CAP_DAC_OVERRIDE CAP_NET_BIND_SERVICE
# 修改后:
AmbientCapabilities=CAP_SYS_ADMIN CAP_FOWNER CAP_SYS_MODULE CAP_DAC_OVERRIDE CAP_SYS_CHROOT CAP_NET_BIND_SERVICE CAP_MKNOD CAP_NET_ADMIN CAP_NET_RAW CAP_SYS_RAWIO CAP_CHOWN
原因:QEMU需要扩展权限访问虚拟硬件
步骤详解6:健康检查禁用
修改对象1:framework配置
# framework/config.cfg新增:
IGNORE_STARTUP_CHECK_RESULT=true # 忽略启动检查
IGNORE_HEALTH_CHECK_RESULT=true # 忽略健康检查
CONTINUOUS_OFFLINE_TIMES=999 # 离线阈值放宽
修改对象2:mc_control配置
# 修改前:
{
"maca_enable": true,
"timeout_mins": 2,
"time_window_mins": 10
}
# 修改后:
{
"maca_enable": false, // 禁用MACA
"timeout_mins": 99, // 超时放宽
"time_window_mins": 99 // 时间窗口放宽
}
禁用原因:
| 原因 | 说明 |
|---|---|
| QEMU性能可能受限 | 虚拟化开销可能导致响应慢 |
| 避免反复重启导致不稳定 | 性能限制下可能频繁触发重启 |
| 测试环境允许失败 | 不影响生产,允许服务失败 |
步骤详解7:初始化脚本裁剪
裁剪对象:S11/S12/S16系列脚本
裁剪原则:
| 操作 | 是否执行 | 原因 |
|---|---|---|
| 保留脚本文件和S编号 | 维护启动依赖链 | |
| 保留目录创建和权限设置 | 业务功能需要 | |
| 删除硬件检查代码 | 无真实硬件 | |
| 删除硬件寄存器读取 | 使用mock数据 | |
| 删除硬件设备初始化 | 虚拟化设备 |
裁剪示例:
# S12BiosInit.sh裁剪前后对比
修改前(真机):
#!/bin/bash
# 硬件检查(第4-12行)
BIOS_DEV="/dev/bios_spi"
if [ ! -e $BIOS_DEV ]; then
log_error "BIOS device not exist"
exit 1
fi
BIOS_VERSION=$(hexdump -C $BIOS_DEV | head -1)
# 目录创建(第13-50行)
mkdir -p /data/backup/bios
chown -R secbox:secbox /data/backup/bios
修改后(QEMU):
#!/bin/bash
# 硬件检查已删除(第4-12行被删除)
# 目录创建(保留)
mkdir -p /data/backup/bios
mkdir -p /data/opt/bmc/conf/bios
chown -R secbox:secbox /data/backup/bios
3.2 打包产物详解
产物1:qemu.cpio.gz(根文件系统镜像)
内容结构:
/
├── bin/ # 系统命令
├── sbin/
│ ├── init → systemd # PID=1进程
│ └── getty → busybox # 串口登录
├── etc/
│ ├── rc.local → rc.sysinit # 初始化入口
│ ├── rc.d/
│ │ ├── rc.sysinit # 主初始化脚本(修改版)
│ │ └── rc.start/ # 业务初始化脚本(裁剪版)
│ │ ├── S11EventInit.sh
│ │ ├── S12BiosInit.sh
│ │ └── S16FileTransferInit.sh
│ └── systemd/system/ # BMC业务服务(降级版)
│ ├── alarm.service
│ ├── om.service
│ └── interface.service
├── lib/modules/
│ ├── qemu/ # Virtio驱动
│ │ ├── virtio.ko
│ │ ├── 9pnet.ko
│ │ └── 9p.ko
│ └─ ko/ # 专用驱动
│ ├── bmc_hisport_drv.ko
│ └── mctp_drv.ko
├── opt/bmc/
│ ├── apps/ # BMC应用(降级版)
│ │ ├── hica/
│ │ └── iam/
│ ├── insmod_9p_vfs.sh # 9p挂载脚本(关键)
│ └─ conf/
│ └── mc_control.json # MACA配置(禁用版)
└── mockdata/ # Mock数据(注入版)
├── i2c/
├── IMU/
└── pciecard/
产物2:zImage_openUBMC(内核镜像)
来源:从uImage提取(跳过64字节uImage头)
提取命令:
dd if=uImage of=zImage_openUBMC bs=1 skip=64
用途:QEMU启动时加载的内核镜像
产物3:hi1711_9p8c.dtb(设备树文件)
来源:qemu_mockup/src/lualib/mock/data/dtb/
用途:QEMU启动时加载的设备树,描述虚拟硬件拓扑
产物4:board_qemu_default.data.gz(发布包)
组成:打包上述3个产物
打包命令:
tar -czf board_qemu_default.data.gz \
qemu.cpio.gz \
zImage_openUBMC \
hi1711_9p8c.dtb
3.3 关键文件来源详解
文件来源1:qemu_mockup conan包
仓库位置:/root/workspace/qemu_mockup
关键内容:
qemu_mockup/src/lualib/mock/
├── script/
│ ├── insmod_9p_vfs.sh # 9p挂载脚本(核心)
│ └── insmod_drv.sh # 驱动加载脚本
├── kernel/
│ ├── virtio.ko # Virtio驱动
│ ├── 9pnet.ko # 9p网络协议
│ └── sys_info.ko # 系统信息虚拟化
├── data/
│ ├── mockdata/ # Mock数据
│ │ ├── i2c/
│ │ ├── IMU/
│ │ └── pciecard/
│ ├── dtb/
│ │ └── hi1711_9p8c.dtb # 设备树文件
│ └ lua/ # Lua脚本
│ ├── gpio.lua
│ └── jtag.lua
└── drivers/ # 虚拟化驱动
文件来源2:真机rootfs
来源路径:rtos_with_driver/rootfs
关键内容:
rootfs/
├── bin/ # 系统命令
├── sbin/init → systemd # Init进程
├── etc/
│ ├── rc.d/rc.sysinit # 初始化脚本(原始版)
│ ├── systemd/system/ # BMC服务(原始版)
│ └── rc.d/rc.start/ # 初始化脚本(原始版)
├── lib/modules/ko/ # 物理驱动(原始版)
├── opt/bmc/apps/ # BMC应用(原始版)
└─ boot/uImage # 内核镜像(原始版)
文件来源映射关系
| 文件类型 | 源路径 | 目标路径 | 说明 |
|---|---|---|---|
| virtio驱动 | qemu_mockup/kernel/*.ko |
lib/modules/qemu/*.ko |
虚拟化驱动 |
| 9p脚本 | qemu_mockup/script/insmod_9p_vfs.sh |
opt/bmc/insmod_9p_vfs.sh |
9p挂载脚本 |
| Mock数据 | qemu_mockup/data/mockdata/* |
mockdata/* |
模拟硬件数据 |
| 设备树 | qemu_mockup/data/dtb/*.dtb |
dtb文件 |
虚拟硬件拓扑 |
| Lua脚本 | qemu_mockup/data/lua/*.lua |
opt/bmc/apps/hwproxy/lualib/*.lua |
硬件代理脚本 |
| 真机rootfs | rtos_with_driver/rootfs/* |
qemu_rootfs/*(修改版) |
基础系统文件 |
四、打包关键约束与依赖关系
4.1 打包依赖关系
依赖配置:build/product/BMC/openUBMC/manifest.yml
qemu:
dependencies:
- conan: qemu_drivers # QEMU驱动包
- conan: qemu_mockup # qemu_mockup包(核心依赖)
- conan: fructrl
options:
qemu: true # fructrl启用QEMU选项
- conan: general_hardware
options:
qemu: true # general_hardware启用QEMU选项
依赖说明:
| 依赖包 | 说明 |
|---|---|
| qemu_mockup | 提供virtio驱动、Mock数据、设备树、启动脚本 |
| qemu_drivers | 提供QEMU专用驱动 |
| 组件qemu选项 | 各组件启用QEMU适配选项 |
4.2 打包关键约束
约束1:9p挂载时机约束
约束内容:insmod_9p_vfs.sh必须在第179行执行(在rm -rf /var/lib之前)
约束原因:
# 错误顺序:
mkdir -p /data/var/lib # 创建物理/data目录
ln -s /data/var/lib /var/lib # 软链接到物理/data
sh insmod_9p_vfs.sh # 9p挂载覆盖/data(软链接失效)
# 正确顺序:
mkdir -p /data/var/lib # 创建目录
sh insmod_9p_vfs.sh # 9p挂载(覆盖/data)
rm -rf /var/lib # 清理/var/lib
ln -s /data/var/lib /var/lib # 软链接到9p挂载的/data(正确)
约束2:服务启动延迟约束
约束内容:所有systemd服务必须有ExecStartPre延迟(uptime > 100秒)
约束原因:
# 错误场景:
ExecStartPre=sleep 5 # 仅延迟5秒
uptime=30秒 # rc.sysinit未完成
→ 服务启动 → /data未挂载 → 服务崩溃
# 正确场景:
ExecStartPre="uptime=...; if [ $uptime -lt 100 ]; then sleep 20"
uptime=100秒 # rc.sysinit已完成
→ 服务启动 → /data已挂载 → 服务正常运行
约束3:脚本裁剪保留约束
约束内容:S11/S12/S16脚本必须保留文件和编号,删除硬件检查
约束原因:
# 错误场景:
删除S11EventInit.sh # 完全删除脚本
→ S12BiosInit.sh依赖S11数据 → 初始化失败
# 正确场景:
保留S11EventInit.sh # 保留脚本文件
删除硬件检查代码 # 删除硬件相关代码
→ S12BiosInit.sh仍按顺序执行 → 初始化成功
4.3 打包流程关键时序
源rootfs复制(第1步)
↓ 立即执行
QEMU定制化处理(第3步)
├─ 虚拟化驱动注入(即时)
├─ 启动脚本修改(sed修改)
├─ Mock数据注入(文件复制)
└─ 服务降级处理(sed修改)
↓ 定制化完成
清理临时文件(第4步)
↓ 清理完成
编译脚本(第5步)
↓ 编译完成
CPIO打包(第6步)
↓ 打包完成
压缩和组装(第7步)
↓ 最终产物生成
五、总结要点
5.1 打包核心要点
| 要点 | 说明 |
|---|---|
| 基础来源 | 真机rootfs + qemu_mockup包 |
| 核心定制 | 虚拟化驱动 + 9p挂载 + Mock数据 |
| 关键修改 | 启动脚本位置 + 服务降级 + 脚本裁剪 |
| 最终产物 | cpio.gz + zImage + dtb |
5.2 真机差异核心要点
| 要点 | 说明 |
|---|---|
| 硬件访问 | 物理寄存器 vs mock文件 |
| 驱动类型 | 物理驱动 vs virtio虚拟化 |
| 数据挂载 | 物理分区 vs 9p虚拟文件系统 |
| 服务安全 | secbox沙箱 vs root无沙箱 |
| 健康检查 | MACA严格监控 vs 全部禁用 |
| 启动流程 | 完整硬件初始化 vs 裁剪版初始化 |
5.3 打包机制核心要点
| 要点 | 说明 |
|---|---|
| 定制化流程 | 7步定制化处理(虚拟化驱动→脚本修改→Mock注入→服务降级→健康禁用→脚本裁剪) |
| 关键约束 | 9p挂载位置(第179行)、服务延迟(uptime>100)、脚本保留(维护依赖) |
| 依赖关系 | qemu_mockup包提供关键文件、真机rootfs提供基础系统 |
| 最终产物 | 三文件打包(cpio.gz+zImage+dtb) |
附录:相关文件路径
A.1 核心脚本路径
| 文件 | 路径 | 说明 |
|---|---|---|
| 打包脚本 | build/works/packet/work_build_qemu_rootfs.py |
主打包逻辑 |
| Mock映射配置 | build/works/packet/qemu_shells/mockdata_mapping.json |
Mock数据映射关系 |
| 启动脚本 | build/works/packet/qemu_shells/config.json |
QEMU配置 |
| Schema配置 | build/works/packet/qemu_shells/schema.json |
Schema定义 |
A.2 数据文件路径
| 文件类型 | 源路径 | 说明 |
|---|---|---|
| Mock数据源 | qemu_mockup/src/lualib/mock/data/mockdata/ |
Mock数据仓库 |
| Virtio驱动源 | qemu_mockup/src/lualib/mock/kernel/ |
Virtio驱动仓库 |
| 启动脚本源 | qemu_mockup/src/lualib/mock/script/ |
启动脚本仓库 |
| 设备树源 | qemu_mockup/src/lualib/mock/data/dtb/ |
设备树文件 |
A.3 打包产物路径
| 产物 | 路径 | 说明 |
|---|---|---|
| CPIO镜像 | output/packet/inner/qemu.cpio.gz |
根文件系统镜像 |
| 内核镜像 | output/packet/inner/zImage_openUBMC |
内核镜像 |
| 设备树 | output/packet/inner/hi1711_9p8c.dtb |
设备树文件 |
| 发布包 | output/packet/board_qemu_default.data.gz |
最终发布包 |
文档结束
维护说明:
- 本文档描述了QEMU打包的完整流程和机制
- 如有修改打包逻辑,请同步更新此文档
- 相关问题请联系OpenUBMC维护团队