以 QEMU 加速嵌入式系統開發

之前有寫過一篇 QEMU 虛擬機器設定的文章,是在講如何用 QEMU安裝 Windows 或是 Linux。但不論是 Windows 或 Linux,只要沒有硬體加速 (ex. Intel HAXM),跑起來都是很辛苦的,所以用處其實不大,實際上用 Virtualbox 或 VMware 會方便很多。

但想不到最近在開發工作上發揮了奇效,用 QEMU 來執行 ARM 的模擬,可以很順利的執行各種 user level 的程式,kernel module 只要跟硬體不相關,也都可以運行的很順利。只要對需要真正硬體部份的程式碼稍做修改,做一些測試的程式碼 (ex. register rw),就可以有效的達到一定的模擬效果。

本文會以 Ubuntu 20.04 為平台,在上面安裝 QEMU,以 Buildroot 來建立 rootfs,使用 kernel 4.4 分別為 i386 / arm /arm64 建立一個最基本的可開機的系統。這邊以 buildroot 來做為 rootfs,在實際開發專案時,只要將 rootfs 與 toolchain 替代成自己平台的的檔案系統即可。

UBuntu 20.04 套件安裝

在執行期間需要一些套件,請下達以下面命令,來安裝所需的套件。

範本檔案

為了簡化示範的流程,本文會用一個預先建立的目錄結構與script,來解說命令,檔案會附在文末。請先下載下來後,放在 ubuntu 內。用以下命令解壓縮。

下載編譯 Buildroot 以建立檔案系統與Toolchain

通常在拿到一個實際的開發平台時,都會有一些預編的檔案系統,基本上都會以這個為基礎,在加上自己專案的檔案。但是由於本文沒有這些東西,所以就從 buildroot 自行編譯一份,這樣較容易讓讀者學習,但功能會較為簡單。

執行下列命令,下載 buildroot 套件,解壓縮並進入設定畫面

如果buildroot編譯後想重新設定,建議將 output 目錄整個刪除,會比較沒有問題。

i386 設定

若要建立 32bit x86 系統,進入系統後,勾選下列項目後,選 exit 離開儲存設定。

  • Toolchain –> Kernel Headers ,選擇 4.4.x
  • Toolchain –> GCC compiler Version ,選擇 gcc 7.x
  • Toolchain –> Enable C++ support,勾選

ARM 設定

若要建立 32bit ARM 系統,進入系統後,勾選下列項目後,選 exit 離開儲存設定。

  • Target options –> Architecture,選擇 ARM little endian
  • Toolchain –> Kernel Headers ,選擇 4.4.x
  • Toolchain –> GCC compiler Version ,選擇 gcc 7.x
  • Toolchain –> Enable C++ support,勾選

ARM64 設定

若要建立 64bit ARM 系統,進入系統後,勾選下列項目後,選 exit 離開儲存設定。

  • Target options –> Architecture,選擇 AArch64 little endian
  • Toolchain –> Kernel Headers ,選擇 4.4.x
  • Toolchain –> GCC compiler Version ,選擇 gcc 7.x
  • Toolchain –> Enable C++ support,勾選

 

選定完畢後,下達 make 來編譯。

解壓 rootfs

完成後,會產生下列檔案

  • rootfs : output/images/rootfs.tar
  • toolchain 執行檔 : output/host/bin

為了符合範例script的設定,請下達下面命令,將 rootfs.tar 解開

 

頭一行命令,會先指定 toolchain 的路徑,以方便後面的kernel編譯。

下載並編譯 Kernel 4.4

接下來要下載並編譯 kernel 4.4,編譯器會使用剛 buildroot 所產生的編譯器。

i386

ARM

ARM64

啟動 QEMU 開機

當完成上面的動作後,基本上就具備了 rootfs / kernel,就可以準備開機了,下達下面的命令,來使用script開機。

runqemu 後面請輸入自己的平台種類,以執行不同的命令。

進入系統後,請用 root 來登入。由於 /dev 內的檔案並沒有自動產生,會發生一些錯誤訊息,請下達下面命令來產生裝置檔。

啟動網路

runqemu 裡的腳本,已經設定好了網路,但系統內並沒有啟動。下達以下命令,可以用 dhcpc 來取得 ip。預設都是取得 10.0.2.15 這個 IP,除了 ping (ICMP) 不能使用外,其它網路連線皆可正常透過 NAT 連外。

可以試著以 telnet 到 ptt 看看。

離開 QEMU

要離開 QEMU,可以在虛擬機內以 poweroff 關機,就會離開。或者按 Ctrl+a,再按x,就可跳離了。

runqemu 說明

執行 QEMU 的主要命令,就是 runqemu 這個程式了,這邊稍微做一下說明。

使用平台的檔案系統與toolchain

本文的例子是用 buildroot 的檔案系統和toolchain,當使用自己的開發平台時,流程會做一些更動,這邊稍微說明一下。就以附件壓縮檔解開後的位置做操作,目錄結構如下

 

Buildroot

Buildroot 的部份就不需要執行了,將你開發的檔案系統所有檔案,複製到 rootfs 下。

Toolchain

既然是用自己的開發平台,相信這部份你也有了,只要將其 bin/ 錄徑設置到 PATH 內即可。

Kernel 編譯

由於我們無法模擬硬體,所以 Kernel 還是使用下載下來的 kernel 4.4,再以自己的 toolchain 做編譯。編譯的命令,參考前面「下載並編譯 Kernel 4.4」的部份,依你是 arm 或 arm64 下達不同的命令,主要的差別會是在 CROSS_COMPILER 的部份,這邊就是改成你toolchain的前綴字,只要填對前綴字應該都可成功編譯過。

執行

最後就是執行 runqemu 了,唯一要注意的就是 rdinit=”/linuxrc” 的這個地方。你可以看自己的 rootfs 根目錄下是使用是用哪個程式做為 init 檔,一般常見的就是 linuxrc, sysvinit 和 init,把它改成你的檔案即可。

其它問題

由於對處理器的架構指令不專門,所以當碰到系統不穩定,其實也沒什麼好辦法,這邊提供一點經驗分享

  • 如有不穩定,可以試著增加記憶體看看
  • 如果碰到 illegal instruction 的訊息,或者是 QEMU 突然跳掉,有可能是 compiler 產生的程式碼該模擬的CPU不支援。以我的經驗來說,ARM的 Machine 一開始是選 vexpress-a9,就碰到上述的跳掉或非法命令的問題,最後試著將機器改成 vexpress-a15,問題就不見了。若有做這方面的修改,記得 dtb 也要做變更。

結語

QEMU 的模擬對我目前的工作相當的有幫助,但仔細想想以往的工作經驗,好像對之前的那些工作就用不上。也難怪我一直推荐朋友QEMU,回應都很冷淡 XD 希望對有需要的人有幫助了~~

附件

qemu_sys_template.tar QEMU使用範例檔

Leave a Reply