我正在编写一个内核模块,它是关于读写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,而不是原始值?我的代码有问题吗?非常感谢。
答案 0 :(得分:5)
问题与你没有完全告诉gcc在内联汇编中使用哪个寄存器这一事实有关,以及你如何以及你也期望gcc对你的片段之间的寄存器没有做任何有趣的事情。内联汇编代码。相关的mov
和xxmsr
说明应位于相同的asm块中。
看看gcc对你的代码做了些什么(我稍微改了一下,使它可以作为常规程序编译)......
来源:
// file: msr.c
#include <stdio.h>
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,糟糕!)。按照说明进行查看。
你可以而且应该写的是以下内容,甚至比以下更短:
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之间移动。