RaspberryPi4でGentoo Linuxを動かす

Raspberry Pi 4が日本でやっと発売されたので、Gentoo Linuxのインストール手順を調べてまとめました。

この手順でインストールを行うと64bitでRaspberry Piを使うことができます。(公式OSのRaspbianだと32bitらしいです)

# 楽な方法
試してないですが、簡単にやるのであれば以下のリポジトリのイメージを使うのが一番早いと思います。自分はsystemd使いたいのと、Gentooといえば自分でstage3展開からセットアップしていくものだと思ったので、この記事では手動でセットアップをしたときの手順を記載します。[^1]

[^1]: 本当の理由はこれの存在に気付かず1から構築する手順を調べてしまったからです。

https://github.com/sakaki-/gentoo-on-rpi-64bit

# ビルド用コンテナイメージ
以下の作業で必要なものを入れたコンテナイメージを用意したので、これを使うと環境準備の手間が省けると思います。この記事はこのイメージを利用した場合を前提に記述していますが、[Dockerfile](https://github.com/int2xx9/raspberrypi-workbench/blob/master/Dockerfile)を参考に必要なものを自分で入れて適宜読み替えれば、このイメージを使わなくともセットアップできると思います。
https://github.com/int2xx9/raspberrypi-workbench

起動は↓のような感じでできると思います。

```shell-session
# docker pull docker.pkg.github.com/int2xx9/raspberrypi-workbench/raspberrypi-workbench:20191204
# docker run --rm -it -v $(pwd)/work:/work --privileged docker.pkg.github.com/int2xx9/raspberrypi-workbench/raspberrypi-workbench:20191204 bash
```

起動すると、存在しない場合以下の3つのリポジトリが/work以下にクローンされます。Raspberry Pi固有のファームウェアやカーネル等はこのリポジトリのものを使用してセットアップを行います。

* /work/firmware
    * https://github.com/raspberrypi/firmware
* /work/linux
    * https://github.com/raspberrypi/linux
* /work/tools
    * https://github.com/raspberrypi/tools

# カーネルコンパイル
```shell-session:カーネルコンパイル
# cd /work/linux
# ARCH=arm64 CROSS_COMPILE=aarch64-unknown-linux-gnu- make bcm2711_defconfig
# ARCH=arm64 CROSS_COMPILE=aarch64-unknown-linux-gnu- make menuconfig
# ARCH=arm64 CROSS_COMPILE=aarch64-unknown-linux-gnu- make -j3
```

menuconfigはしなくともとりあえず起動するカーネルは作れると思います。自分はCPU governorをondemandに変えたりいくつかの設定を変更しました。

`-j3`は使用しているマシンのコア数等に応じて適宜調整します。Core i3-2100の環境でだいたい40分弱くらいでコンパイルできました。

# パーティション作成
パーティションはこんな感じの構成にします。メモリが4GBあるのと、SDカードの書き込みを減らすため、とりあえずスワップは作成しないことにしました。

種類|タイプ|容量
---|---|---
boot|FAT32|127MiB
rootfs|ext4|(上を除いた残り)

実際にパーティションの作成とフォーマットをします。

パーティション作成時、1つ目のパーティションのパーティションタイプ(≠実際にフォーマットするファイルシステム)はFAT32になっていないと、ACTランプが4回点滅してstart.elfを見つけられずエラーとなるみたいなので注意。

```shell-session:partedでパーティション作成
# parted /dev/sdf
(parted) mklabel msdos
(parted) mkpart p fat32 1MiB 128MiB
(parted) mkpart p ext4 128MiB -1
(parted) set 1 boot on
```

次に作成したパーティションをフォーマットします。上のコンテナイメージを使ってる人でこの後/dev/sdf1, /dev/sdf2が見つからない場合、一度コンテナを起動しなおせば出てくると思います。

```shell-session:作成したパーミッションをフォーマット
# mkfs.vfat -F32 /dev/sdf1
# mkfs.ext4 -i 8192 /dev/sdf2
```

# stage3とportageの展開
ここはPCにインストールする場合とだいたい同じような感じです。

```shell-session:stage3とportageの展開
# mount /dev/sdf2 /mnt/gentoo
# cd /mnt/gentoo
# curl 'http://distfiles.gentoo.org/experimental/arm64/stage3-arm64-systemd-20190925.tar.bz2' | tar jxp --xattrs-include='*.*' --numeric-owner
# mkdir -p /mnt/gentoo/etc/portage/repos.conf
# cp /mnt/gentoo/usr/share/portage/config/repos.conf /mnt/gentoo/etc/portage/repos.conf/gentoo.conf
# mkdir -p /mnt/gentoo/var/db/repos/gentoo
# curl 'http://distfiles.gentoo.org/snapshots/portage-latest.tar.bz2' | tar xj --strip 1 -C /mnt/gentoo/var/db/repos/gentoo/
```

# 最低限の設定
rootのパスワードとfstabを設定しておきます。とりあえずこれだけ設定しておけば起動とログインまではできるはずです。

普通のPCに入れる場合と違いchrootしておらずpasswdコマンドが使えないため、パスワードは/etc/shadowを直接書き換えて無理やり設定します。opensslの引数に指定しているrootがパスワードになるので、設定したいパスワードがある場合適当に変更します。

```shell-session:パスワードの設定
# sed --in-place -e 's,^root:\*:,root:'$(openssl passwd -6 root)':,' /mnt/gentoo/etc/shadow
```

fstabを設定します。

```shell-session:fstabの設定
# cat >> /mnt/gentoo/etc/fstab
/dev/mmcblk0p1          /boot           vfat            noauto,noatime  1 2
/dev/mmcblk0p2          /               ext4            noatime         0 1
```

# ブート関連の設定
起動に必要なファイルをコピーします。自分はWifiやBluetoothを使う予定がないため、その関連のファームウェアのコピーはとりあえず行っていません。

```shell-session:ブートに必要なファイルをコピー
# mount /dev/sdf1 /mnt/gentoo/boot/
# cp -r /work/firmware/boot/* /mnt/gentoo/boot/
# cp /work/linux/arch/arm64/boot/Image /mnt/gentoo/boot/kernel8.img
# mv /mnt/gentoo/boot/bcm2711-rpi-4-b.dtb /mnt/gentoo/boot/bcm2711-rpi-4-b.dtb_32
# cp /work/linux/arch/arm64/boot/dts/broadcom/bcm2711-rpi-4-b.dtb /mnt/gentoo/boot/
# cd /work/linux
# ARCH=arm64 CROSS_COMPILE=aarch64-unknown-linux-gnu- make modules_install INSTALL_MOD_PATH=/mnt/gentoo
```

ブート関連の設定ファイルを作成します。

```shell-session:ブート関連の設定ファイルの作成
# cat > /mnt/gentoo/boot/config.txt
arm_64bit=1
enable_gic=1
armstub=armstub8-gic.bin
disable_overscan=1
hdmi_drive=2
dtparam=audio=on
gpu_mem=16
# cat > /mnt/gentoo/boot/cmdline.txt
root=/dev/mmcblk0p2 rootfstype=ext4 rootwait
```

armstub8-gic.binというものが必要みたいなので作成します。よくわかっていないですが、Raspberry Pi 4からはARMの標準的なGICと呼ばれる割り込みコントローラが使えるようになったため、そのGICの初期化を行うためのものみたいです。[^2]

[^2]: 4より前のRaspberry Piは独自の割り込みコントローラを使用していて、それはLegacy Interrupt Controllerと呼ばれているみたいです。

```shell-session:armstub8-gic.binの用意
# cd /work/tools/armstubs
# make CC8=aarch64-unknown-linux-gnu-gcc LD8=aarch64-unknown-linux-gnu-ld OBJCOPY8=aarch64-unknown-linux-gnu-objcopy OBJDUMP8=aarch64-unknown-linux-gnu-objdump armstub8-gic.bin
# cp armstub8-gic.bin /mnt/gentoo/boot/
```

# Raspberry Piを起動する
ここまで行えば起動できるようになっているはずなので、/mnt/gentoo, /mnt/gentoo/bootをアンマウント後、Raspberry PiにSDカードを挿入して起動できるか確認します。

起動しなければなにか間違っているので頑張って調べます。緑色のLED(ACT LED)が点滅してる場合は起動時に何らかのエラーが出ているので、点滅回数とエラーの対応表を見るとなにかわかるかもしれないです。[^3]

[^3]: [ここ](https://www.raspberrypi.org/forums/viewtopic.php?f=28&t=58151#p1485558)とかにその対応の表が掲載されています。

上にも書きましたが、自分の実例で言うと、最初に起動確認したときに緑LEDが4回点滅してstart.elfが見つからないというエラーが発生しました。原因はパーティションタイプがFAT32になっていないことだったので、パーティションタイプを変更したら起動するようになりました。

# 参考資料
* [Raspberry Pi 3 64 bit Install - Gentoo Wiki](https://wiki.gentoo.org/wiki/Raspberry_Pi_3_64_bit_Install)
* [User:NeddySeagoon/Raspberry Pi4 64 Bit Install - Gentoo Wiki](https://wiki.gentoo.org/wiki/User:NeddySeagoon/Raspberry_Pi4_64_Bit_Install)
* [STICKY: Is your Pi not booting? (The Boot Problems Sticky) - Raspberry Pi Forums](https://www.raspberrypi.org/forums/viewtopic.php?f=28&t=58151)
* [Raspberry Pi 3の割込みについてまとめる - Qiita](https://qiita.com/toshinaga/items/e65004cc207a46d17b7b)
* [BCM2711について - Qiita](https://qiita.com/eggman/items/402d8ba20fa021cc4531)