RaspberryPi3 Model Bを64bitで動かす

# やりたいこと
RaspberryPi3 Model Bを64bitで動かしたくなりました。
せっかく64bit CPU (Cortex-A53)が載っているのに、標準イメージ(32bit)で動かすなんてもったいない！ですよね？
カーネルだけではなく、rootfsも含めて64bitで動作させます。

# おおまかな流れ

基本的にgentoo linux wikiの[Raspberry_Pi_3_64_bit_Install](https://wiki.gentoo.org/wiki/Raspberry_Pi_3_64_bit_Install)に沿っています。
さすがgentooだけあって細かく手順を書いてくれてます。

ただし、gentoo linux PCが手元になかったので、Ubuntu16.04 PC上で作業しました。
また、wikiではSDカードに直接書き込んでますが、SDカードがない環境でも作業できるよう、イメージを作成してから流し込むようにしています。

# 環境
- PC: Ubuntu 16.04
- RaspberryPi 3 model B

## ツールのインストール

```
$ sudo apt install gcc-5-aarch64-linux-gnu
$ sudo apt install kpartx
```

## Linux Kernelビルド

```
$ git clone --depth 1 --branch rpi-4.10.y https://github.com/raspberrypi/linux
$ cd linux
$ ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- make bcmrpi3_defconfig
$ ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- make -j9
$ cd ..
```


## 空のディスクイメージ作成

```
$ fallocate -l 2GiB GentooAarch64_`date +%Y%m%d`.img
```

## Partitionの作成

```
$ fdisk GentooAarch64_20171114.img
Welcome to fdisk (util-linux 2.27.1).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.

Device does not contain a recognized partition table.
Created a new DOS disklabel with disk identifier 0x1218c51a.

コマンド (m でヘルプ): o
Created a new DOS disklabel with disk identifier 0x8c0219cc.

コマンド (m でヘルプ): n
Partition type
   p   primary (0 primary, 0 extended, 4 free)
      e   extended (container for logical partitions)
      Select (default p):

Using default response p.
パーティション番号 (1-4, default 1):
First sector (2048-4194303, default 2048):
Last sector, +sectors or +size{K,M,G,T,P} (2048-4194303, default 4194303): +128M

Created a new partition 1 of type 'Linux' and of size 128 MiB.

コマンド (m でヘルプ): n
Partition type
   p   primary (1 primary, 0 extended, 3 free)
      e   extended (container for logical partitions)
      Select (default p):

Using default response p.
パーティション番号 (2-4, default 2):
First sector (264192-4194303, default 264192):
Last sector, +sectors or +size{K,M,G,T,P} (264192-4194303, default 4194303):

Created a new partition 2 of type 'Linux' and of size 1.9 GiB.

コマンド (m でヘルプ): t
パーティション番号 (1,2, default 2): 1
Partition type (type L to list all types): c

Changed type of partition 'Linux' to 'W95 FAT32 (LBA)'.

コマンド (m でヘルプ): t
パーティション番号 (1,2, default 2): 2
Partition type (type L to list all types): 82

Changed type of partition 'Linux' to 'Linux swap / Solaris'.

コマンド (m でヘルプ): p
Disk GentooAarch64_20171114.img: 2 GiB, 2147483648 bytes, 4194304 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x8c0219cc

デバイス                    起動  Start 最後から セクタ  Size Id タイプ
GentooAarch64_20171114.img1        2048   264191  262144  128M  c W95 FA
GentooAarch64_20171114.img2      264192  4194303 3930112  1.9G 82 Linux

コマンド (m でヘルプ): w
The partition table has been altered.
Syncing disks.
```

## ファイルシステムの作成
```
$ sudo kpartx -av GentooAarch64_20171114.img 
add map loop0p1 (253:0): 0 262144 linear 7:0 2048
add map loop0p2 (253:1): 0 3930112 linear 7:0 264192

$ lsblk /dev/loop0
NAME      MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
loop0       7:0    0    2G  0 loop 
├─loop0p2 253:1    0  1.9G  0 part 
└─loop0p1 253:0    0  128M  0 part

$ sudo mkfs -t vfat -F 32 /dev/mapper/loop0p1
mkfs.fat 3.0.28 (2015-05-16)
unable to get drive geometry, using default 255/63

$ sudo mkfs -i 8192 -t ext4 /dev/mapper/loop0p2
mke2fs 1.42.13 (17-May-2015)
Discarding device blocks: done                            
Creating filesystem with 491264 4k blocks and 245760 inodes
Filesystem UUID: 0391b4da-c88d-4cb4-9da8-2a51b7f7f2fa
Superblock backups stored on blocks: 
	32768, 98304, 163840, 229376, 294912

Allocating group tables: done                            
Writing inode tables: done                            
Creating journal (8192 blocks): done
Writing superblocks and filesystem accounting information: done
```

## Root file system

```
$ mkdir mnt
$ sudo mount /dev/mapper/loop0p2 mnt/
$ curl -L -O http://ftp.jaist.ac.jp/pub/Linux/Gentoo/experimental/arm64/stage3-arm64-arm64-20170223.tar.bz2
$ sudo tar xvf stage3-arm64-arm64-20170223.tar.bz2 -C mnt/
$ sudo rm -rf mnt/tmp/ mnt/boot
$ sudo mkdir mnt/tmp/ mnt/boot
```

## Boot partition

```
$ sudo mount /dev/mapper/loop0p1 mnt/boot
$ git clone --depth=1 https://github.com/raspberrypi/firmware.git
  # 確認時のSHA1は008700b83121b92
$ sudo cp -r firmware/boot/* mnt/boot/
$ sudo cp linux/arch/arm64/boot/Image mnt/boot/kernel8.img
$ sudo mv mnt/boot/bcm2710-rpi-3-b.dtb mnt/boot/bcm2710-rpi-3-b.dtb_32
$ sudo cp linux/arch/arm64/boot/dts/broadcom/bcm2710-rpi-3-b.dtb mnt/boot
$ cd linux/
$ sudo ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- make modules_install INSTALL_MOD_PATH=../mnt
$ cd ..
```


## configuration

### rootのパスワード設定（`raspberry`）
```
$ sudo emacs mnt/etc/shadow
root:$6$xxPVR/Td5iP$/7Asdgq0ux2sgNkklnndcG4g3493kUYfrrdenBXjxBxEsoLneJpDAwOyX/kkpFB4pU5dlhHEyN0SK4eh/WpmO0::0:99999:7:::
```

### ファイルシステムのマウント設定
```
$ sudo emacs mnt/etc/fstab
/dev/mmcblk0p1          /boot           vfat            noauto,noatime  1 2
/dev/mmcblk0p2          /               ext4            noatime         0 1
```

## Unmount image

```
$ sudo umount mnt/boot
$ sudo umount mnt
$ sudo kpartx -d GentooAarch64_20171114.img
```

## イメージの書き込み
書き込み先SDカードのデバイスは、差し込み前後の`df -h`や`dmesg`で確認できます。
ただし、`df -h`の出力が`/dev/sdc1`の場合、最後の`1`はパーティションを表すので、`/dev/sdc`を書き込み先とします。

```
$ sudo umount /dev/sdX1
$ sudo dd bs=4M if=GentooAarch64_20171114.img of=/dev/sdX status=progress conv=fsync
$ sync && sync && sync
```


## 64bitであるかどうか確認
上記SDカードでラズパイを起動したら、下記コマンドで64bitで動いているかどうかを確認してみます。
（全く同じ手順であれば、`root`/`raspberry`でログインできるはずです）

```
# Kernel
$ uname -m
aarch64

# rootfs
$ getconf LONG_BIT
64

# rootfs(念押し)
$ readelf -h `which readelf`
  Machine:     AARCH64
```
成功！

# まとめ
せっかくのaarch64なのだから、公式で64bit版サポートして欲しいなと思いつつ、とても勉強になったので結果オーライです。
それにしてもまさか初めてのgentoo linuxがラズパイになるとは思いませんでした汗


# 参考
- [Raspberry_Pi_3_64_bit_Install](https://wiki.gentoo.org/wiki/Raspberry_Pi_3_64_bit_Install)
- [Arch Linux ARMのディスクイメージを作成する（losetup、kpartx）](http://mattintosh.hatenablog.com/entry/20160204/1454596130)
- [【Linux】kpartxでループバックデバイスを簡単にマウントする](http://oplern.hatenablog.com/entry/2017/07/01/164004)
- [BUILD A 64-BIT KERNEL FOR YOUR RASPBERRY PI 3](https://devsidestory.com/build-a-64-bit-kernel-for-your-raspberry-pi-3/)
- [[メモ] Raspberry Pi 3向けの 64bitカーネルをビルドして、使用する](https://qiita.com/mt08/items/ebf5fcef4aebe03ca210)
- [Raspberry Pi 3を64-bitモードで扱うための現状について調べてみた](http://tnishinaga.hatenablog.com/entry/2016/04/17/232617)
- [RASPBERRY PI 3用64BIT DOCKER ENGINEを含むイメージを公開しました](http://atbsd.com/?p=39)
- [イメージ](http://www.tom-yam.or.jp/rpi3/rpi3-arm64-docker-20160416.img.xz)
- [Linuxでrawディスクのimageファイルを扱うあれこれ（空ファイル作成、パーティション作成、マウントなど）](http://vorfee.hatenablog.jp/entry/2016/01/16/170654)
- [Booting 64-bit kernel on Raspberry Pi 3](http://www.tal.org/tutorials/booting-64-bit-kernel-raspberry-pi-3)
- [ディスクイメージのサイズを大きくする](https://qiita.com/takeoverjp/items/a4015a5440aea712889c)