C LANGUAGE TECHNOLOGY

【C言語】Linuxのカーネルモジュールの作り方

2022年8月25日

悩んでいる人
悩んでいる人

C言語でLinuxのカーネルモジュールの作り方を教えて!

こういった悩みにお答えします.

本記事の信頼性

  • リアルタイムシステムの研究歴12年.
  • 東大教員の時に,英語でOS(Linuxカーネル)の授業.
  • 2012年9月~2013年8月にアメリカのノースカロライナ大学チャペルヒル校(UNC)コンピュータサイエンス学部で客員研究員として勤務.C言語でリアルタイムLinuxの研究開発.
  • プログラミング歴15年以上,習得している言語: C/C++PythonSolidity/Vyper,Java,Ruby,Go,Rust,D,HTML/CSS/JS/PHP,MATLAB,Verse(UEFN), Assembler (x64,aarch64).
  • 東大教員の時に,C++言語で開発した「LLVMコンパイラの拡張」,C言語で開発した独自のリアルタイムOS「Mcube Kernel」GitHubにオープンソースとして公開
  • 2020年1月~現在はアメリカのノースカロライナ州チャペルヒルにあるGuarantee Happiness LLCのCTOとしてECサイト開発やWeb/SNSマーケティングの業務.2022年6月~現在はアメリカのノースカロライナ州チャペルヒルにあるJapanese Tar Heel, Inc.のCEO兼CTO.
  • 最近は自然言語処理AIイーサリアムに関する有益な情報発信や,Unreal Editor for Fortnite(UEFN)でゲーム開発に従事.
    • (AI全般を含む)自然言語処理AIの論文の日本語訳や,AIチャットボット(ChatGPT,Auto-GPT,Gemini(旧Bard)など)の記事を50本以上執筆.アメリカのサンフランシスコ(広義のシリコンバレー)の会社でChatGPT/Geminiを訓練するプロンプトエンジニア・マネージャー・Quality Assurance(QA)の業務委託の経験あり.
    • (スマートコントラクトのプログラミングを含む)イーサリアムや仮想通貨全般の記事を200本以上執筆.イギリスのロンドンの会社で仮想通貨の英語の記事を日本語に翻訳する業務委託の経験あり.
    • UEFNで10本以上のゲームを開発し,フォートナイト上で公開(FortniteFortnite.GG).

こういった私から学べます.

C言語を独学で習得することは難しいです.

私にC言語の無料相談をしたいあなたは,公式LINE「ChishiroのC言語」の友だち追加をお願い致します.

私のキャパシティもあり,一定数に達したら終了しますので,今すぐ追加しましょう!

友だち追加

独学が難しいあなたは,元東大教員がおすすめするC言語を学べるオンラインプログラミングスクール5社で自分に合うスクールを見つけましょう.後悔はさせません!

【C言語】Linuxのカーネルモジュール

Linuxのカーネルモジュールは,Linuxカーネルの機能を動的に追加できる仕組みのことです.

カーネルモジュールを利用すると,カーネルの再コンパイルや再起動せずに実行時にカーネルの機能をロード,アンロードすることができます.

これにより,開発やデバッグの時間を削減することが可能になります.

Linuxのカーネルモジュールは1995年のバージョン1.2で登場しました.

また,Linuxの数多くの機能をモジュールとしてコンパイル可能です.

Linuxカーネルの設定ファイル「.config」で選択することができます.

例えば,.configで「CONFIG_XFS_FS=y」と設定するとカーネルの機能を有効にできますが,以下のように「CONFIG_XFS_FS=m」とするとカーネルモジュールとしてコンパイルできます.

カーネルモジュールとビルトインのカーネルコードの性能差はありません.

カーネルモジュールは,モジュールとしてコンパイルされたバグのあるデバイスドライバを選択的に実行することで特定したい時に有用です.

カーネルモジュールはカーネル全体に対してリンクされます.

カーネルモジュールは,以下で定義されたすべてのLinuxカーネルのグローバルシンボルにアクセスできます.

  • EXPORT_SYMBOL(function or variable name)

名前空間の汚染と変数名の意図しない再利用を避けるために,以下の2つの注意点があります.

  • モジュール名のプレフィックスをシンボルにつけること(例:モジュール名がhello_kernel_moduleの場合はhello_kernel_module_func関数)
  • もしシンボルがグローバルの場合,staticをつけること

カーネルのシンボルのリストは/proc/kallsymsにあり,以下のコマンドで表示できます.

また,lsmodコマンドでロードされているモジュールの一覧を確認できます.

カーネルモジュールの解説動画はこちらがわかりやすいです.

カーネルモジュールで「Hello World!」を表示

カーネルモジュールで「Hello World!」を表示する方法を紹介します.

カーネルモジュールのビルド

まず,カーネルモジュールのコード一式をこちらからダウンロードして下さい.

以下のコマンドで解凍した後にディレクトリの内容を表示します.

以下の2つのファイルがあることがわかります.

  • Makefile:カーネルモジュール用の構成ファイル
  • hello_kernel_module.c:カーネルモジュールのコード

カーネルモジュール用のMakefileは,従来のユーザレベルのコード用のMakefileと書き方が少し異なります.

注意点は以下になります.

  • 現在実行しているLinuxカーネルのソースディレクトリKDIRを指定していること
  • カーネルモジュールのソースコードがカーネルソースから外れていること
  • コンパイル後のカーネルモジュールとして,拡張子が.koのファイルが作成されること(このMakefileではhello_kernel_module.koを作成)

hello_kernel_module.cは以下になります.

hello_kernel_module_init関数は,「__init」で定義し,module_initマクロで初期化時のエントリポイントとして設定しているため,カーネルモジュールのロード時に実行します.

hello_kernel_module_exit関数は,「__exit」で定義し,module_exitマクロで終了時のエントリポイントとして設定しているため,カーネルモジュールのアンロード時に実行します.

参考までに,module_init/module_exitマクロはlinux/include/linux/module.hにあります.

makeでビルドします.

カーネルモジュールの実行

カーネルモジュールの実行方法を紹介します.

カーネルモジュールは,rootでないとロードやアンロードできない(実行できない)ことに注意して下さい.

また,カーネルモジュールは特定のカーネルバージョンに対してコンパイルされ,他のカーネルではロードできないことに注意してください.

※このチェックはmodversionsと呼ばれる機構により回避することができますが,危険な場合があります.

insmodコマンドでカーネルモジュールhello_kernel_module.koをロードします.

カーネルモジュールがロードされて「__init」があるhello_kernel_module_init関数が実行します.

dmesgコマンドで確認すると「Hello World!」が表示されていることがわかります.

lsmodコマンドを実行するとhello_kernel_moduleがあることがわかります.

また,modinfoコマンドでhello_kernel_module.koの情報を取得できます.

カーネルモジュールを削除するにはrmmodコマンドを利用します.

カーネルモジュールがアンロードされて「__exit」があるhello_kernel_module_exit関数が実行します.

dmesgコマンドで確認すると「Goodbye World!」が表示されていることがわかります.

カーネルモジュールを利用してカーネル空間とユーザ空間でデータをやり取り

カーネルモジュールを利用してカーネル空間とユーザ空間でデータをやり取りする方法を紹介します.

データのやり取りには,ioctlシステムコールやread/writeシステムコールを利用します.

コード一式はこちらからダウンロードして下さい.

カーネル空間(カーネルモジュール)のコードioctl_kernel_module.cと,ユーザ空間のコードioctl_user.cは以下になります.

実行結果は以下になります.

6行目で123を入力するとioctl関数を呼び出して,カーネルモジュールのmy_ioctl関数を呼び出します.

my_ioctl関数でWR_VALUE/RD_VALUEかを選択して,それぞれmy_write/my_read関数を呼び出します.

9行目で-45を入力するとwrite/read関数を呼び出して,(my_ioctl関数を介さずに)それぞれmy_write/my_read関数を呼び出します.

参考:Rust言語でLinuxのカーネルモジュール

Ubuntu 23.04(Linuxカーネル6.2)においてRust言語でLinuxのカーネルモジュールの作り方を解説している動画です.

※Ubuntu 22.04 LTSではないことに注意して下さい.

また,Ubuntu kernel is getting “Rusty” in Lunarの記事もあわせて読むと理解が深まります!

まとめ

C言語でLinuxのカーネルモジュールの作り方を紹介しました.

カーネルモジュールを作成して,カーネルレベルのプログラミングを習得しましょう!

カーネルモジュールを深く理解したいあなたは,以下を読みましょう!

Linuxカーネルの同期プログラミングを知りたいあなたはこちらからどうぞ.

C言語 Linuxカーネル 同期
【C言語】Linuxカーネルの同期プログラミング

こういった悩みにお答えします. こういった私から学べます. 本記事では,以下のLinuxカーネル「同期」を理解していることを前提としています. 【C言語】Linuxカーネルの同期プログラミング C言語 ...

続きを見る

Linuxカーネルのデバッグ方法を知りたいあなたはこちらからどうぞ.

C言語 Linuxカーネル デバッグ
【C言語】Linuxカーネルのデバッグ方法【printk,BUG_ON,WARN_ON,QEMU,GDB】

こういった悩みにお答えします. こういった私から学べます. 本記事は以下の記事を理解していることを前提とします. 【C言語】Linuxカーネルのデバッグ方法 C言語でLinuxカーネルのデバッグ方法を ...

続きを見る

C言語を独学で習得することは難しいです.

私にC言語の無料相談をしたいあなたは,公式LINE「ChishiroのC言語」の友だち追加をお願い致します.

私のキャパシティもあり,一定数に達したら終了しますので,今すぐ追加しましょう!

友だち追加

独学が難しいあなたは,元東大教員がおすすめするC言語を学べるオンラインプログラミングスクール5社で自分に合うスクールを見つけましょう.後悔はさせません!

-C LANGUAGE, TECHNOLOGY
-, , , ,