ARM的異常處理過程分析_第1頁
ARM的異常處理過程分析_第2頁
ARM的異常處理過程分析_第3頁
ARM的異常處理過程分析_第4頁
ARM的異常處理過程分析_第5頁
已閱讀5頁,還剩10頁未讀 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

1、uC/OS-II官網(wǎng)給出來的ARM7-ARM9移植手冊(AN-104),分析了在ARM中移植的問題,想想從來沒有認真的學(xué)習(xí)過ARM的匯編,趁著這個機會復(fù)習(xí)復(fù)習(xí)吧。其實底層的東西才是創(chuàng)造力的心臟。其中的移植代碼中存在的很多問題比如中斷的關(guān)閉和開啟,任務(wù)級別的情景切換,中斷到任務(wù)的情景切換都是我們在平時移植中講到,我也不在此強調(diào)了。在官網(wǎng)中提供的移植過程中存在異常處理機制,這個本不是在移植過程中考慮的,但是文檔中確實提供了一個比較好的處理方式。我在此對這一段時間的學(xué)習(xí)做一個總結(jié)。首先需要了解ARM的異常處理機制,異常是每一種處理器都必須考慮的問題之一,關(guān)鍵在于如何讓處理,返回地址在什么位置都是需要

2、考慮的,ARM中支持7種異常,其中包括復(fù)位、未定義指令異常、軟中斷異常、預(yù)取指令中止、數(shù)據(jù)中止、IRQ、IFQ。每一種異常運行在特定的處理器模式下。我在此逐一的分析。一般異常發(fā)生后,CPU都會進行一系列的操作,這些操作有一部分是CPU自動完成,有一部分是需要我們程序員完成。首先說明CPU會自動完成的部分,用ARM結(jié)構(gòu)手冊中的代碼描述如下:R14_<exception_mode> = return link               

3、 /這個可以參看寄存器的說明,兩個作用SPSR_< exception_mode > = CPSRCPSR4:0 = exception mode numberCPSR5 = 0                       /AEM指令I(lǐng)f <exception_mode>=Reset or Fiq then  &

4、#160; /只有在復(fù)位和FIQ模式下才會關(guān)閉FIQ中斷CPSR6 = 1 CPSR7 = 1                              /任何異常模式下都會關(guān)閉IRQ中斷PC = exception vector address從上面的代碼中我們可以發(fā)現(xiàn)CPU自

5、動處理的過程包括如下:1、  拷貝CPSR到SPSR_<mode>2、  設(shè)置適當?shù)腃PSR位: 改變處理器狀態(tài)進入ARM狀態(tài);改變處理器模式進入相應(yīng)的異常模式;設(shè)置中斷禁止位禁止相應(yīng)中斷。3、  更新LR_<mode>,這個寄存器中保存的是異常返回時的鏈接地址4、  設(shè)置PC到相應(yīng)的異常向量以上的操作都是CPU自動完成,異常的向量表如下:返回地址問題異常的返回地址也是需要我們注意的地方,不同的異常模式返回地址也是存在差異的,這主要是因為各種異常產(chǎn)生的機理存在差別所導(dǎo)致的。這樣我們

6、的需要在異常進入處理函數(shù)之前或者在返回時調(diào)整返回地址,一般采用進入異常處理函數(shù)前進行手動調(diào)整。下面每一種異常R14保存的值都給了出來,其中也包含了CPU自動處理的部分,根據(jù)保存的R14就可以知道怎樣實現(xiàn)地址的返回。復(fù)位異常:可以看出該模式下的先對來說返回地址也比較簡單,不需要做太多的描述。未定義的指令異常:返回的方式也比較簡單:       MOVS  PC, R14軟中斷異常:返回的方式也比較簡單:       MOVS &

7、#160;PC, R14預(yù)取指令中止異常:返回需要做下面的調(diào)整:SUBS      PC, R14, #4數(shù)據(jù)中止返回地址需要做下面的調(diào)整:如果需要重新訪問數(shù)據(jù)則:SUBS      PC, R14, #8如果不需要重新訪問數(shù)據(jù)則:SUBS      PC, R14, #4IRQ中斷的處理過程:返回地址需要做下面的調(diào)整:       SUBS PC

8、,R14,#4IFQ中斷:返回地址需要做下面的調(diào)整:       SUBS  PC, R14 ,#4從上面的代碼可以知道,對于每一種異常,保存的返回地址都是不一樣的,一般都需要我們手動的跳轉(zhuǎn),當然調(diào)整的時機也需要我們選擇,是在進入處理前跳轉(zhuǎn)還是返回時調(diào)整都是需要我們程序員控制的。在ARM Developer Suite Developer Guide中對ARM處理器的異常處理操作提供能更加詳細的解釋,每一種異常下的處理方式如下文描述:異常返回時另一個非常重要的問題是返回地址的確定,在前面曾提到進入異常時處

9、理器會有一個保存LR 的動作,但是該保存值并不一定是正確的返回地址,下面以一個簡單的指令執(zhí)行流水狀態(tài)圖來對此加以說明。我們知道在ARM 架構(gòu)里,PC值指向當前執(zhí)行指令的地址加8處,也就是說, 當執(zhí)行指令A(yù)(地址0x8000)時,PC 等于指令C 的地址(0x8008)。假如指令A(yù) 是“BL”指令,則當執(zhí)行該指令時,會把PC(=0x8008)保存到LR 寄存器里面,但是接下去處理器會馬上對LR 進行一個自動的調(diào)整動作:LR=LR-0x4。這樣,最終保存在 LR 里面的是 B 指

10、令的地址,所以當從 BL 返回時,LR里面正好是正確的返回地址。同樣的調(diào)整機制在所有LR自動保存操作中都存在,比如進入中斷響應(yīng)時,處理器所做的LR 保存中,也進行了一次自動調(diào)整,并且調(diào)整動作都是LR=LR-0x4。下面,我們對不同類型的異常的返回地址依次進行說明:假設(shè)在指令A(yù) 處(地址0x8000)發(fā)生了異常,進入異常響應(yīng)后,LR 上經(jīng)過調(diào)整保存的地址值應(yīng)該是B 的地址0x8004。1、 如果發(fā)生的是軟件中斷,即A 是“SWI”指令異常是由指令本身引起的,從 SWI 中斷返回后下一條執(zhí)行指令就是

11、B,正好是LR 寄存器保存的地址, 所以只要直接把LR 恢復(fù)給PC。MOVS pc, lr2、 發(fā)生的是Undefined instruction異常異常是由指令本身引起的,從異常返回后下一條執(zhí)行指令就是B,正好是LR 寄存器保存的地址, 所以只要直接把LR 恢復(fù)給PC。MOVS pc, lr3、 發(fā)生的是IRQ或FIQ中斷因為指令不可能被中斷打斷,所以A指令執(zhí)行完以后才能響應(yīng)中斷,此時PC已更新,指向指令D的地址(地址0x800C),LR 上經(jīng)過調(diào)整保存的地址值是C 的地址0x8008。中斷返

12、回后應(yīng)該執(zhí)行B指令,所以返回操作是:SUBS pc, lr, #44、 發(fā)生的是Prefetch Abort異常該異常并不是處理器試圖從一個非法地址取指令時觸發(fā),取出的指令只是被標記為非法,按正常處理流程放在流水線上,在執(zhí)行階段觸發(fā)Prefetch Abort異常,此時LR 上經(jīng)過調(diào)整保存的地址值是B 的地址0x8004。異常返回應(yīng)該返回到A指令,嘗試重新取指令,所以返回操作是:SUBS pc, lr, #45、 發(fā)生的是“Data Abort”CPU訪問存儲器時觸發(fā)該異常,此時PC指向指令D的地址(地址0x800C),LR 上經(jīng)過調(diào)整保存的地

13、址值是C 的地址0x8008。異常返回后,應(yīng)回到指令A(yù),嘗試重新操作存儲器,所以返回操作是:SUBS pc, lr, #8以上就是ARM異常的CPU操作部分,接下來就是程序員應(yīng)該完成的操作。1.         由于CPU會自動跳轉(zhuǎn)到對應(yīng)的異常向量中,因此只需要在在各個異常向量中存放對應(yīng)的操作,最簡單的都是存放一個B指令跳轉(zhuǎn)到對應(yīng)的異常處理函數(shù)的操作即可。但由于B指令的跳轉(zhuǎn)返回只有+-32M,而異常處理函數(shù)的地址可能會超過+-32M,因此可以采用另一種方式實現(xiàn)方式:在異常向量中保存一條指令LDR

14、 PC addr,其中的addr中就保存了異常處理函數(shù)的地址,當然addr的相對地址要小于+-32M。這樣也就解決了跳轉(zhuǎn)范圍的問題。2.         接下來就是異常處理函數(shù)對應(yīng)的操作,可以在進入異常處理之前就進行返回地址的調(diào)整,這樣后面就不用進行處理啦,當然也可以在返回過程中再調(diào)整。一般都是在這個過程中進行調(diào)整。進行壓棧操作,保存對應(yīng)的環(huán)境變量。調(diào)用實際的處理過程等。3.         出棧,恢復(fù)CPU的狀態(tài)和

15、寄存器的值。由于第一步中已經(jīng)調(diào)整好返回地址,這一步不需要再次調(diào)整。當然如果之前沒有調(diào)整,這里則需要進行相應(yīng)的調(diào)整。在uC/OS-II的官網(wǎng)移植中采用通用異常處理函數(shù)的方式實現(xiàn)異常的處理,下面我們來分析其中的部分代碼:首先是處理器部分的移植,包括異常向量、異常的ID號,存儲異常處理函數(shù)地址的地址等:/*ARM的異常ID號,支持7種類型的異常,每一種異常都存在一個ID號*/#define  OS_CPU_ARM_EXCEPT_RESET        0x00#define  O

16、S_CPU_ARM_EXCEPT_UNDEF_INSTR 0x01#define  OS_CPU_ARM_EXCEPT_SWI          0x02#define  OS_CPU_ARM_EXCEPT_PREFETCH_ABORT 0x03#define  OS_CPU_ARM_EXCEPT_DATA_ABORT     0x04#define  OS_CPU_

17、ARM_EXCEPT_ADDR_ABORT     0x05#define  OS_CPU_ARM_EXCEPT_IRQ               0x06#define  OS_CPU_ARM_EXCEPT_FIQ            

18、;   0x07#define  OS_CPU_ARM_EXCEPT_NBR              0x08/*異常向量地址*/#define  OS_CPU_ARM_EXCEPT_RESET_VECT_ADDR              (OS

19、_CPU_ARM_EXCEPT_RESET          * 0x04 + 0x00)           /0x00#define  OS_CPU_ARM_EXCEPT_UNDEF_INSTR_VECT_ADDR        (OS_CPU_ARM_EXCEPT_UNDEF_INS

20、TR    * 0x04 + 0x00)         /0x04#define  OS_CPU_ARM_EXCEPT_SWI_VECT_ADDR                (OS_CPU_ARM_EXCEPT_SWI     

21、60;      * 0x04 + 0x00)             /0x08#define  OS_CPU_ARM_EXCEPT_PREFETCH_ABORT_VECT_ADDR     (OS_CPU_ARM_EXCEPT_PREFETCH_ABORT * 0x04 + 0x00)    &

22、#160;    /0x0c#define  OS_CPU_ARM_EXCEPT_DATA_ABORT_VECT_ADDR         (OS_CPU_ARM_EXCEPT_DATA_ABORT     * 0x04 + 0x00)             

23、0;              /0x10/*這個異常是ARM中不支持的異常*/#define  OS_CPU_ARM_EXCEPT_ADDR_ABORT_VECT_ADDR         (OS_CPU_ARM_EXCEPT_ADDR_ABORT     * 0x04 + 0x00) 

24、                           /0x14#define  OS_CPU_ARM_EXCEPT_IRQ_VECT_ADDR              

25、;  (OS_CPU_ARM_EXCEPT_IRQ            * 0x04 + 0x00)                           /0x18#define 

26、; OS_CPU_ARM_EXCEPT_FIQ_VECT_ADDR             (OS_CPU_ARM_EXCEPT_FIQ            * 0x04 + 0x00)            

27、0;          /0x1c/*存儲異常處理函數(shù)地址的地址*/* ARM exception handlers addresses                   */#define  OS_CPU_ARM_EXCEPT_RESET_HANDLER_ADDR  

28、;         (OS_CPU_ARM_EXCEPT_RESET          * 0x04 + 0x20)                        

29、60;   /0x20#define  OS_CPU_ARM_EXCEPT_UNDEF_INSTR_HANDLER_ADDR     (OS_CPU_ARM_EXCEPT_UNDEF_INSTR    * 0x04 + 0x20)           /0x24#define  OS_CPU_ARM_EXCEPT_SWI_HAN

30、DLER_ADDR             (OS_CPU_ARM_EXCEPT_SWI            * 0x04 + 0x20)        /0x28#define  OS_CPU_ARM_EXCEPT_PREFETCH_ABORT_

31、HANDLER_ADDR  (OS_CPU_ARM_EXCEPT_PREFETCH_ABORT * 0x04 + 0x20)     /0x2c#define  OS_CPU_ARM_EXCEPT_DATA_ABORT_HANDLER_ADDR      (OS_CPU_ARM_EXCEPT_DATA_ABORT     * 0x04 + 0x20)    

32、        /0x30#define  OS_CPU_ARM_EXCEPT_ADDR_ABORT_HANDLER_ADDR      (OS_CPU_ARM_EXCEPT_ADDR_ABORT     * 0x04 + 0x20)           /0x34#define

33、  OS_CPU_ARM_EXCEPT_IRQ_HANDLER_ADDR             (OS_CPU_ARM_EXCEPT_IRQ            * 0x04 + 0x20)           /0

34、x38#define  OS_CPU_ARM_EXCEPT_FIQ_HANDLER_ADDR             (OS_CPU_ARM_EXCEPT_FIQ            * 0x04 + 0x20)         

35、0; /0x3c/*存儲在異常向量中的內(nèi)容,實質(zhì)上是LDR PC,PC,#0x18的機器碼*/#define  OS_CPU_ARM_INSTR_JUMP_TO_SELF              0xEAFFFFFE/* ARM "Jump To Exception Handler" asm instruction    */#define  O

36、S_CPU_ARM_INSTR_JUMP_TO_HANDLER         0xE59FF018異常的初始化函數(shù),首先,完成了在異常向量中存儲指令的操作,采用機器碼的形式就能避免直接訪問寄存器什么的,其次,完成在固定的地址處存放對應(yīng)異常處理函數(shù)的地址。其中采用了賦值的形式也是需要注意的,采用的強制類型轉(zhuǎn)換和指針相結(jié)合的形式。保證了是修改地址處的內(nèi)容。而不是修改地址。/*初始化異常中斷向量*/void  OS_CPU_InitExceptVect (void)  

37、       /*                   OS_CPU_ARM_EXCEPT_UNDEF_INSTR_VECT_ADDR是對應(yīng)中斷向量表的地址               &#

38、160;   OS_CPU_ARM_INSTR_JUMP_TO_HANDLER是保存了對應(yīng)的OS_CPU_ARM_INSTR_JUMP_TO_HANDLER(實質(zhì)上是一個指令)                   實質(zhì)上就是在異常向量中存放了:LDR PC PC, #0x18,也就是讓PC指向?qū)?yīng)的異常處理地址中的內(nèi)容,     

39、;              也就是實現(xiàn)到實際處理函數(shù)的跳轉(zhuǎn)。                   異常處理地址中存儲了實際的異常處理函數(shù)的地址          

40、60;                          其他的異常也有相同的操作,OS_CPU_ARM_INSTR_JUMP_TO_HANDLER是一個指令的機器碼形式         */    (*(IN

41、T32U *)OS_CPU_ARM_EXCEPT_UNDEF_INSTR_VECT_ADDR)       =         OS_CPU_ARM_INSTR_JUMP_TO_HANDLER;    (*(INT32U *)OS_CPU_ARM_EXCEPT_UNDEF_INSTR_HANDLER_ADDR)    = (INT32U)OS_CPU_ARM

42、_ExceptUndefInstrHndlr;     (*(INT32U *)OS_CPU_ARM_EXCEPT_SWI_VECT_ADDR)               =         OS_CPU_ARM_INSTR_JUMP_TO_HANDLER;    (

43、*(INT32U *)OS_CPU_ARM_EXCEPT_SWI_HANDLER_ADDR)            = (INT32U)OS_CPU_ARM_ExceptSwiHndlr;     (*(INT32U *)OS_CPU_ARM_EXCEPT_PREFETCH_ABORT_VECT_ADDR)    =      

44、   OS_CPU_ARM_INSTR_JUMP_TO_HANDLER;    (*(INT32U *)OS_CPU_ARM_EXCEPT_PREFETCH_ABORT_HANDLER_ADDR) = (INT32U)OS_CPU_ARM_ExceptPrefetchAbortHndlr;     (*(INT32U *)OS_CPU_ARM_EXCEPT_DATA_ABORT_VECT_ADDR)      

45、60; =         OS_CPU_ARM_INSTR_JUMP_TO_HANDLER;    (*(INT32U *)OS_CPU_ARM_EXCEPT_DATA_ABORT_HANDLER_ADDR)     = (INT32U)OS_CPU_ARM_ExceptDataAbortHndlr;     (*(INT32U *)OS_CPU_ARM_

46、EXCEPT_ADDR_ABORT_VECT_ADDR)        =         OS_CPU_ARM_INSTR_JUMP_TO_HANDLER;    (*(INT32U *)OS_CPU_ARM_EXCEPT_ADDR_ABORT_HANDLER_ADDR)     = (INT32U)OS_CPU_ARM_ExceptA

47、ddrAbortHndlr;     (*(INT32U *)OS_CPU_ARM_EXCEPT_IRQ_VECT_ADDR)               =         OS_CPU_ARM_INSTR_JUMP_TO_HANDLER;    (*(INT32U

48、*)OS_CPU_ARM_EXCEPT_IRQ_HANDLER_ADDR)            = (INT32U)OS_CPU_ARM_ExceptIrqHndlr;          /*在異常向量中存儲對應(yīng)的操作,實質(zhì)上就是將PC值調(diào)轉(zhuǎn)*/    (*(INT32U *)OS_CPU_ARM_EXCEPT_FIQ_VECT_ADD

49、R)               =         OS_CPU_ARM_INSTR_JUMP_TO_HANDLER;    (*(INT32U *)OS_CPU_ARM_EXCEPT_FIQ_HANDLER_ADDR)        &

50、#160;   = (INT32U)OS_CPU_ARM_ExceptFiqHndlr; 異常類型Mode異常向量內(nèi)容IRQ異常IRQ0x00000018LDR PC,PC,#0x18或者0xE59FF018IFQ異常IFQ0x0000001CLDR PC,PC,#0x180xE59FF018  0x00000038Address of OS_CPU_ARM_ExceptIrqHndlr()  0x0000003CAddress of OS_CPU_ARM_ExceptFiqHndlr()有必要的討論一下,為什么在

51、向量中存儲的是指令: LDR PC,PC,#0x18,我們從上面的地址可以知道,IRQ異常處理函數(shù)地址被存儲到了0x00000038中,異常向量與該地址之間的差值是0x20,那么為什么在其中存儲的值只是0x18呢?這還要討論ARM的流水線結(jié)構(gòu),當前執(zhí)行的命令相比PC指向的地址差0x08。也就是當前執(zhí)行的指令的地址是PC-0x08.當PC指向異常向量以后(取值),還需要等待一個時鐘(譯碼)之后才會被執(zhí)行(真正意義上的執(zhí)行操作),而這時PC值已經(jīng)被更新了。指向了Vector+0x8的位置,因此我們可以知道,當執(zhí)行向量中的代碼時,這時PC=Vector+0x8,而這時相對于固定的0x20-0x08=

52、0x18,這也就是為什么是LDR PC,PC,#0x18,而不是LDR PC,PC,#0x20.采用上面的例子說明IRQ的向量為0x00000018,而設(shè)定好的固定地址用來存儲對應(yīng)異常處理函數(shù)地址的地址是0x00000038,當CPU執(zhí)行完P(guān)C = 0x00000018以后,還需要譯碼、才能被執(zhí)行,這時候PC值已經(jīng)更新為PC = 0x00000018 + 0x08;這時候固定地址距離PC的相對位置位0x00000038 PC = 0x18,而該地址中保存了IRQ中斷的通用處理函數(shù)OS_CPU_ARM_ExceptIrqHndlr()的地址,LDR PC,PC,#0x18這條指令是指將PC+0x18地址處的內(nèi)容加載到PC中,實質(zhì)上也就完成跳轉(zhuǎn)到異常處理函數(shù)的操作。這樣處理的好處是因為LDR的加載范圍是一個固定值+-32M,我們不能保證異常處理程序的地址剛好在+-32M左右,采用這種LDR PC, ADDR(固定地址)的形式就能實現(xiàn)大范圍的跳轉(zhuǎn)操作。       我們僅僅以FIQ中斷處理的形式進行討論,其他的異常有一定的相似性,只是在返回地址上存在差別。這段代碼主要是完成寄存器

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論