ARM異常處理過程
ARM程序在正常執行中,遇到一些特殊情況,需要放下正在執行的工作,去解決異常,然後再返回原來的地方繼續工作,這樣的一套機制稱為ARM異常處理機制。
首先,程序正在正常執行,遇到異常後,不能直接去解決異常,因為此刻程序的一些變量,棧等需要保存,因為等到異常返回後,你要在之前被打斷的地方繼續要原來的目的進行。在程序去處理異常時,需要保存現場,記錄當前的狀態。
那ARM怎樣去記錄當前的狀態呢?具體有以下幾個方面:
1.將CPSR保存到相應異常模式下的SPSR_<mode>,同時當ARM處於Thumb狀態時,要設置T位為ARM狀態,禁止中斷標誌位;
2.將PC保存到相應異常模式下的LR_<mode>中;
3.將狀態寄存器CPSR設置為對應異常模式,CPSR最後四個bit位是異常模式選擇;
4.將PC寄存器指向對應處理異常處理程序的入口,即PC指向異常向量表對應異常類型的地址。
(1)、復位(Reset)(2)、未定義的指令(Undef) (3)、軟件中斷(SWI) (4)、指令預取終止(Abort) (5)、數據訪問異常(DATAABORT) (6)、外部中斷請求(IRQ) (7)、快速中斷請求(FIQ)
異常向量表就是一條條跳轉語句,因為只占用四個字節,所以異常處理程序無法存儲在異常向量表中,需要跳轉到其他地方去執行異常處理程序。
因此,在異常處理之前,首先要完成以上這些操作,不過這些都是硬件自動完成的,所以我們不必操心,但是,在異常處理程序結束後,返回之前的狀態這個過程則需要我們人為設置的。
異常結束返回時:
從SPSR_<mode>恢復CPSR,即恢復異常之前的CPU的狀態
將LR_<mode>恢復PC,PC指向程序被打斷的地方繼續進行,但是不同的異常返回,PC的計算有所不同,下文會講解到。
這些操作都是在ARM狀態下執行的。
好了,異常處理機制暫時完成。
下面來講清楚一些細節問題,上文說到的異常返回時,PC的計算有所不同,那我們來講一下具體有哪些不同:
首先我們要知道,講一下完成指令的過程,ARM狀態下,在異常產生時內核將lr_<mode>=pc-4,意思就是說,這個步驟是要記錄異常返回之後要執行的地址。
但是,lr_<mode>的值是要根據異常的類型進行調整的,如下:
MOV r0,#1 pc-8 正在執行
MOV r1,#2 pc-4 譯碼 這裏保存到lr_<mode>
ADD r0,r0,r1 pc 取指
一條指令(ARM狀態下,一條指令四個字節)分三個階段:取指->譯碼->執行,取指地址(pc)=正在執行的地址+8
(1)從軟件中斷SWI和未定義異常返回:
MOV r0,#1 pc-8
MOV r1,#2 pc-4
ADD r0,r0,r1 pc
這兩種異常是執行SWI指令或未定義指令發生了異常,即是在執行階段發生了異常,所以lr保存的是MOV r1,#2這條指令的地址(pc現在指向異常向量表的0x8(異常處理程序的入口)的地址),
所以異常返回後,執行的指令是從MOV r1,#2這裏開始,所以lr_<mode>的值直接給pc即可,即:
MOVS pc,lr_<mode>
(2)從FIQ、IRQ和預取指令異常返回:
這兩種異常必須要等到當前指令執行完才能去執行異常處理程序,所以執行完當前指令後,預取指令pc和譯碼指令都已經更新了(+4),如下圖:執行MOV r0,#8這條指令時,中斷信號來了,
但是要等到這條指令執行完才能去執行異常處理程序,此時異常處理返回時要從MOV r1,#2這條指令開始執行。
MOV r0,#1 pc-8 <-異常信號到來
MOV r1,#2 pc-4
ADD r0,r0,r1 pc
但是執行完MOV r0,#1後,pc已經更新,指向了下一條指令,如下:
MOV r0,#1 pc-12
MOV r1,#2 pc-8
ADD r0,r0,r1 pc-4
MOV r1,r0 pc
若異常返回時,此時pc-4為ADD r0,r0,r1指令,但是程序應該從MOV r1,#2這條指令開始,所以不能直接將lr_<mode>給pc,而是將lr_<mode> - 4 給pc,即:
SUBS pc,lr,#4
(3)預取指令異常
該異常在取指令時發生異常,但是要在執行階段才響應異常,lr_<mode>為MOV r1,#2 的地址
MOV r0,#1 pc-8 <-異常處理
MOV r1,#2 pc-4
ADD r0,r0,r1 pc <-異常信號到來
此異常可能是取指令時內存沒有訪問權限或者為空,所以在異常處理程序中將內存內容修改好,在返回時再次執行MOV r0,#1,所以返回時pc應指向MOV r0,#1,即
SUBS pc,lr,#4
(4)從數據訪問異常返回:
LDR r0,r3 pc-8 <-異常信號到來
MOV r1,#2 pc-4
ADD r0,r0,r1 pc
此異常是在是在執行LDR r0,r3時訪問數據錯誤導致的異常,返回時要重新執行LDR r0,r3 ,
LDR r0,r3 pc-12
MOV r1,#2 pc-8
ADD r0,r0,r1 pc -4
MOV r1,r0 pc
此時pc已經更新,若要重新執行LDR r0,r3,將pcl指向lr_<mode> - 8 ,即:
SUBS pc, lr, #8
所以總結一下,異常處理程序返回時的地址應根據異常的類型決定
(1)判斷異常程序是在指令執行階段進行還是指令執行完後進行,即pc有沒有更新;
(2)異常程序處理完後是否要重新執行指令。
ARM異常處理過程