Cannot read back from MSR

久未见 提交于 2019-12-02 06:37:28

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 mov and xxmsr instructions 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:

// 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();
}

Compiling (with MinGW gcc 4.6.2):

gcc msr.c -c -S -o msr.s

Disassembly of test3_init() from msr.s:

_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

Note that when the CPU starts executing wrmsr it has ecx=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:

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;
}

Now, disassembly of 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

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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!