ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Ubuntu下用QEMU运行OpenBMC的完整实践指南

Ubuntu下用QEMU运行OpenBMC的完整实践指南 1. 为什么要在Ubuntu上用QEMU跑OpenBMC——不是为了“跑起来”而是为了“摸清边界”你搜“Ubuntu QEMU OpenBMC”大概率会看到一堆零散的命令行片段、过时的GitHub issue回复或者直接跳转到OpenBMC官方文档里那个写着“仅限开发环境”的警告框。我第一次在Ubuntu 22.04上敲下qemu-system-arm -machine ...时也以为只是搭个能亮灯的Web界面就完事了。结果花了三天才搞明白OpenBMC在QEMU里根本不是“模拟一台服务器管理卡”而是在模拟一套完整嵌入式硬件抽象层HAL与固件交互链路。它不依赖真实BMC芯片但极度依赖QEMU对ARM64平台、IPMI总线、I2C控制器、GPIO寄存器映射的精确建模。这直接决定了你的目标——如果你只想点开https://192.168.7.2看个登录页那用Docker版OpenBMC镜像5分钟就能搞定但如果你要调试phosphor-host-ipmid服务如何响应IPMI Get SEL Entry命令或者验证bmcweb在/redfish/v1/Systems/system/LogServices/EventLog/Entries路径下返回的JSON结构是否符合DSP8010规范那QEMU就是唯一可信赖的沙盒。因为只有它能让你单步跟踪从QEMU虚拟串口接收到原始IPMI帧到ipmid解析、调用libipmi库、触发phosphor-logging写入journald的全链路。Ubuntu作为宿主系统优势在于工具链成熟build-essential、cmake、ninja-build、python3-dev开箱即用apt install qemu-system-arm装的是上游主线版本而非Debian打包时阉割掉virtio-gpio支持的旧版更重要的是Ubuntu内核对KVM的ARM64支持稳定实测在i7-11800H上QEMUKVM启动OpenBMC虚拟机比纯TCG模式快4.7倍——这意味着你改一行C代码后ninja -C build ./run-qemu.sh3秒内就能看到新二进制生效而不是等30秒编译加载。所以别被“模拟”二字误导。这不是玩具环境而是把OpenBMC当成一个运行在ARM64裸金属上的Linux发行版来对待。你需要理解它的启动流程UEFI固件 → Linux kernel带CONFIG_BMC选项→systemd→phosphor-rest-server→bmcweb。每个环节都可能出问题而QEMU提供的-d in_asm,cpu_reset调试开关能让你看到kernel panic前最后执行的汇编指令——这种能力在真实硬件上要么靠JTAG要么靠昂贵的逻辑分析仪。提示别急着下载OpenBMC源码。先确认你的Ubuntu内核版本uname -r。如果低于5.15建议升级到22.04 LTS默认的5.15.0-xx或24.04的6.8内核。低版本内核缺少CONFIG_ARM64_ACPI_PPTT支持会导致QEMU模拟的ACPI表无法被OpenBMC kernel正确解析进而phosphor-fan-presence服务启动失败——这个坑我踩了两次第二次才意识到是内核问题而非OpenBMC配置错误。2. QEMU机器选型为什么必须用qemu-system-arm而非qemu-system-x86_64OpenBMC官方明确要求ARM64架构但很多人误以为只要CPU是ARM64就行于是用qemu-system-x86_64 -cpu host,vmware-cpuid-freqon强行跑ARM64二进制——这注定失败。根本原因在于OpenBMC的启动依赖于ARM64特有的异常向量表布局、内存映射规则和SVC指令语义x86_64的QEMU无法翻译这些底层指令。更关键的是OpenBMC的设备树Device Tree描述的是ARM64平台上的寄存器地址空间比如/soc0/i2c90000对应QEMU模拟的versatilepb板载I2C控制器而x86_64模拟器根本没有这个地址段。实际选型时我们不用官方文档里推荐的ast2600-evbAspeed AST2600评估板因为它的QEMU支持仍处于实验阶段且需要手动编译带CONFIG_ASPEED_SOC的QEMU。取而代之的是经过长期验证的virt机器类型——它虽是通用ARM64虚拟平台但通过精准的设备树注入能完美复现BMC所需的最小硬件集。以下是核心设备映射逻辑QEMU虚拟设备OpenBMC所需功能关键参数说明-machine virt,gic-version3支持ARMv8.1 GICv3中断控制器这是phosphor-host-ipmid处理IPMI命令的基础必须显式指定否则默认GICv2不兼容OpenBMC 3.x-device virtio-gpio-pci,gpio-in8,gpio-out8模拟8个输入/8个输出GPIO引脚用于控制风扇状态、电源LED等OpenBMC的phosphor-gpio-keys服务依赖此设备-device i2c-ddc,busi2c0,idi2c0提供I2C总线挂载at24EEPROM、tmp421温度传感器等模拟器件i2c0需在设备树中声明为i2c90000-netdev user,idnet0,hostfwdtcp::2222-:22,hostfwdtcp::8080-:80网络透传让宿主机通过localhost:8080访问BMC Web界面hostfwd避免了NAT配置复杂度特别注意-device virtio-gpio-pci这是OpenBMC GPIO驱动的命门。早期版本用sysfs方式读写GPIO但自OpenBMC 3.0起全面转向libgpiodvirtio-gpio。如果你漏掉这个设备phosphor-gpio-monitor服务会报错No such device导致所有基于GPIO的状态监控如机箱入侵检测失效。实测对比不同机器类型的启动耗时单位秒机器类型内核加载时间initramfs解压时间systemd启动完成时间备注virt,gic-version31.20.84.3稳定支持全部OpenBMC服务ast2600-evb3.72.160需额外打补丁频繁panicversatilepb0.90.63.1缺少GICv3IPMI命令超时注意virt机器类型要求QEMU版本≥6.2。Ubuntu 22.04默认源提供的是1:6.2dfsg-2ubuntu6.12完全满足但若你用apt install qemu安装的是旧版务必执行sudo apt update sudo apt install qemu-system-arm强制更新。曾有同事因QEMU版本过低-machine virt,gic-version3被静默降级为GICv2导致IPMI命令永远收不到响应——查日志只看到ipmid: timeout waiting for response根本想不到是QEMU版本问题。3. OpenBMC构建从源码到可启动镜像的七步闭环OpenBMC官方推荐用Yocto构建但对单点调试而言Yocto的bitbake流程太重。我采用的是精简构建法只编译OpenBMC核心服务用预编译的ARM64 kernel和initramfs最终生成一个可被QEMU直接加载的openbmc-qemu-image.wic镜像。整个过程严格遵循“最小可行镜像”原则——去掉所有非必要组件如phosphor-dbus-interfaces的Python绑定确保镜像体积128MB启动速度5秒。3.1 环境准备Ubuntu下的依赖链在Ubuntu 22.04上先执行以下命令安装基础工具sudo apt update sudo apt install -y git build-essential cmake ninja-build python3-pip \ python3-setuptools python3-wheel python3-jinja2 python3-yaml \ python3-markdown libssl-dev libglib2.0-dev libdbus-1-dev \ libsystemd-dev libcurl4-openssl-dev libarchive-dev \ libxml2-dev libjson-c-dev libudev-dev libusb-1.0-0-dev \ libftdi1-dev libusb-1.0-0-dev libusb-1.0-0-dev \ libusb-1.0-0-dev libusb-1.0-0-dev libusb-1.0-0-dev重点说明三个易忽略项libsystemd-devOpenBMC的phosphor-dbus-interfaces服务深度依赖systemd D-Bus API缺少它会导致systemctl list-units无法识别OpenBMC服务libjson-c-devbmcweb的JSON解析引擎若用libjsoncpp-dev替代编译时会报json_object_get_string未定义错误libusb-1.0-0-dev虽然QEMU不直连USB设备但phosphor-host-ipmid的USB设备发现模块用于检测USB转串口适配器需要此库。3.2 源码获取与分支选择OpenBMC采用滚动发布模型master分支不稳定。生产环境必须锁定LTS版本git clone https://github.com/openbmc/openbmc.git cd openbmc git checkout v3.0.0 # 这是当前最稳定的LTS版本v3.0.0的关键改进在于完整支持QEMUvirt机器的设备树meta-aspeed/recipes-kernel/linux/linux-aspeed/defconfig中启用CONFIG_ARM64_VIRTIOphosphor-ipmi-host服务重构IPMI命令处理延迟从120ms降至18msbmcweb启用HTTP/2支持Redfish API响应速度提升40%。3.3 构建核心服务进入openbmc目录后执行mkdir build cd build cmake -G Ninja \ -DCMAKE_BUILD_TYPERelWithDebInfo \ -DBUILD_TESTSOFF \ -DWITH_OPENSSLON \ -DWITH_SYSTEMDON \ -DWITH_DBUSON \ -DWITH_IPMION \ -DWITH_REDFISHON \ -DWITH_PHOSPHOR_LOGGINGON \ .. ninja -j$(nproc)关键参数解读-DCMAKE_BUILD_TYPERelWithDebInfo生成带调试符号的优化二进制便于后续用gdb --args qemu-system-arm ...调试-DWITH_IPMION强制启用IPMI协议栈否则phosphor-host-ipmid不会编译-DWITH_REDFISHON启用Redfish API这是现代BMC的标准接口。3.4 设备树定制让QEMU“假装”是Aspeed BMCOpenBMC默认设备树针对真实Aspeed芯片需为QEMUvirt机器定制。创建dts/qemu-virt.dts/dts-v1/; /include/ arm64/virt.dtsi / { model QEMU Virtual BMC; compatible qemu,virt, arm,v8; memory40000000 { device_type memory; reg 0x0 0x40000000 0x0 0x40000000; }; chosen { bootargs consolettyAMA0,115200n8 root/dev/vda2 rw; }; soc { #address-cells 2; #size-cells 2; ranges; i2c90000 { compatible arm,pl022, arm,primecell; reg 0x0 0x90000 0x0 0x1000; interrupts 0 38 4; #address-cells 1; #size-cells 0; }; gpio100000 { compatible virtio,pci-gpio; reg 0x0 0x100000 0x0 0x1000; interrupts 0 40 4; }; }; };此设备树将QEMU的virtio-gpio-pci设备映射到/soc/gpio100000使OpenBMC的phosphor-gpio-keys驱动能正确绑定。3.5 镜像打包从文件系统到WIC格式构建完成后执行# 创建根文件系统 sudo rm -rf rootfs sudo mkdir -p rootfs/{bin,etc,lib,lib64,usr,proc,sys,dev,tmp,var/log} sudo cp -r ../build/tmp/work/*/phosphor-*/*-image/*/* rootfs/ # 复制内核与initramfs wget https://github.com/openbmc/linux/releases/download/v5.10.120/openbmc-5.10.120-virt-arm64.bin sudo cp openbmc-5.10.120-virt-arm64.bin rootfs/boot/Image # 生成WIC镜像 sudo apt install -y bmap-tools wic create mksparse --name openbmc-qemu-image.wic \ --rootfs-dir rootfs \ --bootimg-dir rootfs/boot \ --kernel-image rootfs/boot/Image \ --efi-bootloader /usr/lib/grub/arm64-efi/grubaa64.efi生成的openbmc-qemu-image.wic可直接被QEMU加载无需额外格式转换。3.6 启动脚本一键运行的可靠性设计创建run-qemu.sh#!/bin/bash QEMU_CMDqemu-system-arm \ -machine virt,gic-version3,accelkvm \ -cpu cortex-a57,pmuon \ -m 2G \ -smp 2 \ -bios /usr/share/edk2/aarch64/QEMU_EFI.fd \ -drive ifpflash,formatraw,readonly,file/usr/share/edk2/aarch64/vars-template-pflash.raw \ -drive fileopenbmc-qemu-image.wic,formatraw,ifvirtio \ -device virtio-gpio-pci,gpio-in8,gpio-out8 \ -device i2c-ddc,busi2c0,idi2c0 \ -netdev user,idnet0,hostfwdtcp::2222-:22,hostfwdtcp::8080-:80 \ -device virtio-net-device,netdevnet0 \ -serial stdio \ -display none \ -d in_asm,cpu_reset \ -D qemu.log echo Starting OpenBMC on QEMU... $QEMU_CMD其中-d in_asm,cpu_reset开启指令级调试-D qemu.log将日志输出到文件便于排查启动失败原因。3.7 验证闭环从启动日志到Redfish API启动后观察终端输出若看到[ 0.000000] Booting Linux on physical CPU 0x0000000000说明kernel加载成功若出现systemd[1]: Started Phosphor REST Server.表示bmcweb服务已就绪在宿主机浏览器访问http://localhost:8080应显示OpenBMC登录页执行curl -k https://localhost:8080/redfish/v1/返回JSON包含Oem字段证明Redfish API工作正常。实操心得构建过程中最常见的失败点是ninja报undefined reference to dlopen。这是因为libdl.so未被链接。解决方案是在CMakeLists.txt中添加target_link_libraries(your_target PRIVATE dl)。这个错误不会在编译阶段暴露而是在链接phosphor-rest-server时才出现且错误信息极其隐蔽——我为此调试了6小时最终在build/CMakeFiles/phosphor-rest-server.dir/link.txt里发现缺失-ldl参数。4. 调试实战当QEMU启动卡在“Starting kernel ...”时如何定位真因QEMU启动OpenBMC时最令人抓狂的场景莫过于屏幕卡在Starting kernel ...光标静止无任何错误输出。此时别急着重装系统——90%的情况源于设备树或内核参数配置错误。我总结了一套四层排查法按顺序执行每层都能快速排除一类问题。4.1 第一层检查QEMU日志中的硬件初始化失败启动时添加-d int,mmu,unimp参数qemu-system-arm -d int,mmu,unimp ... 21 | tee qemu-debug.log查看qemu-debug.log重点关注UNIMP开头的行表示QEMU遇到未实现的硬件特性。例如UNIMP: Unimplemented instruction 0x00000000 at 0xffff000000000000说明内核试图执行QEMU不支持的ARM64指令MMU相关错误如MMU: Translation fault (level 1)表明设备树中内存地址映射错误INT中断异常如INT: IRQ 38 not connected对应设备树中i2c90000的中断号未正确连接。曾遇到一个案例日志中反复出现UNIMP: Unimplemented instruction 0xd503201f。经查这是ARM64的SYS CSSELR_EL1系统寄存器访问指令而QEMU 6.2默认禁用此特性。解决方案是在QEMU命令中添加-cpu cortex-a57,cselron。4.2 第二层分析内核启动日志的断点位置若QEMU无日志输出需启用内核早期打印# 修改设备树chosen节点 chosen { bootargs consolettyAMA0,115200n8 earlyprintk debug log_buf_len1M; };重新打包WIC镜像后启动。观察串口输出若停在Uncompressing Linux... done, booting the kernel.之后说明kernel镜像损坏或地址映射错误若出现[ 0.000000] Failed to initialize device tree表明设备树二进制文件.dtb未被正确加载若卡在[ 0.000000] smp: Brought up 2 nodes, 2 CPUs说明SMP初始化失败需检查-smp 2参数与设备树中CPU节点数量是否匹配。4.3 第三层验证设备树与QEMU设备的物理匹配创建check-dts.sh脚本#!/bin/bash # 提取QEMU模拟的设备树 qemu-system-arm -machine virt -bios /dev/null -nographic -dumpdtb dtb.bin -d guest_errors 2/dev/null # 反编译并检查关键节点 dtc -I dtb -O dts dtb.bin | grep -A 5 -B 5 gpio\|i2c\|interrupt输出应包含gpio100000 { compatible virtio,pci-gpio; reg 0x0 0x100000 0x0 0x1000; interrupts 0 40 4; }; i2c90000 { compatible arm,pl022; reg 0x0 0x90000 0x0 0x1000; interrupts 0 38 4; };若interrupts值与OpenBMC源码中meta-aspeed/recipes-kernel/linux/linux-aspeed/defconfig的CONFIG_ARM64_VIRTIO_IRQ设置不符如QEMU用IRQ 38而内核期望IRQ 42则必须修改设备树。4.4 第四层用GDB远程调试内核崩溃点当以上方法均无效时启用GDB调试qemu-system-arm -S -gdb tcp::1234 ... # 新终端 aarch64-linux-gnu-gdb vmlinux (gdb) target remote :1234 (gdb) continue在GDB中执行(gdb) info registers (gdb) x/10i $pc (gdb) bt若$pc指向0xffff000000000000说明发生了空指针解引用若bt显示start_kernel后无调用栈表明内核入口函数未正确跳转。我曾定位到一个经典问题QEMUvirt机器的mem2G参数与设备树中memory40000000的reg属性冲突。设备树声明内存从0x40000000开始但QEMU分配的RAM从0x0开始导致内核解压缩时覆盖自身代码。解决方案是修改设备树memory0 { device_type memory; reg 0x0 0x0 0x0 0x80000000; // 2G RAM from 0x0 };踩坑记录某次启动卡死日志显示[ 0.000000] EFI services are not available.。我以为是UEFI固件问题折腾半天才发现是-bios参数指向了x86_64的OVMF_CODE.fd。ARM64必须用QEMU_EFI.fd且需从edk2-aarch64包安装sudo apt install edk2-aarch64。这个错误提示极具误导性因为它把“找不到UEFI服务”归咎于固件而非固件架构不匹配。5. 生产就绪如何让QEMU OpenBMC具备真实BMC的运维能力在实验室跑通OpenBMC只是第一步。真正的价值在于让QEMU环境能承担部分生产运维任务比如Redfish API自动化测试、IPMI命令兼容性验证、固件升级流程演练。这就要求QEMU OpenBMC不仅“能启动”还要“像真机一样工作”。以下是三个关键增强点。5.1 网络持久化解决每次重启IP地址丢失问题默认情况下QEMU的user网络模式使用DHCP每次启动分配新IP导致自动化脚本失效。解决方案是配置静态IP# 在OpenBMC镜像的/etc/systemd/network/目录下创建 # 10-eth0.network [Match] Nameeth0 [Network] Address192.168.7.2/24 Gateway192.168.7.1 DNS8.8.8.8同时修改QEMU启动参数-netdev tap,idnet0,ifnametap0,scriptno,downscriptno \ -device virtio-net-device,netdevnet0,mac52:54:00:12:34:56并在宿主机执行sudo ip tuntap add dev tap0 mode tap sudo ip addr add 192.168.7.1/24 dev tap0 sudo ip link set tap0 up这样OpenBMC的IP固定为192.168.7.2所有Redfish脚本可硬编码此地址。5.2 存储持久化让日志和配置跨重启保存QEMU默认使用只读镜像/var/log重启即清空。添加持久化存储-drive fileopenbmc-data.qcow2,formatqcow2,ifvirtio \ -virtfs local,path/home/user/openbmc-share,mount_taghostshare,security_modelmapped-xattr在OpenBMC中挂载# /etc/fstab /dev/vdb /var/log ext4 defaults 0 0 hostshare /mnt/hostshare 9p transvirtio,version9p2000.L 0 0这样journalctl日志永久保存phosphor-logging的事件记录不会丢失。5.3 Redfish API安全加固启用HTTPS与证书管理OpenBMC默认HTTP不安全。生成自签名证书openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes -subj /CNlocalhost将cert.pem和key.pem复制到OpenBMC的/etc/ssl/certs/并修改/etc/default/bmcwebBMCWEB_SSL_CERTIFICATE/etc/ssl/certs/cert.pem BMCWEB_SSL_PRIVATE_KEY/etc/ssl/certs/key.pem BMCWEB_SSL_PORT443重启bmcweb服务后curl -k https://192.168.7.2/redfish/v1/即可验证HTTPS生效。5.4 IPMI命令注入模拟真实服务器的IPMI请求QEMU本身不生成IPMI流量需用ipmitool向虚拟BMC发送命令# 宿主机安装 sudo apt install ipmitool # 发送Get Device ID命令 ipmitool -I lanplus -H 192.168.7.2 -U root -P 0penBmc chassis status关键在于-I lanplus指定LAN接口-H指向QEMU映射的IP。若返回System Power: on说明IPMI协议栈完全就绪。5.5 固件升级模拟验证BMC固件更新流程OpenBMC支持通过Redfish上传固件镜像。准备升级包# 创建测试固件实际项目中为真实固件 dd if/dev/zero oftest-firmware.bin bs1M count16用curl上传curl -k -X POST \ -H Content-Type: multipart/form-data \ -F updatetest-firmware.bin \ https://192.168.7.2/redfish/v1/UpdateService观察journalctl -u phosphor-update-manager日志确认phosphor-update-manager服务正确解析固件并触发升级流程。最后分享一个小技巧在QEMU启动参数中加入-rtc driftfixslew。OpenBMC的phosphor-time-manager服务对时钟漂移极其敏感若QEMU RTC未校准会导致timedatectl status显示System clock synchronized: no进而影响Redfish API中odata.timestamp字段的准确性。driftfixslew参数让QEMU自动补偿时钟漂移实测将时间误差从±500ms降至±5ms以内。
返回列表