前陣子寫了好幾篇關於 QEMU 建置模擬環境的文章,其中一篇 【利用 Raspberry Pi 4 硬體虛擬化加速開發ARM專案 】,便是利用 ARM CPU 虛擬化的功能,來加速工作中ARM平台的專案開發。
樹莓派4是用了 ARM 的 A72,而 2020 的一件大事就是 Apple 自己做了一個 ARM-based 的 M1 CPU,而且在各種評測上,都獲得了非常好的評價。所以自從 M1 出來以後,就一直對其保持著關注,看看能不能拿來加速開發流程。
本文,就是在 M1 成功利用 QEMU 來模擬系統的教學文章。就先列出在各平台的模擬環境下的表現吧!以下為在各平台下執行 QEMU ARM64 虛擬機,進行 busybox 執行檔 (1.5MB) xz 壓縮的時間。
- M1: 0.4 秒
- RPI4: 1.5秒
- 3950x: 5秒
測試平台
本文所使用的平台是 MAC mini M1 2020, 版本是 12.1, Monterey。本文並不偏重於 macos 的操作,主要是使用其 M1 CPU,以 ssh 操作為主。
先從重置開始吧!
由於之前用 mac os 已經很久了,所以把這步驟記下一下。要清除所有環境,回到原廠設定的話,可以先打開「系統偏好設定」,然後選擇 menubar 的「清除所有內容和設定」。我覺得這是一個相當方便的功能,從某種程度來,這就是重灌吧
如果你需要整個清除硬碟的話,可以在關機後,一直按著電源鍵,大概5~10秒後放開,就可以看到磁碟工具了。不過這部份入手不久,還沒用過。
系統設定
重置後,為方便設定,首先要啟用 ssh server,和關掉一些不必要的安全/省電功能。
- 啟用 ssh: 系統偏號設定 –> 共享 –> 遠端登入
- 終端機權限: 系統偏號設定 –> 安全性與隱私 –> 隱私 –> 開發者工具 –> 啟用終端機,這項有時看不到,則可跳過。
- 關避省電功能: 系統偏號設定 –>能源節約器 –> 避免您的 MAC 在顯示… 勾選
設定完成後重新開機,可以避免 ssh 登入常有問題的狀況,皆下來接以 ssh 來操作。
安裝 brew
brew 是一個類似 Linux 上 apt 的程式,可以讓安裝一些套件,更方便一些。首先訪問 https://brew.sh/index_zh-tw,貼上其首頁的命令,就可以設定基本的項目。
安裝完成後,用 vim 編輯 ~/.bash_profile,設定內容為
1 2 |
eval "$(/opt/homebrew/bin/brew shellenv)" alias ls='ls --color' |
然後將 shell 更換為 bash
1 |
chsh -s /bin/bash |
然後重新登入
安裝相關套件
接下來就用 brew 來安裝相關套件 。若中間有失敗,可刪除檔案「sudo rm -rf /opt/homebrew/」再執行一次即可。
1 |
brew install gcc automake autoconf libtool qemu pigz p7zip coreutils |
安裝 VDE
VDE 是為了實現 QEMU userspace bridge 功能的套件,以 unix socket 來實現這個功能。其官方網站在 https://github.com/lima-vm/vde_vmnet。依照 README.mk 文件來編譯
1 2 3 4 5 6 |
git clone https://github.com/virtualsquare/vde-2.git cd vde-2 autoreconf -fis ./configure --prefix=/opt/vde make sudo make install |
1 2 3 4 5 |
cd git clone https://github.com/lima-vm/vde_vmnet cd vde_vmnet make PREFIX=/opt/vde sudo make PREFIX=/opt/vde install |
啟用 VDE
完成編譯後,就可以啟用 vde 來達成 bridge 的功能,這邊設定 en0 為有線網路的介面,後續還要指定 QEMU 使用指定網路。
1 2 |
/opt/vde/bin/vde_switch --unix /tmp/vde.ctl -d sudo /opt/vde/bin/vde_vmnet --vmnet-mode=bridged --vmnet-interface=en0 /tmp/vde.ctl & |
運行虛擬機
本文主要的用途,還是從 Linux 編譯,再從 MAC 上進行模擬。如同【 以 QEMU 加速嵌入式系統開發】, 在文末也會附上一個類似的檔案,但只修改了其中的 runqemu ,能偵測目前 Host 為 MAC / ARM64 / x86 以套用正確的啟動參數。
MAC 下 mount samba 分享
不熟 macos ,記錄一下設定 gateway 與掛載 samba 分享的指令
1 2 |
route add default 192.168.1.1 mount_smbfs -f 0777 -d 0777 //user@192.168.1.100/share remoteShare |
runqemu 主要差異
1 2 3 4 5 6 7 8 9 10 |
!/bin/bash if [ "$1" = "" ];then echo "Please sepcify ARCH. arm, arm64 or i386" exit 1 fi if [ `uname` = "Darwin" ];then HOST=macos else HOST=`lscpu | head -n 1 | awk '{print $2}'` fi |
在開頭的地方,會以 uname 來判定是 macos 還是一般的 Linux。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
elif [ "$ARCH" = "arm64" ];then if [ "$HOST" = "aarch64" ];then # use pre-setup tap. so, it doesn't need root priviledge PARAM="-M virt -cpu host -accel kvm " elif [ "$HOST" = "macos" ];then PARAM="-M virt,highmem=off -cpu cortex-a72 -accel hvf " # Use Bridge #/opt/vde/bin/vde_switch --unix /tmp/vde.ctl -d #/opt/vde/bin/vde_vmnet --vmnet-mode=bridged --vmnet-interface=en0 /tmp/vde.ctl & #PARAM="$PARAM -device virtio-net-pci,netdev=net0 -netdev vde,id=net0,sock=/tmp/vde.ctl/ " #route add default 192.168.1.1 #mount_smbfs -f 0777 -d 0777 //user@192.168.1.100/share remoteShare else PARAM="-machine virt -cpu cortex-a57 -machine type=virt" fi qemu-system-aarch64 $PARAM \ -nographic -m ${MEM} -kernel ${KERNEL} \ --append "root=/dev/ram0 console=ttyAMA0 rdinit=/linuxrc" -initrd rootfs.img \ -drive if=none,file=../img.ext2,id=hd0,format=raw -device virtio-blk-device,drive=hd0 \ -net user,hostfwd=tcp::8489-:80,$REDIR -net nic -smp ${CORES} fi exit 0 |
在執行 ARM64 Guest 時,會針對 HOST 做不同的參數
- aarch64: 樹莓派4運行 Linux
- macos: MAC M1 的參數
- 其它: x86 Linux
macos 的部份是我們主要要關注的。
1 |
PARAM="-M virt,highmem=off -cpu cortex-a72 -accel hvf " |
-accel hvf 是 M1 上使用硬體加速的參數. highmem=off 好像是避免使用 40bit address 的意思,若無這行會執行失敗。後面提到的 Use Bridge 部份就是我們文章開頭講到的 vde 橋接功能,這個只要在程式開頭跑一次就可以,不用每次執行虛擬機都跑,所以這邊以注解的形式備注。再請讀者,自行下達命令。
結語
這種冷門的文章,還是主要為了自己工作之類的,但願有需要的人也可以獲得一點幫助。
附件
QEMU 編譯架構 (包含 Apple M1 硬體加速參數)