【问题标题】:How do I disable non maskable interrupts programmatically?如何以编程方式禁用不可屏蔽中断?
【发布时间】:2019-08-19 01:08:29
【问题描述】:

我已经读过,为了根据英特尔的系统编程指南(第 3 卷第 9.9 章)暂时关闭分页,我应该在执行其他任何操作之前禁用中断。我可以很容易地用 cli 禁用可屏蔽中断,但是所有关于禁用 NMI 的手册都是

可以通过外部电路禁用 NMI 中断。(软件必须保证在运行期间不会产生异常或中断 模式切换操作。)

我在this OSDEV page 找到了类似于 C 代码的用于禁用 NMI 的代码,但我不太明白它应该是什么意思

void NMI_enable() {
    outb(0x70, inb(0x70) & 0x7F);
 }

 void NMI_disable() {
    outb(0x70, inb(0x70) | 0x80);
 }

感觉代码没有上下文,不知道函数 outb 和 inb 的作用就没有意义。

【问题讨论】:

  • 这完全是硬件特定的。
  • Inb 和 outb 是 CPU 指令,在处理器的文档中进行了描述。 (实际上,一个精简的函数包装器可以方便地从 c 中使用)
  • 英特尔...什么? x64? 8051?
  • 具体是 Intel i7 8700K

标签: c x86-64 interrupt osdev nmi


【解决方案1】:

“带外部电路”是指板上在处理器芯片的 NMI 管脚之前有门,如果这些门关闭(关闭),则没有中断信号会到达处理器芯片的 NMI 管脚。

outb 调用可能会激活/停用这些门。

NMI 表示不可屏蔽,这意味着您不能仅通过软件禁用它们。

【讨论】:

    【解决方案2】:

    CPU 有一个不可屏蔽中断 (NMI) 引脚(或硬件等效),用于触发 NMI。有外部电路(或等效硬件)来防止 NMI 到达 CPU。自 80286 以来,使用的机制是通过与CMOS/Realtime Clock(RTC) 控制器关联的 IO 端口。今天,同样的机制仍在硬件中被模仿。

    CMOS/RTC 端口是 0x70 和 0x71。端口 0x70 用于选择要读取或写入的 CMOS/RTC 地址。 CMOS/RTC 地址的前 2 位不构成实际地址的一部分。最高位被重新用作 NMI 切换。如果您将一个字节写入端口 0x70,其中设置了第 7 位(最高有效位),则禁用 NMI。如果您写入的值清除了第 7 位,则启用 NMI。

    inboutb 函数是对低级 IN(字节)和 OUT(字节)指令的 C 包装器。这些指令读取和写入 IO 端口空间。这个C代码来自NMI_enable:

    outb(0x70, inb(0x70) & 0x7F);
    

    相当于:

    uint8_t curbyte = inb(0x70);   /* Read current port 0x70 state */
    outb(0x70, curbyte & 0x7F);    /* Update current state by clearing NMI bit */
                                   /* and write new value back to port 0x70 */
    

    0x7f 是位模式 01111111。将 01111111 与当前字节进行与运算会清除最高位(启用 NMI)。

    这个C代码来自NMI_disable:

    outb(0x70, inb(0x70) | 0x80);
    

    相当于:

    uint8_t curbyte = inb(0x70);   /* Read current port 0x70 state */
    outb(0x70, curbyte | 0x80);    /* Update current state by setting NMI bit */
                                   /* and write new value back to port 0x70 */
    

    0x80 是位模式 10000000。与当前字节进行 ORing 10000000 设置最高位(禁用 NMI)。

    【讨论】:

      【解决方案3】:

      基本上,从操作系统开发人员的角度来看,您可以放心考虑无法禁用 NMI(即使您实际上可以找到禁用它的方法)。如果 NMI 在操作系统引导阶段发生意味着发生了一些严重的事情(通常是硬件、电源),机器不工作,所以你立即停止你的操作系统,因为你的操作系统无论如何都不会工作。

      【讨论】:

        【解决方案4】:

        我已经阅读过,为了根据英特尔的系统编程指南(第 3 卷第 9.9 章)暂时关闭分页,我应该在执行其他任何操作之前禁用中断。

        英特尔错了。

        NMI 通常表示严重的硬件故障(特别是如果您的软件不是故意导致这些故障,特别是如果您没有启用“机器检查异常”)。忽略关键的硬件故障(通过屏蔽 NMI)会导致极端的未定义行为;这很糟糕。

        理想情况下,您需要有保证的行为。最简单的方法是保证如果存在 NMI,CPU 会发生三倍故障(并重置计算机);通过将 IDT 限制设置为零。这在启动期间非常好(当没有可能丢失的最终用户数据时)。

        一种“不太容易”的方法是使用临时 IDT。为了关闭分页,您可以拥有一个身份映射的 IDT(以及 GDT、堆栈等),以便无论在分页打开还是关闭时是否发生 NMI 都可以启动 NMI 处理程序。在 CPU 模式切换期间可以使用类似的技巧(依赖于 IVT/IDT 条目的大小发生变化的事实,这会导致 NMI 的 IVT/IDT 条目位于不同的地址,具体取决于“NMI 时的 CPU 模式”) .

        当然,理智的人不会在启动后暂时禁用分页(或进行 CPU 模式切换);所以没有理由想要更多的“保证 NMI 上的三重故障”(在启动期间)。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-11-29
          • 2011-02-13
          • 2011-06-30
          • 1970-01-01
          • 2011-08-19
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多