8259A中斷控制器

8259A中斷控制器

8259A晶元是一個中斷管理晶元,中斷的來源除了來自於硬體自身的NMI中斷和來自於軟體的INT n指令造成的軟體中斷之外,還有來自於外部硬體設備的中斷,這些中斷是可屏蔽的。這些中斷也都通過可編程中斷控制器PIC(Programmable Interrupt Controller)進行控制,並傳遞給CPU。

總述


前言

8259A晶元是一個中斷管理晶元,中斷的來源除了來自於硬體自身的NMI中斷和來自於軟體的INT n指令造成的軟體中斷之外,還有來自於外部硬體設備的中斷,這些中斷是可屏蔽的。這些中斷也都通過PIC(Programmable Interrupt Controller)進行控制,並傳遞給CPU。
一個8259A晶元的可以接最多8個中斷源,但由於可以將2個或多個8259A晶元級連(cascade),並且最多可以級連到9個,所以最多可以接64個中斷源。如今絕大多數的PC都擁有兩個8259A,這樣 最多可以接收15個中斷源。
通過8259A可以對單個中斷源進行屏蔽。
在一個8259A晶元有如下幾個內部寄存器
Interrupt Mask Register (IMR)。
Interrupt Request Register (IRR)。
In Service Register (ISR)。
IMR被用作過濾被屏蔽的中斷,IRR被用作暫時放置未被進一步處理的Interrupt,當一個Interrupt正在被CPU處理時,此中斷被放置在ISR中。
除了這幾個寄存器之外,8259A還有一個單元叫做Priority Resolver,當多個中斷同時發生時,Priority Resolver根據它們的優先順序,將高優先順序者優先傳遞給CPU。

8259A工作原理

8259A中斷控制器
8259A中斷控制器
當一個中斷請求從IR0到IR7中的某根線到達IMR時,IMR首先判斷此IR是否被屏蔽,如果被屏蔽,則此中斷請求被丟棄;否則,則將其放入IRR中。
在此中斷請求不能進行下一步處理之前,它一直被放在IRR中。一旦發現處理中斷的時機已到,Priority Resolver將從所有被放置於IRR中的中斷中挑選出一個優先順序最高的中斷,將其傳遞給CPU去處理。IR號越低的中斷優先順序別越高,比如IR0的優先順序別是最高的。
8259A通過發送一個INTR(Interrupt Request)信號給CPU,通知CPU有一個中斷到達。CPU收到這個信號后,會暫停執行下一條指令,然後發送一個INTA(Interrupt Acknowledge)信號給8259A。8259A收到這個信號之後,馬上將ISR中對應此中斷請求的Bit設置,同時IRR中相應的bit會被reset。比如,如果當前的中斷請求是IR3的話,那麼ISR中的bit-3就會被設置,IRR中IR3對應的bit就會被reset。這表示此中斷請求正在被CPU處理,而不是正在等待CPU處理。
隨後,CPU會再次發送一個INTA信號給8259A,要求它告訴CPU此中斷請求的中斷向量是什麼,這是一個從0到255的一個數。8259A根據被設置的起始向量號(起始向量號通過中斷控制字ICW2被初始化)加上中斷請求號計算出中斷向量號,並將其放置在Data Bus上。比如被初始化的起始向量號為8,當前的中斷請求為IR3,則計算出的中斷向量為8+3=11。
CPU從Data Bus上得到這個中斷向量之後,就去IDT中找到相應的中斷服務程序ISR,並調用它。如果8259A的End of Interrupt (EOI)通知被設定位人工模式,那麼當ISR處理完該處理的事情之後,應該發送一個EOI給8259A。
8259A得到EOI通知之後,ISR寄存器中對應於此中斷請求的Bit會被Reset。
如果8259A的End of Interrupt (EOI)通知被設定位自動模式,那麼在第2個INTA信號收到后,8259A ISR寄存器中對應於此中斷請求的Bit就會被Reset。
在此期間,如果又有新的中斷請求到達,並被放置於IRR中,如果這些新的中斷請求中有比在ISR寄存中放置的所有中斷優先順序別還高的話,那麼這些高優先順序別的中斷請求將會被馬上按照上述過程進行處理;否則,這些中斷將會被放在IRR中,直到ISR中高優先順序別的中斷被處理結束,也就是說知道ISR寄存器中高優先順序別的bit被Reset為止。

IRQ2/IRQ9 重定向


兼容性

為什麼要將IRQ2重定向到IRQ9上?這仍然是由於兼容性問題造成的。
早期的IBM PC/XT只有一個8259A,這樣就只能處理8種IRQ。但很快就發現這根本不能滿足需求。所以到了IBM PC/AT,又以級連的方式增加了一個8259A,這樣就可以多處理7種IRQ。原來的8259A被稱作Master PIC,新增的被稱作Slave PIC。但由於CPU只有1根中斷線,Slave PIC不得不級連在Master PIC上,佔用了IRQ2,那麼在IBM PC/XT上使用IRQ2的設備將無法再使用它;但新的系統又必須和原有系統保持兼容,怎麼辦?

新增特性

由於新增加的Slave PIC在原有系統中不存在,所以,設計者從Slave PIC的IRQ中挑出IRQ9,要求軟體設計者將原來的IRQ2重定向到IRQ9上,也就是說IRQ9的中斷服務程序需要去掉用IRQ2的中斷服務程序。這樣,將原來接在IRQ2上的設備現在接在IRQ9上,在軟體上只需要增加IRQ9的中斷服務程序,由它調用IRQ2的中斷服務程序,就可以和原有系統保持兼容。而在當時,增加的IRQ9中斷服務程序是由PC開發商開發的BIOS提供的,不需要用戶進行另外設置。所以就從根本上保證了兼容。

8259A系列晶元的編程


每一個8259A晶元都有兩個I/O ports,程序員可以通過它們對8259A進行編程。
Master 8259A的埠地址是0x20,0x21;Slave 8259A的埠地址是0xA0,0xA1。

8259As的口令

8259A中斷控制器
8259A中斷控制器
程序員可以向8259A寫兩種命令字:
Initialization Command Word (ICW);這種命令字被用作對8259A晶元的初始化。
Operation Command Word (OCW):這種命令被用來向8259A發布命令,以對其進行控制。OCW可以在8259A被初始化之後的任何時候被使用。

8259A主片

下表的內容是Master 8259A的I/O埠地址,以及通過它們所能操作的寄存器。
Address Read/Write Function
0x20 Write Initialization Command Word 1 (ICW1)
Write Operation Command Word 2 (OCW2)
Write Operation Command Word 3 (OCW3)
Read Interrupt Request Register (IRR)
Read In-Service Register (ISR)
0x21 Write Initialization Command Word 2 (ICW2)
Write Initialization Command Word 3 (ICW3)
Write Initialization Command Word 4 (ICW4)
Read/Write Interrupt Mask Register (IMR)
Addresses/Registers for Master 8259A

8259A從片

下表的內容是Slave 8259A的I/O埠地址,以及通過它們所能操作的寄存器。
Address Read/Write Function
0xA0 Write Initialization Command Word 1 (ICW1)
Write Operation Command Word 2 (OCW2)
Write Operation Command Word 3 (OCW3)
Read Interrupt Request Register (IRR)
Read In-Service Register (ISR)
0xA1 Write Initialization Command Word 2 (ICW2)
Write Initialization Command Word 3 (ICW3)
Write Initialization Command Word 4 (ICW4)
Read/Write Interrupt Mask Register (IMR)
Addresses/Registers for Slave 8259A
由於8259A晶元不僅能夠用於IBM PC/X86,也可以被用作MCS-80/85,對於這兩者,在操作模式上有一些不一樣,對於某些寄存器的設置也有所不同。我們後面僅僅討論X86模式相關的內容。

初始化


初始化

當主機上電或複位之後,必須對兩個8259A都進行初始化。事實上,BIOS已經這麼做了。但不幸的是,BIOS對其進行的初始化的結果並非我們所需要。比如,我們要開發保護模式下OS,我們要設置自己的IDT,那麼我們就不能使用BIOS設置的IVT,而在對8259A初始化操作中,我們需要告訴8259A,其相關中斷請求的起始向量號,而我們對IDT的中斷向量布局和BIOS設置的IVT的中斷向量布局可以是不一樣的。這樣,我們也需要對兩個8259A進行初始化。
任何時候,只要向某一個8259A的第一個埠(0x20 for Master,and 0xA0 for Slave)寫入的命令的bit-4(從0算起)為1,那麼這個8259A就認為這是一個ICW1;而一旦一個8259A收到一個ICW1,它就認為一個初始化序列開始了。你可以通過對照上邊的表和後面的表,第一埠可寫的有ICW1,OCW2和OCW3。而ICW1的bit-4要求必須是1,但OCW2和OCW3的bit-4要求必須是0。

協議

8259A的初始化流程協議如下圖所示,程序員對其進行初始化時必須遵守此協議:
ICW1
Bit(s) Function
7:5 Interrupt Vector Addresses for MCS-80/85 Mode.
4 Must be set to 1 for ICW1
3 1 Level Triggered Interrupts
0 Edge Triggered Interrupts
2 1 Call Address Interval of 4
0 Call Address Interval of 8
1 (SINGL) 1 Single PIC
0 Cascaded PICs
0 (IC4) 1 Will be Sending ICW4
0 Don't need ICW4
Initialization Command Word 1 (ICW1)
對於X86,bit-0必須被設置為1;由於當今的IBM PC上都有兩個級連的8259A,所以bit-1應該被設置為0;由於bit-2是為MCS-80/85服務的,我們將其設置為0;bit-3也設置為0;bit-4被要求必須設置為1;bit5:7是為MCS-80/85服務的,對於X86,應將全部將其設為0。
所以,在X86系統上,ICW1應該被設置為二進位00010001 = 0x11。
ICW2
Bit 80x86 Mode
7 I7
6 I6
5 I5
4 I4
3 I3
2 0
1 0
0 0
Initialization Command Word 2 (ICW2)
ICW2被用作指定本8259A中的中斷請求的起始中斷向量,bit0:3必須被設為0;所以,其起始中斷向量必須是8的倍數。比如,我們的OS的設計講來自於Master 8259A的8個中斷請求放在IDT的第32 (從0開始計)個位置到第39個位置,則我們應該將ICW2設為0x20。
這樣,當將來此8259A上接收到一個IRQ時,其低3位會被自動填充為IRQ號。比如,其收到一個IRQ6,將6自動填充到后3位,則生成的向量號為0x26。8259A會在收到CPU發來的第二個INTA信號之後,將生成的向量號放到Data Bus上。
ICW3
Master 8259A和Slave 8259A有不同的ICW3格式。
Bit Function
7 IR7 is connected to a Slave
6 IR6 is connected to a Slave
5 IR5 is connected to a Slave
4 IR4 is connected to a Slave
3 IR3 is connected to a Slave
2 IR2 is connected to a Slave
1 IR1 is connected to a Slave
0 IR0 is connected to a Slave
Initialization Command Word 3 for Master 8259A (ICW3)
Slave 8259A被接在Master 8259A的那個IRQ上,則相應的位就被設置為1,其餘的位都被設置為0。在IBM PC上,Slave 8259A被接在Master 8259A的IRQ2上,則此ICW3的值應該被設置為二進位00000100 = 0x04。
Bit(s) Function
7 Reserved. Set to 0
6 Reserved. Set to 0
5 Reserved. Set to 0
4 Reserved. Set to 0
3 Reserved. Set to 0
2:0 Slave ID
000 Slave 0
001 Slave 1
010 Slave 2
011 Slave 3
100 Slave 4
101 Slave 5
110 Slave 6
111 Slave 7
Initialization Command Word 3 for Slaves (ICW3)
Slave 8259A的ICW3的bit3:7被保留,必須被設為0;而bit0:2被設置為此Slave 8259A被接在Master 8259A的哪個IRQ上。比如,在IBM PC上,Slave 8259A被接在Master 8259A的IRQ2上,則此ICW3應被設為0x02。
ICW4
Bit(s) Function
7 Reserved. Set to 0
6 Reserved. Set to 0
5 Reserved. Set to 0
4 1 Special Fully Nested Mode
0 Not Special Fully Nested Mode
3:2 0x Non - Buffered Mode
10 Buffered Mode - Slave
11 Buffered Mode - Master
1 1 Auto EOI
0 Normal EOI
0 1 8086/8080 Mode
0 MCS-80/85
Initialization Command Word 4 (ICW4)
在80x86模式下,我們不需要使用8259A的特殊功能,因此我們將bit1:4都設為0,這意味使用默認的Full Nested Mode,不使用Buffer,以及手動EOI模式;我們只需要將bit-0設為1,這也正是我們ICW0處提到的我們為什麼必須要ICW4的原因。所以ICW4的值應該被設為0x01。
所以我們可以用下列代碼初始化2個8259A晶元:
inline void init_8259a(void)
{
outb( 0x20,0x11 );
outb( 0xA0,0x11 );
outb( 0x21,0x20 );
outb( 0xA1,0x28 );
outb( 0x21,0x04 );
outb( 0xA1,0x02 );
outb( 0x21,0x01 );
outb( 0xA1,0x01 );
}

操作


操作

一旦按照初始化協議初始化完成之後,程序員就可以在任何時候,以任何順序向8259A發送操作控制字OCW了。
OCW1
Bit PIC 2 PIC 1
7 Mask IRQ15 Mask IRQ7
6 Mask IRQ14 Mask IRQ6
5 Mask IRQ13 Mask IRQ5
4 Mask IRQ12 Mask IRQ4
3 Mask IRQ11 Mask IRQ3
2 Mask IRQ10 Mask IRQ2
1 Mask IRQ9 Mask IRQ1
0 Mask IRQ8 Mask IRQ0
Operation Control Word 1 (OCW1)
OCW1是用來做中斷請求屏蔽用的操作控制字。如果你想屏蔽那個IRQ,只需要對照上表將相應的Bit置為1,然後發送給相應的8259A就可以了。比如我想屏蔽IRQ10,我只需要將0x0A寫到埠0xA1。對應代碼如下:
outb(0x0A,0xA1);
OCW2
Bit(s) Function
7:5 000 Rotate in Auto EOI Mode (Clear)
001 Non Specific EOI
010 Reserved
011 Specific EOI
100 Rotate in Auto EOI Mode (Set)
101 Rotate on Non-Specific EOI
110 Set Priority Command (Use Bits 2:0)
111 Rotate on Specific EOI (Use Bits 2:0)
4 Must be set to 0
3 Must be set to 0
2:0 000 Act on IRQ 0 or 8
001 Act on IRQ 1 or 9
010 Act on IRQ 2 or 10
011 Act on IRQ 3 or 11
100 Act on IRQ 4 or 12
101 Act on IRQ 5 or 13
110 Act on IRQ 6 or 14
111 Act on IRQ 7 or 15
Operation Control Word 2 (OCW2)
通過將bit3:4設置為0,以說明這是一個OCW2。如果bit-6被設為1,則bit0:2有效,其操作則是面向某個IRQ的;否則將bit0:2設為0,其操作是面向整個8259A的所有IRQ的。我們一般只會用到No Specific EOI——因為我們在初始化8259A時,制定的EOI Mode為手動模式,所以當每次對應某個8259A晶元的IRQ的中斷服務程序ISR執行結束后,都需要向8259A發送一個EOI,其對應的OCW2的值為0x20。需要注意的是,由於IBM PC有2個級連的8259A,所以我們每次必須分別給兩個都發一個。
比如下面示例代碼用來向兩個8259A晶元發送EOI,它需要在針對來自於兩個8259A晶元的中斷的服務程序ISR末尾處被調用:
inline void send_eoi(void)
outb( 0x20,0x20 );
outb( 0xA0,0x20 );
OCW3
Bit(s) Function
7 Must be set to 0
6:5 00 Reserved
01 Reserved
10 Reset Special Mask
11 Set Special Mask
4 Must be set to 0
3 Must be set to 1
2 1 Poll Command
0 No Poll Command
1:0 00 Reserved
01 Reserved
10 Next Read Returns Interrupt Request Register
11 Next Read Returns In-Service Register
Operation Control Word 3 (OCW3)
通過將Bit-3設為1,Bit-4設為0,以讓8259A知道這是一個OCW3。OCW3中對我們最有意義的位是bit0:1,我們可以通過將bit-1設為1來通知8259A,下一個讀埠的動作將要讀取IRR或ISR寄存器的內容。
比如下面示例C++代碼用來讀取Master 8259A的IRR寄存器內容到__irr變數中:
void read_irr(unsigned char& __irr)
{
outb(0x02,0x20);
inb(&__irr,0x20);
}

Full Nested Mode

為了讓我們更加理解8259A的中斷控制機理,我們需要說明一下Full Nested Mode。在我們初始化時,只需要將ICW4的bit-4設為0,我們就選擇了Full Nested Mode。
Full Nested Mode其實就是實現按照中斷請求的優先順序別進行搶斷處理的機制——如果當前一個IRQ正在被CPU處理,也就是說,當前CPU正在調用其中斷服務程序ISR;這時8259A又接到了新的IRQ,如果此IRQ的優先順序大於正在處理的IRQ,那麼,此IRQ就會被提交給CPU以優先處理;否則此IRQ則被放置在IRR中,直到所有的高優先順序中斷被處理結束為止。

處理過程

其處理過程大致如下:
在ISR寄存器中有一個8-bit的位元組,範圍為bit[0,7];每一個bit對應一個IRQ(IRQ0-IRQ7對應bit[0,7])。當一個IRQ被提交給CPU之後(收到來自於CPU的第一個INTA信號之後),其對應的bit會被設置為1。比如IRQ6被提交給CPU之後,IS Register的bit-6會被設置為1。當此8259A收到一個EOI之後(對於手動模式,這意味著一個優先順序別最高的中斷請求被處理結束),會將IS Register中被設置的最高優先順序IRQ的對應的bit清為0。比如在收到一個EOI時,發現IS Register的bit-3,bit-5,bit-6被設置,那麼被清除的則是bit-3(越小優先順序別越高)。在清除優先順序最高的bit之後,8259A會到IRR中察看是否有優先順序別高於當前正在處理的IRQ中優先順序別最高的IRQ,如果有,則將此IRQ提交給CPU處理,同時設置相應的bit。還以上面的例子為例,當bit-3被清除之後,如果發現在IRR中有一個IRQ4等待被處理,則將其提交給CPU,在收到來自於CPU的第一個INTA信號之後,則將IS Register的bit-4置為1。
在此過程中,如果8259A接到更高優先順序別的IRQ,則將其立即提交給CPU。比如,當前正在處理的IRQ為IRQ3,IRQ5,那麼IS Register中被設置的bit為bit-3,bit-5;如果此時接到一個IRQ1,則立即將其提交給CPU,在收到來自於CPU的第一個INTA信號之後,則將IS Register的bit-1置為1。
由此過程我們也可以看出,為了實現這種優先順序機制,必須將EOI設為手動模式,也就是說必須將ICW4的bit-1設為0。因為,對於自動EOI模式,8259A會在收到來自於CPU的第2個INTA信號之後,就自動將IS Register中此IRQ對應的bit清0,而事實上,這個時候此IRQ對應的中斷服務程序還沒有被CPU調用,也就是說此IRQ還沒有被處理結束,而由於此IRQ對應的bit已經被清除,如果此IRQ是一個優先順序很高的話,那麼此IRQ的處理完全可以被一個優先順序別更低的IRQ所中斷。這不是我們所需要的。