有没有一种方法可以确定SMM中断已经发生?

3
有没有一种方法可以确定,在某些以编程方式定义的时间间隔内,当前核心上是否发生了SMM条目?
1个回答

5
从 Nehalem 开始,MSR 寄存器 0x34(称为 MSR_SMI_COUNT)计算自系统启动以来发生的 SMI 次数。它是只读的并且特定于英特尔。您可以使用 /dev/cpu/CPUNUM/msr 接口从用户模式可编程地读取此寄存器(或任何其他 MSR 寄存器)。有几个工具使用接口显示 SMI 计数,包括 msr-toolssudo rdmsr -a 0x34)和 turbostat(sudo turbostat --msr 0x34)。
我从 turbostat 源代码(/source/tools/power/x86/turbostat/turbostat.c)中提取了这段代码。 get_msr_fd 函数返回 msr 文件的文件描述符。 get_msr 函数接受 CPU 编号、MSR 偏移量(对于 MSR_SMI_COUNT 是 0x34),以及指向将保存 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;
}

SMI可能每秒发生多次,也可能长时间不发生。但观察 MSR_SMI_COUNT 变化的一种方法是发出同步SMI信号。通常,这可以通过向I/O端口0xB2或0xB3写入一些8位值来完成。您可以参考芯片组手册,确定哪些I/O端口可能会触发SMI。


2
turbostat 版本 17.06.23 默认包含一个每个核心SMI的列。另外,添加新列的语法是 turbostat --add msr0x34,u64,cpu,delta,SMM(根据--help中TSC的示例推测的,我没有看到任何来自它和SMI列的计数,在不带其他参数运行时只显示类似vmstat样式的输出,在每5秒打印一块行数据 :) - undefined
2
通过LAPIC传递SMI是另一种(更简单?)的触发方式。不知道Linux是否有专门的函数来实现这个,但native_apic_mem_write(APIC_ICR, ...)应该可以实现。 - undefined
@MargaretBloom 我认为 APIC_ICR 只能在内核模式下进行写入,对吗?就像我在答案中提到的 I/O 端口一样。 - undefined
@HadiBrais 是的,只能在内核模式下执行。除非某个驱动程序暴露它,但那样做会非常危险。 - undefined
我在我的问题中没有表达清楚,但我是针对用户空间的。我现在已经添加了这个细节。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接