在SMP环境下,你当前的代码在同一时间点只可能运行在某一个处理器上,那么如何这段代码需要操作其他处理器上的寄存器,该如何做呢?举个简单的例子吧,假设我当前的系统中有4颗core (关于Socket, Processor, Core的区分此文不展开),如果我现在想写一段代码来初始化这4颗core上的PMU寄存器(每个core都有自己专属的registers),怎么操作?
其实内核的msr模块提供了借鉴的代码:
get_online_cpus();
for_each_online_cpu(i) {
...
}
put_online_cpus();
上面代码通过for_each_online_cpu来枚举系统中所有core的id值,也就是常说的cpuid. 在上面的例子中,cpuid=0,1,2,3.
有了cpuid,就可以通过rdmsr_safe_on_cpu(cpu...)和wrmsr_safe_on_cpu(cpu...)来操作每个core的寄存器。
那么rdmsr/wrmsr_safe_on_cpu()函数的背后原理是基于什么来获得各个cpu上的寄存器地址呢?答案简单地说就是APIC. 系统中每个cpu将由APIC识别并在系统初始化时将其寄存器base addr记录在一个per_cpu型的变量中,这样通过cpuid就可以获得每个处理器的register base addr.