コアダンプの数だけ強くなれるよ

見習いエンジニアの備忘log

Linuxのカーネルモジュールを作って遊んでみる

今回はLinuxのカーネルモジュール(例えばデバイスドライバ)のプログラミングにトライします。

まず今回はHello World的プログラムを作り、次回は/procファイルシステムへのアクセスなど色々試して遊んでみたいと思います。

環境はLinux(CentOS 7)(64bit)です。

カーネルモジュールとは


カーネル・モジュールはLinuxのユーザー空間ではなくカーネル空間で動作するプログラムの事です。

例としてデバイスドライバと呼ばれるものはカーネルモジュールの1つのです。

ユーザー空間のアプリケーションのプログラミングとは少々お作法が事なります。

[参考]
itpro.nikkeibp.co.jp


まずはHello World


どんなプログラミングでも最初はやはりHello Worldを試すのが一般的ですので今回も例にもれずやっていきます。

事前にカーネルモジュールのプログラミングに必要なものをインストールします。

# カーネルモジュール開発に必要なパッケージをインストール
[user@localhost ~]$ sudo yum install kernel-devel
[user@localhost ~]$ sudo yum install kernel-headers


# インストール後の確認
# devel, heeadersがインストールされていればOKです。
[user@localhost ~]$ rpm -aq|grep kernel
kernel-tools-libs-3.10.0-514.26.2.el7.x86_64
kernel-tools-3.10.0-514.26.2.el7.x86_64
kernel-3.10.0-327.el7.x86_64
kernel-3.10.0-514.26.2.el7.x86_64
kernel-headers-3.10.0-693.5.2.el7.x86_64
kernel-devel-3.10.0-514.26.2.el7.x86_64  
kernel-devel-3.10.0-693.5.2.el7.x86_64


準備が整ったらdmesgにHello Worldのログを出力するmymod.cとビルドするためのMakefileを作ります。

mymod.c

#include <linux/module.h>
#include <linux/init.h>

/* お約束的な宣言 */
MODULE_LICENSE("GPL");

/* insmod実行時に呼び出される */
static int mymod_init(void)
{
    printk(KERN_INFO "Hello World\n");
    return 0;
}

/* rmmod実行時に呼び出される */
static void mymod_exit(void)
{
    printk(KERN_INFO "Goodbye World\n");
}

/* 関数の登録 */
module_init(mymod_init);
module_exit(mymod_exit);


Makefile

obj-m := mymod.o

all:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean



makeを実行するとビルドが開始されます。ビルド後の出来上がった*.koのファイルがカーネルモジュールです。

[user@localhost driver]$ ls
Makefile  mymod.c


[user@localhost driver]$ make
make -C /lib/modules/3.10.0-514.26.2.el7.x86_64/build M=/home/user/driver modules
make[1]: Entering directory `/usr/src/kernels/3.10.0-514.26.2.el7.x86_64'
  CC [M]  /home/user/driver/mymod.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /home/user/driver/mymod.mod.o
  LD [M]  /home/user/driver/mymod.ko
make[1]: Leaving directory `/usr/src/kernels/3.10.0-514.26.2.el7.x86_64'


[user@localhost driver]$ ls -lrt
total 204
-rw-rw-r--. 1 user user   156 Nov  2 23:00 Makefile
-rw-rw-r--. 1 user user   787 Nov  2 23:01 mymod.mod.c
-rw-rw-r--. 1 user user     0 Nov  2 23:01 Module.symvers
-rw-rw-r--. 1 user user 52864 Nov  2 23:01 mymod.mod.o
-rw-rw-r--. 1 user user   422 Nov  2 23:03 mymod.c
-rw-rw-r--. 1 user user 44400 Nov  2 23:04 mymod.o
-rw-rw-r--. 1 user user    34 Nov  2 23:04 modules.order
-rw-rw-r--. 1 user user 94184 Nov  2 23:04 mymod.ko ★これがカーネルモジュール


実行結果


カーネルモジュールが出来上がったので実際にロードしてみます。

insmodコマンドでカーネルにモジュールをロード、lsmodでロード中のモジュールを確認できます。

[user@localhost driver]$ sudo insmod mymod.ko


[user@localhost driver]$ lsmod |grep mymod
mymod                  12496  0



[user@localhost driver]$ dmesg |tail
[ 1121.612492] mymod: loading out-of-tree module taints kernel.
[ 1121.612524] mymod: module verification failed: signature and/or required key missing - tainting kernel
[ 1121.612713] Hello World



カーネルモジュールのロードとdmesgにHello Worldが出力されていることが確認できました。

今度はrmmodでモジュールをアンロードしてみます。

[user@localhost driver]$ sudo rmmod mymod


[user@localhost driver]$ lsmod |grep mymod
[user@localhost driver]$


[user@localhost driver]$ dmesg |tail
[ 1121.612492] mymod: loading out-of-tree module taints kernel.
[ 1121.612524] mymod: module verification failed: signature and/or required key missing - tainting kernel
[ 1121.612713] Hello World
[ 1179.087241] Goodbye World



こちらも期待通りdmesgにメッセージが出力されていますね。

次回はもう少し実用的なプログラムを作ってみます。