FreeBSD上的{rd,wr}msr_safe
这几天改 FreeBSD 的 coretemp(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,并直接返回。