4. I/O APIC 架构:寄存器基址与 IOREDTBL 重定向表项
I/O APIC 是 x86 系统中负责收集外部硬件中断(如 PCI 设备、定时器、键盘等)并将其以消息形式发送给 Local APIC 的关键组件。本章节深入剖析 I/O APIC 的寄存器基址映射机制以及核心数据结构——I/O 重定向表项(IOREDTBL)。
4.1 I/O APIC 寄存器基址与访问方式
I/O APIC 通过一组 内存映射寄存器(Memory-Mapped I/O, MMIO) 与 CPU 通信。系统软件通过读写这些寄存器来配置中断路由、屏蔽中断以及查询状态。
I/O APIC 的寄存器基址由系统芯片组(如 Intel PCH 或 AMD FCH)在复位后默认分配,通常位于 0xFEC00000(对于第一个 I/O APIC)。每个寄存器占用 4 字节对齐的地址空间,但为了兼容旧版 APIC 的索引/数据访问模型,I/O APIC 实际只暴露两个关键的 MMIO 窗口:索引寄存器(Index Register) 和 数据寄存器(Data Register)。
| 偏移地址(基址 +) | 寄存器名称 | 宽度 | 描述 |
|---|---|---|---|
| 0x00 | IOREGSEL(索引寄存器) | 32 位 | 写入要访问的寄存器编号(8 位有效,高 24 位保留) |
| 0x10 | IOWIN(数据寄存器) | 32 位 | 对 IOREGSEL 指定的寄存器进行读写操作 |
| 0x20 | EOI(中断结束寄存器) | 32 位 | 写入 0 表示当前中断处理结束(仅用于 Level Trigger 模式) |
以下是一个典型的 I/O APIC 寄存器访问代码示例(C 语言风格):
// 定义 I/O APIC 基址(假设为 0xFEC00000)
#define IOAPIC_BASE 0xFEC00000
#define IOAPIC_IOREGSEL (IOAPIC_BASE + 0x00)
#define IOAPIC_IOWIN (IOAPIC_BASE + 0x10)
// 读取 I/O APIC 寄存器的函数
uint32_t ioapic_read(uint8_t reg_index) {
volatile uint32_t *regsel = (volatile uint32_t *)IOAPIC_IOREGSEL;
volatile uint32_t *data = (volatile uint32_t *)IOAPIC_IOWIN;
*regsel = reg_index; // 选择寄存器
return *data; // 读取数据
}
// 写入 I/O APIC 寄存器的函数
void ioapic_write(uint8_t reg_index, uint32_t value) {
volatile uint32_t *regsel = (volatile uint32_t *)IOAPIC_IOREGSEL;
volatile uint32_t *data = (volatile uint32_t *)IOAPIC_IOWIN;
*regsel = reg_index; // 选择寄存器
*data = value; // 写入数据
}
4.2 I/O APIC 内部寄存器布局
除了上述 MMIO 窗口,I/O APIC 内部还包含一组通过索引访问的配置寄存器。最重要的两个是:
- IOAPICID(索引 0x00): 标识 I/O APIC 的 ID,用于多 I/O APIC 系统中的仲裁。
- IOAPICVER(索引 0x01): 版本寄存器,高 8 位表示最大重定向表项数量(Max Redirection Entry,实际数量为 Max Redir Entry + 1)。
- IOAPICARB(索引 0x02): 仲裁优先级寄存器(仅用于兼容模式)。
- IOREDTBL[0] ~ IOREDTBL[n](索引 0x10 ~ 0x10 + 2*n): 重定向表项,每个表项占用两个 32 位寄存器(低 32 位 + 高 32 位)。
4.3 IOREDTBL 重定向表项结构详解
IOREDTBL(I/O Redirection Table)是 I/O APIC 的核心数据结构。每个表项对应一个外部中断输入引脚(INTINx),定义了该中断如何被路由到目标 CPU 以及如何被触发。每个 IOREDTBL 表项共 64 位,分为低 32 位(Lower DWord)和高 32 位(Upper DWord)。
| 位范围 | 字段名称 | 描述 |
|---|---|---|
| 63:56 | Destination Field | 目标 CPU 的 APIC ID(在物理模式下)或 Logical Destination(在逻辑模式下) |
| 55:17 | Reserved | 保留位,必须写 0 |
| 16 | Mask | 中断屏蔽位:1 = 屏蔽该中断,0 = 允许中断 |
| 15 | Trigger Mode | 触发模式:0 = Edge(边沿触发),1 = Level(电平触发) |
| 14 | Remote IRR | 远程中断请求寄存器(只读):1 = 正在服务该 Level 中断,0 = 空闲 |
| 13 | Interrupt Input Pin Polarity | 中断输入引脚极性:0 = 高电平有效/上升沿,1 = 低电平有效/下降沿 |
| 12 | Delivery Status | 投递状态(只读):0 = 空闲,1 = 正在发送中断消息 |
| 11 | Destination Mode | 目标模式:0 = Physical(物理),1 = Logical(逻辑) |
| 10:8 | Delivery Mode | 投递模式:000 = Fixed,001 = Lowest Priority,010 = SMI,100 = NMI,101 = INIT,111 = ExtINT |
| 7:0 | Interrupt Vector | 中断向量号(0 ~ 255),必须为 16 字节对齐(即低 4 位为 0) |
4.4 IOREDTBL 中断路由流程示意图
下图展示了从外部设备产生中断信号到 I/O APIC 根据 IOREDTBL 配置生成中断消息的完整流程:
4.5 IOREDTBL 配置实例:路由 PCI 设备中断
假设我们需要将连接到 I/O APIC INTIN16 引脚的 PCI 设备中断路由到 CPU #0(APIC ID = 0),使用 Fixed 投递模式、Level 触发、Active Low 极性,中断向量号为 0x50。对应的 IOREDTBL 配置如下:
// 假设 I/O APIC 基址为 0xFEC00000
// INTIN16 对应的 IOREDTBL 索引:低 32 位 = 0x10 + 16*2 = 0x30,高 32 位 = 0x31
// 配置低 32 位(IOREDTBL[16].low)
// Bit 7:0 = Vector = 0x50
// Bit 10:8 = Delivery Mode = 000 (Fixed)
// Bit 11 = Destination Mode = 0 (Physical)
// Bit 13 = Polarity = 1 (Active Low)
// Bit 15 = Trigger Mode = 1 (Level)
// Bit 16 = Mask = 0 (Unmasked)
uint32_t low_dword = (0x50) | // Vector
(0x0 << 8) | // Delivery Mode = Fixed
(0x0 << 11) | // Destination Mode = Physical
(0x1 << 13) | // Polarity = Active Low
(0x1 << 15) | // Trigger Mode = Level
(0x0 << 16); // Mask = 0
// 配置高 32 位(IOREDTBL[16].high)
// Bit 63:56 = Destination Field = 0x00 (APIC ID 0)
uint32_t high_dword = (0x00 << 24); // Destination = CPU #0
// 写入 I/O APIC
ioapic_write(0x30, low_dword);
ioapic_write(0x31, high_dword);
4.6 多 I/O APIC 与中断路由扩展
现代 x86 平台可能包含多个 I/O APIC 实例(例如,PCH 内部集成一个,独立 PCIe 桥片可能包含另一个)。每个 I/O APIC 拥有独立的 MMIO 基址和 IOREDTBL 表。系统软件通过 ACPI 表(如 MADT)枚举所有 I/O APIC 及其基址。
| I/O APIC 实例 | 典型 MMIO 基址 | 中断输入范围 | 用途 |
|---|---|---|---|
| I/O APIC #0 | 0xFEC00000 | INTIN0 ~ INTIN23 | PCH 内部设备、传统 ISA 中断 |
| I/O APIC #1 | 0xFEC01000 | INTIN0 ~ INTIN15 | PCIe 桥片扩展中断 |
| I/O APIC #2 | 0xFEC02000 | INTIN0 ~ INTIN7 | 专用设备(如 IOMMU) |
在配置多 I/O APIC 系统时,必须确保每个中断源的 IOREDTBL 表项中的 Destination Field 指向正确的目标 CPU,并且 Vector 在整个系统中唯一,以避免中断冲突。