helloを出力するだけの簡単なカーネルモジュールを作成してみる。
環境の作成
gccなど既に入っているのであればここは不要である。
クリーンな環境を想定するので以下のdockerコンテナで作業する。
$ docker run --rm -i -v /lib/modules:/lib/modules \
-v /usr/src/kernels/:/usr/src/kernels/ \
-v /tmp/hello:/tmp/hello \
-t centos:centos7 /bin/bash
# chmod 777 /tmp/hello
# cd /tmp/hello
- 説明
- 終了後削除されるコンテナを作成する(--rm)
- ビルドに必要なデータをコンテナに渡す(-v)
- コンテナではkmod(insmod,rmmod)が入らないのでホストへ受け渡し用にtmpを渡す
- 権限を変えてしまうのは行儀が良くないが面倒なので気にしない
ビルドに必要なものをインストールする
ダウンロードとインストールに少々時間がかかるが、一行で済む。
# yum groupinstall "Development Tools" -y
- 説明
- 特になし。
ソースの作成
ここが本題。
hello.cとMakefileを作成する。
注意点としてはMakefileのインデントはTABなので下のをそのままコピペすると
Makefile:7: *** missing separator (did you mean TAB instead of 8 spaces?). Stop.
となる。
# useradd ymko
# su - ymko
$ cd /tmp/hello
$ ls
Makefile hello.c
#include <linux/module.h>
#include <linux/kernel.h>
static int __init hello_init( void )
{
printk( KERN_INFO "hello module insmod\n" );
return 0;
}
static void __exit hello_exit( void )
{
printk( KERN_INFO "hello module rmmod\n" );
}
module_init( hello_init );
module_exit( hello_exit );
MODULE_DESCRIPTION( "hello world!" );
MODULE_LICENSE( "MIT" );
obj-m := hello.o
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
VERBOSE = 0
default:
$(MAKE) -C $(KDIR) M=$(PWD) KBUILD_VERBOSE=$(VERBOSE) modules
clean:
rm -f *.o *.ko *.mod.c
make
makeである。
$ make
make -C /lib/modules/3.10.0-327.28.2.el7.x86_64/build M=/tmp/hello KBUILD_VERBOSE=0 modules
make[1]: Entering directory `/usr/src/kernels/3.10.0-327.28.2.el7.x86_64'
CC [M] /tmp/hello/hello.o
Building modules, stage 2.
MODPOST 1 modules
CC /tmp/hello/hello.mod.o
LD [M] /tmp/hello/hello.ko
make[1]: Leaving directory `/usr/src/kernels/3.10.0-327.28.2.el7.x86_64'
モジュールのロード・アンロード
ホスト側のroot権限で実行する。
なおコンテナではkmodがないのでinsmod,rmmodがない。kmodをインストールしようとうするとsystemdと衝突して入らない。
# cd /tmp/hello
# insmod hello.ko
# rmmod hello.ko
# dmesg | tail
[292475.726061] hello module insmod
[292488.733643] hello module rmmod
トラブルシュート
-
Makefile:7: *** missing separator (did you mean TAB instead of 8 spaces?). Stop.
- Makefileのインデントがタブじゃない。
-
make: *** /lib/modules/3.10.0-327.28.2.el7.x86_64/build: No such file or directory. Stop.
- /lib/modules/3.10.0-327.28.2.el7.x86_64/buildがない。
- リンクが切れている場合はkernel-develがない。
- ".config"がない。/boot/config-*をコピーしてmake oldconfig、make prepareをしないといけない
参考
Building External Modules(公式ドキュメント)
https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/tree/Documentation/kbuild/modules.txt
Building a custom kernel - FedoraProject
https://fedoraproject.org/wiki/Building_a_custom_kernel?rd=Docs/CustomKernel
HowTos/BuildingKernelModules - CentOS Wiki
https://wiki.centos.org/HowTos/BuildingKernelModules
カーネルモジュール作成メモ
http://www.hakodate-ct.ac.jp/~tokai/tokai/research/kmod.html
[Linux][kernel module] 簡単なローダブルカーネルモジュールのビルドとロード
http://qiita.com/koara-local/items/39002cc1f611e26114f8
SUBDIRS variable in kernel module makefile - Stack Overflow
http://stackoverflow.com/questions/21129224/subdirs-variable-in-kernel-module-makefile
Same as M=. The SUBDIRS= syntax is kept for backwards compatibility.
M =と同じです。SUBDIRS =構文は下位互換性のために保持されています。