有没有办法判断SMM中断发生了?

Bee*_*ope 3 hardware x86 intel

有没有办法从用户空间确定,对于某些以编程方式定义的间隔,当前核心上是否发生了SMM条目?

Had*_*ais 5

从 Nehalem 开始,MSR 寄存器 0x​​34(称为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。

  • 默认情况下,`turbostat` 版本 17.06.23 包含每核心 SMI 列。另外,添加新列的语法是 `turbostat --add msr0x34,u64,cpu,delta,SMM` (我认为,基于 TSC 的 --help 示例。我没有看到任何计数或SMI 列,在没有其他参数的情况下运行,仅显示“vmstat”样式的输出,每 5 秒打印一个行块:) (2认同)
  • 触发 SMI 的另一种(更简单?)方法是通过 LAPIC 传递它。IDK 如果 Linux 有一个特定的函数,那么 `native_apic_mem_write(APIC_ICR, ...)` 无论如何都应该这样做。 (2认同)