デバイスドライバのハローワールド
デバイスドライバと言うとなんだか物々しく聞こえて難しく感じてしまう。
でも実際のところ普通のプログラムとの違いとしては
1 デバイスドライバはカーネル空間で動作し、普通のプログラムはユーザ空間で動作する。
2 カーネルに用意されているデバイスドライバ用の仕組みに乗っかる必要がある
くらいのものだ。
普通のプログラムとは
test_hutuuu.c
#include <stdio.h> int main() { printf("はろーわーるど\n"); return 0; }
こんな簡単なので
gcc ./test_hutuuu.c
ビルドして
./a.out
実行すれば
はろーわーるど
と結果が出る。
ユーザ空間でプログラムを実行する場合は
「mainがエントリーポイント」
ということが決まっている。そういう仕組み。
さてさてデバイスドライバの簡単なコードは・・・
test_driver.c
#include <linux/init.h> #include <linux/module.h> //モジュール初期化関数 static int __init test_driver_init(void) { printk(KERN_DEBUG "ハローワールド\n"); return 0; } //モジュール終了関数 static void __exit test_driver_exit(void) { printk(KERN_DEBUG "ばいばい\n"); } module_init(test_driver_init); module_exit(test_driver_exit); MODULE_LICENSE("GPL2");
mainのハローワールドと比べると少し複雑。
ビルド用にmakefileをtest_driver.cと同じ階層に作って
makefile
obj-m := driverModule.o driverModule-objs := test_driver.o PWD := $(shell pwd) all: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules install: insmod driverModule.ko uninstall: rmmod driverModule.ko clean: rm -f *.o *.ko *.mod.c Module.* module* *~
※コピペする場合は先頭の空白は全てタブに置き換えてね。makefileの謎ルールなので
make
ビルドして
できあがったカーネルオブジェクト(*.ko)をカーネルにロード!とその前に・・・
新しい端末を起動しsyslogを表示する。ドライバではprintfではなくprintkを使うのでカーネルログを見る
sudo tail -f /var/log/syslog
(tailを使うと追記分も表示されるから便利)
sudo insmod driverModule.ko
準備ができた所でドライバをロード!
するとsyslogに
Sep 1 22:00:56 debian kernel: [ 1052.234220] ハローワールド
こんなメッセージが出るはず。ハローワールドを実行するにも一苦労だ!
デバイスドライバのハローワールドで特に重要なのは
・「module_init」でロード時のエントリーポイントを指定できる
・「module_exit」でアンロード時の後処理関数を指定できる
ということ。
//カーネルモジュールをロードしたときは // 初期化(init)処理でtest_driver_initを実行してね、とカーネルに通知 module_init(test_driver_init); //カーネルモジュールをアンロードしたときは // 後始末としてtest_driver_exitを実行してね、とカーネルに通知 module_exit(test_driver_exit);
module_initとmodule_exitを使用しない場合でも、実はビルドもロードも普通にできる。でもそんなことをするとロードされたことをドライバは検知できないから、ただメモリ上に存在するだけで何もしないプログラムになってまう・・・。何の役にも立たない・・・。
module_initはデバイスドライバとすべての起点となる重要なものなのだ。
module_initとmodule_exitはカーネルが用意してくれたデバイスドライバのための仕組みなので、盛大に利用しましょう!
public2016.hatenablog.com
次はユーザランドからの呼び出しについて