カーネルモジュールを作成してみる

helloを出力するだけの簡単なカーネルモジュールを作成してみる。

# 環境の作成

gccなど既に入っているのであればここは不要である。
クリーンな環境を想定するので以下のdockerコンテナで作業する。

```txt
$ 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を渡す
	* 権限を変えてしまうのは行儀が良くないが面倒なので気にしない

# ビルドに必要なものをインストールする

ダウンロードとインストールに少々時間がかかるが、一行で済む。

```txt
# yum groupinstall "Development Tools" -y
```

* 説明
	* 特になし。

# ソースの作成

ここが本題。
hello.cとMakefileを作成する。
注意点としてはMakefileのインデントはTABなので下のをそのままコピペすると
Makefile:7: *** missing separator (did you mean TAB instead of 8 spaces?).  Stop.
となる。

```txt
# useradd ymko
# su - ymko
$ cd /tmp/hello
$ ls 
Makefile hello.c
```

```c: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" );
```

```txt:Makefile
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である。

```txt
$ 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と衝突して入らない。

```txt
# 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 =構文は下位互換性のために保持されています。