我最近在自定義Linux內核(2.6.31.5,x86)驅動程序中遇到了一個問題,其中copy_to_user將定期不將任何字節複製到用戶空間。它會返回傳遞給它的字節數,表明它沒有複製任何內容。在代碼檢查後,我們發現代碼在調用copy_to_user時違反了中斷,而違反了合同。糾正後,問題停止發生。由於這個問題很少發生,我需要證明禁用中斷導致了這個問題。當x86指令禁用中斷時,mov指令導致頁面錯誤時會發生什麼情況?
如果您從arch/x86/lib/usercopy_32.c rep中查看下面的代碼片段: movsl通過CX中的計數將單詞複製到用戶空間。在退出時用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將保持不變並且返回值是正確的。
任何人都可以指向英特爾手冊中指定此行爲的部分,或者指向任何其他可能有用的Linux源代碼?
你提到「代碼禁止中斷」。你可以詳細說明哪些中斷和如何?... – TheCodeArtist
@TheCodeArtist:write_lock_bh();舉行,我的理解是禁用軟件中斷。 – Edward
@TheCode藝術家:謝謝!您的評論讓我更加仔細地研究了write_lock_bh(),讓我看到了方向! – Edward