无法从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对你的内联汇编代码片段之间的寄存器没有做任何有趣的事情。 。 相关的movxxmsr指令应该在同一个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之间移动。