不可屏蔽中断 (NMI) 可以通过以下两种方式之一产生:
- 外部硬件置位 NMI 引脚。
- 处理器在系统总线(Pentium 4、Intel Core Duo、Intel Core 2、Intel Atom 和 Intel Xeon 处理器)或 APIC 串行总线(P6 家族和 Pentium 处理器)上使用交付模式 NMI 接收消息。
和
可以向向量 2 发出可屏蔽的硬件中断(通过 INTR 引脚)以调用 NMI 中断处理程序;然而,这个中断并不是真正的 NMI 中断。激活处理器 NMI 处理硬件的真正 NMI 中断只能通过上面列出的机制之一传递。
因此,如果您只想触发 NMI 处理程序,您可以简单地使用int $2( int 02hin Intel 语法)。但是,如果您需要确保它不被屏蔽,您将需要外部硬件来触发它,或者使用 APIC。
如果选择使用 APIC 发送 NMI,最简单的方法是发送处理器间中断。为此,您需要访问映射到物理内存的本地 APIC 寄存器,默认地址为 0xFEE00000,但可以更改。您需要找到包含 APIC 寄存器的物理页面并将其映射到虚拟内存中,以便您可以访问它们。
为了发送IPI,您需要写入中断配置寄存器。ICR 的低 32 位位于 APIC 页面内的 0x300,高 32 位位于 0x310。要发送 NMI,您需要:
写入 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;
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1297 次 |
| 最近记录: |