高通跃龙IQ-9075跨板刷机实战:将高通EVK开发板镜像写入Thundercomm开发板
背景与动机
手头有一块 Thundercomm 的 高通跃龙IQ-9075 DevKit,出厂自带 Ubuntu x06 固件,但内核版本无法满足项目需求。而高通官方开发板IQ-9075 EVK的 Dragonwing Ubuntu x08 镜像搭载了更新的内核(6.8.0-1064-qcom),且官方提供了完整的刷机流程。
两块开发板均基于高通跃龙 IQ-9075 SoC(内部代号 KODIAK / LeMans,SA8775P),运行 Ubuntu 24.04 ARM64。既然 SoC 和 OS 一致,理论上可以将高通(Qualcomm)的EVK开发板镜像刷入Thundercomm的DevKit开发板。
开发平台对比
官方高通跃龙IQ-9075 EVK 开发板

Thundercomm的高通跃龙IQ-9075 DevKit

刷机包结构对比
Thundercomm的刷机包为 FlatBuild 格式(约 3.2 GB),Qualcomm的刷机包为 iq9_ubuntu_images 目录结构。
逐文件对比发现:
rawprogram1-4.xml与patch1-4.xml内容完全一致,分区标签、扇区偏移、分区大小无差异- 唯一区别在于
rawprogram0.xml中引用的 Ubuntu 镜像文件名不同 - 分区布局(UFS LUN0-4)完全相同,存储层面兼容
对 dtb.bin(64 MB 的多 DTB 容器)进行解析后,在 高通开发板镜像的设备树中找到 DTB#7(Qualcomm QCS9100 Ride),其 qcom,board-id 包含 PlatformID 37、Subtype 1。后续在 Thundercomm开发板的启动日志中也看到了完全一致的标识,说明 Thundercomm开发板大概率可以使用高通开发板的镜像。
尝试一:直接刷入 QC 全套固件
将开发板拨码进入 EDL 模式(第一组第 1、6 位 ON),使用 QDL 工具刷入 高通的全套固件:
qdl.exe --storage ufs --include .\.\iprog_firehose_ddr.elf .\rawprogram\*.xml .\patch\*.xml
刷写过程顺利完成。切换启动拨码后上电,串口(COM9,115200)日志显示启动链已走通大部分:
PBL → XBL (DDR 36GB LPDDR5 @3196MHz) → UEFI → Gunyah Hypervisor → GRUB → Kernel
但在 UEFI 阶段出现异常:
[RM] Error: unexpected value in ehdr
[RM] Static VM (16) not in READY state
[RM] GearVM (16) not started
[...]
gNpaClientSSxBus cannot be created
GearVM(Gunyah Hypervisor 管理的虚拟机 #16)启动失败,NPA(Node Power Architecture)框架报错。
GRUB 菜单在串口上出现大面积乱码(gfxterm 模式输出图形终端控制字符),3 秒后自动引导进入内核,随后内核崩溃:
Unable to handle kernel paging request at virtual address ffff800080e980c0
Internal error: Oops: 0000000096000004 [#1] PREEMPT SMP
Call trace:
dwc3_read1+0x1c/0x38 [dwc3]
dwc3_core_soft_reset+0x18/0xc4 [dwc3]
dwc3_core_init+0x78/0xb94 [dwc3]
dwc3_qcom_probe+0x31c/0x470 [dwc3_qcom]
多个 CPU 随后报 soft lockup,系统挂死。
COM8 串口显示 SAIL(Safety Island)子系统运行正常,说明 SAIL 不受 UFS 刷机影响。
崩溃根因分析
表面上是 USB DWC3 驱动的页面错误,但实际崩溃链路从 UEFI 阶段就已开始:
hypvm.mbn 板级不匹配
→ GearVM ELF 加载失败(unexpected value in ehdr)
→ GearVM 未启动
→ NPA 框架缺少 GearVM 提供的资源节点
→ USB DWC3 控制器的电源/时钟域未使能
→ dwc3_read1 访问未映射寄存器(pte=0000000000000000)
→ Kernel Oops → soft lockup
GearVM 负责电源管理,由 hypvm.mbn(Gunyah Hypervisor 镜像)配置和启动。QC 的 hypvm.mbn 是为其 EVK 编译的,GearVM 的资源分配(内存映射、中断路由、设备直通)与 TC 板不匹配。
对 10 个关键固件做 MD5 校验,Thundercomm 和 高通 全部不同:
| 固件文件 | Thundercomm 大小 (B) | Qualcomm 大小 (B) | 相同? |
|---|---|---|---|
| hypvm.mbn | 1,765,408 | 1,773,600 | 否 |
| tz.mbn | 3,789,824 | 3,953,664 | 否 |
| uefi.elf | 4,005,776 | 4,202,384 | 否 |
| xbl.elf | 872,768 | 876,864 | 否 |
| xbl_config.elf | 401,536 | 401,536 | 否 |
| dtb.bin | 67,108,864 | 67,108,864 | 否 |
| aop.mbn | 208,976 | 208,976 | 否 |
| devcfg_iot.mbn | 61,376 | 61,376 | 否 |
| cpucp.elf | 114,848 | 114,848 | 否 |
| shrm.elf | 36,896 | 36,896 | 否 |
即使文件大小相同,哈希也不同——每个固件都是板级定制的。
尝试二:混合方案(Thundercomm固件 + Qualcomm的系统镜像)
问题出在 NHLOS 固件与硬件不匹配,Ubuntu 系统本身是通用的。因此改用Thundercomm的固件做硬件初始化,仅刷入 Qualcomm 的 Ubuntu 镜像。
组装混合刷机包
目录结构如下:
hybrid_flash/
├── [Thundercomm] xbl.elf, uefi.elf, hypvm.mbn, tz.mbn ... # 全套 NHLOS 固件
├── [Thundercomm] dtb.bin # 设备树
├── [Thundercomm] rawprogram1-4.xml, patch1-4.xml # 分区配置
├── [Thundercomm] gpt_main/*.bin, gpt_backup/*.bin # GPT 分区表
├── [Thundercomm] prog_firehose_ddr.elf # Firehose 烧录器
├── [改] rawprogram0.xml # filename 指向 QC 镜像
└── [Qualcomm] iot-qualcomm-dragonwing-...-x08.img # Ubuntu 系统镜像
使用 PowerShell 从 Thundercomm 的 FlatBuild zip 中提取固件(跳过 8.7 GB 的 Ubuntu 镜像),修改 rawprogram0.xml 中的镜像文件名,并复制 Qualcomm镜像到同目录:
# 从 Thundercomm zip 提取(跳过大镜像)
Add-Type -Assembly System.IO.Compression.FileSystem
$zip = [System.IO.Compression.ZipFile]::OpenRead($tcZipPath)
foreach ($entry in $zip.Entries) {
if ($entry.Name -ne "" -and $entry.Name -notlike "*.img") {
[System.IO.Compression.ZipFileExtensions]::ExtractToFile(
$entry, (Join-Path $hybridDir $entry.Name), $true)
}
}
$zip.Dispose()
# 修改 rawprogram0.xml 中的镜像引用
(Get-Content "$hybridDir\rawprogram0.xml") -replace
'filename="ubuntu-24.04-classic-desktop-arm64-x06.img"',
'filename="iot-qualcomm-dragonwing-classic-desktop-2404-x08-20260210.4096b.img"' |
Set-Content "$hybridDir\rawprogram0.xml"
# 复制 Qualcomm 镜像(8.9 GB)
Copy-Item "$qcDir\iot-qualcomm-dragonwing-*.img" $hybridDir
刷机与结果
cd hybrid_flash
qdl.exe --storage ufs --include .\prog_firehose_ddr.elf .\rawprogram0.xml .\rawprogram1-4.xml .\patch\*.xml
启动成功:
- Thundercomm 的
hypvm.mbn正确初始化 Gunyah Hypervisor - GearVM 正常启动
- NPA 框架完整
- USB DWC3 控制器不再崩溃
- Qualcomm 的 Ubuntu x08 系统正常引导至登录界面
修复首次登录密码问题
串口出现 Ubuntu 登录提示后,输入默认账号密码(ubuntu / ubuntu):
You are required to change your password immediately (administrator enforced).
Changing password for ubuntu.
Current password:
Authentication token manipulation error
密码修改失败,原因是根文件系统以 ro 模式挂载。GRUB 内核命令行默认带 ro 参数,而 PAM 强制改密在 systemd 重新挂载为 rw 之前就已触发。
串口 GRUB 菜单换行错乱,无法手动编辑启动项。因此选择直接修改磁盘镜像中 EFI 分区的 grub.cfg。
镜像 GPT 结构
Qualcomm 的 Ubuntu 磁盘镜像使用 4096 字节扇区的 GPT:
| 分区 | LBA 范围 | 大小 | 格式 |
|---|---|---|---|
| efi | 256 - 131,327 | 512 MB | FAT32 |
| persist | 131,328 - 139,007 | 30 MB | ext4 |
| writable | 139,008 - 2,266,641 | 8.3 GB | ext4 |
EFI 分区中 /EFI/ubuntu/grub.cfg 只有 117 字节,作用是搜索 writable 分区后加载真正的 /boot/grub/grub.cfg:
search.fs_uuid d9ceb9b7-d25f-4edc-b06c-cee825cb7519 root
set prefix=(root)'/boot/grub'
configfile $prefix/grub.cfg
修改 EFI grub.cfg
编写 Python 脚本 patch_efi_grub.py,直接操作镜像二进制:
- 解析 GPT,定位 EFI 分区
- 解析 FAT32 BPB,找到集群参数
- 遍历目录项,定位
grub.cfg - 覆写文件内容,更新目录项中的文件大小字段
FAT32 集群大小为 4096 字节,原文件 117 字节,新内容 285 字节,单集群足够容纳。
替换后的 grub.cfg 绕过原始 /boot/grub/grub.cfg,直接定义启动项:
search.fs_uuid d9ceb9b7-d25f-4edc-b06c-cee825cb7519 root
set prefix=(root)'/boot/grub'
set timeout=5
menuentry 'Ubuntu (rw fix)' {
linux (root)/boot/vmlinux root=UUID=d9ceb9b7-d25f-4edc-b06c-cee825cb7519 rw console=ttyMSM0,115200n8 earlycon
initrd (root)/boot/initrd.img
}
关键变化:内核参数 ro → rw,根文件系统可写挂载。
$ python patch_efi_grub.py patch
找到 grub.cfg:
Cluster: 1149, Size: 117 bytes
Dir entry offset in image: 0x222040
grub.cfg 已更新!新大小:285 bytes
验证成功!
只刷磁盘镜像
修改后只需重刷 LUN0(磁盘镜像),固件保持不动:
qdl.exe --storage ufs --include .\prog_firehose_ddr.elf .\rawprogram0.xml
注意只指定 rawprogram0.xml,不包含 rawprogram1-4.xml 和 patch/*.xml。
重启后串口显示 Ubuntu (rw fix) 菜单项,5 秒后自动启动。密码修改成功,登录系统后执行 sudo update-grub 恢复正常 GRUB 配置。
总结
分区兼容 ≠ 固件兼容
两个包的 rawprogram*.xml 完全一致,但 NHLOS 固件是板级定制的。即使同一颗 SoC,不同厂商的板子在电源管理、Hypervisor 配置、设备树等方面仍存在差异。
Hypervisor 层的级联故障
使用错误的 hypvm.mbn 不会阻止 PBL/XBL/UEFI 启动,但 GearVM 启动失败会导致 NPA 框架不完整,进而使依赖 NPA 的外设(如 USB DWC3)在内核阶段崩溃。排查此类问题应从启动日志的最早异常开始追溯,而非仅关注内核 Oops。
混合方案可行
对于同 SoC 不同开发板,「厂商固件 + 第三方 OS 镜像」的组合是可行的,前提是分区布局一致。本质上是将 SoC 固件初始化与操作系统解耦。
选择性刷写
QDL 支持按 rawprogram*.xml 选择性刷写。只更新磁盘镜像时,仅指定 rawprogram0.xml 即可,省去固件分区的写入时间,在反复调试镜像配置时非常实用。
附录
启动链路
PBL (ROM) → XBL → UEFI → Gunyah Hypervisor → GRUB → Linux Kernel → Ubuntu
↑
GearVM / PVM
NHLOS 固件清单
| 文件 | 功能 |
|---|---|
| xbl.elf | 可扩展引导加载器,DDR/UFS 初始化 |
| uefi.elf | UEFI 固件,设备枚举 |
| tz.mbn | TrustZone 安全世界 (EL3) |
实测时间:2026年3月
固件版本:
- Thundercomm FlatBuild x06(2024.12.10)
- Qualcomm Dragonwing x08(2026.02.10)
如果你跨开发板刷写镜像的过程中遇到任何问题,欢迎在评论区留言讨论!
如果你觉得本文对你有帮助,欢迎点赞、收藏、关注!
更多推荐
所有评论(0)