x86架構中的外部中斷結構-Part 1:中斷控制器的演化

aalanwyr發表於2022-02-17

      本文主要講解了x86體系架構從外部裝置接受中斷的過程,本文是系列文章的第一部分,試圖回答以下問題:

  • 什麼是PIC以及它的用途是什麼?
  • 什麼是APIC以及它的用途是什麼?LAPICI/O APIC的目的是什麼?
  • APIC,xAPIC以及x2APIC之間的區別在哪兒?
  • 什麼是MSI? MSI以及MSI-X之間的存在哪些區別?
  • $PIR, MPtable, ACPI tables的用途是什麼?

       如果你想知道上述問題的答案,或者僅僅想簡單瞭解一下中斷控制器的發展過程,耐心看完本文,你一定會有收穫。

原文地址:

     本文是翻譯的國外大佬的文章,根據自己的理解稍加修改了語序,由於自己也在學習階段,翻譯難免有紕漏,如果感覺有些地方讀不懂,建議可以去看看原文,並向我提出翻譯修改的建議,謝謝。

《External Interrupts in the x86 system. Part 1. Interrupt controller evolution》

Introduction

       對於那些不瞭解中斷(interrupt)是啥的同學,這裡引用Wikipedia的內容進行簡單的介紹:

       在系統程式設計中,中斷是由硬體或軟體向CPU(處理器)發出的一種訊號,提示CPU需要立即處理一些高優先順序任務。 中斷提醒CPU注意高優先順序任務,同時停止CPU當前正在執行的程式碼。 隨後CPU暫停當前執行的程式碼、儲存程式狀態、轉而去執行一箇中斷處理程式(或中斷服務程式,ISR)來響應中斷事件。 中斷是暫時的,在中斷處理程式完成後,處理器恢復到之前執行的程式碼。

        中斷一般分為兩類:硬體中斷和軟體中斷。

  • 硬體中斷:外設一般使用硬體中斷向作業系統傳遞自身需要執行的訊號,在計算機內部,外部裝置通過向處理器傳送電子警報訊號實現硬體中斷,例如磁碟控制器,或者外部裝置,當按下鍵盤上的鍵或移動滑鼠時會觸發硬體中斷,從而使處理器讀取按鍵值或滑鼠位置。啟動硬體中斷的行為被稱為中斷請求(IRQ)。
  • 軟體中斷:軟體中斷是由處理器本身的異常,或者是指令集中特殊指令在執行時引起的中斷。 前者通常稱為陷阱(trap)或異常(exception),用於處理程式執行期間發生的錯誤或事件,這些錯誤或事件無法在程式內處理。 例如,數字除以零,會引發除零異常,由此產生軟體中斷。

       本文主要講解的是硬體中斷IRQ

       中斷的目的是什麼? 舉個例子,在網路卡傳輸資料包的過程中,我們希望資料包到達後立即對來自網路卡的傳入資料包執行操作,而不是cpu連續詢問網路卡«我的資料包到達了嗎?»,輪詢方式會浪費cpu處理的時間,在這個案例之下可以使用外部硬體中斷 IRQ,網路卡的中斷線應該連線到 CPU 的 INTR 線,網路卡每收到一個資料包,就通過中斷線發出訊號,通知cpu資料包已經收到,然後cpu停下手頭的工作,去讀取這個資料包。

         但是如果有很多外部裝置我們該怎麼辦?不可能將每個裝置的中斷線直接連線到CPU上,雖然通訊效率高,但 在 CPU 上製作大量的 INTR 引腳是不現實的。

 

       為了解決多個外設的中斷線連線CPU的問題,一個特殊的晶片被設計出來,這就是中斷控制器(an interrupt controller)。

PIC(可程式設計中斷控制器 Programm Interrupt Controller

      第一個中斷控制器晶片是 Intel 8259 PIC。 它有 8 條輸入線(IRQ0-7)和 1 條輸出線(連線中斷控制器和 CPU 的 INTR 線)。 當其輸入線上的任意一個裝置發生中斷時,8259 將通過 INTR 線發出中斷訊號。 於是CPU 知道某個裝置請求了中斷,處理器將詢問 PIC的 8 條輸入線(IRQx),並判斷哪條是此中斷的來源。 這個輪詢有一些開銷,但現在我們有 8 條中斷線而不是 1 條。

     

         很快 8 條輸入線就不夠用了。 為了增加中斷線的總數,兩個 8259 控制器(主控制器master和從控制器slave)以級聯方式進行連線(Dual PIC)。

           0 7 IRQ 由第一個 Intel 8259 PIC(主)處理,從 8 15 IRQ 由第二個 Intel 8259 PIC(從)處理。 只有主裝置直接連線到 CPU 並可以發出中斷訊號。 如果第 8-15 行有中斷,第二個 PIC(從機)將通過 IRQ2 線向主機傳送中斷訊號,然後主機向 CPU 傳送中斷訊號。 這種級聯中斷佔用了 16 條線路中的 1 條,但對所有外部裝置總共產生了 15 條中斷線(8+7

         

     上述中斷控制器級聯方案很快被開發社群採用,現在當有人談論PIC(可程式設計中斷控制器)時,通常是指Dual PIC system即雙PIC級聯絡統。過了一段時間,8259改進為8259A。有了這個控制器,晶片組中就包含了雙PIC系統。當外部裝置連線的主匯流排是ISA時,這個系統就足夠了。不同的裝置需要連線到不同的IRQ線路,因為ISA匯流排的中斷是不可共享的。       裝置中斷幾乎都按照如下標準進行對映:   

Example (from here):

IRQ 0 — system timer

IRQ 1 — keyboard controller

IRQ 2 — cascade (interrupt from slave controller)

IRQ 3 — serial port COM2

IRQ 4 — serial port COM1

IRQ 5 — parallel port 2 and 3 or sound card

IRQ 6 — floppy controller

IRQ 7 — parallel port 1

IRQ 8 — RTC timer

IRQ 9 — ACPI

IRQ 10 — open/SCSI/NIC

IRQ 11 — open/SCSI/NIC

IRQ 12 — mouse controller

IRQ 13 — math co-processor

IRQ 14 — ATA channel 1

IRQ 15 — ATA chanel2

Intel 8259晶片的配置和工作通過I如下I/O埠進行:

     

Chip

Register

I/O port

Master PIC

Command

0x0020

Master PIC

Data

0x0021

Slave PIC

Command

0x00A0

Slave PIC

Data

0x00A1

8259A更加完整的說明文件在此連結here

         後來,外設數量超過了15臺,PCI匯流排也逐漸替代了ISA匯流排,相比於靜態的ISA匯流排,PCI匯流排上的裝置可以動態的加入到系統中,同時匯流排上的中斷可以共享,這樣可以實現利用一條中斷線IRQ連線多個裝置。最後,為了解決中斷線不足的問題,設計者決定將所有PCI裝置的中斷分配到PIRQ線(Programmable Interrupt Request 可程式設計中斷請求)。

         例如,假設我們在PIC控制器和20個PCI裝置上有4條空閒的中斷線。我們可以將來自5臺裝置的中斷合併成一條PIRQx線,並將這些PIRQx線連線到PIC控制器。在這種情況下,如果一條PIRQx線路上出現中斷,處理器必須詢問與該線路相連的所有裝置的中斷情況,確定對哪個裝置響應。由此將PCI中斷線與PIRQx線連線的裝置稱為PIR路由器。使用這種方法必須要確保PIRQx線路沒有連線到ISA匯流排中斷上(這會產生衝突),同時要確保PIRQx線路分佈是均衡的(我們連線到一條線路的裝置越多,CPU在響應哪個裝置的中斷時需要輪詢的次數就越多)。

           

 

        Note:上圖展示了PCI裝置->PIR的連線過程,在實際電路中,它們之間的連線更加複雜。實際上,每個PCI裝置有4條中斷線(INTA、INTB、INTC、INTD)和多達8箇中斷函式,其中每個函式只能有一個INTx中斷。每個中斷函式將使用哪條INTx線取決於晶片組配置。

       從本質上講,中斷函式彼此間是獨立的。例如,一個PCI裝置可以具有Smbus控制器函式、SATA控制器函式和LPC橋接函式。從作業系統(OS)的角度來看,每個函式就像一個單獨的裝置,有自己的配置空間(PCI配置)。 PIC控制器的中斷路由資訊由BIOS傳送給作業系統,BIOS主要通過$PIR 、3Ch暫存器、3Dh暫存器來對PCI 進行配置。

       $PIR 表規範可以在微軟提供的網站查詢,或者從 PCI BIOS Specification獲取相關資訊。

APIC

        最後一種方法主要用於多處理器系統。本質上,PIC只能向一個CPU傳送中斷,在多處理器系統中,需要均衡的向CPU通知中斷。這個問題的解決方案是新增一種新的PIC介面----APIC(Advanced PIC)。

       每一個處理器都新增一個特殊的控制器LAPIC(local APIC),以及提供外部裝置中斷路由的I/O APIC控制器。這些所有的控制器都連線在APIC 匯流排上,裝置連線示意圖如下。

   

         當一個外部中斷訊號輸入到 APIC的I/O口上,這個控制器會將該中斷訊號傳送到系統中任意一個CPU上的LAPIC上,在上述傳輸方式中,APIC控制器可以均衡的將中斷訊號傳入不同的處理器上。第一款APIC晶片是82489DX,它是一個單獨的晶片,內部含有LAPIC和APIC,對於上圖中的雙處理器系統,需要三個這樣的晶片:兩個用於LAPIC,一個用於I/O APIC。後來,LAPIC功能直接包含在處理器中,APIC部分與82093AA晶片分離。

         APIC 82093AA晶片有24個輸入,APIC體系架構最多可支援16個CPU。中斷0-15用於舊的ISA中斷,以便與舊的系統相容,中斷16-23用於所有PCI裝置。通過這種劃分,ISA和PCI中斷之間的所有衝突都可以輕鬆避免。隨著空閒中斷線數量的增加,也可以用來增加PIRQx線的數量。APIC和LAPIC程式設計可以通過MMIO完成。LAPIC暫存器通常放在地址0xFEE00000上,APIC暫存器放在地址0xFEС00000上,因此可以需要重新配置它們。與PIC的情況一樣,最初獨立的晶片後來會成為晶片組(處理器)的一部分。

        APIC 體系結構的下一代是xAPIC (x -extended),可以完全向後相容,並且系統支援的CPU個數增加到了256。xAPIC的下一代體系架構是x2APIC.該系統可以支援的CPUs數量增加到了  2^32。可以在xAPIC模式下執行,也可以在新的x2APIC模式下執行。在這種新模式下,控制器程式設計不是通過MMIO完成的,而是通過MSR暫存器(速度快得多)。根據該連結(this link,),IOMMU來支援該模式的程式設計。

        值得一提的是,系統中可能有多個APIC控制器。例如,南橋中的APIC負責24次中斷,北橋中的另一個APIC負責32次中斷。在APIC系統中,中斷通常被稱為GSI(全域性系統中斷)。因此,上述南北橋系統整體的GSIs為0-55。我們如何確定CPU內部是否含有LAPIC,以及它支援哪種APIC體系結構?我們可以通過檢查CPUID中的標誌位來確定。

        為了幫助OS 發現 LAPIC 和 APIC硬體的存在,以及使用它們。BIOS可以通過MPtable(舊方法)或ACPI表(在本例中是MADT表)來提供有關它們的資訊,並載入到OS中。除了上述資訊,MPtable和ACPI都應該包含具體的中斷路由資訊。這包含著哪個裝置具體使用哪個中斷線的資訊(類似於$PIR表),以及相互對映關係。

        我們可以通過檢視官方文件(official specification)來了解MPtable,早些時候,該規範出現在英特爾網站上,但目前只能在存檔版本中找到。ACPI規範可在UEFI網站上找到(當前版本為6.2)。

MSI

        隨著APIC的發展,所有裝置的中斷線導致系統變得異常複雜並且增加了錯誤概率。同時PCI express匯流排也取代了PCI匯流排,PCIe匯流排簡化了中斷系統,該匯流排中沒有中斷線,但是為了向下相容,中斷訊號(INTx#)用一種單獨的訊息進行模擬。PCI匯流排中,中斷的連線是通過物理佈線實現的。而PCIe匯流排中的中斷是邏輯連線的,並通過PCIe 橋接器進行傳輸。PCI express引入了一種全新的中斷傳遞方法——MSI(訊息訊號中斷)。在這種方式中,裝置只需將資料寫入CPU LAPICMMIO區域中的一個特殊位置,即可發出有關中斷的訊號。訊號傳輸示意圖如下:

       

       早些時候,單個PCI裝置只包含4箇中斷,但是現在可以提供多達32箇中斷。在MSI的情況下,沒有共享的中斷線:每個中斷自然地對應於它的裝置。 MSI中斷還解決了另一個問題。例如,一個裝置進行一個記憶體寫入事務,並希望通過中斷髮出其完成的訊號。但是,寫入事務在傳輸過程中可能會在匯流排上延遲(裝置無法知道)。在這種情況下,中斷訊號可能提前到達CPU,因此處理器將讀取尚未生效的資料。如果使用MSI,MSI資訊將以與資料訊息相同的方式傳輸,因此不能提前傳送,從而不會出現衝突的情況。

       需要注意的是,沒有LAPIC,MSI中斷將無法工作,但是MSI可以取代APIC(正如上圖所示,進一步簡化了電路的設計)。隨和一段時間的發展,MSI擴充套件到了MSI-X,現在每個裝置最多可以處理2048箇中斷,並且可以指定哪一個CPU去處理哪一個中斷,這對網路卡等高負載裝置都非常的有用。MSI不需要單獨的BIOS表來支援,但外設需要指明它自身與哪一個MSI訊號相對應,這些資訊都需要包含在外設的驅動程式中。

Сonclusion

   在本文中,我們學習了有關中斷控制器演變的相關知識,並大致瞭解了x86中斷外設的一些基本知識。

    在Part2部分中,我們將進行練習,瞭解如何在Linux中使用前面提到的每個中斷控制器。

    在Part3部分,我們將研究coreboot程式碼,並檢視晶片組中需要哪些設定才能實現正確的中斷路由資訊。

Links:

Acknowledgments

Special thanks to Jacob Garber from the coreboot community for helping me with this article translation.

Special thanks to Alex's suggestion for Computer architecture review

  

        

 

相關文章