1. 程式人生 > >ARM異常處理過程

ARM異常處理過程

恢復 width 禁止 span -c 遇到 處理程序 .com 存儲

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異常處理過程