因爲中斷這塊的知識和代碼都佔較大篇幅,所以分紅兩章來說,本章不包含任何中斷的代碼,只講理論部分,以及中斷的大概流程。代碼實現部分由下一章來說解html
【自制操做系統09】中斷的代碼實現linux
爲了讓你們清楚目前的程序進度,畫了到目前爲止的程序流程圖,以下。git
這裏咱們先從形象的角度來描述,中斷就是讓操做系統中止手中正在進行的工做,先把中斷信號對應的處理程序執行完畢,再回到以前的程序中繼續進行,這樣一個機制。編程
一個很形象的說法是,咱們的操做系統就是 中斷驅動 的,能夠把操做系統簡單理解爲一個 死循環,無時無刻不在等待中斷的來臨,被動 地執行相應的任務。數組
while(true){ 操做系統代碼 }
外部中斷經過兩個引腳鏈接到 CPU 上,一個是可屏蔽中斷 INTR,一個是不可屏蔽中斷 NMIide
對於可屏蔽中斷,Linux 的處理方式是分紅 上半部 和 下半部。上半部執行時關閉中斷,馬上執行完畢;下半部執行時打開中斷,此時若是有其餘中斷進來,則讓給其餘中斷(也是上半部執行完畢)。學習
內部中斷可分爲 軟中斷 和 異常,兩者均是不可屏蔽的(即不受 eflags 的 IF 位影響)測試
咱們知道一箇中斷對應着一個 中斷號(中斷向量號),下面列表說明操作系統
中斷號 | 含義 | 來源 | 類型 | 是否有錯誤碼 |
---|---|---|---|---|
0 | divide error | DIV and IDIV instructions | Fault | 無 |
1 | debug | any code or data reference | Fault/Trap | 無 |
2 | NMI Interrupt | NMI | Interrupt | 無 |
3 | Breakpoint | INT3 instruction | Trap | 無 |
4 | Overflow | INTO instruction | Trap | 無 |
5 | bound range exceeded | BOUND instruction | Fault | 無 |
6 | invalid opcode | UD2 instruction or reserved opcode.1 | Fault | 無 |
7 | device not available | floationg-point or WAIT/FWAIT instruction | Fault | 無 |
8 | double fault | any instruction that can generate an exception, an NMI, or an INTR | Fault | Y(0) |
9 | CoProcessor Segment Overrun | Floating-point instruction.2 | Fault | 無 |
10 | invalid TSS | task switch or TSS access | Fault | Y |
11 | segment not present | loading segment registers or accessing system segments | Fault | Y |
12 | stack segment fault | stack operations and SS register loads | Fault | Y |
13 | general protection | any memory reference and other protection checks | Fault | Y |
14 | page fault | any memory reference | Fault | Y |
15 | reserved | |||
16 | floating-point error | floating-point or WAIT/FWAIT instruction | Fault | 無 |
17 | alignment check | any data refrence in memory.3 | Fault | Y(0) |
18 | machine check | error codes and source are model dependent.4 | Fault | 無 |
19 | SIMD floating-point exception | SIMD floating-point instruction5 | Fault | 無 |
20-31 | reserved | |||
32-255 | maskable interrupts | External Interrupt from INTR pin or INT n instruction | Interrupt | 無 |
門 | type值 | 存在位置 | 用法 |
---|---|---|---|
任務門 | 0101 | GDT、LDT、IDT | 與TSS配合實現任務切換,不過大多數操做系統都不這麼玩 |
中斷門 | 1110 | IDT | 進入中斷後屏蔽中斷(eflags的IF位置0),linux利用此實現系統調用,int 0x80 |
陷阱門 | 1111 | IDT | 進入中斷後不屏蔽中斷 |
調用門 | 1100 | GDT、LDT | 用戶用call或jmp指令從用戶進程進入0特權級 |
你看,正如上一講所說,中斷門進入後先是屏蔽了中斷,也就是中斷例程的 上半部,程序中能夠隨時打開中斷,也就天然到了 下半部,這就是 linux 系統的處理方式。debug
如何找到中斷描述符表呢?你猜的沒錯,正如找 段描述符表,頁表 等同樣,有個 IDTR 寄存器存儲它的位置(0-15位是表界限,16-47位表示表基址),有個 lidt 指令負責加載 IDTR。經典作法,咱們見過太屢次了,就很少說啦,不理解的能夠從本系列開頭開始看喲。
上圖就表示了整個中斷處理的過程,不過還有幾處圖中沒有顯示
特權級檢查:CPL <= 門描述符DPL && CPL > 目標代碼段DPL
棧的處理:將 CS、EIP、EFLAGS、SS、ESP 寄存器的值壓入中斷處理程序使用的棧
咱們以前說過,外部設備發出中斷信號,進入 CPU 的 INT 引腳上。但若是有多個外部設備近乎同時發送中斷信號,CPU 先處理哪個呢?未被處理的中斷信號又記錄在哪裏呢?這時候就須要有個 中間的代理設備 來負責這個事情。
這個代理設備叫作 可編程中斷控制器 PIC,其中 8259A 芯片是最多見的一種,咱們這裏把它的內部結構展現出來,因爲是硬件相關,就不展開細說了,但因爲以後要爲其進行編程,因此你們先有個印象。
因爲到此篇幅過長,且中斷代碼的實現也是須要很大篇幅描述的,包括 可編程中斷控制器的初始化,IDT 的初始化,以及中斷例程代碼的編寫,因此將放在下一章進行講解。
若是你對自制一個操做系統感興趣,不妨跟隨這個系列課程看下去,甚至加入咱們,一塊兒來開發。
《操做系統真相還原》這本書真的贊!強烈推薦
當你看到該文章時,代碼可能已經比文章中的又多寫了一些部分了。你能夠經過提交記錄歷史來查看歷史的代碼,我會慢慢梳理提交歷史以及項目說明文檔,爭取給每一課都準備一個可執行的代碼。固然文章中的代碼也是全的,採用複製粘貼的方式也是徹底能夠的。
若是你有興趣加入這個自制操做系統的大軍,也能夠在留言區留下您的聯繫方式,或者在 gitee 私信我您的聯繫方式。
本課程打算出系列課程,我寫到哪以爲能夠寫成一篇文章了就寫出來分享給你們,最終會完成一個功能全面的操做系統,我以爲這是最好的學習操做系統的方式了。因此中間遇到的各類坎也會寫進去,若是你能持續跟進,跟着我一塊寫,必然會有很好的收貨。即便沒有,交個朋友也是好的哈哈。
目前的系列包括