HelloYou
をテンプレートにして作成
[
トップ
] [
新規
|
一覧
|
単語検索
|
最終更新
|
ヘルプ
|
ログイン
]
開始行:
* Hello You [#g827f53c]
先の [[hello_world.c>HelloWorld]] を修正して、課題だった...
#code(c,hello_world.c);
** パラメータを受け取る手段 [#tbc32536]
モジュールはパラメータを受け取ることができます。主な手段...
|手段|パラメータ引き渡し方法|設定単位|.config|ドキュメン...
|&ogdefs(module_param,module_param,moduleparam.h);|insmod...
|&ogdefs(DEVICE_ATTR, DEVICE_ATTR);|sysfs node|デバイス毎...
|&ogfileone(debugfs,Documentation/filesystems/debugfs.txt...
|&ogfileone(procfs,Documentation/filesystems/proc.txt);|p...
#textbox(note, sysfs, procfs, debugfs は必ずある...
sysfs, procfs, debugfs は .config の記述により有無を選択...
debufs はディストリビューションや評価環境によっては「無し...
}}
いずれの方法もノードができます。ノードは属性の設定次第で ...
#textbox(caution, module_param を pchar 型パラメータで使...
module_param を pchar 型(文字列)で扱う場合は、バッファ確...
}}
** パラメータを入力する [#l11ed3fc]
*** モジュール組み込み時に入力する [#eaccf835]
まず、パラメータ無しで insmod, rmmod を試します。ソース・...
#pre(soft){{
&span(ConsoleOut){$ };&span(ConsoleIn){sudo insmod hello_...
&span(ConsoleOut){[sudo] password for };&span(ConsoleOut,...
&span(ConsoleOut){$ };&span(ConsoleIn){sudo rmmod hello_w...
&span(ConsoleOut){$ };&span(ConsoleIn){dmesg};
}}
dmesg が出力した最後は次のようになります。your_name と re...
#pre(soft){{
&span(ConsoleOut){[355028.315777] hello_world: module ver...
&span(ConsoleOut){[355028.319261] hello_world_init: Hello...
&span(ConsoleOut){[355036.306520] hello_world_exit: Goodb...
}}
パラメータを付けて起動しましょう。your_name=Hanako としま...
#pre(soft){{
&span(ConsoleOut){$ };&span(ConsoleIn){sudo insmod hello_...
&span(ConsoleOut){$ };&span(ConsoleIn){sudo rmmod hello_w...
&span(ConsoleOut){$ };&span(ConsoleIn){dmesg};
}}
dmesg が出力した最後は次のようになります。your_name に指...
#pre(soft){{
&span(ConsoleOut){[355218.292794] hello_world_init: Hello...
&span(ConsoleOut){[355236.027700] hello_world_exit: Goodb...
}}
*** モジュールを組み込んだ後にパラメータを入力する [#f909...
パラメータは /sys/module/hello_world/parameters の下にノ...
#pre(soft){{
&span(ConsoleOut){$ };&span(ConsoleIn){sudo insmod hello_...
&span(ConsoleOut){$ };&span(ConsoleIn){ls -la /sys/module...
&span(ConsoleOut){total 0};
&span(ConsoleOut){drwxr-xr-x 2 root root 0 8月 22 10:...
&span(ConsoleOut){drwxr-xr-x 6 root root 0 8月 22 10:...
&span(ConsoleOut){-rw-r--r-- 1 root root 4096 8月 22 10:...
&span(ConsoleOut){-rw-r--r-- 1 root root 4096 8月 22 10:...
}}
ノードのサイズが 4096 です。理由を探ってみましょう。&ogde...
#code(c,/int\s*sysfs_add_file_mode_ns/../^}$/,ogfileone:/...
#textbox(note, module_param を charp 型で使う場合の長さ制...
&ogdefs(module_param(),module_param); を charp 型で使う場...
}}
#code(c,/int\s*param_set_charp/../^}$/,ogfileone:/kernel/...
ノードを読み出してみます。ls -la (stat) で報告された長さ...
#pre(soft){{
&span(ConsoleOut){$ };&span(ConsoleIn){cat /sys/module/he...
&span(ConsoleOut){0};
&span(ConsoleOut){$ };&span(ConsoleIn){cat /sys/module/he...
&span(ConsoleOut){Taro};
&span(ConsoleOut){$ };&span(ConsoleIn){cat /sys/module/he...
&span(ConsoleOut){000000 30 0a};
&span(ConsoleOut){000002};
&span(ConsoleOut){$ };&span(ConsoleIn){cat /sys/module/he...
&span(ConsoleOut){000000 54 61 72 6f 0a};
&span(ConsoleOut){000005};
}}
your_name ノードに書き込んでみます。その後、rmmod してみ...
#pre(soft){{
&span(ConsoleOut){$ };&span(ConsoleIn){sudo sh -c "echo -...
&span(ConsoleOut){$ };&span(ConsoleIn){sudo rmmod hello_w...
&span(ConsoleOut){$ };&span(ConsoleIn){dmesg};
...省略...
&span(ConsoleOut){[355334.490992] hello_world_init: Hello...
&span(ConsoleOut){[355455.780006] hello_world_exit: Goodb...
}}
** エラーを返してみよう [#g5d06117]
Linux kernel 内のエラーの扱い方を見ていきます。関数の結果...
#textbox(note,自分が作るモジュール内の作法は?){{
自分で作るモジュール内は色々な都合で独自の作法でも良いで...
}}
*** Linux kernel 内の作法通り負の errno 値 (-Exxx) を返す...
&ogdefs(module_init(),module_init,init.h); で指定した関数...
#pre(soft){{
&span(ConsoleOut){$ };&span(ConsoleIn){sudo insmod hello_...
&span(ConsoleOut){insmod: ERROR: could not insert module ...
&span(ConsoleOut){$ };&span(ConsoleIn){dmesg};
...省略...
&span(ConsoleOut){[790263.729065] hello_world_init: Hello...
&span(ConsoleOut){$ };&span(ConsoleIn){sudo insmod hello_...
&span(ConsoleOut){insmod: ERROR: could not insert module ...
&span(ConsoleOut){$ };&span(ConsoleIn){dmesg};
...省略...
&span(ConsoleOut){[790263.729065] hello_world_init: Hello...
&span(ConsoleOut){[790515.608190] hello_world_init: Hello...
}}
何回試しても、同じようにエラーになります。insmod が失敗し...
エラーが発生した場合、状況に合わせて &ogfileone(include/u...
#code(c,ogfileone:/include/uapi/asm-generic/errno-base.h);
*** 仕様外の正の値を返す [#xe2190cf]
&ogdefs(module_init(),module_init,init.h); で指定した関数...
#pre(soft){{
&span(ConsoleOut){$ };&span(ConsoleIn){sudo insmod hello_...
&span(ConsoleOut){$ };&span(ConsoleIn){dmesg};
...省略...
&span(ConsoleOut){[792581.467679] hello_world_init: Hello...
&span(ConsoleOut){[792581.467700] do_init_module: 'hello_...
&span(ConsoleOut){[792581.467700] do_init_module: loading...
&span(ConsoleOut){[792581.467740] CPU: 1 PID: 15413 Comm:...
&span(ConsoleOut){[792581.467766] Hardware name: innotek ...
&span(ConsoleOut){[792581.467779] 0000000000000000 ffff8...
&span(ConsoleOut){[792581.467793] ffff8800048258c0 ffff8...
&span(ConsoleOut){[792581.467803] ffff8800776b7eb0 00000...
&span(ConsoleOut){[792581.467813] Call Trace:};
&span(ConsoleOut){[792581.467839] [<ffffffff817d0d19>] d...
&span(ConsoleOut){[792581.467851] [<ffffffff817cd175>] d...
&span(ConsoleOut){[792581.467867] [<ffffffff811026bc>] l...
&span(ConsoleOut){[792581.467916] [<ffffffff810fe260>] ?...
&span(ConsoleOut){[792581.467937] [<ffffffff811030ee>] S...
&span(ConsoleOut){[792581.467950] [<ffffffff8110312e>] S...
&span(ConsoleOut){[792581.467963] [<ffffffff817d8b72>] s...
}}
dmesg 出力を見るとスタック・ダンプ (stack dump) が見つか...
#code(c,/init suspiciously returned/..=15,ogfileone:/kern...
&ogdefs(dump_stack(),dump_stack); は割り込みが遅延するな...
&ogdefs(dump_stack(),dump_stack); を呼ぶまでにどのような...
#textbox(note,SyS_finit_module() の追跡は省略します){{
&ogdefs(SYSCALL_DEFINEx() マクロ,SYSCALL_DEFINEx); と &og...
}}
#textbox(note,インライン展開された関数はスタック・ダンプ...
gcc の最適化により関数がインライン展開されることがありま...
}}
始めの方に表示される "CPU: 1 PID: 15413 Comm: insmod " も...
#textbox(note,割り込み処理の場合は PID と Comm は割り込み...
割り込み処理内でも dump_stack() は使えます。この場合 PID ...
}}
#code(c,/void\s*dump_stack_print_info/../^}$/,ogfileone:/...
** バッファ・オーバーランが心配 [#x78584d7]
グローバル変数 your_name 周辺の実装を見てバッファ・オーバ...
*** module_param charp で扱える文字列の長さ [#p4905ed8]
先に結論から示します。&ogdefs(param_set_charp()); 関数内...
&ogdefs(module_param(),module_param); を出発点にします。...
#code(c,/define\s*module_param_named/../^\s*$/,ogfileone:...
幸いなことに &ogdefs(param_ops_charp); は見つかりました。...
&ogdefs(param_ops_int); は見つかりません。気になるなら、...
#code(c,/param_ops_int/..+10}$/,ogfileone:/include/linux/...
何処かにシンボルを定義する記述があるはずです。&ogdefs(par...
#code(c,/define\s*STANDARD_PARAM_DEF/../param_set_charp/,...
ここにたどり着くのに &ogrefs(kernel_param_ops); 構造体が...
改めて見つかった結果をよく見ると、&ogrefs(kernel_param_op...
マクロを使った巧妙なテンプレートを使っていると思われる場...
&ogdefs(param_get_charp(),param_get_charp); と &ogdefs(pa...
|メソッド名接尾辞または一部|system call との対応|h
|_get|read()|
|_set|write()|
|_read|read()|
|_write|write()|
#textbox(context,▼ここからちょっと脱線);
Linux kernel の中では _get, _put の組み合わせもよく使われ...
|メソッド名接尾辞または一部|機能|h
|_get|参照カウンタを増やす。|
|_put|参照カウンタを減らす。カウンタが 0 になったら _rele...
#textbox(context,▲ここまでちょっと脱線);
&ogdefs(param_set_charp(),param_set_charp);の実装を見てい...
#code(c,/int\s*param_set_charp/../^}$/,ogfileone:/kernel/...
次に興味深いのは &ogdefs(maybe_kfree_parameter);(*(char *...
#code(c,/static\s*void\s*maybe_kfree_parameter/../^}$/,og...
#code(c,/void\s*[*]\s*kmalloc_parameter/../^}$/,ogfileone...
#textbox(note,リスト操作は別のページで扱う予定です){{
リスト操作は排他制御を伴うのが普通です。一見した限りでは ...
}}
&ogrefs(slab_is_available(),slab_is_available,include/lin...
#textbox(note,kernel boot command line の module パラメー...
次の書式で kernel の boot command line (あるいは kernel p...
&br;
&span(Alias){module};.&span(Alias){parameter_name};=&span...
}}
*** printk で構築できる文字列の長さ [#tf707e05]
printk で構築できる文字列の長さは &ogdefs(vprintk_emit(),...
#code(c,/define\s*PREFIX_MAX/../define\s*LOG_LINE_MAX/,og...
&ogdefs(printk(),printk,printk.c); から追いかけると &ogse...
#code(c,/int\s*vprintk_emit/../\s*}\s*$/,ogfileone:/kerne...
次のコードは vprintk_emit() の中ほどです。
#code(c,/vscnprintf.*sizeof/..=15,ogfileone:/kernel/print...
このページのサンプルでは幅指定が無い %s 書式を使いました...
** 次はよりデバイスドライバらしく [#radc1f38]
ここまでは、単純なモジュールの作り方を見てきました。次は...
終了行:
* Hello You [#g827f53c]
先の [[hello_world.c>HelloWorld]] を修正して、課題だった...
#code(c,hello_world.c);
** パラメータを受け取る手段 [#tbc32536]
モジュールはパラメータを受け取ることができます。主な手段...
|手段|パラメータ引き渡し方法|設定単位|.config|ドキュメン...
|&ogdefs(module_param,module_param,moduleparam.h);|insmod...
|&ogdefs(DEVICE_ATTR, DEVICE_ATTR);|sysfs node|デバイス毎...
|&ogfileone(debugfs,Documentation/filesystems/debugfs.txt...
|&ogfileone(procfs,Documentation/filesystems/proc.txt);|p...
#textbox(note, sysfs, procfs, debugfs は必ずある...
sysfs, procfs, debugfs は .config の記述により有無を選択...
debufs はディストリビューションや評価環境によっては「無し...
}}
いずれの方法もノードができます。ノードは属性の設定次第で ...
#textbox(caution, module_param を pchar 型パラメータで使...
module_param を pchar 型(文字列)で扱う場合は、バッファ確...
}}
** パラメータを入力する [#l11ed3fc]
*** モジュール組み込み時に入力する [#eaccf835]
まず、パラメータ無しで insmod, rmmod を試します。ソース・...
#pre(soft){{
&span(ConsoleOut){$ };&span(ConsoleIn){sudo insmod hello_...
&span(ConsoleOut){[sudo] password for };&span(ConsoleOut,...
&span(ConsoleOut){$ };&span(ConsoleIn){sudo rmmod hello_w...
&span(ConsoleOut){$ };&span(ConsoleIn){dmesg};
}}
dmesg が出力した最後は次のようになります。your_name と re...
#pre(soft){{
&span(ConsoleOut){[355028.315777] hello_world: module ver...
&span(ConsoleOut){[355028.319261] hello_world_init: Hello...
&span(ConsoleOut){[355036.306520] hello_world_exit: Goodb...
}}
パラメータを付けて起動しましょう。your_name=Hanako としま...
#pre(soft){{
&span(ConsoleOut){$ };&span(ConsoleIn){sudo insmod hello_...
&span(ConsoleOut){$ };&span(ConsoleIn){sudo rmmod hello_w...
&span(ConsoleOut){$ };&span(ConsoleIn){dmesg};
}}
dmesg が出力した最後は次のようになります。your_name に指...
#pre(soft){{
&span(ConsoleOut){[355218.292794] hello_world_init: Hello...
&span(ConsoleOut){[355236.027700] hello_world_exit: Goodb...
}}
*** モジュールを組み込んだ後にパラメータを入力する [#f909...
パラメータは /sys/module/hello_world/parameters の下にノ...
#pre(soft){{
&span(ConsoleOut){$ };&span(ConsoleIn){sudo insmod hello_...
&span(ConsoleOut){$ };&span(ConsoleIn){ls -la /sys/module...
&span(ConsoleOut){total 0};
&span(ConsoleOut){drwxr-xr-x 2 root root 0 8月 22 10:...
&span(ConsoleOut){drwxr-xr-x 6 root root 0 8月 22 10:...
&span(ConsoleOut){-rw-r--r-- 1 root root 4096 8月 22 10:...
&span(ConsoleOut){-rw-r--r-- 1 root root 4096 8月 22 10:...
}}
ノードのサイズが 4096 です。理由を探ってみましょう。&ogde...
#code(c,/int\s*sysfs_add_file_mode_ns/../^}$/,ogfileone:/...
#textbox(note, module_param を charp 型で使う場合の長さ制...
&ogdefs(module_param(),module_param); を charp 型で使う場...
}}
#code(c,/int\s*param_set_charp/../^}$/,ogfileone:/kernel/...
ノードを読み出してみます。ls -la (stat) で報告された長さ...
#pre(soft){{
&span(ConsoleOut){$ };&span(ConsoleIn){cat /sys/module/he...
&span(ConsoleOut){0};
&span(ConsoleOut){$ };&span(ConsoleIn){cat /sys/module/he...
&span(ConsoleOut){Taro};
&span(ConsoleOut){$ };&span(ConsoleIn){cat /sys/module/he...
&span(ConsoleOut){000000 30 0a};
&span(ConsoleOut){000002};
&span(ConsoleOut){$ };&span(ConsoleIn){cat /sys/module/he...
&span(ConsoleOut){000000 54 61 72 6f 0a};
&span(ConsoleOut){000005};
}}
your_name ノードに書き込んでみます。その後、rmmod してみ...
#pre(soft){{
&span(ConsoleOut){$ };&span(ConsoleIn){sudo sh -c "echo -...
&span(ConsoleOut){$ };&span(ConsoleIn){sudo rmmod hello_w...
&span(ConsoleOut){$ };&span(ConsoleIn){dmesg};
...省略...
&span(ConsoleOut){[355334.490992] hello_world_init: Hello...
&span(ConsoleOut){[355455.780006] hello_world_exit: Goodb...
}}
** エラーを返してみよう [#g5d06117]
Linux kernel 内のエラーの扱い方を見ていきます。関数の結果...
#textbox(note,自分が作るモジュール内の作法は?){{
自分で作るモジュール内は色々な都合で独自の作法でも良いで...
}}
*** Linux kernel 内の作法通り負の errno 値 (-Exxx) を返す...
&ogdefs(module_init(),module_init,init.h); で指定した関数...
#pre(soft){{
&span(ConsoleOut){$ };&span(ConsoleIn){sudo insmod hello_...
&span(ConsoleOut){insmod: ERROR: could not insert module ...
&span(ConsoleOut){$ };&span(ConsoleIn){dmesg};
...省略...
&span(ConsoleOut){[790263.729065] hello_world_init: Hello...
&span(ConsoleOut){$ };&span(ConsoleIn){sudo insmod hello_...
&span(ConsoleOut){insmod: ERROR: could not insert module ...
&span(ConsoleOut){$ };&span(ConsoleIn){dmesg};
...省略...
&span(ConsoleOut){[790263.729065] hello_world_init: Hello...
&span(ConsoleOut){[790515.608190] hello_world_init: Hello...
}}
何回試しても、同じようにエラーになります。insmod が失敗し...
エラーが発生した場合、状況に合わせて &ogfileone(include/u...
#code(c,ogfileone:/include/uapi/asm-generic/errno-base.h);
*** 仕様外の正の値を返す [#xe2190cf]
&ogdefs(module_init(),module_init,init.h); で指定した関数...
#pre(soft){{
&span(ConsoleOut){$ };&span(ConsoleIn){sudo insmod hello_...
&span(ConsoleOut){$ };&span(ConsoleIn){dmesg};
...省略...
&span(ConsoleOut){[792581.467679] hello_world_init: Hello...
&span(ConsoleOut){[792581.467700] do_init_module: 'hello_...
&span(ConsoleOut){[792581.467700] do_init_module: loading...
&span(ConsoleOut){[792581.467740] CPU: 1 PID: 15413 Comm:...
&span(ConsoleOut){[792581.467766] Hardware name: innotek ...
&span(ConsoleOut){[792581.467779] 0000000000000000 ffff8...
&span(ConsoleOut){[792581.467793] ffff8800048258c0 ffff8...
&span(ConsoleOut){[792581.467803] ffff8800776b7eb0 00000...
&span(ConsoleOut){[792581.467813] Call Trace:};
&span(ConsoleOut){[792581.467839] [<ffffffff817d0d19>] d...
&span(ConsoleOut){[792581.467851] [<ffffffff817cd175>] d...
&span(ConsoleOut){[792581.467867] [<ffffffff811026bc>] l...
&span(ConsoleOut){[792581.467916] [<ffffffff810fe260>] ?...
&span(ConsoleOut){[792581.467937] [<ffffffff811030ee>] S...
&span(ConsoleOut){[792581.467950] [<ffffffff8110312e>] S...
&span(ConsoleOut){[792581.467963] [<ffffffff817d8b72>] s...
}}
dmesg 出力を見るとスタック・ダンプ (stack dump) が見つか...
#code(c,/init suspiciously returned/..=15,ogfileone:/kern...
&ogdefs(dump_stack(),dump_stack); は割り込みが遅延するな...
&ogdefs(dump_stack(),dump_stack); を呼ぶまでにどのような...
#textbox(note,SyS_finit_module() の追跡は省略します){{
&ogdefs(SYSCALL_DEFINEx() マクロ,SYSCALL_DEFINEx); と &og...
}}
#textbox(note,インライン展開された関数はスタック・ダンプ...
gcc の最適化により関数がインライン展開されることがありま...
}}
始めの方に表示される "CPU: 1 PID: 15413 Comm: insmod " も...
#textbox(note,割り込み処理の場合は PID と Comm は割り込み...
割り込み処理内でも dump_stack() は使えます。この場合 PID ...
}}
#code(c,/void\s*dump_stack_print_info/../^}$/,ogfileone:/...
** バッファ・オーバーランが心配 [#x78584d7]
グローバル変数 your_name 周辺の実装を見てバッファ・オーバ...
*** module_param charp で扱える文字列の長さ [#p4905ed8]
先に結論から示します。&ogdefs(param_set_charp()); 関数内...
&ogdefs(module_param(),module_param); を出発点にします。...
#code(c,/define\s*module_param_named/../^\s*$/,ogfileone:...
幸いなことに &ogdefs(param_ops_charp); は見つかりました。...
&ogdefs(param_ops_int); は見つかりません。気になるなら、...
#code(c,/param_ops_int/..+10}$/,ogfileone:/include/linux/...
何処かにシンボルを定義する記述があるはずです。&ogdefs(par...
#code(c,/define\s*STANDARD_PARAM_DEF/../param_set_charp/,...
ここにたどり着くのに &ogrefs(kernel_param_ops); 構造体が...
改めて見つかった結果をよく見ると、&ogrefs(kernel_param_op...
マクロを使った巧妙なテンプレートを使っていると思われる場...
&ogdefs(param_get_charp(),param_get_charp); と &ogdefs(pa...
|メソッド名接尾辞または一部|system call との対応|h
|_get|read()|
|_set|write()|
|_read|read()|
|_write|write()|
#textbox(context,▼ここからちょっと脱線);
Linux kernel の中では _get, _put の組み合わせもよく使われ...
|メソッド名接尾辞または一部|機能|h
|_get|参照カウンタを増やす。|
|_put|参照カウンタを減らす。カウンタが 0 になったら _rele...
#textbox(context,▲ここまでちょっと脱線);
&ogdefs(param_set_charp(),param_set_charp);の実装を見てい...
#code(c,/int\s*param_set_charp/../^}$/,ogfileone:/kernel/...
次に興味深いのは &ogdefs(maybe_kfree_parameter);(*(char *...
#code(c,/static\s*void\s*maybe_kfree_parameter/../^}$/,og...
#code(c,/void\s*[*]\s*kmalloc_parameter/../^}$/,ogfileone...
#textbox(note,リスト操作は別のページで扱う予定です){{
リスト操作は排他制御を伴うのが普通です。一見した限りでは ...
}}
&ogrefs(slab_is_available(),slab_is_available,include/lin...
#textbox(note,kernel boot command line の module パラメー...
次の書式で kernel の boot command line (あるいは kernel p...
&br;
&span(Alias){module};.&span(Alias){parameter_name};=&span...
}}
*** printk で構築できる文字列の長さ [#tf707e05]
printk で構築できる文字列の長さは &ogdefs(vprintk_emit(),...
#code(c,/define\s*PREFIX_MAX/../define\s*LOG_LINE_MAX/,og...
&ogdefs(printk(),printk,printk.c); から追いかけると &ogse...
#code(c,/int\s*vprintk_emit/../\s*}\s*$/,ogfileone:/kerne...
次のコードは vprintk_emit() の中ほどです。
#code(c,/vscnprintf.*sizeof/..=15,ogfileone:/kernel/print...
このページのサンプルでは幅指定が無い %s 書式を使いました...
** 次はよりデバイスドライバらしく [#radc1f38]
ここまでは、単純なモジュールの作り方を見てきました。次は...
ページ名: