【自制操作系統08】中斷


由於中斷這塊的知識和代碼都占較大篇幅,因此分成兩章來講,本章不包含任何中斷的代碼,只講理論部分,以及中斷的大概流程。代碼實現部分由下一章來講解

【自制操作系統09】中斷的代碼實現

一、到目前為止的程序流程圖

為了讓大家清楚目前的程序進度,畫了到目前為止的程序流程圖,如下。

二、什么是中斷

這里我們先從形象的角度來描述,中斷就是讓操作系統停止手中正在進行的工作,先把中斷信號對應的處理程序執行完畢,再回到之前的程序中繼續進行,這樣一個機制。

一個很形象的說法是,我們的操作系統就是 中斷驅動 的,可以把操作系統簡單理解為一個 死循環,無時無刻不在等待中斷的來臨,被動 地執行相應的任務。

while(true){
    操作系統代碼
}

三、中斷的分類

外部中斷

外部中斷通過兩個引腳連接到 CPU 上,一個是可屏蔽中斷 INTR,一個是不可屏蔽中斷 NMI

  • INTR:硬盤、打印機、網卡等設備發出的中斷信號,可通過 eflags 寄存器的 IF 位將所有這些外部設備的中斷屏蔽
  • NMI:電源掉電、內存讀寫錯誤、總線奇偶校驗錯誤等災難性的錯誤,不可屏蔽,CPU 必須立刻處理

對於可屏蔽中斷,Linux 的處理方式是分成 上半部下半部。上半部執行時關閉中斷,立刻執行完畢;下半部執行時打開中斷,此時如果有其他中斷進來,則讓給其他中斷(也是上半部執行完畢)。

內部中斷

內部中斷可分為 軟中斷 和 異常,二者均是不可屏蔽的(即不受 eflags 的 IF 位影響)

  • 軟中斷:就是軟件發起的中斷,最常見的也是我們之后進行系統調用的,就是 int 8位立即數,可表示 256 中中斷。還有一些不常用的,甚至可以叫做異常,下面簡單列出

    • int3:中斷向量號3,調試斷點指令
    • into:中斷向量號4,中斷溢出指令
    • bound:中斷向量號5,檢查數組索引越界指令
    • ud2:中斷向量號6,未定義指令,常用於軟件測試中主動發起這個中斷
  • 異常:指令執行期間 CPU 內部產生的錯誤引起,如分母為 0 將發起 6 號中斷(異常),未定義的指令發起 6 號中斷

    • Fault(故障):可恢復的錯誤。發生此中斷時,CPU 將機器狀態恢復到異常之前的狀態,之后調用中斷處理程序,結束后返回。常見的如 缺頁異常
    • Trap(陷阱):有意的異常。通常是調試程序中用 int3 指令主動觸發。
    • Abort(終止):不可恢復的異常。直接將此程序從進程表中去掉。

四、中斷號

我們知道一個中斷對應着一個 中斷號(中斷向量號),下面列表說明

中斷號 含義 來源 類型 是否有錯誤碼
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

五、中斷描述符表 IDT

我們先來回顧一下上一講 【自制操作系統07】深入淺出特權級 說的四種門描述符

type值 存在位置 用法
任務門 0101 GDT、LDT、IDT 與TSS配合實現任務切換,不過大多數操作系統都不這么玩
中斷門 1110 IDT 進入中斷后屏蔽中斷(eflags的IF位置0),linux利用此實現系統調用,int 0x80
陷阱門 1111 IDT 進入中斷后不屏蔽中斷
調用門 1100 GDT、LDT 用戶用call或jmp指令從用戶進程進入0特權級

你看,正如上一講所說,中斷門進入后先是屏蔽了中斷,也就是中斷例程的 上半部,程序中可以隨時打開中斷,也就自然到了 下半部,這就是 linux 系統的處理方式。

如何找到中斷描述符表呢?你猜的沒錯,正如找 段描述符表頁表 等一樣,有個 IDTR 寄存器存儲它的位置(0-15位是表界限,16-47位表示表基址),有個 lidt 指令負責加載 IDTR。經典做法,我們見過太多次了,就不多說啦,不理解的可以從本系列開頭開始看喲。

六、中斷處理過程

上圖就表示了整個中斷處理的過程,不過還有幾處圖中沒有顯示

特權級檢查:CPL <= 門描述符DPL && CPL > 目標代碼段DPL

棧的處理:將 CS、EIP、EFLAGS、SS、ESP 寄存器的值壓入中斷處理程序使用的棧

七、8259A芯片

我們之前說過,外部設備發出中斷信號,進入 CPU 的 INT 引腳上。但如果有多個外部設備近乎同時發送中斷信號,CPU 先處理哪一個呢?未被處理的中斷信號又記錄在哪里呢?這時候就需要有個 中間的代理設備 來負責這個事情。

這個代理設備叫做 可編程中斷控制器 PIC,其中 8259A 芯片是最常見的一種,我們這里把它的內部結構展示出來,由於是硬件相關,就不展開細說了,但由於之后要為其進行編程,所以大家先有個印象。

八、中斷代碼實現

由於到此篇幅過長,且中斷代碼的實現也是需要很大篇幅描述的,包括 可編程中斷控制器的初始化,IDT 的初始化,以及中斷例程代碼的編寫,所以將放在下一章進行講解。

【自制操作系統09】中斷的代碼實現

寫在最后:開源項目和課程規划

如果你對自制一個操作系統感興趣,不妨跟隨這個系列課程看下去,甚至加入我們(下方有公眾號和小助手微信),一起來開發。

參考書籍

《操作系統真相還原》這本書真的贊!強烈推薦

項目開源

項目開源地址:https://gitee.com/sunym1993/flashos

當你看到該文章時,代碼可能已經比文章中的又多寫了一些部分了。你可以通過提交記錄歷史來查看歷史的代碼,我會慢慢梳理提交歷史以及項目說明文檔,爭取給每一課都准備一個可執行的代碼。當然文章中的代碼也是全的,采用復制粘貼的方式也是完全可以的。

如果你有興趣加入這個自制操作系統的大軍,也可以在留言區留下您的聯系方式,或者在 gitee 私信我您的聯系方式。

課程規划

本課程打算出系列課程,我寫到哪覺得可以寫成一篇文章了就寫出來分享給大家,最終會完成一個功能全面的操作系統,我覺得這是最好的學習操作系統的方式了。所以中間遇到的各種坎也會寫進去,如果你能持續跟進,跟着我一塊寫,必然會有很好的收貨。即使沒有,交個朋友也是好的哈哈。

目前的系列包括


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM