windows - 如何在同一系统上发送 nmi

标签 windows windows-7 x86 x86-64

我需要在我正在使用的系统上发送 NMI。我想测试我已经实现的一些东西。有没有 Windows 驱动程序例程可以让我们做到这一点?我想我可以使用 __outword 写入端口。还有其他办法吗?

我还有一个问题。是否有任何特定情况会导致 NMI? (但是,我不希望系统出现 BSOD 或三重故障。)

谢谢

最佳答案

来自Intel's Software Development Manual: System Programming Guide :

The nonmaskable interrupt (NMI) can be generated in either of two ways:

  • External hardware asserts the NMI pin.
  • The processor receives a message on the system bus (Pentium 4, Intel Core Duo, Intel Core 2, Intel Atom, and Intel Xeon processors) or the APIC serial bus (P6 family and Pentium processors) with a delivery mode NMI.

It is possible to issue a maskable hardware interrupt (through the INTR pin) to vector 2 to invoke the NMI interrupt handler; however, this interrupt will not truly be an NMI interrupt. A true NMI interrupt that activates the processors NMI-handling hardware can only be delivered through one of the mechanisms listed above.

因此,如果您只想触发 NMI 处理程序,则只需使用 int $2(英特尔语法中的 int 02h)即可。但是,如果您需要确保它不被屏蔽,则需要外部硬件来触发它,或者使用 APIC。


如果您选择使用 APIC 发送 NMI,最简单的方法是发送处理器间中断。为此,您需要访问本地 APIC 的寄存器,这些寄存器映射到物理内存,默认位于地址 0xFEE00000,尽管可以更改。您需要找到包含 APIC 寄存器的物理页并将其映射到虚拟内存中,以便您可以访问它们。

为了发送IPI,您需要写入中断配置寄存器。 ICR 的低 32 位位于 APIC 页内的 0x300,高 32 位位于 0x310。要发送 NMI,您需要:

  1. 获取要将 NMI 发送到的处理器的 APIC ID。如果您想将其发送到正在运行的处理器,这很简单,因为您可以从 APIC 的 0x20 位 24-31 读取它。
  2. 将 APIC ID 写入目标字段,高位 ICR 寄存器的第 24-31 位。
  3. 将值 0x4400 写入低位 ICR 寄存器。该值的第 8-10 位表示您正在发送 NMI,第 14 位表示您正在使用断言触发模式。

写入 APIC 寄存器时,必须写入完整的 32 位值。此外,ICR 中的位 13、16-17 和 20-55 是保留的,因此不应更改它们的值。您还必须在写入低位之前写入 ICR 的高位,因为 IPI 是由写入低位触发的。

下面是用 C 语言向当前处理器发送 NMI 的示例。

#define APIC_ID_OFFSET 0x20
#define ICR_LOW_OFFSET 0x300
#define ICR_HIGH_OFFSET 0x310
// Convenience macro used to access APIC registers
#define APIC_REG(offset) (*(unsigned int*)(apicAddress + offset))

void *apicAddress; // This should contain the virtual address that the APIC registers are mapped to

// Get the current APIC ID. Leave it in the high 8 bits since that is where it needs to be written anyway
unsigned int apicID = APIC_REG(APIC_ID_OFFSET) & 0xFF000000;
unsigned int high = APIC_REG(ICR_HIGH_OFFSET) & 0x00FFFFFF;
high |= apicID;
unsigned int low = APIC_REG(ICR_LOW_OFFSET) & 0xFFF32000;
low |= 0x4400;
APIC_REG(ICR_HIGH_OFFSET) = high;
APIC_REG(ICR_LOW_OFFSET) = low;

关于windows - 如何在同一系统上发送 nmi,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7422708/

相关文章:

c++ - 我目前正在创建我的第一个 Windows 设备驱动程序 "Hello world."事件。我正在使用 Microsoft Visual Studio 2012。

c++ - 如何判断我的进程是否是从 Windows 自动运行键启动的?

windows-7 - WiX MSI 完成后,如何以管理员身份启动应用程序?

x86 - 当我从内联汇编中调用 C++ 函数时,如何将参数传递给它们

mysql - 将 MSSQL 数据库备份导入 MySQL 工作台

windows - 无法在 VC++ 2010 中设置 glew

windows-7 - 使用文件夹名称中的空格注册 DLL

gcc 编译 SDL 的正确命令行参数

security - 合法代码中出现 0x90 (NOP) 序列

linux - 自修改代码总是在 Linux 上出现段错误