我最近在自定义Linux内核(2.6.31.5,x86)驱动程序中遇到了一个问题,其中copy_to_user会定期不将任何字节复制到用户空间。它将返回传递给它的字节数,表明它没有复制任何东西。代码检查后,我们发现代码在调用copy_to_user时禁用了中断,这违反了它的合同。纠正此问题后,问题就停止了。因为问题很少发生,我需要证明禁用中断会导致问题。
如果你看一下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)
我的两个想法是:
有人可以向我指出英特尔手册中指定此行为的部分,还是指向任何可能有用的其他Linux源代码?
答案 0 :(得分:8)
我找到了答案。我的#2建议是正确的,机制正好在我面前。页面错误确实发生,但fixup_exception机制用于提供异常/继续机制。此部分将条目添加到异常处理程序表:
".section __ex_table,\"a\"\n" \
" .align 4\n" \
" .long 4b,5b\n" \
" .long 0b,3b\n" \
" .long 1b,6b\n" \
".previous" \
这说:如果IP地址是第一个条目,并且在故障处理程序中遇到异常,则将IP地址设置为第二个地址并继续。
因此,如果异常发生在“4:”,则跳转到“5:”。如果异常发生在“0:”,则跳转到“3:”,如果异常发生在“1:”,则跳转到“6:”。
缺少的部分位于arch / x86 / mm / fault.c中的do_page_fault()中:
/*
* If we're in an interrupt, have no user context or are running
* in an atomic region then we must not take the fault:
*/
if (unlikely(in_atomic() || !mm)) {
bad_area_nosemaphore(regs, error_code, address);
return;
}
in_atomic返回true,因为我们在write_lock_bh()锁中! bad_area_nosemaphore最终会进行修复。
如果发生page_fault(由于工作空间的概念不太可能),那么函数调用将失败并跳出__copy_user宏,未复制的字节设置为size,因为preemption已被禁用。
答案 1 :(得分:4)
页面错误不是可屏蔽的中断。事实上,它们在技术上根本不是中断 - 而是例外,尽管我同意差异更具语义性。
当您在原子上下文中禁用中断时copy_to_user失败的原因是因为代码对此进行了明确的检查。
请参阅http://lxr.free-electrons.com/source/arch/x86/lib/usercopy_32.c#L575