I am writing a kernel module and it is about reading and writing MSRs. I wrote a simple program for testing but it still fails. All it is doing is writing to MSR, then reading it back. Here is the code:
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;
}
The output looks like:
exit_write: hi=00000000 lo=0000000b
exit_write2: hi=00000000 lo=00000000
Can someone tell me why the return value is 0 in the second output, instead of the original? Is there something wrong with my code? Thanks a lot.
The problem has to do with the fact that you don’t fully tell gcc which registers you’re using in inline assembly and how and you also expect that gcc doesn’t do anything funky to the registers between the fragments of your inline assembly code. Related
movandxxmsrinstructions should be in the same asm block.Look what gcc does with your code (I’ve altered it a tiny bit to make it compilable as a regular program)…
Source:
Compiling (with MinGW gcc 4.6.2):
Disassembly of
test3_init()from msr.s:Note that when the CPU starts executing
wrmsrit hasecx=0x38d (OK),edx=0 (OK),eax=0 (not 0xb, oops!). Follow the instructions to see it.What you can and should write instead is something like the following, even shorter than it was:
Now, disassembly of
test3_init2():Also, remember that every CPU has its own MSR and you may want to set this MSR on all of them. Another important consideration is that the thread in which you’re manipulating an MSR should not be moved between different CPUs until you’re done with the MSR.