6

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

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

我在这个 OSDEV 页面上找到了看起来像用于禁用 NMI 的 C 代码,但我不太明白它应该是什么意思

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

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

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

4

4 回答 4

7

The CPU has a Non-Maskable Interrupt (NMI) pin (or hardware equivalent) that is used to trigger an NMI. There is external circuitry (or hardware equivalent) to prevent NMIs from reaching the CPU. Since the 80286 the mechanism used was through IO ports associated with the CMOS/Realtime Clock(RTC) controller. This same mechanism is still mimicked in hardware today.

The CMOS/RTC ports are 0x70 and 0x71. Port 0x70 is used to select a CMOS/RTC address to read or write from. The top 2 bits of the CMOS/RTC address don't form part of the actual address. The top most bit was re-purposed to be the NMI toggle. If you write a byte to port 0x70 where bit 7 (most significant bit) is set, NMI is disabled. If you write a value where bit 7 is clear then NMIs are enabled.

The inb and outb functions are C wrappers around the low level IN (byte) and OUT (byte) instructions. These instructions read and write to the IO port space. This C code from NMI_enable:

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

Is the equivalent of:

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 is the bit pattern 01111111. ANDing 01111111 with the current byte clears the top most bit (enabling NMI).

This C code from NMI_disable:

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

Is the equivalent of:

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 is the bit pattern 10000000. ORing 10000000 with the current byte sets the top most bit (disabling NMI).

于 2019-03-28T17:16:40.493 回答
6

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

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

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

于 2019-03-28T09:55:46.153 回答
1

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

英特尔错了。

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

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

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

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

于 2020-05-04T04:04:37.943 回答
0

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

于 2020-05-04T03:10:05.413 回答