Windows 如何在同一系统上发送nmi

Windows 如何在同一系统上发送nmi,windows,windows-7,x86,x86-64,Windows,Windows 7,X86,X86 64,我需要在我正在工作的系统上发送nmi。我想测试一些我已经实现的东西。是否有任何windows驱动程序例程允许我们这样做?我想我可以用uu-outford向端口写入数据。还有别的办法吗 我还有一个问题。是否存在导致NMI的特定情况?(但是,我不希望系统出现BSOD或三重故障。) 感谢: 不可屏蔽中断(NMI)可通过以下两种方式之一生成: 外部硬件断言NMI引脚 处理器通过系统总线(奔腾4、Intel Core Duo、Intel Core 2、Intel Atom和Intel Xeon处理器)或

我需要在我正在工作的系统上发送nmi。我想测试一些我已经实现的东西。是否有任何windows驱动程序例程允许我们这样做?我想我可以用uu-outford向端口写入数据。还有别的办法吗

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

感谢:

不可屏蔽中断(NMI)可通过以下两种方式之一生成:

  • 外部硬件断言NMI引脚
  • 处理器通过系统总线(奔腾4、Intel Core Duo、Intel Core 2、Intel Atom和Intel Xeon处理器)或APIC串行总线(P6系列和奔腾处理器)接收消息,并采用NMI传递模式

可以向向量2发出可屏蔽硬件中断(通过INTR引脚),以调用NMI中断处理程序;但是,该中断不会真正成为NMI中断。激活处理器NMI处理硬件的真正NMI中断只能通过上面列出的一种机制传送

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


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

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

  • 获取要将NMI发送到的处理器的APIC ID。如果您想将其发送到正在运行的处理器,这很简单,因为您可以从位24-31的0x20处的APIC读取它
  • 将APIC ID写入高ICR寄存器的目标字段位24-31
  • 将值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;