Linuxデバイスドライバ(第三版)読書ノート2
2.2.ハローワールドモジュールの多くのプログラミング書は、「ハローワールド」の例から始まり、可能な最も簡単なプログラムを示す方法として、この本はカーネルモジュールであって、プログラムではない.そのため、根気のない読者に対して、以下のコードは完全な「ハローワールド」モジュールです.
2.3.カーネルモジュールはアプリケーションと比べて
私たちが深く入る前に、カーネルモジュールとアプリケーションの間のさまざまな違いを強調する必要があります.大部分の小さいアプリケーションと中型のアプリケーションは最初から最後まで一つのタスクを処理します.個々のカーネルモジュールは自分だけを登録して、将来の要求にサービスします.そしてその初期化関数はすぐに終了します.言い換えれば、 モジュール初期化関数のタスクは、後でモジュールの関数を呼び出すために準備されます.モジュールが「ここでは私にできることです.」と言っているようです.モジュールの脱退関数はモジュールがアンマウントされた時に呼び出されます.カーネルに教えているようです.「もうそこにはいません.何もしなくてもいいです.」というプログラムの種類はイベントドライバのプログラミングのようですが、すべてのアプリケーションはイベントドライブではありません.カーネルモジュールはそれぞれです.もう一つの主要な違いは、イベント駆動のアプリケーションとカーネルコードの間では、関数を終了します.終了したアプリケーションは資源の放出に怠けてもいいです.または完全にクリーンアップをしないでください. しかし、モジュールの終了関数は、初期化関数によって確立されたものごとに注意して回復しなければなりません.そうでなければ、システムが再起動するまでいくつかのものを残します.
一つのモジュールはカーネル空間で動作しますが、アプリケーションはユーザ空間で実行します.この概念はオペレーティングシステム理論の基礎です.
Unixは、ユーザ空間からカーネル空間への変換を行い、いつ一つのアプリケーションがシステム呼び出しを発行しても、またはハードウェアによって中断されても、実行システムが呼び出したカーネルコードは、プロセスのコンテキストで動作します.呼び出しプロセスを表し、プロセスのアドレス空間にアクセスできます.言い換えれば、処理中断コードはプロセスにとって非同期です.モジュールの役割はカーネルを広げる機能です.モジュール化されたコードはカーネル空間で実行されます.よく一つの駆動が行われる前に述べた二つのタスクです.モジュールの中のいくつかの関数はシステム呼び出しの一部として実行されます.一部は中断処理を担当しています.
カーネルプログラミングにはいくつかの並行ソースがあります.もちろん、Linuxシステムは複数のプロセスを実行しています.同じ時間で、プロセスだけでなく、あなたの駆動を使ってみてもいいです.ほとんどの設備はプロセッサを中断できます.非同期処理を中断し、他のことをしようとするあなたの駆動中に呼び出される可能性があります.
結果として、Linuxカーネルコードは、ドライバコードを含めて再入力可能である必要があります.複数のコンテキストで同時に実行することができます.データ構造は、複数の実行スレッドを分離するように注意して設計しなければなりません.コードはデータの破壊を防ぐために、共有データに注意してアクセスしなければなりません.処理の同時化と競合を避けるために.(不幸な実行順序によって希望されない行為が発生した場合)のコードはよく考慮し、微妙かもしれません.正確な同時管理は正しいカーネルコードを作成する時に必要です.
アプリケーションは仮想メモリに存在します.非常に大きなスタック領域があります.もちろん、関数呼び出しの履歴と現在アクティブな関数によって作成されたすべての自動変数を保存します.カーネルとは逆に、非常に小さいスタックがあります.4096バイトのページまで小さいかもしれません.このスタックを共有するためには、このカーネル空間呼び出しチェーンと関数が必要です.巨大な自動変数を明らかにするのはいい考えではありません.大きな構造が必要なら、呼び出し時間内に動的に割り当てるべきです.
しばしば、カーネルAPIを見ると、二重アンダースコアで始まる関数名に出会います.このようなマークの関数名は、通常は低層のインターフェースコンポーネントです.注意して使用してください.本質的には、ダブルアンダースコアは、プログラマに教えます.「この関数を呼んだら、あなたが何をしているかを確認します.」
カーネルコードは浮動小数点算術ができません.
2.4.2.モジュールのロードとアンインストール
モジュールが作成された後、次のステップはカーネルにロードされます.私たちが指摘したように、insmoodはあなたのためにこの作業を完了します.このプログラムはモジュールのコードセグメントとデータセグメントをカーネルにロードします.次に、モジュールの中の未解決の記号をカーネルの符号表に接続します.ただし、コネクタに似ていません.モジュールのディスクファイルは修正されません. メモリ内のコピーです.
興味のある読者はカーネルがinsmodule.ccで定義されているシステムコールに依存しています.関数sys uinitmooduleはカーネルメモリを割り当ててモジュールを保存します.(このメモリはvmallcで割り当てられています.8章の「vmalloとその友達」を見てください.)次にモジュールのコードをこのメモリ領域にコピーし、カーネル符号表解決モジュールのカーネル参照を利用し、モジュールの初期化関数を呼び出してすべてのものを起動する. カーネルコードを実際に見たら、システムで呼び出された名前はsys_をプレフィクスとして発見されます.これはすべてのシステムに対して呼び出されたもので、他の関数がありません.これを覚えてください.
2.5.カーネル符号表
カーネル符号表とは何ですか?
OKです.基本的なシステムの呼び出しとモジュールの概念を理解しましたが、もう一つの非常に重要な概念であるカーネル符号表を理解し続ける必要があります.
この中の各表の項目は共通のカーネル記号を表しています.これらの記号は私達のLKMに引用されてもいいです.この書類をよく見てください.面白いことがたくさんあります.
このファイルは本当に面白いです.彼は私達のLKMがそれらの関数を呼び出すことができるのを見てくれます.しかし、これも同時に問題をもたらします.私達のLKMの中でアクセスしたシンボルごとに(関数名のような)このファイルの中に入れられます.他の人にも見られます.そのため、経験豊富なシステム管理者は私達の小さなLKMを発見し、彼を殺します.
管理者が私たちのLKMを発見するのを阻止する方法はたくさんあります.第二章で述べた方法は「Hacks」と呼ばれます.しかし、第二章の内容を見ていると、中には「LKM記号はどうやって入れられますか?proc/ksmsに入れられませんか?」このような方法は.第二章ではこの問題に言及していませんでした.
あなたは特別な技術が必要ではないです.モジュールの記号が表示されないようにします.LKM開発者たちは次のような一般的なコードを使ってモジュールの記号を宣言します.
static struct smbol modules={
//*自分の記号表を定義します!*/
璢include
//*参照したい記号表*/
…
}
register mtab(&modulemusyms);
/*実際の登録業務*/
私が言ったように、私達は外に私達の記号を公開する必要はありません.だから私達は次のような言葉を使えばいいです.
register usymtab(NULL);
この文はinitudule()の関数に入れなければなりません.覚えてください.
私たちはinsmoodがどのように共通のカーネル記号に対応して未定義の記号を解決するかを見ました.テーブルにはグローバルカーネル項目のアドレスと関数と変数が含まれています.モジュール化の駆動を完了する必要があります.モジュールをロードすると、モジュールから出力される記号がカーネルシンボルテーブルの一部になります.通常、モジュールが自分の機能を完成するために出力する必要はありません.何の記号ですか?記号を出力する必要がありますが、他のモジュールはそれらを使う時の恩恵になります. 新しいモジュールはあなたのモジュールで出力する記号を使うことができます.他のモジュールの上に新しいモジュールを積み重ねてもいいです.モジュールは主流のカーネルソースに積み重なっても実現しました.msdosファイルシステムはfatモジュールから出力される記号に依存しています.ある入力USB デバイスモジュールはusbcoreと入力モジュールの上に積み重ねられています.
linuxカーネルヘッドファイルは、あなたのシンボルの視認性を管理するために便利なファイルを提供しています.したがって、名前空間の汚染が減少しました. EXPORTUSYMBOL(name) EXPORT SY MBOLL(name);
ほとんどのカーネルコードは、関数、データ構造、変数の定義を得るために多くのヘッダファイルを含んでいます.それらに触れる時にこれらのファイルをチェックしますが、いくつかのファイルがモジュールに対して特殊で、ロード可能なモジュールの中に必ず現れます.したがって、ほとんどのモジュールコードには以下の内容があります. #include #include moude.hは大量のロードモジュールに必要な関数とシンボルの定義を含んでいます.init.hはあなたの初期化とクリーンアップ関数を指定してください.上の「hello world」の例で見たように、これは次のセクションでまた話します. ほとんどのモジュールはまた、モジュールローディング時にモジュールにパラメータを送ることができるようにmoudeleparam.hを含みます.
#include<linux/init.h>
#include<linux/module.h>
MODULE_LICENSE("DualBSD/GPL");
static inthello_init(void)
{
printk(KERN_ALERT"Hello, world
");
return 0;
}
static voidhello_exit(void)
{
printk(KERN_ALERT"Goodbye, cruel world
");
}
module_init(hello_init);
module_exit(hello_exit);
2.3.カーネルモジュールはアプリケーションと比べて
私たちが深く入る前に、カーネルモジュールとアプリケーションの間のさまざまな違いを強調する必要があります.大部分の小さいアプリケーションと中型のアプリケーションは最初から最後まで一つのタスクを処理します.個々のカーネルモジュールは自分だけを登録して、将来の要求にサービスします.そしてその初期化関数はすぐに終了します.言い換えれば、 モジュール初期化関数のタスクは、後でモジュールの関数を呼び出すために準備されます.モジュールが「ここでは私にできることです.」と言っているようです.モジュールの脱退関数はモジュールがアンマウントされた時に呼び出されます.カーネルに教えているようです.「もうそこにはいません.何もしなくてもいいです.」というプログラムの種類はイベントドライバのプログラミングのようですが、すべてのアプリケーションはイベントドライブではありません.カーネルモジュールはそれぞれです.もう一つの主要な違いは、イベント駆動のアプリケーションとカーネルコードの間では、関数を終了します.終了したアプリケーションは資源の放出に怠けてもいいです.または完全にクリーンアップをしないでください. しかし、モジュールの終了関数は、初期化関数によって確立されたものごとに注意して回復しなければなりません.そうでなければ、システムが再起動するまでいくつかのものを残します.
一つのモジュールはカーネル空間で動作しますが、アプリケーションはユーザ空間で実行します.この概念はオペレーティングシステム理論の基礎です.
Unixは、ユーザ空間からカーネル空間への変換を行い、いつ一つのアプリケーションがシステム呼び出しを発行しても、またはハードウェアによって中断されても、実行システムが呼び出したカーネルコードは、プロセスのコンテキストで動作します.呼び出しプロセスを表し、プロセスのアドレス空間にアクセスできます.言い換えれば、処理中断コードはプロセスにとって非同期です.モジュールの役割はカーネルを広げる機能です.モジュール化されたコードはカーネル空間で実行されます.よく一つの駆動が行われる前に述べた二つのタスクです.モジュールの中のいくつかの関数はシステム呼び出しの一部として実行されます.一部は中断処理を担当しています.
カーネルプログラミングにはいくつかの並行ソースがあります.もちろん、Linuxシステムは複数のプロセスを実行しています.同じ時間で、プロセスだけでなく、あなたの駆動を使ってみてもいいです.ほとんどの設備はプロセッサを中断できます.非同期処理を中断し、他のことをしようとするあなたの駆動中に呼び出される可能性があります.
結果として、Linuxカーネルコードは、ドライバコードを含めて再入力可能である必要があります.複数のコンテキストで同時に実行することができます.データ構造は、複数の実行スレッドを分離するように注意して設計しなければなりません.コードはデータの破壊を防ぐために、共有データに注意してアクセスしなければなりません.処理の同時化と競合を避けるために.(不幸な実行順序によって希望されない行為が発生した場合)のコードはよく考慮し、微妙かもしれません.正確な同時管理は正しいカーネルコードを作成する時に必要です.
アプリケーションは仮想メモリに存在します.非常に大きなスタック領域があります.もちろん、関数呼び出しの履歴と現在アクティブな関数によって作成されたすべての自動変数を保存します.カーネルとは逆に、非常に小さいスタックがあります.4096バイトのページまで小さいかもしれません.このスタックを共有するためには、このカーネル空間呼び出しチェーンと関数が必要です.巨大な自動変数を明らかにするのはいい考えではありません.大きな構造が必要なら、呼び出し時間内に動的に割り当てるべきです.
しばしば、カーネルAPIを見ると、二重アンダースコアで始まる関数名に出会います.このようなマークの関数名は、通常は低層のインターフェースコンポーネントです.注意して使用してください.本質的には、ダブルアンダースコアは、プログラマに教えます.「この関数を呼んだら、あなたが何をしているかを確認します.」
カーネルコードは浮動小数点算術ができません.
2.4.2.モジュールのロードとアンインストール
モジュールが作成された後、次のステップはカーネルにロードされます.私たちが指摘したように、insmoodはあなたのためにこの作業を完了します.このプログラムはモジュールのコードセグメントとデータセグメントをカーネルにロードします.次に、モジュールの中の未解決の記号をカーネルの符号表に接続します.ただし、コネクタに似ていません.モジュールのディスクファイルは修正されません. メモリ内のコピーです.
興味のある読者はカーネルがinsmodule.ccで定義されているシステムコールに依存しています.関数sys uinitmooduleはカーネルメモリを割り当ててモジュールを保存します.(このメモリはvmallcで割り当てられています.8章の「vmalloとその友達」を見てください.)次にモジュールのコードをこのメモリ領域にコピーし、カーネル符号表解決モジュールのカーネル参照を利用し、モジュールの初期化関数を呼び出してすべてのものを起動する. カーネルコードを実際に見たら、システムで呼び出された名前はsys_をプレフィクスとして発見されます.これはすべてのシステムに対して呼び出されたもので、他の関数がありません.これを覚えてください.
2.5.カーネル符号表
カーネル符号表とは何ですか?
OKです.基本的なシステムの呼び出しとモジュールの概念を理解しましたが、もう一つの非常に重要な概念であるカーネル符号表を理解し続ける必要があります.
この中の各表の項目は共通のカーネル記号を表しています.これらの記号は私達のLKMに引用されてもいいです.この書類をよく見てください.面白いことがたくさんあります.
このファイルは本当に面白いです.彼は私達のLKMがそれらの関数を呼び出すことができるのを見てくれます.しかし、これも同時に問題をもたらします.私達のLKMの中でアクセスしたシンボルごとに(関数名のような)このファイルの中に入れられます.他の人にも見られます.そのため、経験豊富なシステム管理者は私達の小さなLKMを発見し、彼を殺します.
管理者が私たちのLKMを発見するのを阻止する方法はたくさんあります.第二章で述べた方法は「Hacks」と呼ばれます.しかし、第二章の内容を見ていると、中には「LKM記号はどうやって入れられますか?proc/ksmsに入れられませんか?」このような方法は.第二章ではこの問題に言及していませんでした.
あなたは特別な技術が必要ではないです.モジュールの記号が表示されないようにします.LKM開発者たちは次のような一般的なコードを使ってモジュールの記号を宣言します.
static struct smbol modules={
//*自分の記号表を定義します!*/
璢include
//*参照したい記号表*/
…
}
register mtab(&modulemusyms);
/*実際の登録業務*/
私が言ったように、私達は外に私達の記号を公開する必要はありません.だから私達は次のような言葉を使えばいいです.
register usymtab(NULL);
この文はinitudule()の関数に入れなければなりません.覚えてください.
私たちはinsmoodがどのように共通のカーネル記号に対応して未定義の記号を解決するかを見ました.テーブルにはグローバルカーネル項目のアドレスと関数と変数が含まれています.モジュール化の駆動を完了する必要があります.モジュールをロードすると、モジュールから出力される記号がカーネルシンボルテーブルの一部になります.通常、モジュールが自分の機能を完成するために出力する必要はありません.何の記号ですか?記号を出力する必要がありますが、他のモジュールはそれらを使う時の恩恵になります. 新しいモジュールはあなたのモジュールで出力する記号を使うことができます.他のモジュールの上に新しいモジュールを積み重ねてもいいです.モジュールは主流のカーネルソースに積み重なっても実現しました.msdosファイルシステムはfatモジュールから出力される記号に依存しています.ある入力USB デバイスモジュールはusbcoreと入力モジュールの上に積み重ねられています.
linuxカーネルヘッドファイルは、あなたのシンボルの視認性を管理するために便利なファイルを提供しています.したがって、名前空間の汚染が減少しました. EXPORTUSYMBOL(name) EXPORT SY MBOLL(name);
ほとんどのカーネルコードは、関数、データ構造、変数の定義を得るために多くのヘッダファイルを含んでいます.それらに触れる時にこれらのファイルをチェックしますが、いくつかのファイルがモジュールに対して特殊で、ロード可能なモジュールの中に必ず現れます.したがって、ほとんどのモジュールコードには以下の内容があります. #include