私は最近、カスタムLinuxカーネル(2.6.31.5、x86)ドライバで、copy_to_userが周期的にユーザー領域にバイトをコピーしないという問題が発生しました。渡されたバイト数を返します。何もコピーしていないことを示します。コード検査の後、私たちはコードが割り込みを無効にしているのに対し、copy_to_userはその契約に違反しています。これを修正した後、問題は停止しました。問題はあまり頻繁に起こっていないので、割り込みを無効にすると問題が発生したことを証明する必要があります。mov命令でx86で割り込みが無効になっているページフォルトが発生するとどうなりますか?
以下のコードスニペットをarch/x86/lib/usercopy_32.c repから見てください。 movslは単語をCXのカウントでuserspaceにコピーします。終了時にサイズがCXで更新されます。 movslが正しく実行されると、CXは0になります。 CXはゼロではないので、movs? copy_to_userの定義と観察された動作に適合させるために、命令を実行してはいけません。私がしているしている
/* Generic arbitrary sized copy. */
#define __copy_user(to, from, size) \
do { \
int __d0, __d1, __d2; \
__asm__ __volatile__( \
" cmp $7,%0\n" \
" jbe 1f\n" \
" movl %1,%0\n" \
" negl %0\n" \
" andl $7,%0\n" \
" subl %0,%3\n" \
"4: rep; movsb\n" \
" movl %3,%0\n" \
" shrl $2,%0\n" \
" andl $3,%3\n" \
" .align 2,0x90\n" \
"0: rep; movsl\n" \
" movl %3,%0\n" \
"1: rep; movsb\n" \
"2:\n" \
".section .fixup,\"ax\"\n" \
"5: addl %3,%0\n" \
" jmp 2b\n" \
"3: lea 0(%3,%0,4),%0\n" \
" jmp 2b\n" \
".previous\n" \
".section __ex_table,\"a\"\n" \
" .align 4\n" \
" .long 4b,5b\n" \
" .long 0b,3b\n" \
" .long 1b,2b\n" \
".previous" \
: "=&c"(size), "=&D" (__d0), "=&S" (__d1), "=r"(__d2) \
: "3"(size), "0"(size), "1"(to), "2"(from) \
: "memory"); \
} while (0)
2つのアイデア:
- 割り込みが無効になっている場合は、ページフォルトが発生し、その後 担当しません。 movs?何もせずにスキップされます。戻り値 は、 定義が指定したとおり、ユーザー・スペースにコピーされなかった量、および観察された動作がCXになります。
- ページフォールトは発生しますが、割り込みが無効になっているためLinuxが処理できないため、ページフォールトハンドラはどのようにページフォールトハンドラがこれを行うのか分かりませんが、ページフォルトハンドラは命令をスキップします。この場合も、この場合CXは変更されずに戻り値が正しいことになります。
この動作を指定するIntelのマニュアルのセクションを指摘できますか、または参考にできる追加のLinuxソースを教えてください。
あなたは "コードが割り込みを無効にしていた"と言います。あなたはどんな割り込みとどのように詳しく説明できますか?... – TheCodeArtist
@TheCodeArtist:write_lock_bh();私の理解によってソフトウェア割り込みを無効にする。 – Edward
@TheCodeArtist:ありがとう!あなたのコメントはwrite_lock_bh()をもっと詳しく見て、私に方法を示しました! – Edward