Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I disable non maskable interrupts programmatically?

I've read that in order to temporarily turn off paging according to Intel's system programming guide (volume 3 chapter 9.9) I should disable interrupts before doing anything else. I can easily disable maskable interrupts with cli but all the manual says about disabling NMI's is

NMI interrupts can be disabled with external circuitry.(Software must guarantee that no exceptions or interrupts are generated during the mode switching operation.)

I've found code that looks like C code for disabling NMI's at this OSDEV page but I don't quite understand what it's supposed to mean

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

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

it feels like that code has no context and doesn't make sense without knowing what the functions outb and inb do.

like image 344
KeepForgettingMyUserName Avatar asked Mar 28 '19 09:03

KeepForgettingMyUserName


2 Answers

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

like image 115
Michael Petch Avatar answered Sep 24 '22 15:09

Michael Petch


"with external circuitry" means that on the board there are gates before the NMI pins of the processor chip and if these gates are turned off (closed), no interrupt signals will reach the processor chip's NMI pins.

The outb calls probably activate/deactivate these gates.

NMI means non-maskable and it means you cannot disable them with software only.

like image 37
Paul Ogilvie Avatar answered Sep 21 '22 15:09

Paul Ogilvie