首页 > 解决方案 > 如何以编程方式禁用不可屏蔽中断?

问题描述

我已经阅读过,为了根据英特尔的系统编程指南(第 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 的作用是没有意义的。

标签: cx86-64interruptosdevnmi

解决方案


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).


推荐阅读