在 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 qemu
Ubuntu 镜像使用 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-data

Headless 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 直通或驱动问题。

本次实测结果


© Ying Bun 2021 - 2026