从 Nehalem 开始,MSR 寄存器 0x34(称为MSR_SMI_COUNT)计算自系统启动以来发生的 SMI 数量。它是只读的且特定于英特尔。您可以使用该接口从用户模式可编程地读取该寄存器(或任何其他 MSR 寄存器)/dev/cpu/CPUNUM/msr。有多种工具使用该界面来显示 SMI 计数,包括msr-tools ( sudo rdmsr -a 0x34) 和turbostat ( sudo turbostat --msr 0x34)。
我从 Turbostat 源代码 (/source/tools/power/x86/turbostat/turbostat.c) 中提取了此代码。该get_msr_fd函数返回文件的文件描述符msr。该get_msr函数接受 CPU 编号、MSR 偏移量(0x34 MSR_SMI_COUNT)以及指向保存 MSR 值的 64 位位置的指针(尽管MSR_SMI_COUNT是一个 32 位计数器,并且高 32 位被保留)。
int get_msr_fd(int cpu)
{
char pathname[32];
int fd;
fd = fd_percpu[cpu];
if (fd)
return fd;
sprintf(pathname, "/dev/cpu/%d/msr", cpu);
fd = open(pathname, O_RDONLY);
if (fd < 0)
err(-1, "%s open failed, try chown or chmod +r /dev/cpu/*/msr, or run as root", pathname);
fd_percpu[cpu] = fd;
return fd;
}
int get_msr(int cpu, off_t offset, unsigned long long *msr)
{
ssize_t retval;
retval = pread(get_msr_fd(cpu), msr, sizeof(*msr), offset);
if (retval != sizeof *msr)
err(-1, "cpu%d: msr offset 0x%llx read failed", cpu, (unsigned long long)offset);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
SMI 可能每秒发生多次,也可能在很长一段时间内不发生。但观察变化的一种方法MSR_SMI_COUNT是发出同步 SMI。通常,这可以通过将一些 8 位值写入 I/O 端口 0xB2 或 0xB3 来完成。您可以参考芯片组手册来确定哪些 I/O 端口可能触发 SMI。