RaspbianのLinuxカーネルをビルドしてインストールする

RaspbianのLinuxカーネルをビルドしてインストールする手順です。

手順は
https://www.raspberrypi.org/documentation/linux/kernel/building.md
を見れば書いてあります。

以下は、Raspberry Pi Zero Wの場合の例です。

# カーネルソースをダウンロード

raspbianで使っているカーネルのソースコードはgithubにあり、リリース時のタグが打ってあります。
執筆時点の最新版はraspberrypi-kernel_1.20180417-1です。

```
wget https://github.com/raspberrypi/linux/archive/raspberrypi-kernel_1.20180417-1.tar.gz
tar xf raspberrypi-kernel_1.20180417-1.tar.gz
```

#　ビルドの準備

パッケージをインストール

```
sudo apt-get install build-essential bc git bison flex
```

クロスコンパイラをインストール

```
git clone https://github.com/raspberrypi/tools
```

クロスコンパイラにパスを通す。

```
export PATH=$PATH:/vagrant/tools/arm-bcm2708/arm-rpi-4.9.3-linux-gnueabihf/bin
```
# vagrant のワークアラウンド

自分はvagrantを使っている。vagrantだとmmapが動かないせいでエラーが起きるので、scripts/link-vmlinux.shに修正を行う

```
sortextable()
{
        ${objtree}/scripts/sortextable ${1}        
}
```
を

```
sortextable()
{
    cp ${1} /tmp/.${1}
    scripts/sortextable /tmp/.${1}
    cp /tmp/.${1} ${1}
}
```
にする。

# カーネルのビルド

.configの生成

```
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- bcmrpi_defconfig
```

カーネルとモジュールとDTBをビルド

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

#インストール

以下のスクリプトをカーネルのディレクトリで実行する。

```
set -x
export KERNEL_RELEASE=`cat include/config/kernel.release`
export INSTALL_MOD_PATH=../$KERNEL_RELEASE
mkdir -p ../$KERNEL_RELEASE/boot/overlays
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf-  modules_install
scripts/mkknlimg arch/arm/boot/zImage ../$KERNEL_RELEASE/boot/kernel.img
cp arch/arm/boot/dts/*.dtb ../$KERNEL_RELEASE/boot/
cp arch/arm/boot/dts/overlays/*.dtbo ../$KERNEL_RELEASE/boot/overlays/
cd ..
tar cvjf $KERNEL_RELEASE.tar.bz2 $KERNEL_RELEASE/
```

ひとつ上のディレクトリに4.14.34.tar.bz2 のようなファイルができています。

このファイルをraspberry piに転送してから、コピーします。

```
cd /tmp
tar xf 4.14.34.tar.bz2 
sudo cp -a 4.1.34/boot 4.1.34/lib /
```

コピーする前に、/bootはバックアップしといた方が良いです。

カーネルだけ変更したい場合は、/boot/kernel.imgだけ変更してください。

# mkknlimg

* raspbianではmkknlimgを使ってkernel.imgの最後にデータを埋め込みます。
* 埋め込まれるデータはこんな感じです。zImageが埋め込み前、kernel.imgが埋め込み後です。

```
$ ls -l linux-raspberrypi-kernel_1.20180417-1/arch/arm/boot/zImage 4.14.34/boot/kernel.img 
-rw-rw-r-- 1 vagrant vagrant 4676776 Jul  2 15:54 4.14.34/boot/kernel.img
-rwxrwxr-x 1 vagrant vagrant 4676544 Jul  2 11:17 linux-raspberrypi-kernel_1.20180417-1/arch/arm/boot/zImage
$ cmp linux-raspberrypi-kernel_1.20180417-1/arch/arm/boot/zImage 4.14.34/boot/kernel.img 
cmp: EOF on linux-raspberrypi-kernel_1.20180417-1/arch/arm/boot/zImage
$ hexdump -C   linux-raspberrypi-kernel_1.20180417-1/arch/arm/boot/zImage |tail -n 10
00475b30  ac 61 f5 ad e4 80 f9 3d  57 bb f2 76 1e af b8 47  |.a.....=W..v...G|
00475b40  cc df 7e a6 67 89 f9 bd  58 ce 7d 62 9e cf ef 50  |..~.g...X.}b...P|
00475b50  e6 6f fd 9c ca ed dc 97  54 f6 f2 bb 2d e5 5f d8  |.o......T...-._.|
00475b60  db 6e a5 73 30 cf 2d 71  5e ba 95 4a 5b 0b b4 df  |.n.s0.-q^..J[...|
00475b70  e6 4a 55 0e ef 66 30 fc  1f 82 cc bd d1 5c 66 9c  |.JU..f0......\f.|
00475b80  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00475b90  c0 5b 47 00 81 5b 47 00  d8 5b 47 00 3c 46 00 00  |.[G..[G..[G.<F..|
00475ba0  d4 5b 47 00 c4 5b 47 00  c0 08 00 00 cc 5b 47 00  |.[G..[G......[G.|
00475bb0  d0 5b 47 00 c8 5b 47 00  00 00 00 00 00 00 00 00  |.[G..[G.........|
00475bc0
$ hexdump -C  4.14.34/boot/kernel.img  |tail -n 20
00475b80  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00475b90  c0 5b 47 00 81 5b 47 00  d8 5b 47 00 3c 46 00 00  |.[G..[G..[G.<F..|
00475ba0  d4 5b 47 00 c4 5b 47 00  c0 08 00 00 cc 5b 47 00  |.[G..[G......[G.|
00475bb0  d0 5b 47 00 c8 5b 47 00  00 00 00 00 00 00 00 00  |.[G..[G.........|
00475bc0  00 00 00 00 00 00 00 00  00 00 00 00 04 00 00 00  |................|
00475bd0  32 38 33 78 01 00 00 00  04 00 00 00 32 38 33 58  |283x........283X|
00475be0  01 00 00 00 04 00 00 00  32 37 30 58 01 00 00 00  |........270X....|
00475bf0  04 00 00 00 44 44 54 4b  01 00 00 00 04 00 00 00  |....DDTK........|
00475c00  44 54 4f 4b 4c 69 6e 75  78 20 76 65 72 73 69 6f  |DTOKLinux versio|
00475c10  6e 20 34 2e 31 34 2e 33  34 20 28 76 61 67 72 61  |n 4.14.34 (vagra|
00475c20  6e 74 40 75 62 75 6e 74  75 2d 62 69 6f 6e 69 63  |nt@ubuntu-bionic|
00475c30  29 20 28 67 63 63 20 76  65 72 73 69 6f 6e 20 34  |) (gcc version 4|
00475c40  2e 39 2e 33 20 28 63 72  6f 73 73 74 6f 6f 6c 2d  |.9.3 (crosstool-|
00475c50  4e 47 20 63 72 6f 73 73  74 6f 6f 6c 2d 6e 67 2d  |NG crosstool-ng-|
00475c60  31 2e 32 32 2e 30 2d 38  38 2d 67 38 34 36 30 36  |1.22.0-88-g84606|
00475c70  31 31 29 29 20 23 38 20  4d 6f 6e 20 4a 75 6c 20  |11)) #8 Mon Jul |
00475c80  32 20 30 32 3a 30 38 3a  31 30 20 55 54 43 20 32  |2 02:08:10 UTC 2|
00475c90  30 31 38 00 8f 00 00 00  4b 56 65 72 e8 00 00 00  |018.....KVer....|
00475ca0  04 00 00 00 52 50 54 4c                           |....RPTL|
```
* [Raspberry Pi 2 カーネル4.0.7のクロスコンパイルメモ](http://nokute.hatenablog.com/entry/2015/07/08/235005) によるとこのデータはDeviceTreeの判別に使うらしいです。
* GPUで動いているブートローダーが、これをみてDTBをRAMにロードしているっぽいです。GPUで動いているブートローダのelfファイルにそれらしい文字列が含まれてました。

```
$ strings start.elf |grep DTOK
DTOK
Kernel trailer DTOK property says %s
```

# todo
* version文字列を配布されたイメージと同じにして、カーネルだけ置き換えた時に、モジュールを読み込めるか、確認する。
* 「raspberry piに転送してから、コピー」ではなく、イメージファイルを直接書き換える方法を調べる。

# 参考
* https://www.raspberrypi.org/documentation/linux/kernel/building.md
* [Raspberry Pi 2のカーネルをビルドしてみた](http://d.hatena.ne.jp/embedded/20150923/p1)