Skip to content

Instantly share code, notes, and snippets.

@ink-splatters
Forked from akihikodaki/README.en.md
Created July 18, 2023 23:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ink-splatters/1da938aeb2629d6e5460af596a0d823e to your computer and use it in GitHub Desktop.
Save ink-splatters/1da938aeb2629d6e5460af596a0d823e to your computer and use it in GitHub Desktop.
Linux Desktop on Apple Silicon in Practice

Linux Desktop on Apple Silicon in Practice

I bought M1 MacBook Air. It is the fastest computer I have, and I have been a GNOME/GNU/Linux user for long time. It is obvious conclusion that I need practical Linux desktop environment on Apple Silicon.

Fortunately, Linux already works on Apple Silicon/M1. But how practical is it?

  • Two native ports exist.
  • QEMU can run code on CPU natively. But what about GPU? Unfortunately, QEMU is also not optimized so much for macOS.

As I needed Linux desktop right now, I decided to hack QEMU. The most difficult challenge is obviously accelerated graphics, but there is Virgil 3D; a bridge to expose host OpenGL to the guest. https://virgil3d.github.io

It unfortunately didn't work on macOS host. So I just made it work. That's it. Here is a video demonstrating OpenGL on Linux on Apple Silicon/M1:

https://www.youtube.com/watch?v=k0bVlVQU2JQ&list=PLesZxBYUPr3wdU3sONUv4Q7UDOg1Dn_Ue&index=4

Modifications

QEMU

ui/cocoa

  • Added OpenGL support.
  • Enforced pixel by pixel display.
  • Added cursor composition.
  • Releases mouse grabs properly when the key window changes. (@kov, 2021-05-12)
  • Allow to capture all keys including ones handled by macOS (@kov, enable it by adding full-grab=on to cocoa display specification, 2021-05-12)
  • Improved key mappings (e.g. Japanese IME keys, 2021-06-17)
  • Allowed to build with ui/gtk and ui/sdl2 at the same time (2022-07-06)

hw/block

  • File locking on macOS is fixed. (2021-07-07, Add file.locking=on to drive to prevent drive breakage in case you concurrently launch the same virtual machine by mistake.)

net

hvf

  • Fix AArch64 ID functions for recent Linux versions. (@agraf, 2022-02-07)

coreaudio

  • Fix device change (2022-02-26)

Virgil 3D renderer

Improved OpenGL ES support.

Do It Yourself

@knazarov's Homebre Formulae

It is independently maintained so may be a bit older, but you may still find it useful.

https://github.com/knazarov/homebrew-qemu-virgl

Setup

1. Open a terminal.

2. Install GLib, Meson, Pixman, pkg-config and spice-protocol with Homebrew.

brew install glib meson pixman pkg-config spice-protocol

3. Make a empty directory and change the working directory to it.

4.

curl -L https://gist.github.com/akihikodaki/87df4149e7ca87f18dc56807ec5a1bc5/raw/8cbc9c9e04b4ca80bee9e3f70764870ea60e8697/run.sh | bash -

5.

bin/qemu-img create var/virtio.raw 64G

It doesn't consume the physical space until it has data, so you can make the image very large. However, you will see odd behavior if you try to write data more than the physical disk allows.

6.

curl -LO https://download.fedoraproject.org/pub/fedora/linux/releases/36/Silverblue/aarch64/iso/Fedora-Silverblue-ostree-aarch64-36-1.5.iso

8.

./run -cdrom Fedora-Silverblue-ostree-aarch64-36-1.5.iso

Proceed the installation process, and now you can run Fedora by executing ./run.

Note: you won't get keyboard to work before Linux boots because TianoCore, the UEFI firmware does not support virtio-keyboard used in this configuration.

Updating

Just download the latest run.sh and execute it in your workspace directory.

Choosing OpenGL profile

Edit run.

  • gl=off will disable Virgil 3D GPU. Most stable but laggy.
  • gl=core will enable OpenGL.framework. Unstable.
  • gl=es will enable ANGLE. Stable and fast.

Upstreaming

Upstreaming is in progress. Hopefully the features I implemented will work just by running brew install qemu in the future.

Some insights

QEMU

This QEMU modification is not secure. The graphics acceleration code lives in the same process with everything else of the virtual machine and it is huge; the graphics stack involves LLVM for shader compilation, and a simple bug in the stack can lead to complete takeover of the guest.

vhost-user-gpu provides graphics acceleration isolation, but it needs modifications to run outside Linux because:

  • historically, vhost-user is a re-implementation of Linux kernel's vhost interface, and it relies on kernel headers for interface definitions and
  • vhost-user uses eventfd which is only available on Linux.

It shouldn't be difficult, but I'm satisfied even without process isolation so I don't. The graphics acceleration process would be still shared and it would remain possible that one graphical process exploit leads to disclosure of the entire graphics output anyway.

Linux desktop on Apple Silicon/M1 in general

As I described here, such a virtualization software is practical and efficient approach to run Linux desktop. The performance overhead is also acceptable for daily use, and it even provides better integration of Linux and macOS. For example, you can switch macOS and Linux with three-finger gesture on trackpad. You can use VirtFS.

However, there are complexities that such a virtualization adds. It basically means sharing one hardware with two systems, so you have to allocate the resource properly or it ends up with bad user experience. The allocation problem happens everywhere (HID like keyboard, computing resource like CPU, power management, etc.). This approach is efficient but not the best.

In long term, native Linux port is the best option. Asahi Linux is promising and you may find it favorable than my modified QEMU for your use case even today.

Apple Silicon で実践Linuxデスクトップ

M1 MacBook Airを買いました. これは私が持ってる一番速いコンピュータで, 私は長年の GNOME/GNU/Linux ユーザーでもあります. ここから, Apple Silicon でLinux デスクトップ環境が必要であるという明らかな結論が導かれます.

幸いにも, Linux は Apple Silicon で既に動作します. しかし 実用性 はどうでしょうか?

  • 2つのネイティブの移植があります.
    • Corellium. これは古くなっています. https://corellium.com/blog/linux-m1
    • Asahi Linux. 大幅に改善されており, 場合によっては実用的と言えます. しかし, 今のところグラフィックスアクセラレーションなどが欠けています. https://asahilinux.org
  • QEMU は CPU上でコードをネイティブ動作させることが可能です. しかし GPU についてはどうでしょう? また, 残念ながら, QEMU は macOS 向けにあまり最適化されていません.

私は Linux デスクトップが直ちに必要だったので, QEMU をハックすることにしました. 最大の困難は当然グラフィックスアクセラレーションですが, このために用いることができる, Virgil 3D という, ホストの OpenGL をゲストに見せるブリッジが存在します. https://virgil3d.github.io

残念ながらこれは macOS ホスト上で動きませんでした. そういうわけで 動くようにしました. 以上! 以下は Apple Silicon/M1 上での OpenGL を実演する動画です.

https://www.youtube.com/watch?v=k0bVlVQU2JQ&list=PLesZxBYUPr3wdU3sONUv4Q7UDOg1Dn_Ue&index=4

改変

QEMU

ui/cocoa

  • OpenGL サポートを追加.
  • Pixel by pixel 表示を実装.
  • カーソルの合成を追加.
  • キーウィンドウが変化したときにマウスの捕捉を適切に解除するように修正. (@kov, 2021-05-12)
  • macOS によって処理されているキーも含めて全てのキーを捕捉する機能を追加. (@kov, full-grab=oncocoa ディスプレイ指定に追加することで有効にしてください. 2021-05-12)
  • キーマッピングを改善 (日本語 IME キーなど, 2021-06-17)
  • ui/gtk や ui/sdl2 との同時ビルドを可能に (2022-07-06)

hw/block

  • macOS でのファイルロッキングを修正. (2021-07-07, 間違って同じ仮想マシンを 並行に起動してしまった場合にディスクが壊れるのを防ぐためには drivefile.locking=on を追加してください.)

net

hvf

  • 最新の Linux のために AArch64 ID レジスタを修正 (@agraf, 2022-02-07)

coreaudio

  • デバイスの変更処理を修正 (2022-02-26)

Virgil 3D renderer

OpenGL ES サポートを改善

Do It Yourself

@knazarov の Homebrew formulae

独自に保守されているため少し古いかもしれませんが, 便利かもしれません.

https://github.com/knazarov/homebrew-qemu-virgl

セットアップ

1. ターミナルを開く.

2. GLib, Meson, Pixman, pkg-config, そして spice-protocol を Homebrew でインストールする.

brew install glib meson pixman pkg-config spice-protocol

3. 空のディレクトリを作って working directory をそれに変更する.

4.

curl -L https://gist.github.com/akihikodaki/87df4149e7ca87f18dc56807ec5a1bc5/raw/8cbc9c9e04b4ca80bee9e3f70764870ea60e8697/run.sh | bash -

5.

bin/qemu-img create var/virtio.raw 64G

データが記録されるまで物理領域を消費しないため, イメージをかなり大きくできます. ただし, 物理ディスクが許容する以上のデータを書き込むとおかしな挙動が現れます.

6.

curl -LO https://download.fedoraproject.org/pub/fedora/linux/releases/36/Silverblue/aarch64/iso/Fedora-Silverblue-ostree-aarch64-36-1.5.iso

8.

./run -cdrom Fedora-Silverblue-ostree-aarch64-36-1.5.iso

インストールプロセスを進めてください. ./run を実行することで Fedora を起動できるようになるはずです.

注: Linux が起動するまでキーボードは利用できません。これは、この構成で利用している virtio-keyboard に UEFI ファームウェアの TianoCore が対応していないためです。

更新

単に最新の run.sh をダウンロードしてワークスペースディレクトリで実行して ください.

OpenGL プロファイルを選択する

run を編集してください.

  • gl=off は Virgil 3D GPU を無効にします. 安定していますがラグいです.
  • gl=core は OpenGL.framework を有効にします. 不安定です.
  • gl=es は ANGLE を有効にします. 安定していて速いです.

アップストリーミング

アップストリーミングが進行中です. 願わくば将来は私が実装した機能が brew install qemu とするだけで動作するようになるはずです.

考察

QEMU

この QEMU の改変は セキュアではありません . グラフィックスアクセラレーションのコードが仮想マシンの他のあらゆるもの全てと同じプロセスに存在していて, そのコードは巨大です. グラフィックススタックはシェーダコンパイルのために LLVM を含んでおり, その中の簡単な不具合1つでゲストの完全な乗っ取りが可能です.

vhost-user-gpu はグラフィックスアクセラレーションの分離を提供しますが, Linux 以外で動作するように修正が必要です.

  • 歴史的には, vhost-user は Linux カーネルの vhost インターフェイスの再実装となっていて, インターフェイス定義のためにカーネルヘッダに依存しています.
  • vhost-user は Linux でしか利用できない eventfd を利用しています.

これは難しくないでしょうが, プロセス分離がなくても満足してるのでやりません. やってもグラフィックスアクセラレーションプロセスは共有されたままになるでしょうし, 単独のグラフィカルプロセスの攻撃がグラフィックス出力全体の暴露につながるのは変わりないでしょう.

Apple Silicon/M1 上の Linux デスクトップ一般について

先に説明したとおり, このような仮想化ソフトウェアは Linux デスクトップを実行する 実用的で効率的な方法です. 性能上のオーバーヘッドも日常的な利用には許容できる範囲で, Linux と macOS のよりよい統合を提供しさえします. 例えば, macOS と Linux をトラックパッド上の3本指ジェスチャーで切り替えられます. VirtFS も使えます.

しかし, 仮想化による複雑さもあります. 要は1つのハードウェアを2つのシステムで 共有することになるので, 資源を適切に割り当てなければユーザー体験を悪化させます. この問題はあらゆる場面でおきます (キーボードのような HID, CPU のような計算資源, 電力管理などなど). この方法は 効率的 ですが 最善 ではありません.

長期的には ネイティブの Linux 移植が最善でしょう. Asahi Linux は期待できます. 今でも利用法によっては私が改変した QEMU よりよいかもしれません.

set -eux
mkdir -p depot_tools build/qemu source/angle source/libepoxy source/virglrenderer source/qemu var
git -C depot_tools init
git -C depot_tools fetch https://chromium.googlesource.com/chromium/tools/depot_tools.git 268d645853ee8e1b884260049e5464a5ca2d8a30
git -C depot_tools checkout 268d645853ee8e1b884260049e5464a5ca2d8a30
git -C source/angle init
git -C source/angle fetch https://github.com/akihikodaki/angle macos
git -C source/angle checkout FETCH_HEAD
git -C source/libepoxy init
git -C source/libepoxy fetch https://github.com/akihikodaki/libepoxy.git macos
git -C source/libepoxy checkout FETCH_HEAD
git -C source/virglrenderer init
git -C source/virglrenderer fetch https://github.com/akihikodaki/virglrenderer.git macos
git -C source/virglrenderer checkout FETCH_HEAD
git -C source/qemu init
git -C source/qemu fetch https://github.com/akihikodaki/qemu.git macos
git -C source/qemu checkout FETCH_HEAD
export DEPOT_TOOLS_UPDATE=0
export PATH="$PWD/depot_tools:$PATH"
cd source/angle
scripts/bootstrap.py
gclient sync -D
gn gen --args=is_debug=false ../../build/angle
cd ../..
ninja -C build/angle
[ -e build/libepoxy/meson-info ] || meson "-Dc_args=-I$PWD/source/angle/include" -Degl=yes -Dx11=false "--prefix=$PWD" build/libepoxy source/libepoxy
meson install -C build/libepoxy
[ -e build/virglrenderer/meson-info ] || meson "-Dc_args=-I$PWD/source/angle/include" "--pkg-config-path=$PWD/lib/pkgconfig" "--prefix=$PWD" build/virglrenderer source/virglrenderer
meson install -C build/virglrenderer
cd build/qemu
PKG_CONFIG_PATH="$PWD/../../lib/pkgconfig" ../../source/qemu/configure "--extra-cflags=-I$PWD/../../source/angle/include" "--extra-ldflags=-L$PWD/../angle" "--prefix=$PWD/../.."
meson install
[ -e ../../var/edk2-arm-vars.fd ] || cp pc-bios/edk2-arm-vars.fd ../../var
cd ../..
cat > run <<'EOF'
#!/bin/bash
d="$(dirname "{BASH_SOURCE[0]}")"
exec sudo DYLD_FALLBACK_LIBRARY_PATH="$d/build/angle:$d/lib" "$d/bin/qemu-system-aarch64" -machine virt,accel=hvf -cpu host -smp 8 -m 4G -device ich9-intel-hda -device hda-output,audiodev=audio -device virtio-gpu-gl -device virtio-keyboard -device virtio-net,netdev=net -device virtio-rng -display cocoa,gl=es -drive "if=pflash,format=raw,file=$d/share/qemu/edk2-aarch64-code.fd,readonly=on" -drive "if=pflash,format=raw,file=$d/var/edk2-arm-vars.fd" -drive "id=virtio,if=none,format=raw,file=$d/var/virtio.raw,discard=on" -device virtio-blk,backend_defaults=on,drive=virtio -audiodev coreaudio,id=audio,out.fixed-settings=false -netdev vmnet-shared,id=net -chardev qemu-vdagent,id=spice,name=vdagent,clipboard=on -device virtio-serial -device virtserialport,chardev=spice,name=com.redhat.spice.0 -full-screen -runas "$(id -u):$(id -g)" "$@"
EOF
chmod a+x run
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment