Linux デバイスドライバ -Hello-
投稿日: | |
---|---|
タグ: |
目次
キーワード
- カーネルメッセージ
- ライセンス
- ログレベル
本稿はLinuxデバイスドライバ(モジュール)プログラミングに関するメモ.第1弾.
Linuxは実行中にカーネルの機能の追加や削除できる. それらの処理には次のコマンドを使用する.
- insmod
- カーネルにモジュールを追加するコマンド.
- rmmod
- カーネルからモジュールを取り除くコマンド.
- modprobe
- モジュールをカーネルに追加したりカーネルから取り除いたりする高レベルインタフェースなコマンド.モジュールをロードする場合,多くの点でinsmodと同じだが,ロード対象のモジュールが必要とするモジュールもロードする.ただしmodprobeはインストール済みのモジュールを格納したディレクトリからしか探さないため,作業ディレクトリから依存するモジュールをロードする時はは,insmodを使わなければならない.
Linuxのデバイスやモジュールのクラス
- キャラクタ型デバイス
-
バイトストリームとして扱われるデバイスで,その機能を提供するのがキャラクタ型デバイスドライバ.通常キャラクタ型デバイスドライバには以下のシステムコールが実装される.
- open
- close
- read
- write
- ブロック型デバイス
- ブロック単位でアクセスするデバイス.ブロックとは512バイトあるいはそれ以外の2のべき乗のデータのかたまりのことである.代表的な例にはディスクが挙げられる.
- ネットワークインタフェース
- ネットワークインタフェースはデータパケットの送受信を担当する.ネットワークインタフェースのほとんどはハードウェアを伴うデバイスであるが,ループバックインタフェースのようにソフトウェアだけのデバイスもある.ネットワークデバイスドライバの通信は他の2つのデバイスドライバとは異なり,ストリーム指向ではない.それゆえ対応するファイルノードを持たない.
デバイスドライバとアプリケーション
デバイスドライバとアプリケーションの違いについて,いくつか例を示す.
- アプリケーションはリソースを大雑把に解放するか全く解放しないが,デバイスドライバは取り除かれる際に全ての資源を解放しないとシステムが再起動されるまでリソースが解放されない.
- アプリケーション(Cのコード)はライブラリをリンクされるのでそこで定義された関数やオブジェクトを呼び出すことができる.しかしデバイスドライバはカーネルだけにリンクされるので,呼び出せる関数らはカーネルが公開しているものに限る.
- 基本的にデバイスドライバはカーネル空間の中で実行され,アプリケーションはユーザ空間の中で実行される.
- デバイスドライバは複数のシステムによって呼び出されることが珍しくない.それゆえデバイスドライバは再投入可能であるべき.
- アプリケーションが利用するスタック領域に比べ,デバイスドライバが利用するスタック領域はわずか.そのため大きな自動変数を宣言するのは望ましくない.
Hello, World
学習に用いた本はオライリーの「LINUX デバイスドライバ」でLinux 2.6を対象としている.
実行環境
カレントディレクトリには後述するhello.cとMakefile,Linuxカーネル3.0.9のソースコードをビルドしたものを配置する.後述する実行中のカーネルはこのビルドしたものである.
ソフトウェア | 内容 |
---|---|
OS(Linux) | 3.0.9 |
ディストリビューション | Ubuntu 12.04 |
make | GNU make 3.81 |
ブートローダ | grub 2 |
- 設定ファイル(.config)の作成と編集.
- カーネルのコンパイル
- コンパイルしたカーネルをインストール
- ブートローダの設定を書き換える.
hello.c
はじめにモジュールをロードした際と取り除いた際にカーネルメッセージを出力する例を示す.
#include <linux/init.h>
#include <linux/module.h>
MODULE_LICENSE("Dual BSD/GPL");
static int hello_init(void)
{
printk(KERN_ALERT "Hello, World\n");
return 0;
}
static void hello_exit(void)
{
printk(KERN_ALERT "Goodbye, World\n");
}
module_init(hello_init);
module_exit(hello_exit);
3行目はライセンスの宣言.本によるとコード的に必須な記述ではないらしいが,ないと,次のようなエラーが出力される.
[ 7092.616521] hello: module license 'unspecified' taints kernel. [ 7092.616525] Disabling lock debugging due to kernel taintカーネルによって認識されるライセンスは次の6種類.
文字列 | 意味 |
---|---|
"GPL" | GNU General Public Licenseの任意のバージョン |
"GPL v2" | GPL バージョン2のみ |
"GPL and additional rights" | |
"Dual BSD/GPL" | |
"Dual MPL/GPL" | |
"Proprietary" | 所有者のある |
printkはカーネルメッセージを出力する関数である.Cの文法と一致しないが,デバイスドライバのコーディングではこのような特殊な記述が多いようだ.KERN_ALERTはログレベル,すなわち重要度を表している.これにより,printkはメッセージの深刻さを分類する.ログレベルを示す文字列は次の8つである.深刻度は次の数字が小さいほど高い.
深刻度 | 定数 | 用途 |
---|---|---|
1 | KERN_EMERG | 緊急メッセージ.通常クラッシュを起こすような状態を表す. |
2 | KERN_ALERT | すぐに対応が必要な状況を表す. |
3 | KERN_CRIT | 危機的状況を表す. |
4 | KERN_ERR | エラー状況(例:ハードウェアのトラブル)を通知する. |
5 | KERN_WARNING | 疑わしい状況についてのワーニング. |
6 | KERN_NOTICE | 状況としては正常だが,注意が必要な状態. |
7 | KERN_INFO | 情報メッセージ.設定時に検出したハードウェアに関する情報などを表示する. |
8 | KERN_DEBUG | デバッグ用のメッセージ |
Makefile
前述のソースコードのコンパイルは一般的なCのコンパイルと異なる.以下にそのために必要な特別なMakefileの文を記述する.
obj-m := hello.o
この1行を記述したコンパイルを次のように実行することで,カーネルのビルドシステムが前述のコードをコンパイルする.
user% make -C $PWD/linux-3.0.9 M=$PWD modules
Cオプションを使用した場合,makeは指定したディレクトリに移動してから処理を開始する."M=パス"はmodulesターゲットを作成する前に,モジュールのソースディレクトリにあるMakefileに戻ることを表す.正常にコンパイルができたならば,カレントディレクトリにいくつかのファイルとモジュールhello.koができているはずである.
実行例
実行例は次の通りである.
user% sudo insmod hello.ko user% dmesg | tail -1 [ 5947.430306] Hello, World user% sudo rmmod hello.ko user% dmesg | tail -1 [ 6088.515992] Goodbye, Worlddmesgはカーネルのメッセージを出力したり制御したりするコマンドである.sudoやtailにのコマンドの詳細については省略する.