APIC: Advanced Programmable Interrupt Controller高级可编程中断控制器总结
简介:
APIC 是装置的扩充组合用来驱动 Interrupt 控制器。在目前的建置中,系统的每一个部份都是经由 APIC Bus 连接的。"本机 APIC" 为系统的一部份,负责传递 Interrupt 至指定的处理器;举例来说,当一台机器上有三个处理器则它必须相对的要有三个本机 APIC。自 1994 年的 Pentium P54c 开始Intel 已经将本机 APIC 建置在它们的处理器中。实际建置了 Intel 处理器的电脑就已经包含了 APIC 系统的部份。
组成
I/O APIC的组成为: 一组24条IRQ线,一张24项的中断复位向表(Interrupt Redirection Table),可编程寄存器,通过APIC总线发送和接收APIC信息的一个信息单元。与8259A的IRQ引脚不同,中断优先级与引脚号没有关系: 中断复位向表中的每一项都有可以被单独编程以指明中断向量和优先级、目标处理器以及选择处理器的方式。复位向表中的信息用于把每个外部IRQ信号转换为一条消息,然后,通过APIC总线把消息发送给一个或者多个本地APIC单元。
系统中另一个重要的部份为 I/O APIC。系统中最多可拥有 8 个 I/O APIC。它们会收集来自 I/O 装置的 Interrupt 讯号且在当那些装置需要 interrupt 时传送讯息至本机 APIC。每个 I/O APIC 有一个专有的 interrupt 输入 (或 IRQ) 号码。Intel 过去与目前的 I/O APIC 通常有 24 个输入 -- 其它的可能有多逹 64 个。而且有些机器拥有数个 I/O APIC,每一个分别有自己的输入号码,加起来一台机器上会有上百个 IRQ 可供装置 Interrupt 使用。
然而,系统中若没有 I/O APIC,那本机 APIC 就没有用处。像这样的状况下,Windows 2000 会还原使用 8259 PIC 。
作用
CPU内部必须内置APIC单元。Intel多处理规范的核心就是高级可编程中断控制器(Advanced Programmable Interrupt Controllers--APICs)的使用。CPU通过彼此发送中断来完成它们之间的通信。通过给中断附加动作(actions),不同的CPU可以在某种程度上彼此进行控制。每个CPU有自己的APIC(成为那个CPU的本地APIC),并且还有一个I/O APIC来处理由I/O设备引起的中断,这个I/O APIC是安装在主板上的,但每个CPU上的APIC则不可或缺,否则将无法处理多CPU之间的中断协调。
一条APIC总线把"前端"I/O APIC连接到本地APIC。来自外部设备的IRQ线连接到I/O APIC,因此,相对于本地APIC,I/O APIC起到路由器的作用。
APIC由 local APIC and IO APIC及中间的 APIC bus组成. Local APIC within processor而 IO APIC within chipset(一般都在南桥里). LINT0 and LINT1是local APIC的两个 input pins. 一般都和 INTR & NMI shared共享.即 pin name is: LINT0/INTR & LINT1/NMI. 当 IO APIC被设成 "bypass mode"(即不靠IO APIC传递 interrupts),则 8259的 INTR会接到 local APIC的 LINT0;而 chipset内的 NMI logic 也会接到 local APIC的 LINT1.
APIC是专有的 bus,用来传递 interrupts;好处是:dedicated bus,所以可以减少 memory bus traffic;而且,在多处理器的系统也可以 share interrupts(找闲的CPU来处理 interrupts);当然,可以接更多的 interrupt sources....
一般接到 IO APIC输入端的 interrupt sources都是固定的;depends on chipset designer. 还没看过可以变换的,所以UEFI的BIOS在处理IOxAPIC时,是不需要重新配置interrupts的
PCIDEVICE
Title = "NB PCI-E Root Port #1"
Bus = 00h
Dev = 01h
Fun = 00h
BridgeBus = 021h
GPEbit = 09h
SleepNum = 03h
ASLdeviceName = "NPE1"
//<PIC_Link> ; <APIC_Link>,Describe PCI Device IntA pin, how it is connected onto PIC and (or) IO APIC input.
IntA = LNKA; 16
IntB = LNKB; 17
IntC = LNKC; 18
IntD = LNKD; 19
Token = "NB_IOxAPIC_SUPPORT" "=" "0"
DeviceType = OnBoard
PCIBusSize = PciEx
PCIBridge = Yes
WakeEnabled = Yes
End
IRQLINK
Name = "LNKA"
Reg = 060h
IrqList = 3,4,5,6,7,10,11,12,14,15
InterruptType = LevelLow
End
结合上述的code和图说明:
PIRQ[A…H]#是chipset中8路interrupt signals。
在PIC Mode时,每一路PIRQx#可以配置到IRQ table的任何一个IRQ# pin上。当然这是PIC mode时的配置,现要说明的是什么是IRQ Table:
由上表可知,chipset中的IRQ table由2个8259级联而成,总共提供15个Interrupts,其中用于PCI routing的IRQx有IRQ3…7,IRQ9…12,IRQ14,IRQ15,另外的interrupts用于如system timer HEPI #0和HEPI #1。所以PIRQ[A…H]#可以接到IRQ Table中的Pin List#有3,4,5,6,7,9,10,11,12,14和15,具体接在哪一个pin#上,是需要BIOS去配置的。怎么配置?就是要往PCH的PIRQ[n]_ROUT寄存器中填值。
PIRQ[n]_ROUT是配置PIRQ[A…H]的interrupt routing control 寄存器,
PIRQA---->61H
PIRQB---->62H
PIRQC---->63H
PIRQD---->64H
PIRQE---->68H
PIRQF---->69H
PIRQG---->6AH
PIRQH---->6BH
其中IRQ Routing[bit3:0]不同的值表示将PIRQx 分配到不同的IRQx
PIRQ[A…H]在BIOS code中对应LNK[A…H]
LNKx在.sdl中有定义成IrqList = 3,4,5,6,7,10,11,12,14,15 表示IRQ table
在APIC Mode时,PIRQ[A…H]被分配到IOAPIC的INTIN[16…23],如上图所示,一一对应。那么IOAPIC的 interrupt mapping是怎么样的呢?
如上表,IOAPIC提供了24路interrupts,其中16-23是PCI IRQ routing的interrupts。比较PIC Mode的图表和APIC Mode时的图表,可以不同Mode时的interrupt结构。
现在要说明的是INT[A…D]是如何与PIRQ[A…H] routing起来的呢?
PCI Device的offset:3C,offset:3D分别代表着Interrupt Line (ILINE)和Interrupt Pin (IPIN),但是在PCI config里ILINE和IPIN都是OR,无法修改的,那么怎样才能修改ILINE和IPIN呢?在PCH的10.1.34---10.1.41对应着D31IP-D22IP (Device xx Interrupt Pin Register),描述了PCH上PCIe device的IPIN分配情况,要想修改IPIN,就得改D31IP-D22IP中某个register。
同样,在PCH的10.1.42—10.1.49对应着D31IR-D22IR (Device xx Interrupt Route Register),描述了PCH上PCIe Device的ILINE的分配情况。通过修改DxxIP和DxxIR可以改变interrupt pin和PIRQx的分配情况。
从Device到PIRQ[A…H],再到PIC或APIC的整个架构如下:
现在说说APIC:
APIC分为Local APIC和IO APIC,Local APIC的介绍可参考Intel® 64 and IA-32 Architectures Software Developer’s Manual Volume 3A: CHAPTER 9 ADVANCED PROGRAMMABLE INTERRUPT CONTROLLER (APIC)
IO APIC是集成在PCH内的APIC,负责将external interrupt resources report给CPU的Local APIC,在UEFI 的BIOS code中有如下定义:
在BIOS code中是怎么样对IRQ进行配置的呢,可以参考PciInterrupts.c中的ProgramPciIrq().
OS是怎么知道IRQ Routing的呢?
整个platform上的IRQ Routing必须由BIOS report给OS,BIOS可以通过以下几种方式report IRQ Routing给OS:
上一篇: 关于PHP生成静态页面详细讲荽
下一篇: PHP批量去除PHP文件中bom的代码