无法从MSR回读
我正在编写一个内核模块,它是关于读写MSR的。 我写了一个简单的测试程序,但它仍然失败。 它所做的只是写入MSR,然后再读回来。 这是代码:
static int __init test3_init(void) { uint32_t hi,lo; hi=0; lo=0xb; asm volatile("mov %0,%%eax"::"r"(lo)); asm volatile("mov %0,%%edx"::"r"(hi)); asm volatile("mov $0x38d,%ecx"); asm volatile("wrmsr"); printk("exit_write: hi=%08x lo=%08x\n",hi,lo); asm volatile("mov $0x38d,%ecx"); asm volatile("rdmsr":"=a"(lo),"=d"(hi)); printk("exit_write2: hi=%08x lo=%08x\n",hi,lo); return 0; }
输出如下:
exit_write: hi=00000000 lo=0000000b
exit_write2: hi=00000000 lo=00000000
有人能告诉我为什么第二个输出中的返回值为0,而不是原始值? 我的代码有问题吗? 非常感谢。
这个问题与你没有完全告诉gcc在内联汇编中使用哪个寄存器这一事实有关,以及你也期望gcc对你的内联汇编代码片段之间的寄存器没有做任何有趣的事情。 。 相关的mov
和xxmsr
指令应该在同一个asm块中。
看看gcc对你的代码做了什么(我已经改变了一点点,使它可以作为常规程序编译)…
资源:
// file: msr.c #include typedef unsigned uint32_t; #define printk printf #define __init static int __init test3_init(void) { uint32_t hi,lo; hi=0; lo=0xb; asm volatile("mov %0,%%eax"::"r"(lo)); asm volatile("mov %0,%%edx"::"r"(hi)); asm volatile("mov $0x38d,%ecx"); asm volatile("wrmsr"); printk("exit_write: hi=%08x lo=%08x\n",hi,lo); asm volatile("mov $0x38d,%ecx"); asm volatile("rdmsr":"=a"(lo),"=d"(hi)); printk("exit_write2: hi=%08x lo=%08x\n",hi,lo); return 0; } int main(void) { return test3_init(); }
编译(使用MinGW gcc 4.6.2):
gcc msr.c -c -S -o msr.s
从msr.s中反汇编test3_init()
:
_test3_init: pushl %ebp movl %esp, %ebp pushl %esi pushl %ebx subl $32, %esp movl $0, -12(%ebp) movl $11, -16(%ebp) movl -16(%ebp), %eax mov %eax,%eax movl -12(%ebp), %eax mov %eax,%edx mov $0x38d,%ecx wrmsr movl -16(%ebp), %eax movl %eax, 8(%esp) movl -12(%ebp), %eax movl %eax, 4(%esp) movl $LC0, (%esp) call _printf mov $0x38d,%ecx rdmsr movl %edx, %ebx movl %eax, %esi movl %esi, -16(%ebp) movl %ebx, -12(%ebp) movl -16(%ebp), %eax movl %eax, 8(%esp) movl -12(%ebp), %eax movl %eax, 4(%esp) movl $LC1, (%esp) call _printf movl $0, %eax addl $32, %esp popl %ebx popl %esi popl %ebp ret
请注意,当CPU开始执行wrmsr
它具有ecx
= 0x38d(OK), edx
= 0(OK), eax
= 0(不是0xb,oops!)。 按照说明查看。
您可以而且应该写的是以下内容,甚至比以下更短:
static int __init test3_init2(void) { uint32_t hi,lo; hi=0; lo=0xb; asm volatile("wrmsr"::"c"(0x38d),"a"(lo),"d"(hi)); printk("exit_write: hi=%08x lo=%08x\n",hi,lo); asm volatile("rdmsr":"=a"(lo),"=d"(hi):"c"(0x38d)); printk("exit_write2: hi=%08x lo=%08x\n",hi,lo); return 0; }
现在,反汇编test3_init2()
:
_test3_init2: pushl %ebp movl %esp, %ebp pushl %esi pushl %ebx subl $48, %esp movl $0, -12(%ebp) movl $11, -16(%ebp) movl $909, %ecx movl -16(%ebp), %eax movl -12(%ebp), %edx wrmsr movl -16(%ebp), %eax movl %eax, 8(%esp) movl -12(%ebp), %eax movl %eax, 4(%esp) movl $LC0, (%esp) call _printf movl $909, -28(%ebp) movl -28(%ebp), %ecx rdmsr movl %edx, %ebx movl %eax, %esi movl %esi, -16(%ebp) movl %ebx, -12(%ebp) movl -16(%ebp), %eax movl %eax, 8(%esp) movl -12(%ebp), %eax movl %eax, 4(%esp) movl $LC1, (%esp) call _printf movl $0, %eax addl $48, %esp popl %ebx popl %esi popl %ebp ret
另外,请记住每个CPU都有自己的MSR,您可能希望在所有这些MSR上设置此MSR。 另一个重要的考虑因素是,在您完成MSR之前,您操作MSR的线程不应在不同的CPU之间移动。