天天看點

《作業系統真象還原》——0.20 BIOS中斷、DOS中斷、Linux中斷的差別

本節書摘來自異步社群《作業系統真象還原》一書中的第0章,第0.20節,作者:鄭鋼著,更多章節内容可以通路雲栖社群“異步社群”公衆号檢視

在計算機系統中,無論是在實模式,還是在保護模式,在任何情況下都會有來自外部或内部的事件發生。如果事件來自于cpu内部就稱為異常,即exception。例如,cpu在計算算法時,發現分母為0,就抛出了除0異常。如果事件來自于外部,也就是該事件由外部裝置發出并通知了cpu,這個事件就稱為異常。

bios和dos都是存在于實模式下的程式,由它們建立的中斷調用都是建立在中斷向量表(interrupt vector table,ivt)中的。它們都是通過軟中斷指令int 中斷号來調用的。

中斷向量表中的每個中斷向量大小是4位元組。這4位元組描述了一個中斷處理例程(程式)的段基址和段内偏移位址。因為中斷向量表的長度為1024位元組,故該表最多容納256個中斷向量處理程式。計算機啟動之初,中斷向量表中的中斷例程是由bios建立的,它從實體記憶體位址0x0000處初始化并在中斷向量表中添加各種處理例程。

bios中斷調用的主要功能是提供了硬體通路的方法,該方法使對硬體的操作變得簡單易行。這句話是否也表明了不通過bios調用也是可以通路硬體的?必須是的,否則bios中斷處理程式又是如何操作硬體呢?操作硬體無非是通過in/out指令來讀寫外設的端口,bios中斷程式處理是用來操作硬體的,故該處理程式中一定到處都是in/out指令。

bios為什麼添加中斷處理例程呢?

(1)給自己用,因為bios也是一段程式,是程式就很可能要重複性地執行某段代碼,它直接将其寫成中斷函數,直接調用多省心。

(2)給後來的程式用,如加載器或boot loader。它們在調用硬體資源時就不需要自己重寫代碼了。

bios是如何設定中斷處理程式的呢?

bios也要調用别人的函數例程。

bios夠底層吧?難道它還要依賴别人?是啊,bios也是軟體,也要有求于别人。首先硬體廠商為了讓自己生産的産品易用,肯定事先寫好了一組調用接口,必然是越簡單越好,直接給接口函數傳一個參數,硬體就能傳回一個輸出,如果不易用的話,廠商肯定倒閉了。

那這些硬體自己的接口代碼在哪裡呢?

每個外設,包括顯示卡、鍵盤、各種控制器等,都有自己的記憶體(主機闆也有自己的記憶體,bios就存放在裡面),不過這種記憶體都是隻讀存儲器rom。硬體自己的功能調用例程及初始化代碼就存放在這rom中。根據規範,第1個記憶體單元的内容是0x55,第2個存儲單元是0xaa,第3個存儲機關是該rom中以512位元組為機關的代碼長度。從第4個存儲單元起就是實際代碼了,直到第3個存儲單元所示的長度為止。

有問題了,cpu如何通路到外設的rom呢?

通路外設有兩種方式。

(1)記憶體映射:通過位址總線将外設自己的記憶體映射到某個記憶體區域(并不是映射到主機闆上插的記憶體條中)。

(2)端口操作:外設都有自己的控制器,控制器上有寄存器,這些寄存器就是所謂的端口,通過in/out指令讀寫端口來通路硬體的記憶體。

控制顯示卡用的便是記憶體映射+端口操作的方式,這個以後會在操作顯示卡時介紹。

從記憶體的實體位址0xa0000開始到0xfffff這部分記憶體中,一部分是專門用來做映射的,如果硬體存在,硬體自己的rom會被映射到這片記憶體中的某處,至于如何映射過去的,咱們暫時先不要深入了,這是硬體完成的工作。

如圖0-11所示,bios在運作期間會掃描0xc0000到0xe0000之間的記憶體,若在某個區域發現前兩個位元組是0x55和0xaa時,這意味着該區域對應的rom中有代碼存在,再對該區域做累加和檢查,若結果與第3個位元組的值相符,說明代碼無誤,就從第4個位元組進入。這時開始執行了硬體自帶的例程以初始化硬體自身,最後,bios填寫中斷向量表中相關項,使它們指向硬體自帶的例程。

《作業系統真象還原》——0.20 BIOS中斷、DOS中斷、Linux中斷的差別

中斷向量表中第0h~1fh項是bios中斷。

有沒有新的疑問?外設的記憶體是如何被映射的?我也不知道,這是早期硬體工程師們大膽且天才的做法,他們在很久以前就解決了。有知道的同學希望你告訴我,哈哈,在這裡,我就先當它是我的公設了。

另外,上面說的是bios在填寫中斷向量表,那該表是誰建立的呢?答案就是cpu原生支援的,不用誰負責建立。之前我曾說過,軟體是靠硬體來運作的,軟體能實作什麼功能,很大程度上取決于硬體提供了哪些支援。軟體中隻要執行int 中斷向量号,cpu便會把向量号當作下标,去中斷向量表中定位中斷處理程式并執行。

dos是運作在實模式下的,故其建立的中斷調用也建立在中斷向量表中,隻不過其中斷向量号和bios的不能沖突。

0x20~0x27是dos中斷。因為dos在實模式下運作,故其可以調用bios中斷。

dos中斷隻占用0x21這個中斷号,也就是dos隻有這一個中斷例程。

dos中斷調用中那麼多功能是如何實作的?是通過先往ah寄存器中寫好子功能号,再執行int 0x21。這時在中斷向量表中第0x21個表項,即實體位址0x21*4處中的中斷處理程式開始根據寄存器ah中的值來調用相應的子功能。

而linux核心是在進入保護模式後才建立中斷例程的,不過在保護模式下,中斷向量表已經不存在了,取而代之的是中斷描述符表(interrupt descriptor table,idt)。該表與中斷向量表的差別會在講解中斷時詳細介紹。是以在linux下執行的中斷調用,通路的中斷例程是在中斷描述符表中,已不在中斷向量表裡了。

linux的系統調用和dos中斷調用類似,不過linux是通過int 0x80指令進入一個中斷程式後再根據eax寄存器的值來調用不同的子功能函數的。再補充一句:如果在實模式下執行int指令,會自動去通路中斷向量表。如果在保護模式下執行int指令,則會自動通路中斷描述符表。

以上主要對bios中斷多介紹了一點,盡管對dos說得不多,不過有了bios中斷的表述,相信同學們對dos中斷調用也清楚了,其原理介于bios中斷調用和linux中斷調用之間。後面在實作系統調用時,全是基于linux思想的,是以在此對linux系統調用的介紹點到為止。

繼續閱讀