クロスコンパイラがない言語のバイナリを Windows 上で作る必要があったため、 QEMU でその環境を作成した。ターゲットマシン上でやってもよかったのだが、非常に非力で終わる気配がなかったため強力なマシンでビルドをしようと思ったのがきっかけ。環境構築はそう何度もやらなさそうで忘れそうだったため、防備として記す。

qemu の入手

qemu の公式ページ に入手方法がいくつか記載されているので、記載されているいずれかの方法を用いて qemu をシステムにインストールする。
https://qemu.weilnetz.de/ からインストーラーをダウンロードしてインストールする方法がお手軽なのでおすすめ。

インストールできたら、 PATH を通す。システムの PATH 上に追加したくない場合は、そのシェル内だけで有効な PATH を都度設定するとよい。

> set PATH=%PATH%;C:\Program Files\qemu
> qemu-system-aarch64.exe --version
QEMU emulator version 9.0.0 (v9.0.0-12054-g923cf646f4)
Copyright (c) 2003-2024 Fabrice Bellard and the QEMU Project developers

起動イメージの入手

UEFI の入手

https://releases.linaro.org/components/kernel/uefi-linaro/16.02/release/qemu64/ からファームウェアをダウンロードする。

https://packages.debian.org/search?keywords=qemu-efi-aarch64&searchon=names から quem 向けの安定板 EFI イメージのパッケージをダウンロードする。(.deb ファイルをダウンロードする。ダウンロード対象は実行可能パッケージファイルなので、ブラウザによってはダウンロードがブロックされることがある。名前を付けて保存するとよい。)

ダウンロードしたファイルを展開し、ファームウェアファイルを取り出す。 artar (unxz) が必要になるので、 WSL などを使って作業する。

$ ar -x qemu-efi-aarch64_2022.11-6+deb12u1_all.deb
$ ls
control.tar.xz  data.tar.xz  debian-binary  qemu-efi-aarch64_2022.11-6+deb12u1_all.deb
$ tar -xf data.tar.xz
$ ls
control.tar.xz  data.tar.xz  debian-binary  qemu-efi-aarch64_2022.11-6+deb12u1_all.deb  usr

usr ディレクトリの下の方にある QEMU_EFI.fd が、今回欲しいファイル。

usr/
└── share
    ├── AAVMF
    │   ├── AAVMF_CODE.fd
    │   ├── AAVMF_CODE.ms.fd -> AAVMF_CODE.fd
    │   ├── AAVMF_CODE.snakeoil.fd -> AAVMF_CODE.fd
    │   ├── AAVMF_VARS.fd
    │   ├── AAVMF_VARS.ms.fd
    │   └── AAVMF_VARS.snakeoil.fd
    ├── doc
    │   └── qemu-efi-aarch64
    │       ├── README.Debian
    │       ├── changelog.Debian.gz
    │       └── copyright
    ├── qemu
    │   └── firmware
    │       ├── 40-edk2-aarch64-secure-enrolled.json
    │       ├── 50-edk2-aarch64-secure.json
    │       └── 60-edk2-aarch64.json
    └── qemu-efi-aarch64
        ├── PkKek-1-snakeoil.key
        ├── PkKek-1-snakeoil.pem
        └── QEMU_EFI.fd

OS の入手

今回は Ubuntu の ARM 向けイメージを用いることにする。 ARM 向けバイナリ配布ページ から、OS のインストーラーをダウンロードする。

エミュレーターの初期設定

自分の PC 上のどこかのディレクトリに作業ディレクトリを作成し、ファームウェアイメージと OS イメージをあらかじめ配置しておくこと。

仮想ストレージの作成

qcow2 は qemu の仮想ストレージフォーマット。 ここでは 32GB の容量を確保しておく。

> qemu-img.exe crate -f qcow2 storage.qcow2 32G
Formatting 'storage.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=34359738368 lazy_refcounts=off refcount_bits=16

OS のインストール

OS のイメージと仮想ストレージを同時に接続し、 qemu を起動する。-accel オプションを付けることによってパフォーマンスを向上させることができるので、必要に応じて追加する (なくてもよい)。

>qemu-system-aarch64.exe -accel help
Accelerators supported in QEMU binary:
tcg

> qemu-system-aarch64.exe -m 4096 -cpu cortex-a72 -smp 4 -M virt -nographic -bios QEMU_EFI.fd 
    -drive id=hd0,if=none,file=ubuntu-24.04-live-server-arm64.iso,format=raw
    -device virtio-blk-device,drive=hd0
    -drive id=hd1,file=storage.qcow2,format=qcow2
#   -accel tcg

ターミナル内でインストール ウィザードが立ち上がるので、指示に従って OS を仮想ストレージにインストールする。インストールの最終ステップはかなり時間がかかるので、映画でも見て待ってよい (自分の環境では 90分 くらいかかった)

TODO: インストールステップ セクションの詳細について追加

エミュレーターの起動

OS のインストールが終わったら、インストールに利用したイメージを外してエミュレータを起動できる。ホスト側からアクセスして利用することができるように、ssh のポートマッピングを設定する。

> qemu-system-aarch64.exe -m 4096 -cpu cortex-a72 -smp 4 -M virt -nographic -bios QEMU_EFI.fd
    -drive id=hd1,file=storage.qcow2,format=qcow2
    -device virtio-net-device,netdev=net0
    -netdev user,hostfwd=tcp:127.0.0.1:22222-:22,id=net0
    -accel tcg

仮想マシンを起動したターミナルをそのまま使ってもよいが、 ssh localhost -l ubuntu -p 22222 で SSH 経由でターミナルにアクセスできるため、こちらを使ってもよい。(scp できる)

CPU 情報の確認

lscpuuname -p などで確認できる。

$ uname -p
aarch64

$ lscpu
Architecture:             aarch64
  CPU op-mode(s):         32-bit, 64-bit
  Byte Order:             Little Endian
CPU(s):                   4
  On-line CPU(s) list:    0-3
Vendor ID:                ARM
  Model name:             Cortex-A72
    Model:                3
    Thread(s) per core:   1
    Core(s) per socket:   4
    Socket(s):            1
    Stepping:             r0p3
    BogoMIPS:             125.00
    Flags:                fp asimd evtstrm aes pmull sha1 sha2 crc32 cpuid
# --- 省略 --- #