HelloWorldソースコード解説

HelloWorldソースコード解説

今回は、以前の記事にて作成したHelloWorldのソースコードについて見ていきます。


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

MODULE_LICENSE("Dual BSD/GPL");

static int hello_init(void)
{
	printk(KERN_ALERT "driver loaded\n");
	printk(KERN_ALERT "Hello World\n");
	return 0;
}

static void hello_exit(void)
{
	printk(KERN_ALERT "driver unloaded\n");
}

module_init(hello_init);
module_exit(hello_exit);

まずは上記コードをビルドし、生成されたドライバはどのような動作をするのか確認します。

このドライバはinsmodコマンドなどによりロードされるとsyslogに「driver loaded」と「Hellow World」という文字列を出力します。

# insmod hello.ko
# tail -n 2 /var/log/messages
Aug 17 05:31:03 localhost kernel: driver loaded
Aug 17 05:31:03 localhost kernel: Hello World

tailコマンドはファイルの末尾部分を出力するコマンドです。
-nオプションをつけることで、出力する行数を指定できます。

今度はドライバ「hello」をアンロードします。

# rmmod hello
# tail -n 1 /var/log/messages
Aug 17 19:07:17 localhost kernel: driver unloaded

アンロードすると、syslogに「driver unloaded」という文字列が出力されます。

では、ソースコードの解説に移ります。

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

アプリケーションを開発する場合、インクルードするヘッダファイルは「stdio.h」や「string.h」などになると思いますが、それらはユーザー空間で使用するライブラリであり、ドライバ開発ではインクルードしません。
代わりに、「linux/module.h」や「linux/init.h」などをインクルードします。


MODULE_LICENSE("Dual BSD/GPL");

この行はMODULE_LICENSEマクロでドライバのライセンスを定義しています。
この行を記述することによりこのドライバは「GPLである」と明示したことになり、GPL規約に準拠する必要があります。
この行がなくてもコンパイルは通りますが、警告が出力されます。


static int hello_init(void)
{
	printk(KERN_ALERT "driver loaded\n");
	printk(KERN_ALERT "Hello World\n");
	return 0;
}

上記で定義している「hello_init」関数はドライバロード時、つまりinsmodコマンド実行時などに呼び出されるエントリポイントです。
ロード時のエントリポイントの指定は「module_init」マクロで行います。
アプリケーションのエントリポイントは必然的にmain関数となりますが、ドライバの場合は「module_init」マクロでエントリポイントを指定することになります。

戻り値に「0」を返すことで、insmodコマンドは成功します。ロード時の処理で何らかのエラーが発生した場合は0以外を返します。(上記サンプルでは、無条件で「0」を返しています。)

関数内ではprintk関数を呼び出しています。
似た関数としておなじみのprintf関数がありますが、ドライバでは標準ライブラリをインクルードしていないので当然使えません。
というよりそもそも、カーネル空間で動作するドライバはコンソール画面(標準出力)がないので、使いようがありません。

しかし、それではデバックが大変なので代わりに用意されたのがprintk関数です。

printk関数
int printk ( const char *fmt, … )

書式指定(fmt)の先頭に「<番号>」を付けると、メッセージのログレベル(優先度)を指定できる。
「include/linux/kernel.h」にマクロ定義。
・KERN_EMERG
  システムは使用できない
・KERN_ALERT
  即時にアクションを取る必要がある
・KERN_CRIT
  かなり憂慮すべき状態
・KERN_ERR
  エラー状態
・KERN_WARNING
  警告状態
・KERN_NOTICE
  異常ではないが、重要な状態
・KERN_INFO
  情報
・KERN_DEBUG
  デバッグ・メッセージ

printk関数の出力先はカーネルバッファです。
カーネルバッファはdmesgコマンドで参照できます。

また、syslogdやklogdがカーネルバッファをsyslog(/var/log/message)に定期的に出力しているので、syslogからでも確認できます。


static void hello_exit(void)
{
	printk(KERN_ALERT "driver unloaded\n");
}

「hello_exit」関数はドライバアンロード時、つまりrmmodコマンド実行時などに呼び出されるエントリポイントです。
アンロード時のエントリポイントの指定は「module_exit」マクロで行います。
関数の戻り値は不要です。

タグ