c - 为什么会触发 BUG_ON(!in_nmi())?

标签 c linux kernel panic

我有一个内核BUG,我不知道为什么会触发它。

[ 242.337362] kernel BUG at arch/x86/kernel/cpu/mce/core.c:1364!
[ 242.337366] invalid opcode: 0000 [#1] SMP NOPTI

这是 CentOS 8.5,x86_64 上的内核 4.18.0-348.el8.x86_64。

core.c 第 1364 行是:

    nmi_exit();

(上一行在 do_machine_check() 内):

通过检查nmi_exit()

https://elixir.bootlin.com/linux/v4.18/source/include/linux/hardirq.h#L78

#define nmi_exit()                      \
    do {                            \
        trace_hardirq_exit();               \
        rcu_nmi_exit();                 \
        BUG_ON(!in_nmi());              \
        preempt_count_sub(NMI_OFFSET + HARDIRQ_OFFSET); \
        ftrace_nmi_exit();              \
        lockdep_on();                   \
        printk_nmi_exit();              \
    } while (0)

看起来我遇到了这个BUG_ON(!in_nmi());,但我检查了do_machine_check(),它应该仍然是in_nmi (自第 1255 行 nmi_enter();),为什么触发了 BUG_ON(!in_nmi());

其他:

  1. 这里是CentOS 4.18内核源码下载:

https://vault.centos.org/8.5.2111/BaseOS/Source/SPackages/kernel-4.18.0-348.el8.src.rpm

最佳答案

I got a kernel BUG, I don't know why it was triggered?

您遇到的特定错误试图使用无效的操作码:0000 [#1] SMP NOPTI

我将解决这个问题、原因以及解决问题的方法。首先,我将定义一些术语。

什么是不可屏蔽中断 (NMI)?

NMI 是一种硬件中断,不受操作系统(例如 CentOS 8.5)启用的任何中断屏蔽的影响。在几乎所有情况下,它都是对 non-recoverable hardware errors 的回应。 .

NMI 有哪些典型用途? 1

  • 低级调试,例如早期 Apple Macintosh 的“程序员按钮”。
  • 超出可纠正范围的 ECC 内存奇偶校验错误可能会导致系统停止运行。
  • 迫在眉睫的厄运,例如突然断电使系统静止。
  • 定期启用硬件看门狗计时器,以便在错过一个时出现 panic 。

第二个 NMI 是否可以在处理第一个 NMI 时到达?

从我记事起,Linux 就一直支持 Intel 嵌套 NMI。 Intel nested NMI support 中的漏洞2012 年令人兴奋。英特尔拥有 NMI iret flaw这要求 NMI 处理程序在处理 NMI 时避免触发页面错误或断点。

在 ARM64 和 PowerPC 中支持 nest NMI 已在 May 20th, 2020 上提交给 Linux .

为什么 BUG_ON() 会准确执行?

从 Linux 2.6 开始,BUG_ON() 是用于出现严重错误时的调试宏。如果传递给宏的值为真,Linux 内核将触发无效指令。这导致 CPU 抛出无效操作码异常。通常,如果在进程中发生这种情况,则该进程会死亡。如果这种情况发生在 NMI 期间,那就要严重得多。

BUG_ON(!in_nmi()) 转换为 BUG_ON(true)?

因此 in_nmi() 是检查当前 NMI 的当前抢占位是否设置为真。

什么是 NOPTI? 2

Linux 使用它来禁用 Meltdown(内核页表隔离)缓解措施。通常将 nopti 添加到内核引导选项以禁用。

补救措施?

如果是软件问题,我该怎么办? 最有可能

  • 尝试在启用 Meltdown 的情况下启动系统(如果当前已禁用)。或者在禁用它的情况下启动(如果启用)。
  • 如果可能,将 Linux 升级到 5.4.100 或更高版本。一个例子bug在英特尔 Icelake 发布前 2 年由英特尔报告。
  • 迁移到 AlmaLinux 或 Rocky Linux,CentOS 8.5的精神继承者。

如果是硬件缺陷怎么办? 不太可能

  • 尝试一次更换一个(与系统逻辑板兼容的配置),直到找到有缺陷的那个。
  • 更换系统逻辑板和/或其他 PCIe 设备。

长话短说

此问题的一个工作理论是 NMI 是由未纠正的硬件内存错误和编码错误造成的情况,即在第二次增加增加了 preempt_counter 之前检查 BUG_ON(!in_nmi())。

在这种特殊情况下,原始发布者使用工具 einj_mem_uc 来生成模拟内存错误。这会启动 NMI。

关于c - 为什么会触发 BUG_ON(!in_nmi())?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73592210/

相关文章:

python - 关于在 python 脚本中导入 psutil 的问题

linux - 将命令输出存储到变量时如何保留换行符?

linux - ~/.smartgit/<main-smartgit-version> <main-smartgit-version> 中给出的版本是什么? settings.xml 文件在哪里?

关于指针大小的混淆

c - C 中的简单字符串运行时错误?

c - 优化代码和意见

c - gdb 观察点未激活

linux - 从头开始加固 BSD

linux - struct load_info 中的字段strmap 是什么意思?

linux - hrtimer 即使未启动也会运行