delphij's Chaos

选择chaos这个词是因为~~实在很难找到一个更合适的词来形容这儿了……

30 Jul 2010

FreeBSD上的{rd,wr}msr_safe

这几天改 FreeBSDcoretemp(4) 遇到了一个问题。直接使用 rdmsr 的话,如果那个 MSR 不存在,则会触发 #GP(0),不了解 CPU 型号的情况下直接去杵肯定是不行的。后来翻了一下 cpuctl(4) 的代码发现 FreeBSD 上也有 rdmsr_safe。它的实现并不复杂( sys/amd64/amd64/support.S):


        movq    PCPU(CURPCB),%r8 // %r8 = PCPU(CURPCB); 将当前CPU的编号保存到r8。
        movq    $msr_onfault,PCB_ONFAULT(%r8) // 设置发生异常时调用msr_onfault。

然后是翻译 AMD64 ABI:


        movl    %edi,%ecx // 参数1放到ecx
        rdmsr // 实际执行rdmsr(将ecx指定的MSR的高、低32bit结果放到edx、eax中)
        salq    $32,%rdx  // rdx <<= 32
        movl %eax,%eax // 将rax最高32 bit清零
        orq     %rdx,%rax // rax |= rdx
        movq    %rax,(%rsi) // rax 存入 *rsi
        xorq    %rax,%rax // 返回值默认为0

最后恢复先前的异常处理状态。


        movq    %rax,PCB_ONFAULT(%r8)
        ret

msr_onfault是一个很简单的处理程序,它将异常处理指针清零,然后将rax置为EFAULT,并直接返回。