APIC 可编程中断控制器¶
什么是 APIC¶
在 x86/x64 计算机体系结构中,高级可编程中断控制器(APIC)是一种关键的硬件组件,旨在管理和协调系统内的中断请求。
中断是计算机系统中的一种异步通信机制,用于响应外部事件,如设备状态变化、错误条件或其他重要的系统通知。随着计算机系统的发展和性能需求的提高,早期的中断控制器(如 8259 PIC)逐渐显露出限制,特别是在多处理器系统的环境中。为了克服这些限制,高级可编程中断控制器(APIC)被引入,为计算机系统提供了更灵活、高效的中断处理机制。
APIC 不仅简单地分配中断向量,还提供了更为复杂的功能,如中断优先级、中断屏蔽、中断向量分发等。这使得它成为多处理器系统中协调中断处理的理想选择,并在大型、高性能的计算机系统中发挥关键作用。APIC 的作用不仅仅局限于中断处理,它还协助处理器间通信、同步和系统管理。通过提供多处理器系统中的高级中断控制和协同工作机制,APIC 极大地推动了操作系统和应用程序在复杂环境下的性能表现。
在本实验中,我们不会涉及到深入的 APIC 编程和使用,只需要专注于利用它实现基本的时钟中断和 I/O 设备中断。
APIC 的初始化与编程¶
在基于 APIC 的系统中,每个 CPU 都由一个本地 APIC(LAPIC)控制。LAPIC 通过 MMIO(Memory Mapped I/O)方式映射到物理内存中的某个地址空间,这个地址空间称为 LAPIC 寄存器空间。同时,系统中还有一个 I/O APIC(IOAPIC),它是一个独立的芯片,负责管理系统中所有 I/O 设备的中断请求。I/O APIC 也通过 MMIO 方式映射到物理内存中的某个地址空间。
x2APIC 是 xAPIC 的变体和扩展,主要改进解决了支持的 CPU 数量和接口性能问题,它们都属于 LAPIC 的实现。在本实验中,我们将使用 xAPIC 来实现 LAPIC 的初始化和编程,在之后的描述中,出现的 APIC 均代指 xAPIC。
APIC 的初始化过程基本包括以下几个步骤:
-
禁用 8259 PIC,使得系统只使用 APIC 进行中断处理。
这一步被 UEFI BIOS 自动完成,我们无需关心。
-
检测系统中是否存在 APIC。
-
确定 APIC 的地址空间,即 LAPIC 和 IOAPIC 的 MMIO 地址空间。
由于我们采用了虚拟地址空间,所以这里需要将物理地址映射到虚拟地址空间中,之后再进行 APIC 的相关操作。
-
操作 SPIV(Spurious Interrupt Vector Register, 0xF0)寄存器,启用 APIC 并设置 Spurious IRQ Vector。
-
设置计时器相关寄存器:
- TDCR(0x3E0): Divide Configuration Register,设置分频系数。
- TICR(0x380): Initial Count Register,设置初始计数值。
- LVT Timer(0x320): Local Vector Table Timer,设置中断向量号和触发模式。
-
禁用 LVT LINT0, LVT LINT1,LVT PCINT,向对应寄存器写入 Mask 位。
-
设置错误中断 LVT Error 到对应的中断向量号。
-
连续写入两次 0 以清除错误状态寄存器。
-
向 EOI 寄存器写入 0 以确认任何挂起的中断。
-
设置 ICR 寄存器:
- Destination Shorthand(bit 18-19): 设置为 2,始终将中断发送给所有 APIC
- Delivery Mode(bit 8-10): 设置为 5,INIT De-assert 模式所需
- Level(bit 14): 设置为 0,INIT De-assert 所需
- Trigger Mode(bit 15): 设置为 1,INIT De-assert 所需
设置完成后等待 Delivery Status(bit 12) 为 0。
-
设置 TPR 寄存器为 0,允许接收中断。
以上过程的代码示例会在实验任务文档中进行详细描述,具体细节和设置原因涉及对称多处理 SMP 等内容,不做理解要求,如有兴趣可以自行查阅参考资料了解。
Local APIC 寄存器¶
在启用分页内存的情况下,需要对 LAPIC 寄存器地址进行映射,并虚拟内存地址进行操作。每个寄存器位宽为 32 位,并期望以 32 位整数的形式进行写入和读取。
Offset | Register name | Read/Write permissions |
000h - 010h | Reserved | |
020h | LAPIC ID Register | Read/Write |
030h | LAPIC Version Register | Read only |
040h - 070h | Reserved | |
080h | Task Priority Register (TPR) | Read/Write |
090h | Arbitration Priority Register (APR) | Read only |
0A0h | Processor Priority Register (PPR) | Read only |
0B0h | EOI register | Write only |
0C0h | Remote Read Register (RRD) | Read only |
0D0h | Logical Destination Register | Read/Write |
0E0h | Destination Format Register | Read/Write |
0F0h | Spurious Interrupt Vector Register | Read/Write |
100h - 170h | In-Service Register (ISR) | Read only |
180h - 1F0h | Trigger Mode Register (TMR) | Read only |
200h - 270h | Interrupt Request Register (IRR) | Read only |
280h | Error Status Register | Read only |
290h - 2E0h | Reserved | |
2F0h | LVT Corrected Machine Check Interrupt (CMCI) Register | Read/Write |
300h - 310h | Interrupt Command Register (ICR) | Read/Write |
320h | LVT Timer Register | Read/Write |
330h | LVT Thermal Sensor Register | Read/Write |
340h | LVT Performance Monitoring Counters Register (PCINT) | Read/Write |
350h | LVT LINT0 Register | Read/Write |
360h | LVT LINT1 Register | Read/Write |
370h | LVT Error Register | Read/Write |
380h | Initial Count Register (for Timer) | Read/Write |
390h | Current Count Register (for Timer) | Read only |
3A0h - 3D0h | Reserved | |
3E0h | Divide Configuration Register (for Timer) | Read/Write |
3F0h | Reserved |
你可以参考文末给出的参考资料以获取这些寄存器的细节信息。