Raspberry Pi 3 で 公式 arm64 Debian を動かす

## 背景

みなさんはRaspberry Piには[Raspbian](https://www.raspbian.org/)という，Debianから派生したOSを入れていると思います．Raspberry Pi Foundationも[Raspbianが公式のOSだと謳っています](https://www.raspberrypi.org/downloads/)．

### なぜデフォルトがDebianではないのか

32ビットARM向けのDebianには `armel` と `armhf` の2種類があります[^1]．前者はARMv4T以上，後者はARMv7 (かつThumb-2およびVFP3-D16[^4]) 以上をサポートします．

ところで，Raspberry PiのARMのバージョンは以下となっています．全モデルのRaspberry Piで同じOSを使うとすると，Raspberry Pi 1がARMv6なので，まず `armhf` は使えません．しかし `armel` はsoft float (たぶん[^2]) なので使いたくなかったみたいです[^3]．

|モデル|ARMのバージョン|
|:--|:--|
|Raspberry Pi 1|ARMv6|
|Raspberry Pi 2|ARMv7|
|Raspberry Pi 3|ARMv8|

そこで，Raspberry Pi 1でも対応しているVFPv2を使うDebianのポートを作ることにしたっぽい．根気がすごいですね．

### Debian for 64-bit ARM

Raspberry Pi 3はRaspbianとかだと32ビットの互換モードで動きますが，ちゃんとしたARMv8なので64ビットでも動きます．
ところで，Debianには`arm64`という64ビットARM向けのポートがあります．
https://wiki.debian.org/RaspberryPi3 を見てみたら，公式のDebian `arm64`イメージをそのままRaspberry Pi 3で動かせそうだったのでやってみました．

今思えばRaspberry Pi 2，3で`armhf`動かせるよな．こっちの方が需要ありそう．


## Raspberry Pi 3を64ビットモードで動かす手順

基本的には https://www.raspberrypi.org/forums/viewtopic.php?f=72&t=137963 や https://wiki.gentoo.org/wiki/Raspberry_Pi_3_64_bit_Install に書いてあるので詳しくは書きません．

1. Debianの`qemu-debootstrap`で`/`をインストールする．
2. `/boot`を適当に準備する．
    * `start_cd.elf`と`fixup_cd.dat`
    * カーネルとモジュールを https://packages.debian.org/stretch/linux-image-4.9.0-4-arm64 から持ってくる．
    * device tree `bcm2837-rpi-3-b.dtb` は https://packages.debian.org/stretch/linux-image-4.9.0-4-arm64 にあるやつを使う．起動するカーネルとバージョンが合わないとブートしないので注意．
        * バージョン合わせをよしなにやってくれるスクリプト `/etc/kernel/postinst.d/raspi3-dtb` を書いた[^5]のでぜひ使ってください．
    * `config.txt` と `cmdline.txt` の例は下に書いておきます．
        * 初回起動時はinitrdがないので，initrdのエントリはコメントアウトします．
    * ファイルがなかったり間違えてたりしたらTFTPのロードやNFSのマウントが止まるので，トラブルシューティングの参考にしてください．
3. 起動する．
4. `raspi3-dtb`スクリプトをコピーする．
5. `apt-get update && apt-get install linux-image-arm64`
    * ここでinitrdが作られます．

```conf:config.txt
arm_64bit=1
kernel=vmlinuz64
# 初回起動時はコメントアウトし，以降はコメントアウトしない．
initramfs initrd64.img
cmdline=cmdline.txt
device_tree=bcm2837-rpi-3-b.dtb
enable_uart=1
gpu_mem=16
```

```conf:cmdline.txt
console=ttyAMA0,115200 root=/dev/nfs nfsroot=${サーバのIPアドレス}:/srv rw ip=dhcp rootwait rootdelay=2
```

```sh:/etc/kernel/postinst.d/raspi3-dtb
#!/bin/sh -e

version="$1"

if [ -z "${version}" ]; then
        echo >&2 "W: $0: ${DPKG_MAINTSCRIPT_PACKAGE:-kernel package} did not pass a version number"
        exit 2
fi

if [ -n "$2" ]; then
        bootdir=$(dirname "$2")
else
        bootdir="/boot"
fi

dtb="/usr/lib/linux-image-${version}/broadcom/bcm2837-rpi-3-b.dtb"
dtb_base=$(basename "${dtb}")
dtb_new="${bootdir}/${dtb_base}-${version}"

cp "${dtb}" "${dtb_new}"
if [ "${bootdir}" = "/boot" ]; then
        ln -fs "boot/${dtb_base}-${version}" "/${dtb_base}"
fi
```




[^1]: https://www.debian.org/ports/
[^2]: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0472jj/chr1359124234797_00011.html によるとARM1136JF-Sまでずっとsoft floatだが， http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0211k/index.html によるとARM1136JF-SはARMv6で，そうなるとARMv6まではずっとsoft floatだったんだなって．
[^3]: https://www.raspbian.org/RaspbianFAQ
[^4]: Raspberry Pi 2，3はVFPv4なのでOK: https://github.com/Terminus-IMRC/auxv-rpi
[^5]: 公式っぽいスクリプトがある https://packages.debian.org/stretch/raspi3-firmware が，なんか /boot/firmware にSDカードをマウントすることを前提に作られていて，自分の環境と合わなかったので自分で書いた．