在 Mac 上用 Headless QEMU 跑 Ubuntu,改大疆 4G 模块为 EC25 并接入 VoHive
date
Jul 3, 2026
slug
dji-4g-vohive-mac-headless-qemu
status
Published
summary
Mac 上用 headless QEMU 改大疆 4G 模块并接入 VoHive。
tags
QEMU
VoHive
DJI
macOS
Linux
type
Post
URL
在 Mac 上用 Headless QEMU 跑 Ubuntu,改大疆 4G 模块为 EC25 并接入 VoHive
结论:UTM GUI 不是必须的。用 QEMU/HVF 直接起一个 headless Ubuntu VM,可以把大疆 4G 模块 USB 直通进去,发 AT 指令永久改成 Quectel EC25 身份,再部署 VoHive 管理短信、网络和 eSIM。
适用场景
你手里有一个大疆 4G 模块 1 代。它本质是移远 Quectel EG25-G,但默认 USB 身份是大疆私有 `2ca3:4006`,Linux 通用驱动不会自动按 EC25 处理。目标是把它改成通用 Quectel EC25 身份 `2c7c:0125`,并在 Linux 里跑 VoHive。
本方案适合:
- Mac Apple Silicon,例如 M 系列芯片。
- 不想手点 UTM GUI,或者 UTM USB 直通/界面流程不稳定。
- 需要可复现、可脚本化的 VM + USB passthrough 流程。
总体架构
- macOS 负责插 USB 模块和运行 QEMU。
- QEMU/HVF 启动 ARM64 Ubuntu cloud image。
- QEMU 用 `usb-host` 把模块直通进 Ubuntu。
- Ubuntu 里加载 `option` / `qmi_wwan`,生成 AT 串口和 QMI 网卡。
- 通过 `/dev/ttyUSB2` 发 AT 指令改 USB 身份。
- VoHive 跑在 Ubuntu 里,Web 端口转发到 Mac 的 `127.0.0.1:7575`。
为什么不用 UTM GUI
UTM 底层也是 QEMU。GUI 建 VM 可行,但有几个麻烦:
- 创建流程长,USB 直通选项容易点错。
- 模块从 `2ca3:4006` 改成 `2c7c:0125` 后会重新枚举,GUI 直通规则容易断。
- Headless QEMU 可以同时写死旧 VID/PID 和新 VID/PID,改身份前后都能自动接住。
- 整个 VM 入口可以变成一个脚本,后续迁移和复盘更清楚。
一句话:UTM 适合人肉装机,QEMU 脚本适合把事情做成工程。
前置依赖
Mac 上需要:
brew install qemuUbuntu 镜像使用 ARM64 cloud image。cloud image 比 live-server ISO 更适合 headless 启动和 cloud-init 自动初始化。
curl -fL -o ~/Downloads/ubuntu-24.04-cloudimg-arm64.img \
https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-arm64.img扩盘到 20G:
qemu-img resize ~/Downloads/ubuntu-24.04-cloudimg-arm64.img 20G
qemu-img info ~/Downloads/ubuntu-24.04-cloudimg-arm64.img确认 `virtual size` 是 `20 GiB`。
准备 cloud-init seed.iso
创建 `user-data` 和 `meta-data`,至少做这些事:
- 创建 `ubuntu` 用户。
- 注入本机 SSH public key。
- 开启 SSH。
- 安装 `socat`、`usbutils`、`curl`。
- 安装当前内核对应的 extra modules,确保 `option` 模块存在。
注意:不要把真实密码写进公开博客。实际密码和本机路径放本地敏感记录。
示例结构:
#cloud-config
hostname: vohive-vm
manage_etc_hosts: true
users:
- name: ubuntu
sudo: ALL=(ALL) NOPASSWD:ALL
groups: users
shell: /bin/bash
lock_passwd: false
ssh_authorized_keys:
- <YOUR_SSH_PUBLIC_KEY>
ssh_pwauth: true
package_update: true
package_upgrade: false
packages:
- socat
- usbutils
- curl
runcmd:
- [ sh, -c, "apt-get update && apt-get install -y linux-modules-extra-$(uname -r)" ]
- [ sh, -c, "modinfo option >/dev/null 2>&1 && echo option-ready > /tmp/option-status || echo option-missing > /tmp/option-status" ]
power_state:
mode: reboot
message: "Rebooting after linux-modules-extra install so option module can load"
timeout: 30
condition: true生成 seed:
xorriso -as mkisofs -V cidata -joliet -rock \
-o seed.iso user-data meta-dataHeadless QEMU 启动脚本
核心点是 `usb-host` 同时绑定两个身份:
- 改写前:`2ca3:4006`
- 改写后:`2c7c:0125`
这样模块软重启、重新枚举后,VM 仍能接住。
#!/bin/bash
set -euo pipefail
eval "$(/opt/homebrew/bin/brew shellenv)" 2>/dev/null
cd ~/vohive-vm
exec qemu-system-aarch64 \
-machine virt,highmem=on \
-accel hvf -cpu host -smp 2 -m 2048 \
-drive if=pflash,format=raw,file=/opt/homebrew/share/qemu/edk2-aarch64-code.fd,readonly=on \
-drive if=pflash,format=raw,file=/tmp/vohive-vars.fd \
-drive if=virtio,format=qcow2,file=disk.qcow2 \
-drive if=virtio,format=raw,file=seed.iso,readonly=on \
-device qemu-xhci,id=xhci \
-device usb-host,bus=xhci.0,vendorid=0x2ca3,productid=0x4006 \
-device usb-host,bus=xhci.0,vendorid=0x2c7c,productid=0x0125 \
-netdev user,id=n0,hostfwd=tcp:127.0.0.1:2222-:22,hostfwd=tcp:127.0.0.1:7575-:7575 \
-device virtio-net-pci,netdev=n0 \
-monitor unix:/tmp/vohive-mon.sock,server,nowait \
-display none -serial mon:stdio进入 Ubuntu:
ssh -p 2222 ubuntu@127.0.0.1打开 VoHive:
http://127.0.0.1:7575在 Ubuntu 里确认模块
先看 USB:
lsusb改写前应该看到类似:
2ca3:4006 DJI Technology Co., Ltd. Baiwang加载驱动并生成串口:
sudo apt-get update
sudo apt-get install -y "linux-modules-extra-$(uname -r)" socat usbutils curl
sudo modprobe option
echo 2ca3 4006 | sudo tee /sys/bus/usb-serial/drivers/option1/new_id
sleep 2
ls -la /dev/ttyUSB*预期会出现:
/dev/ttyUSB0
/dev/ttyUSB1
/dev/ttyUSB2
/dev/ttyUSB3
/dev/ttyUSB4发送 AT 指令改身份
先确认 AT 通道。一般 `/dev/ttyUSB2` 是 AT 口:
echo "ATI" | sudo timeout 8 socat - /dev/ttyUSB2,crnl读当前 USB 配置:
echo 'AT+QCFG="usbcfg"' | sudo timeout 8 socat - /dev/ttyUSB2,crnl预期改写前类似:
+QCFG: "usbcfg",0x2CA3,0x4006,1,1,1,1,1,0,0
OK永久写成 Quectel EC25 身份:
echo 'AT+QCFG="usbcfg",0x2C7C,0x0125,1,1,1,1,1,0,0' | \
sudo timeout 8 socat - /dev/ttyUSB2,crnl确认写入:
echo 'AT+QCFG="usbcfg"' | sudo timeout 8 socat - /dev/ttyUSB2,crnl软重启模块:
echo 'AT+CFUN=1,1' | sudo timeout 8 socat - /dev/ttyUSB2,crnl等 20-30 秒后验证:
lsusb
ls /dev/ttyUSB*
ls /dev/cdc-wdm*
ip link show wwan0改写成功后应看到:
2c7c:0125 Quectel Wireless Solutions Co., Ltd. EC25 LTE modem
/dev/cdc-wdm0
wwan0部署 VoHive
原始上游安装脚本曾经会下载 GitHub release 资产;如果上游 release 资产缺失,会出现 404。这时可以使用备份 release 仓库或手工指定可用 asset。
安装逻辑:
curl -fsSL https://raw.githubusercontent.com/iniwex5/vohive-release/master/install.sh -o /tmp/install.sh
# 如果上游 asset 404,可将 release repo 换成可用镜像,并修正 asset 名称。
sudo bash /tmp/install.sh安装成功后应看到:
/opt/vohive/bin/vohive
/opt/vohive/config/config.yaml
vohive.service active验证服务:
systemctl is-active vohive
curl -I http://127.0.0.1:7575/Mac 侧访问:
http://127.0.0.1:7575首次登录后立刻改密码。
把 EC25 设备加入 VoHive
VoHive 可以先扫描发现硬件。如果后台列表为空,先触发 rescan,或者用 API 添加设备。关键字段是:
- `usb_path`: `/sys/bus/usb/devices/<实际路径>`
- `at_port`: `/dev/ttyUSB2`
- `control_device`: `/dev/cdc-wdm0`
- `interface`: `wwan0`
- `device_backend`: `qmi`
添加后应看到:
running: true
healthy: true
control_online: true
physical_present: true如果 `network_connected=false` 或 `registration_state_label=denied`,说明 USB、AT、QMI、VoHive 都通了,剩下是 SIM / APN / 运营商注册问题,不是 Mac 直通或驱动问题。