デバイスドライバを実装する
この記事はIS17erアドベントカレンダー8日目の記事として書かれました。
きっかけ
やってみようと思ったインターンの応募条件にデバイスドライバ開発経験があったため。とりあえず開発経験ゼロなのはやばいので簡単なものから書いていこうと思います。
【追記】
この記事の次の日の記事に、より複雑なデバイスドライバを実装する記事を書こうと思ったのですが、インターンに受かってしまったのでモチベが消失してしまいました。
Hello Device Driver!
デバイスドライバのHello Worldプログラムを調べながらとりあえず書いてみます。
こちらを大いに参考にしています。
環境構築
今回は本物のハードウェアを必要としないデバイスドライバなのでEC2の無料インスタンスを使いました。sshログイン後
$ sudo yum groupinstall "Development Tools" -y
$ sudo yum install kernel-devel -y
$ sudo yum install kernel-headers -y
をします。一応
$ rpm -aq | grep kernel
kernel-4.9.62-21.56.amzn1.x86_64
kernel-tools-4.9.62-21.56.amzn1.x86_64
kernel-devel-4.9.62-21.56.amzn1.x86_64
kernel-headers-4.9.62-21.56.amzn1.x86_64
のようにバージョンが統一されていることを確認してください。
実装
Linuxの場合、言語はCまたはアセンブリに限定されます。今回はCで実装を行います。
通常のCプログラムはmain関数がエントリポイントになりますが、デバイスドライバ用のCプログラムでは、デバイスのロード時とアンロード時にそれぞれエントリポイントが用意されており、そこを実装する形となります。
#include <linux/module.h>
#include <linux/init.h>
int init_module(void) {
printk(KERN_INFO "Hello World\n");
return 0;
}
void cleanup_module(void) {
return;
}
init_module
がロード時のエントリポイント、cleanup_module
がアンロード時のエントリポイントに対応します。カーネル空間で実行されるプログラムなので、ユーザ空間用のライブラリであるinclude/stdio.h
にあるprintf
の代わりに、printk
を使って文字列を出力します。出力先はカーネルバッファです。printk
の文字列の前に
- KERN_INFO
- KERN_DEBUG
- KERN_ERR
などinclude/linux/kernel.h
に定義されている定数を指定することで出力レベルを調整できます。
次にMakefileを作ります。
obj-m := hello.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
$ sudo insmod hello.ko
$ dmesg
[167497.775137] Hello World
$ sudo rmmod hello
insmod
はデバイスを挿入するコマンド、rmmod
はデバイスを取り出すコマンドです。dmesg
でカーネルバッファの中身を出力して、きちんとHello Worldが出力されていることを確認します(他にもいろいろ出力されると思いますが、一番下を確認してください)。
つづき
とりあえず、これが簡単なのはHello Worldだからで、普通のデバイスドライバはUSB部分などの実装がすごく大変なようです。
明日の記事でもうちょっと難しい実装をするかもしれません。