5 初始化PIC(harib03d)
那好,現在欠債(指昨天沒講完的部分)也還清了,就繼續往后講吧。我們接著昨天繼續做鼠標指針的移動。為達到這個目的必須使用中斷,而要使用中斷,則必須將GDT和IDT正確無誤地初始化。

那就趕緊使用中斷吧……但是,還有一件該做的事沒做——還沒有初始化PIC。那么我們現在就來做。
所謂PIC是“programmable interrupt controller”的縮寫,意思是“可編程中斷控制器”。PIC與中斷的關系可是很密切的喲。它到底是什么呢?在設計上,CPU單獨只能處理一個中斷,這不夠用,所以IBM的大叔們在設計電腦時,就在主板上增設了幾個輔助芯片?,F如今它們已經被集成在一個芯片組里了。
PIC是將8個中斷信號集合成一個中斷信號的裝置。PIC監視著輸入管腳的8個中斷信號,只要有一個中斷信號進來,就將唯一的輸出管腳信號變成ON,并通知給CPU。IBM的大叔們想要通過增加PIC來處理更多的中斷信號,他們認為電腦會有8個以上的外部設備,所以就把中斷信號設計成了15個,并為此增設了2個PIC。
那它們的線路是如何連接的呢?如下頁圖所示。
與CPU直接相連的PIC稱為主PIC(master PIC),與主PIC相連的PIC稱為從PIC(slave PIC)。主PIC負責處理第0到第7號中斷信號,從PIC負責處理第8到第15號中斷信號。master意為主人,slave意為奴隸,筆者搞不清楚這兩個詞的由來,但現在結果是不論從PIC如何地拼命努力,如果主PIC不通知給CPU,從PIC的意思也就不能傳達給CPU?;蛟S是從這種關系上考慮,而把它們一個稱為主人,一個稱為奴隸。
另外,從PIC通過第2號IRQ與主PIC相連。主板上的配線就是這樣,無法用軟件來改變。

為什么是第2號IRQ呢?事實上筆者也搞不清楚。是不是因為第0號和第1號已經被占用了,而第2號現在還空著,所以就用它了呢。嗯……如果有人想進一步了解這個問題,請一定打電話問問IBM的大叔們。
■■■■■
有人可能會納悶兒,怎么突然講起硬件來了?這是因為,如果不懂得這部分的硬件結構,就無法順利設定PIC。
int.c的主要組成部分
void init_pic(void) /* PIC的初始化 */ { io_out8(PIC0_IMR, 0xff ); /* 禁止所有中斷 */ io_out8(PIC1_IMR, 0xff ); /* 禁止所有中斷 */ io_out8(PIC0_ICW1, 0x11 ); /* 邊沿觸發模式(edge trigger mode)*/ io_out8(PIC0_ICW2, 0x20 ); /* IRQ0-7由INT20-27接收 */ io_out8(PIC0_ICW3, 1 << 2); /* PIC1由IRQ2連接 */ io_out8(PIC0_ICW4, 0x01 ); /* 無緩沖區模式 */ io_out8(PIC1_ICW1, 0x11 ); /* 邊沿觸發模式(edge trigger mode)*/ io_out8(PIC1_ICW2, 0x28 ); /* IRQ8-15由INT28-2f接收 */ io_out8(PIC1_ICW3, 2 ); /* PIC1由IRQ2連接 */ io_out8(PIC1_ICW4, 0x01 ); /* 無緩沖區模式 */ io_out8(PIC0_IMR, 0xfb ); /* 11111011 PIC1以外全部禁止 */ io_out8(PIC1_IMR, 0xff ); /* 11111111 禁止所有中斷 */ return; }
以上是PIC的初始化程序。從CPU的角度來看,PIC是外部設備,CPU使用OUT指令進行操作。程序中的PIC0和PIC1,分別指主PIC和從PIC。PIC內部有很多寄存器,用端口號碼對彼此進行區別,以決定是寫入哪一個寄存器。
具體的端口號碼寫在bootpack.h里,請參考這個程序。但是,端口號相同的東西有很多,可能會讓人覺得混亂。不過筆者并沒有搞錯,寫的是正確的。因為PIC有些很細微的規則,比如寫入ICW1之后,緊跟著一定要寫入ICW2等,所以即使端口號相同,也能夠很好地區別開來。
■■■■■
現在簡單介紹一下PIC的寄存器。首先,它們都是8位寄存器。IMR是“interrupt mask register”的縮寫,意思是“中斷屏蔽寄存器”。8位分別對應8路IRQ信號。如果某一位的值是1,則該位所對應的IRQ信號被屏蔽,PIC就忽視該路信號。這主要是因為,正在對中斷設定進行更改時,如果再接受別的中斷會引起混亂,為了防止這種情況的發生,就必須屏蔽中斷。還有,如果某個IRQ沒有連接任何設備的話,靜電干擾等也可能會引起反應,導致操作系統混亂,所以也要屏蔽掉這類干擾。
ICW是“initial control word”的縮寫,意為“初始化控制數據”。因為這里寫著word,所以我們會想,“是不是16位”?不過,只有在電腦的CPU里,word這個詞才是16位的意思,在別的設備上,有時指8位,有時也會指32位。PIC不是僅為電腦的CPU而設計的控制芯片,其他種類的CPU也能使用,所以這里word的意思也并不是我們覺得理所當然的16位。
ICW有4個,分別編號為1~4,共有4個字節的數據。ICW1和ICW4與PIC主板配線方式、中斷信號的電氣特性等有關,所以就不詳細說明了。電腦上設定的是上述程序所示的固定值,不會設定其他的值。如果故意改成別的什么值的話,早期的電腦說不定會燒斷保險絲,或者器件冒煙;最近的電腦,對這種設定起反應的電路本身被省略了,所以不會有任何反應。
ICW3是有關主—從連接的設定,對主PIC而言,第幾號IRQ與從PIC相連,是用8位來設定的。如果把這些位全部設為1,那么主PIC就能驅動8個從PIC(那樣的話,最大就可能有64個IRQ),但我們所用的電腦并不是這樣的,所以就設定成00000100。另外,對從PIC來說,該從PIC與主PIC的第幾號相連,用3位來設定。因為硬件上已經不可能更改了,如果軟件上設定不一致的話,只會發生錯誤,所以只能維持現有設定不變。
■■■■■
因此不同的操作系統可以進行獨特設定的就只有ICW2了。這個ICW2,決定了IRQ以哪一號中斷通知CPU?!鞍??怎么有這種事?剛才不是說中斷信號的管腳只有1根嗎?”嗯,話是那么說,但PIC還有個挺有意思的小竅門,利用它就可以由PIC來設定中斷號了。
大家可能會對此有興趣,所以再詳細介紹一下。中斷發生以后,如果CPU可以受理這個中斷,CPU就會命令PIC發送2個字節的數據。這2個字節是怎么傳送的呢?CPU與PIC用IN或OUT進行數據傳送時,有數據信號線連在一起。PIC就是利用這個信號線發送這2個字節數據的。送過來的數據是“0xcd 0x? ? ”這兩個字節。由于電路設計的原因,這兩個字節的數據在CPU看來,與從內存讀進來的程序是完全一樣的,所以CPU就把送過來的“0xcd 0x? ? ”作為機器語言執行。這恰恰就是把數據當作程序來執行的情況。這里的0xcd就是調用BIOS時使用的那個INT指令。我們在程序里寫的“INT 0x10”,最后就被編譯成了“0xcd 0x10”。所以,CPU上了PIC的當,按照PIC所希望的中斷號執行了INT指令。
這次是以INT 0x20~0x2f接收中斷信號IRQ0~15而設定的。這里大家可能又會有疑問了?!爸苯佑肐NT 0x00~0x0f就不行嗎?這樣與IRQ的號碼不就一樣了嗎?為什么非要加上0x20? ”不要著急,先等筆者說完再問嘛。是這樣的,INT 0x00~0x1f不能用于IRQ,僅此而已。
之所以不能用,是因為應用程序想要對操作系統干壞事的時候,CPU內部會自動產生INT 0x00~0x1f,如果IRQ與這些號碼重復了,CPU就分不清它到底是IRQ,還是CPU的系統保護通知。
這樣,我們就理解了這個程序,把它保存為int.c。今后要進行中斷處理的還有很多,所以我們就給它另起了一個名字。從bootpack.c的HariMain調用init_pic。
我們來運行一下“make run”。因為這只是內部設定,所以畫面上沒有什么變化,雖然覺得不過癮沒有特別大的成就感,但看起來可以正常運行。
- Linux系統文件安全實戰全攻略
- Social Media Mining with R
- Learning Windows Server Containers
- PLC控制系統應用與維護
- STM32庫開發實戰指南:基于STM32F4
- Microsoft Operations Management Suite Cookbook
- 嵌入式實時操作系統μC/OS原理與實踐
- 完美應用RHEL 8
- OpenSolaris設備驅動原理與開發
- Python UNIX和Linux系統管理指南
- 鴻蒙HarmonyOS應用開發入門
- Android NDK Beginner's Guide
- 辦公自動化教程(Windows7+Office2010)
- BuddyPress Theme Development
- 基于Arduino的嵌入式系統入門與實踐