Raspberry Pi2　Linuxカーネルのクロスコンパイル方法(仮想環境Ubuntu14.04による)

##目的
Raspberry Pi2のカーネルコンフィグの変更、デバイスドライバの作成などを予定しているため、
備忘録として記載します。
私は２箇所ぐらいハマりましたが、以下の手順に従えばハマらずに済むと思います。

##使用機器および知識
　・OS X El Capitan 10.11.4(Mac)
　・[VirtualBox](https://www.virtualbox.org/wiki/Downloads)(5.0.16)
　・Ubuntu14.04(32bit、isoファイル)
　・Raspberry Pi2 Model B
　・microSD(既に[RASPBIAN JESSIE](https://www.raspberrypi.org/downloads/raspbian/)がインストールされている状態)
　・[Disk Arbitrator](https://github.com/aburgh/Disk-Arbitrator/releases)(Mac上のmicroSDオートマウントを阻止するツール)
　・ターミナル上のコマンド操作

##前提知識：クロスコンパイルの必要性
クロスコンパイルを行う理由は、Linuxカーネルのビルド時間を短縮するためです。
貧弱な環境(Raspberry Pi2)でLinuxカーネルをビルドする場合は終了までに何時間もかかりますが、
Mac(Windows)のような高性能なCPUを搭載した環境でビルドする場合は数十分で終了します。
しかし、単純にMacでビルドしたカーネルは、Raspberry Pi上で動作しません。
その理由は、Macの環境(CPU)で動作する事を前提として、ビルドが行われているからです。

そこで、TOOL-CHAINを用いたクロスコンパイルによって、
Mac(Ubuntu)でRaspberry Pi2環境(CPU)向けのカーネルを作成します。

##仮想環境の準備
クロスコンパイルには、bash(シェル)が必要です。
Macにはbashが存在しますが、私の環境ではクロスコンパイル中にエラーが発生しました。
そのため、代用としてUbuntu(14.04、32bit)を仮想環境上に導入します。

　1）Mac版の[VirtualBox](https://www.virtualbox.org/wiki/Downloads)をダウンロード
　2）VitualBoxをインストール
　3）[Ubuntu14.04(32bit)](https://www.ubuntulinux.jp/download/ja-remix)のisoファイルをダウンロード
　4）VirtualBoxを利用して、UbunutuをMacに導入([参考サイト](http://prog.quarklink.org/linux/virtualbox/))
　5）Ubuntuの画面サイズ設定を変更(変更しない場合、解像度640×480で固定。[参考サイト](http://mogi2fruits.net/blog/os-software/windows/2389/))
　6）UbuntuとMacの間で、ファイル交換が可能な状態に変更([参考サイト](http://giraffydev.hatenablog.com/entry/mount-virtualbox-ubuntu-osx-folder))
　7）以下のコマンドを入力し、/home/username以下のファイル名を日本語から英語に変更　
　　　例）デスクトップ(日本語)　>　Desktop(英語)

```
$ $ LANG=C xdg-user-dirs-gtk-update
```

最後の7）は、単純にパス指定中に英語・日本語の入力切替を行うのが面倒なだけでなく、
ビルドに失敗しないようにするためです。
以前、私は2byte文字(日本語)のせいで、ビルドにコケた事がありました(別のボードですが)。

##クロスコンパイル環境の作成、クロスコンパイルの実行
この節の操作は、全てUbuntu(仮想環境)で行います。

まず、vim(エディタ)とgit(バージョン管理システム)をインストールします。
vimは必須ではありませんが、viより操作しやすいため、このタイミングで導入します。
余談ですが、gitは[「Linus Torvalds(Linuxの産みの親)が約2週間で作成」](https://jp.linux.com/news/linuxcom-exclusive/428524-lco2015041401)したらしい。素晴らしい。

```
$ sudo apt-get install vim
$ sudo apt-get install git
```

続いて、TOOL-CHAINをgitからインストールします。
一連のファイルは、ユーザのホームディレクトリ以下のtools(/home/username/tools)に格納されます。

```
$ cd ~/
$ git clone https://github.com/raspberrypi/tools
```

TOOL-CHAINを使用する際に長いパスを記述するのは面倒なため、環境変数を設定します。
以下のコマンドを入力し、.bashrc(bashの設定ファイル)の末尾に２つのPATHを追加します。

```
$ vi ~/.bashrc

追加するPATH
PATH="$PATH":~/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian
PATH="$PATH":~/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/bin
```
![スクリーンショット 2016-04-16 18.52.14.png](https://qiita-image-store.s3.amazonaws.com/0/99011/b56ee1fa-f1f5-7c4e-41c7-f77b484972ed.png)


続いて、gitからLinuxカーネルのソースを取得します。
Desktop直下にLinuxコードをクローンします。

```
$ cd ~/Desktop
$ git clone --depth=1 https://github.com/raspberrypi/linux
```

linuxディレクトリに移動し、Raspberry Pi2用のkernel7.imgを指定します。
その後、Raspberry Pi2用のコンフィグファイル(.config)を作成します。
ここでのBCM2709は正しい[SOC(System on a Chip)](http://e-words.jp/w/SoC.html)を指定していませんが、
公式サイト通りなので、気にしない事にします(Raspberry Pi2のSOCは、BCM2836)。

```
$ cd /home/username/Desktop/linux
$ KERNEL=kernel7
$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- bcm2709_defconfig
```

自分好みにカーネルコンフィグを設定します(画像はコンフィグ画面)。
今回、私は"Power Management options > Suspend to RAM and standby"を有効化しました。
(私は変えたいコンフィグ設定が見つけられない事が多いです。恐らく、探し方があるのでしょうね)

```
$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
```
![スクリーンショット 2016-04-16 19.31.56.png](https://qiita-image-store.s3.amazonaws.com/0/99011/6c4623ee-7513-3d26-0402-65c669e26235.png)

最後に、以下のコマンドでクロスコンパイルを行います。
30分以上はかかりますので、技術書や漫画を読むなり、ゲームするなり、掃除するなり、暇を潰しましょう。

```
$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- zImage modules dtbs
```

ちなみに、64bit版Ubuntuを使用した方は、このタイミングでビルド失敗します(使用するgccが異なるため)。
PATHを以下のように変更すれば、ビルドが通る筈(私は未検証。公式と別の方の報告では成功してます)。

```
PATH="$PATH":~/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64
PATH="$PATH":~/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin
```

##microSDに作成したファイル(zImageやモジュール)をインストール
既にmicroSDにはRASPBIAN JESSIEがインストールされている状態と仮定します。

まず、Macに差し込んだmicroSDをUbuntu(仮想環境)に認識させます。
microSDのマウント情報が欲しいので、`mount`をMacのターミナル上で入力します。
今回は、各パーティションが以下のように割り当てられている事が分かりました。

```
/dev/disk2s6 on /Volumes/boot (msdos, local, nodev, nosuid, noowners)
/dev/disk2s1 on /Volumes/RECOVERY (msdos, local, nodev, nosuid, noowners)
```

この２つのパーティションをアンマウントします。

```
$ sudo umount /dev/disk2s6
$ sudo umount /dev/disk2s1
//もしくは
$ sudo diskutil umountDisk /dev/disk2
```

次に、VirtualBox vmdkファイル(./sd-card.vmdk)を作成します。
コマンド末尾の"/dev/disk2"は、環境に合わせて変更します。
例えば、マウント情報が"/dev/disk1s1"ならば、"/dev/disk1"と変更します。

```
$ sudo VBoxManage internalcommands createrawvmdk -filename ./sd-card.vmdk -rawdisk /dev/disk2
```

"./sd-card.vmdk"と"/dev/disk2"のパーミッション(権限)を
書き込み、読み込み、実行可能状態に変更します。念のため、所有者情報も変更します。
(このパーミッション変更、Macを再起動する度に必要です。面倒)

```
$ sudo chmod 777 /dev/disk2
$ sudo chmod 777 ./sd-card.vmdk
$ sudo chown username /dev/disk2
$ sudo chown username ./sd-card.vmdk

// usernameは適宜、置き換えなければなりません。
```

Ubuntuの電源を落として、Oracle VM Virtualマネージャ(VirtualBoxを起動した直後の画面)を
開いた状態にします。
そこから、「設定(①) > ストレージ(②) > ハードディスクの追加(③)」を選択し、
「既存のディスクの選択」を選択します。その後"sd-card.vmdk"を「コントローラ：SATA」に追加します。
私はこのタイミングで「Resource busy」というエラーが出ましたが、
原因はmicroSDが再びマウントされていたからでした。アンマウントすれば、追加できる筈です。
![修正.png](https://qiita-image-store.s3.amazonaws.com/0/99011/6fd8cd66-7e27-88bb-3366-58a3c30fdabd.png)


Ubuntuを起動し、Ubuntuターミナル上で`lsblk`コマンドを入力すると、microSD情報が確認できます。
ここで、Ubuntuが起動できなければ、Mac側でmicroSDのマウント状況を確認してください。
アンマウントをしてからUbuntuを起動しても失敗する場合(再びマウントされてしまう場合)、
Disk Arbitratorによって再マウントをブロックします。
Disk Arbitratorの右下にあるModeを"Block mounts"に設定した状態で、
disk2s1(Device欄)を選択した後、unmountボタンをクリックします。disk2s6にも同じ操作をします。
(/etc/fstabを編集してオートマウントを防ぐ事は、El Capitanではできません)
![スクリーンショット 2016-04-17 0.16.45.png](https://qiita-image-store.s3.amazonaws.com/0/99011/95ea3523-b440-2b27-a442-a8fde607dffb.png)






Ubunutuが無事に起動できれば、Ubuntuターミナル上でmicroSDをマウントします。

```
mkdir mnt/fat32
mkdir mnt/ext4
sudo mount /dev/sdb1 mnt/fat32
sudo mount /dev/sdb2 mnt/ext4
```

モジュールをインストールします。

```
sudo make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- INSTALL_MOD_PATH=mnt/ext4 modules_install
```

Device Treeをインストールし、古いカーネルの情報をバックアップします。
最後にmicroSDをアンマウントしたら、実機で動作確認を行います。

```
sudo cp mnt/fat32/$KERNEL.img mnt/fat32/$KERNEL-backup.img
sudo scripts/mkknlimg arch/arm/boot/zImage mnt/fat32/$KERNEL.img
sudo cp arch/arm/boot/dts/*.dtb mnt/fat32/
sudo cp arch/arm/boot/dts/overlays/*.dtb* mnt/fat32/overlays/
sudo cp arch/arm/boot/dts/overlays/README mnt/fat32/overlays/
sudo umount mnt/fat32
sudo umount mnt/ext4
```
以上で、作業は終了です。


##参考
[KERNEL BUILDING(Raspberry Piの公式ヘルプ)](https://www.raspberrypi.org/documentation/linux/kernel/building.md)