談談對中斷的理解
- 2021 年 8 月 22 日
- 筆記
- 01.嵌入式Linux, 06.ARM, 07.單片機
一.中斷的理解
中斷是指CPU在執行過程中,出現了突發事件,CPU必須暫停當前程序的運行,保持現場,轉而處理突發事件,處理完畢之後,恢復現場繼續執行。
中斷按照來源可以分為:
- 內部中斷:來自CPU內部,通常由軟件中斷指令和一些異常錯誤觸發
- 外部中斷:來自CPU外部,通常由外設觸發,經由中斷控制器轉發請求到CPU,然後進行處理
二.單片機的中斷
在玩單片機的時候,中斷用的最多的就是外設觸發中斷了基本就是:
- 中斷源的優先級與打開使能中斷通道
- 綁定EXIT與GPIO,配置中斷觸發方式,引腳是浮空輸入
- 編寫中斷服務程序
這個階段對中斷的理解還停留在:外設觸發中斷、CPU響應中斷、執行中斷服務程序。
三.ARM的異常中斷
在ARM的學習過程中,對異常中斷又有了更深入的理解,涉及到ARM的工作模式、異常中斷、中斷向量表、環境保存與恢復等
ARM工作模式&&異常中斷&&中斷向量表
從ARM的工作模式到異常中斷:
以及ARM的中斷向量表,一般是32Bytes,一個異常中斷佔4Bytes,一般是一個跳轉指令:
其中,中斷優先級的劃分如下:
可以看出:
- 複位就是直接去0x0000_0000地址執行
- FIQ放在中斷向量表最後面,可以直接在中斷向量表後編寫FIQ處理程序,呼應了快速中斷
- FIQ的優先級比IRQ高,可以打斷IRQ
- 系統調用就是利用SWI(軟件中斷)進行處理的
進入中斷和退出中斷的操作
- 將下一條指令地址保存在lr寄存器中,具體是pc+4還是pc+8取決於異常的種類
- 將當前的CPSR拷貝到對應的SPSR
- 根據異常修改CPSR的值
- 根據向量表跳轉到中斷處理程序執行,在中斷處理程序中進行環境保存與恢復
退出異常中斷時的情況:
- 將lr寄存器減去相應的偏移,賦值給pc
- 將SPSR中的值賦值給CPSR
- 清除中斷標誌位(如果在進入中斷是設置了)
中斷異常服務程序
中斷中斷服務程序一般要做的是:
/* und異常處理,進入異常前,硬件完成的事情:將CPSR拷貝到SPSR,將被中斷指令的地址存儲在lr中 */
do_und:
ldr sp, =0x34000000 /* und的棧指針,指向64M 的SDRAM的最高地址,為C函數分配空間 */
stmdb sp!, {r0-r12,lr} /* 保存現場 */
mrs r0, cpsr /* mrs讀出寄存器的值,通過r0寄存器向下面的函數傳參 */
bl Und_Process
ldmia sp!, {r0-r12, pc}^ /* 恢復現場,注意:一定要加!來保存sp的改變 */
- 設置棧,通過sp_und來設置
- 保存現場,包括r0~r12寄存器、lr寄存器,保存lr也是必須的,因為lr中的是異常處理完之後的返回地址
- 調用C處理函數
- 恢復現場,利用ldmia sp!, {r0-r12,pc}^ 恢復各個寄存器的值,將lr寄存器的值賦值給pc寄存器(有待考證,ia是先 後 ),^順便把SPSR中的值恢復到CPSR中
所謂保持現場與恢復現場就是對r0~r12寄存器進行入棧和出棧
中斷控制器
在初始化中斷控制器的時候,主要是打開使能位即可,SRCPND和INTPND是在中斷處理函數里使用的,判斷是哪一個中斷請求的
四.Linux的中斷
Linux中接觸操作系統之後,有了中斷、異常、系統調用的概念,
中斷、異常、系統調用
硬件上的處理:在CPU初始化的時候設置中斷使能標誌,這個中斷使能標誌對異常、中斷、系統調用都是等效的。然後根據內部或者外部事件設置中斷標誌位,根據中斷向量表調用相應的中斷服務例程。
所以,無論是中斷、異常、系統調用,都會在中斷向量表中進行跳轉處理,接下來就是針對性的服務了。
如果是中斷,直接進入設備驅動中,反饋(鼠標、鍵盤的輸入);
如果是異常,直接轉到異常服務例程來做處理;
如果是系統調用,由於系統調用的量很大,不同的系統調用在系統調用表中區分,選擇不同的系統調用實現;
當然,在處理異常中斷的時候,要注意保護現場和恢復現場,可以參考ARM來理解。
Kernel的中斷處理機制
由於中斷會打斷進程的正常調度與運行,勢必要求中斷服務程序盡量短小精悍,然而大多數中斷處理程序中的工作量不會很小。
Linux內核的中斷處理框架是將中斷的處理分為了上半部和下半部:
當然,可以在/proc/interrupts中查看系統中斷的統計信息,包括每個中斷號上的中斷在CPU上發生的次數。
Linux設備驅動中使用中斷的設備需要申請和釋放中斷,使用內核提供的request_irq()和free_irq()接口。
中斷下半部的實現
Linux實現中斷下半部的機制主要有tasklet、工作隊列、軟中斷、線程化irq。
tasklet的執行上下文是軟中斷,執行的時機是上半部返回的時候,只需要定義tasklet及其處理函數,並關聯兩者就可以。關於tasklet的調度,在需要調度tasklet的時候引用一個tasklet_schedule()函數就可以。
工作隊列的執行上下文是內核線程,所以是可以調度和睡眠的。
軟中斷是一種傳統的下半部處理機制,執行時機通常是上半部返回的時候。
五.中斷作為計算機系統中必要的存在
從UBoot、STM32等的啟動代碼中也可以看出,中斷向量表為計算機系統的一種基礎服務存在。