必要になりそうなので、勉強。Linuxだと参考資料がいろいろあるけど
FreeBSDは少ない。でもまあ *BSDだとツリー内にドキュメント入っているん
だろうなってことで、探すと /usr/share/examples/kld/cdev にキャラクタ
デバイスの参考資料があった。なんとなくわかったけど、Hello World的な
ものの方がいいかなって思って、書いてみた。
はじめに
はじめにローダブルモジュール用のディレクトリを作成します。
ソースツリーの sys/modules 以下にディレクトリを作成します。
とりあえず sample_moduleという名前にしました。
% cd 8.1.0/sys/modules % mkdir sample_module
Makefileを作成する
次に Makefileを作成します。作り方とかよくわからないので、
modulesにある他のローダブルモジュールの Makefileをコピーして、
ソースファイルだけ変更します。以下のようになりました。
# $FreeBSD$ .PATH: . KMOD= sample_module SRCS= sample_module.c .include <bsd.kmod.mk>
modules/以下って Makefileだけ置いて、ソースは dev/の下に置くって
いうのが流儀のようなんですが、今回はそんなこと気にせず、sample_module
以下にソースコードを置きます。できあがるモジュール名が sample_module、
そのソースが sample_module.cとします。詳しくはわかってないですが、
ローダブルモジュールは bsd.kmod.mkを includeする必要があるようなので、
書いておきます。
ソースを書く
ロードしたときに、ロードしました、アンロードしたときにアンロード
しましたというメッセージを出すだけのシンプルなものです。
#include <sys/param.h> #include <sys/systm.h> #include <sys/kernel.h> #include <sys/module.h> #include <sys/conf.h> static int sample_module_load(module_t mod, int cmd, void *arg) { switch (cmd) { case MOD_LOAD: printf("Load module\n"); break; case MOD_UNLOAD: printf("Unloaded kld character device driver\n"); break; default: return EOPNOTSUPP; } return 0; } DEV_MODULE(cdev, sample_module_load, NULL);
ロードとアンロードのときに printfを呼んでいるだけです。
肝心なところは、DEV_MODULEというマクロです。manpageによると以下の
ような説明となっています。
DEV_MODULE(name, modeventhand_t evh, void *arg); name : 名前 evh : モジュールのイベントハンドラ。load, unload, shutdownなどの ときに呼ばれるハンドラ arg : イベントハンドラに与えられる引数
manpageではイベントハンドラで、make_dev(デバイスファイルの作成)、
destroy_dev(デバイスドライバの削除)を呼べるようです。そのあたりは
まだ理解ができていないので、今後の課題となります。
DEV_MODULEの定義を見てみましょう。定義は sys/sys/conf.hにあります。
#define DEV_MODULE(name, evh, arg) \ static moduledata_t name##_mod = { \ #name, \ evh, \ arg \ }; \ DECLARE_MODULE(name, name##_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE)
moduledata_tという構造体変数を作成して、DECLARE_MODULEマクロを
呼び出しています。これ以上深追いはしませんが、DECLARE_MODULEのmanpageを
読むと、DECLARE_MODULEマクロを使うことでカーネルモジュールの宣言を
行うことができるようです。
とにかくこれで準備ができたので、makeします。
make
makeします。
Warning: Object directory not changed from original /usr/home/syohei/freebsd/8.1.0/sys/modules/sample_module cc -O2 -pipe -fno-strict-aliasing -Werror -D_KERNEL -DKLD_MODULE -nostdinc -I. -I@ -I@/contrib/altq -finline-limit=8000 --param inline-unit-growth=100 --param large-function-growth=1000 -fno-common -mno-align-long-strings -mpreferred-stack-boundary=2 -mno-mmx -mno-3dnow -mno-sse -mno-sse2 -mno-sse3 -ffreestanding -fstack-protector -std=iso9899:1999 -fstack-protector -Wall -Wredundant-decls -Wnested-externs -Wstrict-prototypes -Wmissing-prototypes -Wpointer-arith -Winline -Wcast-qual -Wundef -Wno-pointer-sign -fformat-extensions -c sample_module.c ld -d -warn-common -r -d -o sample_module.kld sample_module.o :> export_syms awk -f /usr/home/syohei/freebsd/8.1.0/sys/modules/sample_module/../../conf/kmod_syms.awk sample_module.kld export_syms | xargs -J% objcopy % sample_module.kld ld -Bshareable -d -warn-common -o sample_module.ko sample_module.kld objcopy --strip-debug sample_module.ko
警告が出ているようですが、カーネルオブジェクトの .koファイルが
できました。
ロードする
FreeBSDでは kldloadでロードできます。Linuxでいうところの insmodです。
% sudo kldload ./sample_module.ko
kldloadはデフォルトでは /boot/kernel以下からファイルを探すので、
明示的にカレントディレクトリであることを指定する必要があります。
printfで文字列が出るんじゃないかって思ったんですが、まあでないよね
ってことで、dmesgを確認します。
% dmesg | tail -n 1 Load sample_module
ちゃんとメッセージが記録されていました。
アンロードする
同じ手順でアンロードしてみます。unloadは kldunloadで行えます。
% sudo kldunload sample_module.ko % dmesg | tail -n 1 Unloaded sample_module
ちゃんとメッセージが出てますね。