QEMU で Raspberry Pi 3 用のバイナリを動かす

## はじめに

突然ですが、

-   ARM で動く (Type-1) VMM を作りたい
-   &#x2013;> ARM で OS なしで自分のコードが動かしたい (ベアメタルプログラミング)
-   &#x2013;> デバッグなどのために QEMU で OS なしに自分のコードを動かしたい
-   &#x2013;> QEMU で Raspberry Pi エミュレーション環境の構築と動作確認をしたい <&#x2013; 今ここ

という経緯があり QEMU で Raspberry Pi 3 用のイメージを動かしたくなったのでやってみました。

## 参考ページ

-   QEMUでRaspberry Pi 3のUARTをベアメタルで動かす by @eggman: <https://qiita.com/eggman/items/045bf5525fcf78209b79>

今回も、ほぼ参考ページの通りやっただけの記事になっております..

## 環境

-   OS (Distribution): Ubuntu 18.04.4 LTS
-   Linux kernel: Linux uefi-ubuntu 4.15.0-96-generic

## QEMU の ビルド

Ubuntu 18.04.4 の apt でインストール可能な QEMU は Raspberry Pi 3 のエミュレーションに未対応のため、自分で QEMU をビルドします。

### ビルドの準備

まずは、QEMU のビルドに必要なパッケージを apt でインストールします。
`apt build-dep <パッケージ名>` で `<パッケージ名>` に該当するもののビルドに必要なパッケージをまとめてインストールできるようです (参考にしたページを見て知りました..) 。

ただ、Ubuntu での apt のデフォルト設定では、ビルド時の依存関係に関するレポジトリが設定されていないので、まずはこれを設定します。
以下のページを参考に `/etc/apt/sources.list` を書き換えてみました。

-   apt build-dep がエラーになるときの対処方法 by @tetsu<sub>koba</sub>: <https://qiita.com/tetsu_koba/items/904b03e908b040ed447d>

僕の環境は Ubuntu 16.04 からアップデートしたものなので、参考ページの `/etc/apt/sources.list` と少し様子が違いましたが、
`deb` から始まる行をコピペして `deb-src` にしたものを足していけば大丈夫そうです。

あとは、 `apt update` して `apt build-dep` を実行します。
まとめると、実行するコマンドは以下のようになります。

    $ sudo vim /etc/apt/sources.list #上記の通り編集
    $ sudo apt update
    $ sudo apt build-dep qemu

### ソースコードのダウンロード & ビルド

次に、QEMU のソースコードを `git clone` でダウンロードし、 v5.0.0 (執筆時の最新バージョン)タグにチェックアウトしてビルドします。
回線やマシンのスペックによりますが、git clone と make はそこそこ時間がかかると思います。

コマンドは以下の通りです。

    $ cd ~
    $ git clone git://git.qemu.org/qemu.git
    $ cd qemu
    $ git checkout -b v5.0.0-release refs/tags/v5.0.0
    $ git submodule update --init
    $ ./configure --prefix=`pwd`/build --target-list=arm-softmmu,aarch64-softmmu --audio-drv-list=alsa
    $ make -j5

(2021.05.09 追記: 最近の QEMU は Ninja というビルドツールを使うらしく、これをセットアップしないと ./configure が失敗するようです。こちらのページが参考になりました。[QEMUコンパイルガイド - コードワールド](https://www.codetd.com/ja/article/12543267))

ちなみに、make の `-j` オプションはコンパイル時の並列数を指定するものです。
CPU のコアがたくさんあるなら大きめの数字にすると速くビルドが終わるかもしれないです。
僕は、コア数 + 1 をよく指定します (適切な値については諸説あるらしい)。

システム全体で使えるようにするなら、この後に `sudo make install` を実行するといいんですが、僕はシステムに入っている QEMU と混ざるのは嫌なので、インストールせずに進めます。
ビルドされた QEMU のバイナリがどこにあるのかわからなかったので、以下のコマンドで見つけます。

    $ find . -name 'qemu-system-*'
    ./aarch64-softmmu/qemu-system-aarch64
    ./arm-softmmu/qemu-system-arm

`qemu-system-aarch64` というのが QEMU の実行ファイルです。

以下のようにして、ビルドした QEMU が raspberry pi 3 のエミュレートに対応していることを確認します。

    $ ./aarch64-softmmu/qemu-system-aarch64 -machine help | grep rasp
    raspi2               Raspberry Pi 2B
    raspi3               Raspberry Pi 3B

## サンプルバイナリの準備と実行

今回は [参考ページにあるサンプルコード](https://qiita.com/eggman/items/045bf5525fcf78209b79#%E3%82%BD%E3%83%BC%E3%82%B9%E3%82%B3%E3%83%BC%E3%83%89) をビルドして QEMU 上で動かしてみます。

### サンプルコードのビルド

次に [参考ページにあるサンプルコード](https://qiita.com/eggman/items/045bf5525fcf78209b79#%E3%82%BD%E3%83%BC%E3%82%B9%E3%82%B3%E3%83%BC%E3%83%89) から QEMU 上で試しに動かす ELF バイナリを作ります。
aarch64 向けのクロスコンパイラをインストールし、それを使ってサンプルコードをビルドします。

    $ sudo apt install gcc-aarch64-linux-gnu
    $ mkdir ~/raspberrypi-baremetal-sample-src
    $ cd ~/raspberrypi-baremetal-sample-src
    $ # ↑で適当に作ったディレクトリにソースを用意
    $ ls
    Makefile  boot.S  kernel.c  linker.ld
    $ make
    aarch64-linux-gnu-gcc -mcpu=cortex-a53 -fpic -ffreestanding -c boot.S -o boot.o
    aarch64-linux-gnu-gcc -mcpu=cortex-a53 -fpic -ffreestanding -std=gnu99 -O2 -Wall -Wextra -c kernel.c -o kernel.o
    kernel.c: In function 'mmio_write':
    kernel.c:6:4: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
       *(volatile uint32_t*)reg = data;
        ^
    kernel.c: In function 'mmio_read':
    kernel.c:12:11: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
       return *(volatile uint32_t*)reg;
               ^
    aarch64-linux-gnu-gcc -T linker.ld -o kernel.elf -ffreestanding -O2 -nostdlib boot.o kernel.o
    $

ビルドが成功すれば、 `kernel.elf` というバイナリファイルができます。
(なんか warning 出ていますが、気にせず進めます。)

このサンプルは
-   UART に "Hello kernel World!" を表示する。
-   その後入力待ちになり、入力した文字をそのまま表示する。

という動きをします。

### ELF バイナリを QEMU で動かしてみる

では先ほどビルドした ELF バイナリを実際に動かしてみましょう。

    $ ~/qemu/aarch64-softmmu/qemu-system-aarch64  -M raspi3 -nographic -kernel ./kernel.elf
    HHHHelellello, kernel World!
    ello, kernel World!
    lo, kernel Woro, kld!
    ernel World!
    QEMU: Terminated
    $

なんだか表示がひどいことになっていますが、これは 4 コアで同時に "Hello kernel World!" を表示した結果です(たぶん)。
上の実行例ではやっていませんが、"Hello kernel World!" (x4 だったはずのなにか) の表示後にキー入力すると、その文字がそのまま表示されます。
Ctrl-a x の順でキー入力をすると、QEMU を終了できます。

ちなみに、表示が崩れるのでコアを1つにしてようと QEMU の `-smp` オプションを付けてみましたがだめでした。
raspi3 のエミュレーション時はコア数は 4 で固定のようです。
同様にメモリも 1 GiB で固定のようでした(もしかしたら変える方法あるかもしれまんせんが..)

## おわりに

というわけで、QEMU 上で Raspberry Pi 3 用のバイナリを動かしてみました。
しばらくこれで ARM のベアメタルプログラミングで遊べるといいですね。