Edited at

Raspberry Pi Zero用のカーネルをクロスコンパイルし、ドライバモジュールを作成する

More than 1 year has passed since last update.

Raspberry Pi Zeroを5GHzの無線LANに参加させたいのですが、2015/11/21にリリースされたJessieだと、手持ちのWifiアダプタGW-450Sは使用できませんでした。githubにあるドライバ (https://github.com/gnab/rtl8812au) をカーネルモジュールとしてコンパイルする必要があるようです。

本稿では、他のマシンでRaspberry Pi Zero用のカーネルをクロスコンパイルする手順と、今回のGW-450Sを例に外部ドライバをカーネルモジュールとして導入する手順を紹介したいと思います。

※カーネルのコンパイルをRaspberry Pi Zeroでも行えますが、Raspberry Pi Zeroのカーネルイメージにデフォルトで使われている.configを用いたところ、14時間かかりました。。。作成モジュールが相当多いため、時間がかかるようです。


2017/2追記

Raspberry Pi Zero上で同一バージョンのカーネルソースを取得し、モジュールのみコンパイル、という方法で短時間で達成できます。

参考

https://www.max2play.com/en/forums/topic/howto-raspberry-pi-3-realtek-802-11ac-rtl8812au/

こちらの方がオススメです。


環境はUbuntu 14.04 LTSです。以下、64bitマシンで作業する前提で記述します。


カーネルのクロスコンパイル

「石を売る」さんの「Raspberry Pi2のカーネルの再構築とGW-450Dを使えるようにする。」を参考にさせていただきました。


作業フォルダの作成

$ mkdir -p $HOME/src/Raspberry_Pi_Zero

$ cd $HOME/src/Raspberry_Pi_Zero


必要なパッケージのインストール

たまたまIntel Edisonのカーネルビルドも行っていたので、インストールが必要なパッケージはありませんでしたが、以下のパッケージが必要になります。

$ sudo aptitude install build-essential git openssh-server ncurses-dev


toolchainとkernel sourceのダウンロード

クロスコンパイルに必要なツールと、Raspberry Piのカーネルソースをダウンロードします。

$ git clone --depth=1 git://github.com/raspberrypi/tools.git

$ git clone --depth=1 git://github.com/raspberrypi/linux.git


環境変数の設定

$ ls tools/arm-bcm2708

$ export PATH=`pwd`/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin:$PATH
$ export ARCH=arm
$ export CROSS_COMPILE=arm-linux-gnueabihf-

クロスコンパイラが使えるか確認します。

$ arm-linux-gnueabihf-gcc -v


Raspberry Pi Zeroより.config取得

Raspberry Pi Zeroから取得します。

$ cd linux

$ ssh pi@(Raspberry Pi Zeroのアドレス) 'sudo modprobe configs'
$ ssh pi@(Raspberry Pi Zeroのアドレス) 'zcat /proc/config.gz' > config-pizero
$ mv config-pizero .config


カーネルに命名

Makefile内の EXTRAVERSION を指定すると、カーネル名の後ろに名前がつけられます。今回は mod としました。カーネルのバージョンが4.1.15だったので、4.1.15-modになります。(後でカーネル名やフォルダ名としてまた出てきます)

$ vim Makefile

EXTRAVERSION = -mod


menuconfigの実行

別途、使用したいデバイス等があれば設定します。menuconfigのお作法に倣って設定、保存をしてください。

$ make menuconfig


カーネルのビルド

$ make -j 4

-jの後の数字はCPUコア数に応じて変えます。2倍程度が一般的です。

Core2 Duo T7600(2.33GHz)のデュアルコアなマシンで30分弱で終わりました。


モジュールとカーネルをまとめる

$ cat include/config/kernel.release

4.1.15-mod+
$ export KERNEL_RELEASE=`cat include/config/kernel.release`
$ export INSTALL_MOD_PATH=../$KERNEL_RELEASE
$ mkdir -p $INSTALL_MOD_PATH
$ mkdir -p ../$KERNEL_RELEASE/boot
$ make modules
$ make modules_install
$ cp arch/arm/boot/Image ../$KERNEL_RELEASE/boot/kernel-$KERNEL_RELEASE.img
$ cd ..


Raspberry Pi Zeroで一度動作確認

出来上がったカーネルが動作するか確認します。

$ cd $KERNEL_RELEASE

$ tar zcvf $KERNEL_RELEASE.tar.gz boot lib
$ scp $KERNEL_RELEASE.tar.gz pi@(Raspberry Pi ZeroのIPアドレス):/home/pi/
$ ssh pi@(Raspberry Pi ZeroのIPアドレス)

ログイン後

$ sudo tar zxC / -f 4.1.15-mod+.tar.gz

$ ls /boot
(今回作成したkernel-4.1.15-mod+.imgがあることを確認)

$ sudo vim /boot/config.txt
末尾に以下を追加
kernel=kernel-4.1.15-mod+.img

Raspberry Pi Zeroを再起動します。uname -aで今回設定したカーネル名が表示されるか確認してください。

起動に失敗した場合、SDカードを取り出して、先ほどのconfig.txtを元に戻せば修正前の状態で起動できます。


rtl8812モジュールのビルド

前項の「カーネルのクロスコンパイル」を実施済みが前提になります。このパートのみ再度行う場合は、前項中にある「環境変数の設定」を実施して、クロスコンパイラが使用できる状態にしてください。

githubにあるドライバのページ(https://github.com/gnab/rtl8812au) にある手順に従います。


ドライバソースのダウンロード

$ cd $HOME/src/Raspberry_Pi_Zero

$ git clone https://github.com/gnab/rtl8812au


設定の変更

$ vim Makefile

ターゲットをI386_PCからARM_RPIに変更します。

(変更前)

CONFIG_PLATFORM_I386_PC = y
...
CONFIG_PLATFORM_ARM_RPI = n

(変更後)
CONFIG_PLATFORM_I386_PC = n
...
CONFIG_PLATFORM_ARM_RPI = y

続いて、クロスコンパイラ(CROSS_COMPILE)、カーネルバージョン(KVER)とこれに付随して指定されるディレクトリ(KSRC, MODDESTDIR)を変更します。ディレクトリは絶対参照から相対参照に切り替えています。

カーネルバージョンは「4.1.15-mod+」を決め打ちしていますので、適宜変更してください。(以後も登場します)

(変更前)

ifeq ($(CONFIG_PLATFORM_ARM_RPI), y)
EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
ARCH := arm
CROSS_COMPILE :=
KVER := $(shell uname -r)
KSRC ?= /lib/modules/$(KVER)/build
MODDESTDIR := /lib/modules/$(KVER)/kernel/drivers/net/wireless/
endif

(変更後)
ifeq ($(CONFIG_PLATFORM_ARM_RPI), y)
EXTRA_CFLAGS += -DCONFIG_LITTLE_ENDIAN
ARCH := arm
CROSS_COMPILE := arm-linux-gnueabihf-
KVER := 4.1.15-mod+
KSRC := ../$(KVER)/lib/modules/$(KVER)/build
MODDESTDIR := ../$(KVER)/lib/modules/$(KVER)/kernel/drivers/net/wireless/
endif


ドライバモジュールのビルド

$ make


ドライバのコピー

$ cp 8812au.ko ../4.1.15-mod+/lib/modules/4.1.15-mod+/kernel/drivers/net/wireless


Raspberry Pi Zeroへの転送

前項「Raspberry Pi Zero側で一度動作確認」を実施して、カーネルイメージを再送、再起動してください。


再起動後

$ sudo depmod

このあと、GW-450SをUSBポートに刺すと無事使えるようになるはずです。


おまけ


カーネルコンパイルをRaspberry Pi Zero上で行いたい場合

いばらの道です。

$ cd $HOME

$ bash -c "$(curl -fsSSL https://raw.githubusercontent.com/moutend/raspi-kernel/master/raspi-kernel)"
$ cd /usr/src/linux-...
$ sudo modprobe configs
$ zcat /proc/config.gz > .config
$ time make

real 742m7.551s
user 700m51.830s
sys 29m42.700s

$ make modules
$ make modules_install


現在使用中のカーネルからconfigを取得

configを取得できるカーネルコンフィグがあることを初めて知りました。

CONFIG_IKCONFIG=m

CONFIG_IKCONFIG_PROC=y

このオプションが組み込まれたカーネルで、以下を実行します。

$ sudo modprobe configs

$ zcat /proc/config.gz > .config


Todo

最初のインストールイメージに対して更新したい。

PiTFTの変更を反映したい(本稿で作成するGW-450S等のモジュールと一緒に用いたい)