簡介:
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: