dSPACE VEOS QEMU Coupling:
Buildroot 鏡像製作與雙模式配置實務
以 VEOS 2026-A 的 QEMU Coupling(dsQEMU)為基礎,完整說明如何在 Build Server 上把一份 Buildroot 鏡像做成可用的 POSIX-Based V-ECU,以及在 icount 與 idle-detect 兩種時間同步模式下各自需要的編譯環境與鏡像配置——每個步驟都附手動操作指令與對應的驗證方法。
dSPACE VEOS 的 QEMU Coupling(本文簡稱 dsQEMU)讓一顆完整的 Linux 系統以 POSIX-Based V-ECU 的形式加入 VEOS 的模擬時間軸,與 Plant FMU、Classic AUTOSAR vECU、Restbus 容器在同一個 OSA 內協同運作。這使得「跑在 SoC 上的 Linux 應用」得以在沒有實體硬體的階段就進入整合驗證。
實務上最容易被低估的一段,是鏡像本身。一份能在原生 QEMU 開機的最小 Linux,並不等於一份能在 VEOS 時間軸上工作的 V-ECU 鏡像。本文以 Buildroot 為例,把這段差距拆解為「Build Server 端的編譯環境配置」與「鏡像產出後的模擬環境配置」兩個階段,並逐步標示每個動作的驗證方式。
本文適用環境
| 模擬主機 | Ubuntu 24.04 LTS + dSPACE VEOS 2026-A(Simulator Console 26.1)、veos-qemu 26.1(QEMU 9.2.3 基礎) |
| Build Server | Ubuntu 24.04 LTS、Buildroot(BR2_VERSION = 2026.08-git,make print-version = 2026.05-586-gdf6f3ad43f)、基準 configs/qemu_x86_64_defconfig |
| Guest | x86_64、Linux 6.18.7(icount 模式使用)、BusyBox init、rootfs 為單一 raw ext2 映像 |
| idle-detect 專用 | Guest kernel 由 VEOS 強制替換為 veos-linux 6.6.119;模擬主機需具備 /dev/kvm |
文中路徑以 $HOME/buildroot(Build Server)與 ~/dsqemu(模擬主機)表示;主機位址、帳號請替換為您自身環境的值。所有指令均為一般使用者權限,不需要 sudo。
1. 為什麼原始鏡像不能直接使用
這個問題的答案必須分成兩種模式來回答,因為兩者的失敗原因完全不同。以未經調整的原始鏡像實測:
| 項目 | icount 模式 | idle-detect 模式 |
|---|---|---|
| 能開機嗎 | ✅ 能,可開到 buildroot login: |
❌ 不能,/dev 是空的 |
| 能執行測試嗎 | ❌ 不能:沒有受測應用、沒有網路位址 | ❌ 不能(尚未進入 userspace) |
| 問題性質 | 缺少測試載具與網路配置 | 結構性:開機路徑與原始鏡像的假設不符 |
1.1 idle-detect 模式的開機路徑差異
idle-detect 是 hypervisor 模式,VEOS 會強制指定自己的 guest kernel,並經由該 kernel 內建的 initramfs 進入您的 rootfs。實測到的關鍵事實是:它使用 chroot() 而非 switch_root,且僅建立了一個裝置節點。
Linux kernel 的 CONFIG_DEVTMPFS_MOUNT 自動掛載 /dev 只在「kernel 自行掛載 root 檔案系統」時觸發,走 initramfs + chroot 這條路徑不會發生。而 Buildroot 預設的 /etc/fstab 並沒有 devtmpfs 條目——它信賴那個自動掛載。結果是:
1.2 一句話總結
原始鏡像是「能在 QEMU 裡開機的最小 Linux」;而 dsQEMU 需要的是「能在 VEOS 的時間軸上、透過虛擬 Ethernet 與其他模擬參與者交換資料、且不與模擬時鐘與 console 通道衝突的 V-ECU」。本文其餘篇幅就是在填補這段差距。
2. 兩種同步模式如何決定配置策略
在動手改任何設定之前,必須先理解兩種模式對鏡像的支配關係,否則很容易把「該改 JSON 的事」改到鏡像裡去。
| 面向 | icount(CPU 模擬) | idle-detect(Hypervisor) |
|---|---|---|
| Guest kernel | 您自己編譯的(Buildroot 6.18.7) | VEOS 的 veos-linux 6.6.119,由 VEOS 以 -kernel 指定 |
| KVM | 不需要 | 必須具備 /dev/kvm |
| 時間同步程度 | 部分同步(按指令數截斷) | 完全同步(偵測 idle 才推進時間) |
| kernel config 是否有效 | ✅ 有效,是您控制的 | ❌ 完全無效,您的 kernel 不會被載入 |
Guest /lib/modules |
可用 | ❌ 版本不符,任何 insmod 必然失敗 |
| CPU 數 | 可 > 1,建議 1(重現性) | VEOS 強制 -smp 1 |
| 中斷點凍結模擬時間 | ❌ 不支援 | ✅ 支援 |
| 實測加速比(單節點) | 0.95 | 1.000 |
| 實測開機至應用啟動 | 約 9 秒 | 約 0.4 秒 |
| 雙節點時間一致性 | 各自獨立推進 | lockstep(兩 guest 時間完全相同) |
策略結論:Build Server 上只需要維護一套 .config 與一份 overlay,即可同時滿足兩種模式。原因是兩種模式對鏡像的要求是聯集而非互斥——idle-detect 的額外要求(明確掛載 devtmpfs、不依賴核心模組)在 icount 下無害;而 icount 專屬的 kernel 設定在 idle-detect 下只是被忽略。切換模式只需更換 JSON 配置檔。
2.1 各模式對鏡像的具體要求
icount 需要的(與 kernel 相關)
- •
VIRTIO_BLK/VIRTIO_NET/VIRTIO_PCI內建於 kernel - •
SERIAL_8250_CONSOLE內建(console 走ttyS0) - •
EXT4_FS;Buildroot 的rootfs.ext2由 ext4 驅動掛載 - • 選用:
CONFIG_IP_PNP,讓位址可由 kernel 命令列指定
idle-detect 需要的(與 rootfs 相關)
- • init 第一個動作就掛 devtmpfs(不可依賴 kernel automount)
- • 不得依賴
/lib/modules(版本必然不符) - • 需有熵源,或移除所有熵消費者(由 JSON 提供 virtio-rng)
- • 不得有任何行程搶佔
/dev/console - • 不得有任何時間同步機制(NTP/
hwclock)覆寫模擬時鐘
2.2 這五件事不要改鏡像——改 JSON 就好
以下項目常被誤判為需要重建鏡像,實際上都屬於模擬環境的配置:
| 現象/原始設定 | 正確的處理位置 |
|---|---|
Buildroot 原生啟動腳本使用 console=tty1 console=ttyS0 | JSON 的 -append 只保留 console=ttyS0(VEOS 會加 -nographic,tty1 無用) |
原生使用 -net user | 移除。VEOS 自行以 socket 形式把網卡接上 Ethernet cluster |
| NIC 型號預設為 e1000 | JSON 明寫 model=virtio-net-pci——veos-linux kernel 沒有 e1000 驅動 |
| 多核心設定 | JSON 寫 -smp 1(idle-detect 會被 VEOS 強制為 1) |
| idle-detect 下 console 全黑 | JSON 補 -serial stdio——該模式 VEOS 會加 -nodefaults,取消了預設 serial 裝置 |
3. Build Server 端:編譯環境配置
本節從取得 Buildroot 原始碼開始,目標產物是兩個檔案:output/images/bzImage 與 output/images/rootfs.ext2。以下每個步驟都分為操作與驗證兩部分。
取得 Buildroot 原始碼與建置相依套件
Buildroot 本身不需要安裝——它是一棵以 make 驅動的原始碼樹,解開即可使用。真正需要準備的是建置主機的相依套件與一個明確可追溯的版本。本步驟是整份流程唯一需要 sudo 的地方,且只發生在 Build Server 上。
(a) 建置主機相依套件
以下為 Buildroot 官方要求的必要套件,於 Ubuntu 24.04 的對應安裝指令。libncurses-dev 是 make menuconfig 的前提,缺少時只有互動式設定會失敗,命令列設定不受影響。
(b) 取得原始碼——方式一:git(建議)
git 是建議方式,因為它讓「用了哪一版」成為可查證的事實,而不是文件裡的一句描述。上游正式位置在 GitLab,GitHub 為官方鏡像。
(c) 取得原始碼——方式二:tarball(離線/受管環境)
(d) 版本識別:兩個值,用途不同
這一點值得特別說明,因為它常導致文件與實機對不上。Buildroot 的 BR2_VERSION 是開發中版本字串,指向「下一個」發行版;而在 git 樹內,make print-version 會展開為 git describe 的結果——那才是可重現的識別。以本文的基準環境實測:
請把 make print-version 的輸出記錄進測試報告,而不是記錄 2026.08-git。前者可以精準還原同一棵樹,後者在數個月內會對應到成百上千個不同的提交。
(e) 四項環境限制
| 限制 | 說明 |
|---|---|
| 不以 root 執行 | Buildroot 官方明確要求。以 root 建置會讓 target 檔案的擁有者與權限失去意義,並可能影響建置主機本身 |
| 路徑不可含空白 | Buildroot 不支援含空白的路徑,症狀會出現在建置中段而非一開始 |
| 磁碟空間 | 實測值:本文組態完整建置後整棵樹約 17 GB(其中 output/ 16 GB、dl/ 659 MB)。建議預留 30 GB 以上 |
| 網路可達性 | 建置過程會從上游抓取各套件的原始碼。受管網路請見下方 (f) |
(f) 受管網路環境:先抓齊原始碼再離線建置
建立基準組態與備份
以 Buildroot 官方的 QEMU x86_64 defconfig 為起點,並在改動前保留原始 .config,讓整個變更集可回溯、可還原。
建立 board/veos 目錄並置入專案檔案
所有 VEOS 專用內容集中於一個 board 目錄,不散落在 Buildroot 樹的其他位置,讓上游更新與專案內容彼此隔離。
CRLF 是本步驟最常見的失敗原因,症狀為建置時出現 bad interpreter: /bin/sh^M。它不會在複製階段報錯,只會在建置或開機時才顯現。
四個 overlay 檔案的內容與理由
這四個檔案是鏡像從「可開機的 Linux」變成「V-ECU」的關鍵。每一項都對應一個實測到的具體失敗。
(a) etc/inittab——最關鍵的一個檔案
做兩件事:早期掛載 devtmpfs 與 移除 getty。
-
順序有意義:devtmpfs 必須在
mkdir -p /dev/pts /dev/shm之前,否則那兩個目錄會被隨後掛上的 devtmpfs 遮蔽。在 kernel 已掛載過的情況下重複掛載是無害的(同一個 superblock)。 -
為何移除 getty:在 dsQEMU 下
/dev/console不是操作員終端,而是 guest 唯一的 log 通道(VEOS 將其擷取為<Name>.qemu.stdout.log)。getty 會呼叫vhangup()取得該 tty 所有權,使其他行程的 console 檔案描述子失效——受測應用會靜默地停止輸出。這是最容易被誤判為「應用沒啟動」的失敗模式:判斷方法是觀察對端節點的接收計數是否仍在增加。 -
為何用 overlay 而非
BR2_TARGET_GENERIC_GETTY=n:後者是在 target-finalize 階段以 sed 加入 getty 行,關閉它並不會移除output/target/etc/inittab中已存在的那一行,需重建 skeleton 或make clean。overlay 在 rootfs 產生階段整檔覆蓋,只需make即生效。
(b) etc/network/interfaces——靜態位址
必須靜態的原因:VEOS 的 Ethernet cluster 內沒有 DHCP server。保留預設設定時 S40network 會執行 udhcpc 廣播並等到逾時:
在 icount 模式下,這段等待是真實的實時成本,每次開機都要支付;更根本的是沒有位址就無法通訊。另需注意:Buildroot 的 kernel 預設沒有 CONFIG_IP_PNP,因此無法用 kernel 命令列 ip=... 就地指定位址——這正是 STEP 5 加入 config fragment 的動機。
(c) etc/veos-sut.conf——受測應用參數
將行為參數外置為設定檔,使「改對端位址」或「改週期」不需要重新編譯應用;命令列旗標可覆蓋檔案值。
(d) etc/init.d/S90veos-sut——開機自動啟動
編號 90 的理由:必須排在 S40network 之後,確保 eth0 已取得位址。實測鏡像內的執行順序為 S01seedrng → S01syslogd → S02klogd → S02sysctl → S11modules → S40network → S50crond → S50dropbear → S90veos-sut。
不要使用 start-stop-daemon -b。 -b(background)會把子行程的 stdout 導向 /dev/null,造成與 getty 相同的症狀——應用確實在執行,但輸出永遠不會出現在 log 裡。
(e) post-build.sh——單趟建置編出受測應用
以 Buildroot 剛建立的 target toolchain 編譯受測應用並安裝至 /opt/sut/。採用 post-build hook 而非「預先編好放進 overlay」的原因是:make clean 會連 toolchain 一併刪除,預編路線需要兩趟建置;post-build hook 在 rootfs 組裝前執行,此時 toolchain 已存在,因此單趟建置即可完成。
-g 是刻意保留的:遠端 GDB 除錯時,符號解析由 GDB host 端所保存的同一份 binary 提供。
kernel config fragment(僅 icount 模式有效)
此片段合併於 Buildroot 的 kernel defconfig 之上。內容刻意保持最小——因為在 idle-detect 模式下這顆 kernel 根本不會被載入。
修改 fragment 之後必須執行 make linux-rebuild。變更 BR2_LINUX_KERNEL_CONFIG_FRAGMENT_FILES 不會讓 Buildroot 認為 kernel 已過期,單純 make 會沿用舊 kernel 並回報成功。
套用 .config
下表為完整變更清單。使用 utils/config 而非 menuconfig,使整個組態可腳本化、可重現、可納入版本控制。
| 符號 | 值 | 理由 |
|---|---|---|
| BR2_TOOLCHAIN_BUILDROOT_CXX | y | 前提條件:gdb 的 Config.in 要求 BR2_INSTALL_LIBSTDCPP,而它只由 C++ toolchain 提供 |
| BR2_PACKAGE_GDB | y | gdb 套件(會 select gdbserver) |
| BR2_PACKAGE_GDB_SERVER | y | guest 端 gdbserver,遠端除錯用 |
| BR2_PACKAGE_IPROUTE2 | y | 靜態位址設定;行為較 BusyBox 內建 ip 一致 |
| BR2_PACKAGE_ETHTOOL | y | 虛擬網卡診斷 |
| BR2_PACKAGE_TCPDUMP | y | guest 端封包擷取 |
| BR2_PACKAGE_STRACE | y | 追蹤受測應用的 syscall |
| BR2_PACKAGE_SOCAT | y | socket 轉接 |
| BR2_PACKAGE_DROPBEAR | y | 救援用 shell(經 TAP 或 slirp 進入) |
| BR2_TARGET_ROOTFS_EXT2_SIZE | "512M" | 原 60 MB 容不下新增套件 |
| BR2_ROOTFS_OVERLAY | board/veos/rootfs-overlay | 置入 VEOS 專用檔案 |
| BR2_ROOTFS_POST_BUILD_SCRIPT | 兩個路徑 | 附加於官方 hook 之後,編譯受測應用 |
| BR2_LINUX_KERNEL_CONFIG_FRAGMENT_FILES | board/veos/linux-veos.fragment | 套用 STEP 5 的 kernel 片段 |
若偏好互動式設定,對應的 make menuconfig 路徑為:Toolchain → Enable C++ support、Target packages → Debugging, profiling and benchmark → gdb → gdbserver、Target packages → Networking applications → iproute2 / ethtool / tcpdump / socat / dropbear、Filesystem images → ext2/3/4 root filesystem → exact size、System configuration → Root filesystem overlay directories、System configuration → Custom scripts to run before creating filesystem images。
執行建置
首次建置必須完整重建,因為 Buildroot 無法增量重新配置 toolchain;後續僅改動 overlay 或應用原始碼時,增量建置即可。
變更 C++ toolchain 後只執行 make 會產生不一致的 output。反之,在 toolchain 未變動時執行 make clean 只是白花時間重建未變更的 toolchain——請依實際變更範圍選擇。
鏡像內容驗證(不需開機)
這是整個 Build Server 階段最有價值的一個步驟:用 debugfs 直接檢查 ext2 映像的內容,在進入模擬之前就確認每一項配置真的進到鏡像裡了。少了這一步,配置錯誤只會在開機階段以間接症狀出現。
4. 鏡像產出後:模擬環境端的配置
鏡像本身完成後,還需要在模擬主機上完成四件事才能執行:部署與基準保存、撰寫 JSON 連接配置、匯入產生 OSA、載入並執行。
部署鏡像並保留乾淨母版
guest 以 rw 掛載 rootfs,每執行一次就會寫入(log、SSH host key、隨機種子)。若不還原,每次測試的起點都不同,問題將難以重現。
若鏡像尺寸較大,也可改用 qcow2 加 backing file,使每輪只需丟棄薄薄一層差異檔:
撰寫 icount 模式的 JSON 配置
dsQEMU 的 V-ECU 由一份 Type 為 DsVeosQemu 的 JSON 描述,經 veos model import 轉為 OSA。以下為可直接使用的完整範例。
configs/br-x86_64-icount.json| 欄位 | 說明與注意事項 |
|---|---|
| Name | VPU 名稱,不可含空白。同時決定 log 檔名 <Name>.qemu.stdout.log |
| StepSize | 同步時間步(秒)。建議與 vECU 的 base step 及 veos sim config -e 三者一致,否則會出現封包丟棄或抖動 |
| ClusterName | 要接入的 VEOS Ethernet cluster 名稱。大小寫敏感;多個 JSON 使用相同名稱時,匯入階段會自動建立 cluster 與 channel 並完成接線 |
| MacAddress | 預設值為全零,務必自訂且每節點唯一,否則 cluster 上會位址衝突 |
| Qemu.Arguments(ETH) | 一律寫 model=virtio-net-pci。veos-linux kernel 不含 e1000 驅動,用預設型號在 idle-detect 下 guest 會看不到網卡 |
| Resources | 絕對路徑清單,匯入時嵌入 OSA,以 ${Resource:<basename>} 引用。不支援相對路徑;單檔超過 1 GB 不建議嵌入 |
| RedirectStdout / Stderr | log / file / both。建議 both,使 console 同時進入 VEOS log 與獨立檔案 |
OSA 會把鏡像嵌入。重新部署鏡像之後若未重建 OSA,執行的仍是舊 guest,而且不會有任何警告。凡是更新鏡像,就要重新 veos model import。
撰寫 idle-detect 模式的 JSON 配置
與 icount 版本相比只有四處差異,但每一處都是必要的。
| 差異 | 原因 |
|---|---|
移除 -kernel 與 -smp | VEOS 自行指定 veos-linux kernel 並強制 -smp 1。自訂這些參數會被拒絕 |
加入 -serial stdio | 該模式 VEOS 會加 -nodefaults,取消預設 serial 裝置。不加則 console 全黑,模擬看似正常但一行 guest 輸出都沒有 |
| 加入 virtio-rng 裝置 | veos-linux 不含 CONFIG_RANDOM_TRUST_CPU,決定性模擬環境也沒有中斷抖動可供收集熵,CRNG 將永不初始化。實測 random.trust_cpu=on 無效 |
Resources 只留 rootfs | guest kernel 不再被使用,無須嵌入 |
configs/br-x86_64-idle-detect.json(節錄差異段)VEOS 自動加入與禁止覆寫的參數
| 類別 | icount | idle-detect |
|---|---|---|
| 未指定時自動加入 | -nographic、網卡選項 | 同左,另加 -no-reboot、-nodefaults |
| VEOS 控制(需明確允許才可覆寫) | -icount、-rtc clock=vm、-accel tcg,thread=single | -rtc base=epoch,clock=vm、-kernel <veos-linux>、-cpu host |
| 絕對禁止自訂 | -veos | -veos、-S、-enable-kvm、-smp 1 |
| VEOS 追加的 kernel 參數 | — | hpet=disable tsc=reliable nohz=off veos.clock_tick_ns=<StepSize>(勿重複設定) |
兩種 KVM 錯誤訊息要分清楚:
Could not access KVM kernel module: No such file or directory → /dev/kvm 根本不存在,屬於虛擬機/BIOS 設定問題,且變更後需完整關機再開機(guest 內 reboot 無效)。
... Permission denied → 裝置存在但無權限,屬於權限設定問題。
匯入產生 OSA 並確認拓撲
< /dev/null 不可省略。VEOS Model Console 會檢查 stdin 是否帶有修改輸入,透過腳本或 SSH 非互動呼叫時,省略它會讓指令一直等待到連線逾時。互動式終端機下不受影響。
通過條件:所有 VPU 都在、存在對應的 cluster、且每個 eth0 connector 的 ChannelReference 不是 null。實測正確的樣子:
只要各 JSON 的 ClusterName 相同,不需要手動執行 model add 或 model connect——匯入階段會自動建立 cluster、channel 並完成接線。僅在加入非 JSON 來源的參與者(例如 SystemDesk 產出的 Classic vECU)時,才需要 veos model connect --autoconnect-communication-controllers。
載入、執行與觀察
請保留 Run QEMU executable: 那一整行。它是整個流程中最有價值的診斷資訊——顯示 VEOS 最終組出的完整命令列(您的參數加上 VEOS 追加的參數)。網卡型號、同步模式、kernel 路徑、追加的 kernel 參數,全部可從這一行確認。
5. 驗證判準
驗證要成立,判準必須事前訂好、可觀測、且能區分「看起來過了」與「真的過了」。以下判準均已在實機環境驗證通過。
5.1 icount 模式:開機與應用執行
| # | 判準 | 通過條件 | 失敗時檢查 |
|---|---|---|---|
| 1.1 | 載入成功 | 輸出含 Simulation loaded. | ERROR 行、.qemu.stderr.log |
| 1.2 | 同步模式正確 | 含 Synchronization mode 'icount' | JSON 的 Veos.SynchronizationMode |
| 1.3 | 網卡型號正確 | Run QEMU 行含 model=virtio-net-pci | JSON 的 ETH Qemu.Arguments |
| 1.4 | rootfs 掛載成功 | console 含 VFS: Mounted root ... on device | -drive 參數、鏡像完整性 |
| 1.5 | 到達 userspace | Run /sbin/init as init process 之後仍有輸出 | 見 §6 失敗模式 |
| 1.6 | 網路已配置 | console 不含 udhcpc: no lease | /etc/network/interfaces |
| 2.1 | 應用啟動 | console 含應用的啟動行(監聽埠、對端、週期) | S90veos-sut、/opt/sut/ |
| 2.2 | 週期正確 | guest 時間 ÷ 傳送計數 = 設定週期 | veos-sut.conf 的 PERIOD_MS |
| 2.3 | 時鐘由 VEOS 驅動 | 連續兩行報告的時間差 = REPORT_EVERY × PERIOD_MS | 同步模式、StepSize |
| 2.4 | 加速比合理 | SimulationTime / ElapsedTime ≈ 0.9–1.0 | 主機負載、guest 內忙迴圈 |
EXT4-fs (vda): mounting ext2 file system using the ext4 subsystem 這一行本身就是一項驗證:它證實了「Buildroot 的 ext2 映像由 ext4 驅動掛載」這條路徑成立(EXT4_USE_FOR_EXT2),不需要另外提供 ext2 驅動。
5.2 idle-detect 模式:額外的五項判準
| # | 判準 | 通過條件 |
|---|---|---|
| 5.1 | hypervisor 參數已加入 | Run QEMU 行含 -S -enable-kvm -smp 1 -cpu host -kernel <veos-linux.bzImage> |
| 5.2 | 真的使用 VEOS kernel | console 含 Linux version 6.6.119-...-veos26.1.0 |
| 5.3 | veos-clock 生效 | console 含 Entering VEOS simulator mode,且 veos-qemu 印出 Found idle breakpoint |
| 5.4 | /dev 已填充 | console 不含 can't open /dev/null(此即 STEP 4 (a) 的直接驗證) |
| 5.5 | 加速比接近 1.000 | 完全時間同步的特徵。實測 SimulationTime 90.4 / ElapsedTime 90.401 |
| 5.6 | 雙節點 lockstep | 兩個 guest 報告的時間完全相同,且雙向計數相等(零封包遺失) |
判準 5.6 是兩種模式最本質的差別。icount 下兩個 guest 各自推進自己的時間;idle-detect 下它們共用 VEOS 的模擬時鐘。這一項不成立,就不是真正的完全同步——即使其他判準全部通過。
6. 失敗模式與判讀
dsQEMU 環境中多數失敗不會產生錯誤訊息,只會表現為「某個數字不對」或「某段輸出不見了」。下表為實測整理的對照。
| 症狀 | 根因 | 處理 |
|---|---|---|
can't open /dev/null ×N,應用無輸出 | devtmpfs 未掛載(idle-detect 的 chroot 路徑) | inittab 第一個 sysinit 動作掛 devtmpfs |
| 應用無輸出,但對端接收計數持續增加 | console fd 被搶走:getty 的 vhangup(),或 start-stop-daemon -b 把 stdout 導向 /dev/null | 移除 getty;啟動腳本改為 > /dev/console 2>&1 & |
console 完全空白,但 Found idle breakpoint 已出現 | idle-detect 的 -nodefaults 取消了預設 serial 裝置 | JSON 加 -serial stdio |
卡在 Initializing random number generator... | 無熵源,CRNG 永不初始化 | JSON 加 virtio-rng 裝置(或移除所有熵消費者) |
開機時出現 udhcpc: no lease | cluster 內沒有 DHCP server | overlay 設定靜態位址 |
| guest 看不到網卡 | 使用了預設 e1000,veos-linux 無此驅動 | JSON 寫 model=virtio-net-pci,並從 Run QEMU 行確認 |
| 接收計數恆為 0 | cluster 未接通、MAC 重複、對端位址不互指,或對端未開機 | 依序檢查 ChannelReference、ClusterName 大小寫、MAC 唯一性、對端 console |
| 收送計數差距持續擴大 | 對端當機或封包被丟棄 | 看對端 console 最後幾行;匯出 bus log 分析 |
| 收送計數差距固定不變 | 不是故障:兩節點開機時間差造成的偏移 | 差值 ÷ 每秒封包數 應約等於開機時間差 |
veos model 指令沒有回應 | Model Console 在等 stdin 的修改輸入 | 加 < /dev/null |
| 改了鏡像但行為沒變 | OSA 內嵌的是舊鏡像 | 重新 veos model import |
| 每次執行結果不同 | rootfs 未還原 golden;或 rng-random 引入主機隨機性 | 每輪還原母版;需位元級重現時改用內建 rng 或移除熵消費者 |
建置時 bad interpreter: /bin/sh^M | 從 Windows 複製的腳本是 CRLF | sed -i 's/\r$//' <檔案> |
6.1 先判斷是「慢」還是「死結」
開機停住時,第一件事不是看 console,而是確認模擬時間有沒有在前進:
實測經驗值可作為量級參考:一個真實的 guest 內死結,曾出現「300 秒實時只推進 2.55 秒 guest 時間」的比例。這與「單純比較慢」的量級差距非常明顯,據此即可分流後續診斷方向。
7. 回歸測試與工程化建議
組態即程式碼
以 utils/config 而非互動式 menuconfig 套用設定,讓整份 .config 變更可腳本化、可審閱、可納入版本控制。overlay、應用原始碼、JSON 配置一併版控。
先驗鏡像,再進模擬
以 debugfs 在開機前確認鏡像內容(STEP 8)。這能把「配置沒進鏡像」與「模擬環境配置錯誤」兩類問題徹底分離,省下大量診斷時間。
用 JSON 換行為
把 gdbserver 開關、應用選擇、位址等做成讀取 kernel 命令列的參數。切換測試情境只需改 JSON,不需重建鏡像——單次迭代由 30 分鐘降到數秒。
每次變更鏡像設定或 JSON 之後,建議至少執行以下三項回歸:
-
配置檔驗證以原廠 schema 檢查所有 JSON,並加上專案自訂規則(名稱不含空白、網卡型號、MAC 非預設值、idle-detect 未自訂受管參數)。
-
雙節點 icount 聯測兩個 guest 掛入同一 Ethernet cluster,確認雙向通訊與封包計數關係成立——這一項同時涵蓋開機、應用、網路與拓撲。
-
rootfs × veos-linux kernel 相容性探測在 icount 模式下以 veos-linux kernel 開機自家 rootfs。這是一個很有價值的技巧:由於 icount 允許指定任意 kernel,該組合測到的正是 idle-detect 的鏡像條件,因此能在不具備 KVM 的環境下,先把「鏡像相容性」與「主機能力」兩件事分離。
結語
把 Buildroot 鏡像帶進 VEOS QEMU Coupling,工作量並不在於「改很多設定」,而在於理解每個設定對應哪一個具體失敗。本文的配置清單並不長——一份 .config、一個 kernel fragment、四個 overlay 檔案、一支 post-build 腳本、兩份 JSON——但每一項都源自一個實測到的症狀,而多數症狀不會以錯誤訊息的形式出現。
這也是為什麼本文堅持每個步驟都附上驗證方法:在虛擬 ECU 的整合環境裡,「沒有報錯」從來不等於「配置正確」。建立一套可重複執行、判準事前訂好的驗證流程,是讓 SIL 測試結果可信的前提。
需要導入協助?
捷策動能提供 dSPACE VEOS/SystemDesk 虛擬驗證平台的導入規劃、環境建置、鏡像客製與 SIL 測試流程設計服務,涵蓋 Buildroot/Yocto 客製 Linux、Classic AUTOSAR vECU、Restbus 模擬與 CI 整合。歡迎與我們的技術團隊討論您的專案需求。
本文技術內容基於 dSPACE VEOS 2026-A 實機環境驗證,所引用的行為與數值均為實測結果。相關原廠規範請參閱 dSPACE VEOS Manual「Basics on VEOS QEMU Coupling」與「How to Debug a POSIX-Based V-ECU Remotely with GDB」等章節。文中路徑、位址與名稱請依實際環境調整。