Kernel Moduleの作成方法(公式ドキュメントのメモ)

ここの内容のメモ。このページは、Kernelに組み込まれていないモジュールの作成方法を記している。主に、動的な(カーネルビルド時に組み込まれていない)モジュールをビルドしようとしている開発者向けのものとなっている。以降、KBUILDという言葉が何度かでてくるが、これはLinux Kernelのビルドシステムのことである。基本的には、このKBUILDの力をたくさん借りて、モジュールをビルドすることになる。

まず、モジュールのビルドに必須のものは、①ビルドされたカーネル、②そのカーネルをビルドする時に使用されたコンフィギュレーションとヘッダツリー、の2つである。これらが用意されているかどうかの確認は、以下のコマンドを実行すればいいらしい(よく分かってない)。

$ make -C <path_to_kernel_src> M=`pwd` modules_prepare

ビルドは以下のようなコマンドで行う。makeコマンドの-Cオプションは、コマンドの実行前に移動する先のディレクトリを指定する。Mは、ビルドした完成物を保存する前に移動する先のディレクトリを指定する。つまり、カーネルソースの方のディレクトリに移動して、そこでのMakefileを実行し戻ってくる、というようなことをしている。

$ make -C <path_to_kernel_src> M=$PWD

KBUILDシステムは、M=オプションがあることで、外部モジュールがビルドされていると認識する。特に、現在動いているカーネルで可動するモジュールをビルドする場合は、以下のコマンドを実行することになる。

$ make -C /lib/modules/`uname -r`/build M=$PWD

KBUILDシステムのmakeで使用できるtargetは以下のものがある。デフォルトターゲットはmodulesなので、モジュールのビルドにはターゲットの指定は必要ない。

  • modules モジュールのビルド。
  • modules_install モジュールのインストール。
  • clean ビルドで作成された全てのものの削除。
  • help 他のtargetに関する情報の出力。
現在稼働中のカーネルにインストールするモジュールをビルドする方法

ビルドするには、カレントディレクトリにMakefileを作る必要がある。最も簡易的なMakefileは以下の1文で構成される。

obj-m := <module_name>.o

この1行は、モジュールの名前を決めている。またここで指定された名前に関連するソースコードがモジュールの本体になるので、とても重要な1文になる。具体的な動作としては、まず、KBUILDシステムはカレントディレクトリにある<module_name>.cというファイルから<module_name>.oというファイルをコンパイルし、その後<module_name>.koというKOファイルがビルドされる、という流れだ。

具体的には、以下のような環境を作成すればビルドできる。

~/hoge$ tree
.
├── Makefile
└── fuga.c

0 directories, 2 files
~/hoge$ cat Makefile 
obj-m   := fuga.o
~/hoge$ cat fuga.c 
#include <linux/init.h>
#include <linux/module.h>
MODULE_AUTHOR("ru7h");
MODULE_LICENSE("Dual BSD/GPL");

static int test_init(void) { return 0; }
static void test_exit(void) { }

module_init(test_init);
module_exit(test_exit);
~/hoge$ make -C /lib/modules/`uname -r`/build M=$PWD

この方法は、ソースファイルが1つの場合にしか使えない。もし、複数のファイルに分けて開発をしたい場合、さらに以下の1行が必要になる。

<module_name>-y := <src1>.o <src2>.o ...

ソースコードが複数ある場合の具体例を以下に示す。カレントディレクトリには、fuga.cとpiyo.cがあって、これら2つを元にhoge.koというカーネルモジュールを作成する例である。

obj-m 	:= hoge.o
hoge-y := fuga.o piyo.o
$ ls
Makefile  fuga.c  piyo.c

このモジュールの依存関係についての記述は、Kbuildというファイルに記述することもできる。Kbuildシステムは、最初にKbuildというファイルを探し、なければMakefileを探すといった手続きをする。従って、Makefileの記述をべっこにして管理することも可能(この利点はいまいち分からなかった)。

includeに関して

モジュールのソースコードにおいて、ヘッダファイルをincludeする方法はいくつかある。

まず、同ディレクトリにある.hファイルは#include “*.h”のような感じでインクルードできる。Kernelのヘッダファイルは、#include <linux/init.h>のような感じでインクルードできる。これらの場合は、特に追加で指定する必要はない。

しかし、作業ディレクトリ内でヘッダファイルを分割して管理している場合、KBUILDシステムがそのファイルの居場所が分かるように、PATHを指定してあげる必要がある。例えば以下のようなディレクトリツリーで開発を行う場合、Makefileも以下のように追加記述する必要がある。(なお、このような構成の開発は非推奨らしい。)

.
├── Makefile
├── include
│   └── fuga.h
└── src
    ├── fuga.c
    └── piyo.c
obj-m 		:= hoge.o
hoge-y 		:= src/fuga.o src/piyo.o
# include pathの指定をしてあげる
# ビルドする時、カレントディレクトリが変更されるので、pathの指定には絶対パスを使用する。
# $(src)は絶対パスを指定するのに必要。
ccflags-y 	:= -I$(src)/include

コメント

タイトルとURLをコピーしました