ARM異常(chang)處理
時(shi)間:2018-09-29 來源(yuan):未知
只要(yao)正常(chang)的(de)程(cheng)序流被暫時中止,處理器就進(jin)入異常(chang)模(mo)式。例如響應一個來(lai)自外設的(de)中斷。在(zai)處理異常(chang)之前,ARM內核(he)保存當(dang)前的(de)處理器狀(zhuang)態,這樣當(dang)處理程(cheng)序結束(shu)是可以(yi)恢復執(zhi)行(xing)原來(lai)的(de)程(cheng)序。
注意:如果同時發生兩個或更多異常(chang),那么(me)將按照固定的順序來處理異常(chang) 。
ARM支持的異常(chang)種(zhong)類:

一(yi)、異(yi)常的進入與(yu)退出
當一種異常發(fa)生時,硬件就會自動執行如下動作:
(1)將(jiang)CPSR保存到相應異常模式下的SPSR中(zhong)
(2)把PC寄存器保存到相應(ying)異常模(mo)式下的LR中
(3)將CPSR設置成相應的異常(chang)模式
(4)設置PC寄(ji)存器的值為相應處理程序的入口地(di)址
可以總(zong)結如下圖(tu):

呵呵,在這里我(wo)們需要重點研究的(de)是(shi),異常(chang)產生后,后PC會指到(dao)哪里去呢?這個事情(qing)實際(ji)不需要我(wo)們操(cao)心,ARM核在設計(ji)的(de)時候就(jiu)已經確定好了,也就(jiu)是(shi)經常(chang)我(wo)們所說的(de)異常(chang)向量(liang)表。異常(chang)向量(liang)表:

在(zai)(zai)ARM7,ARM9/10等處理器,異常向量表可以存放在(zai)(zai)以 0x00000000或0xffff00000其(qi)始的地址(zhi)。默認是(shi)以零地址(zhi)開始存放的。可能(neng)有(you)些同學(xue)還是(shi)有(you)些暈,我們(men)來舉個(ge)例子說(shuo)明一下。
例如:ARM處理器(qi)正在(zai)執行(xing)指(zhi)(zhi)令,此(ci)時外(wai)部硬件產生(sheng)了一(yi)個中斷。此(ci)時將產生(sheng)IRQ異常,然(ran)后ARM核就會(hui)自動完成我們上面說的4步。完成前(qian)3步后,ARM核會(hui)強制(zhi)將pc的值修(xiu)(xiu)改為0x18。修(xiu)(xiu)改完成后,處理器(qi)就開始從0x18這個地址取指(zhi)(zhi)令執行(xing)。
從(cong)上圖(tu)可以(yi)知道,不同的異常產生時,ARM核修改(gai)的PC值(zhi)不一(yi)樣。例(li)如:如果是swi指令引(yin)起的異常,ARM核后就會修改(gai)pc的值(zhi)為0x08。
是(shi)不(bu)是(shi)異(yi)常(chang)向量表,一定(ding)要放在0x00000000或0xffff00000其(qi)始(shi)的地址呢?答案:不(bu)是(shi),現在cortex-A系列的處理(li)器可(ke)以將(jiang)異(yi)常(chang)向量表放在任何位置,拿ARM核收(shou)到異(yi)常(chang)后(hou),它怎么知道應(ying)該將(jiang)pc的值修改為多少呢?這就(jiu)需(xu)要我們(men)通過協處理(li)指(zhi)令(ling)告訴它了。
例如(ru):在(zai)cortex-A8上,我們可以操作如(ru)下協處(chu)理指令,來告訴(su)ARM核異常向量(liang)表的位(wei)置。
cortex-A8官方手冊:3.2.68節(jie)有詳(xiang)細說明

如(ru)將告訴(su)ARM核,異常向量表存放在0x20008000
ldr r0,=0x20008000
mcr p15,0,r0,c12,c0,0
好了,到這里大家已經知(zhi)道了異(yi)(yi)常(chang)是什么,當(dang)異(yi)(yi)常(chang)產(chan)(chan)生的(de)(de)時(shi)候(hou),ARM核都會自(zi)動做那些(xie)事(shi)(shi)情(qing)。當(dang)然(ran),當(dang)異(yi)(yi)常(chang)產(chan)(chan)生的(de)(de)時(shi)候(hou),我(wo)(wo)們(men)應該對異(yi)(yi)常(chang)做出處理(li),處理(li)完之后,要返回(hui)異(yi)(yi)常(chang)產(chan)(chan)生之前(qian)的(de)(de)場(chang)景(jing)繼續運行。就像,有(you)些(xie)時(shi)候(hou),我(wo)(wo)們(men)在做事(shi)(shi)情(qing)的(de)(de)時(shi)候(hou),生病了,我(wo)(wo)們(men)就需要到醫生那里去治(zhi)療一下(xia),等治(zhi)療完成之后,就必須把生病前(qian)的(de)(de)事(shi)(shi)情(qing)接著后面(mian)干。
有些人,肯定忍(ren)不住了,我知道了異(yi)常(chang)(chang),也知道異(yi)常(chang)(chang)產生(sheng)后,pc會(hui)指向異(yi)常(chang)(chang)向量(liang)表,那(nei)異(yi)常(chang)(chang)向量(liang)表中,到底放(fang)什么(me)東(dong)西(xi)呀,我該怎(zen)么(me)處(chu)理我的異(yi)常(chang)(chang)呢(ni)?
首先,回答(da)第一(yi)個問題,異常向量表中存放的就(jiu)是(shi)去醫(yi)生(sheng)的火箭。坐上(shang)火箭就(jiu)可以到醫(yi)生(sheng)哪了,這叫(jiao)一(yi)個字"快"。醫(yi)生(sheng),火箭.....
呵呵,別折磨大家了,我們公布答案吧!看下面

從上面我們(men)可以知道,異常向量表里面存(cun)放的(de)(de)(de)(de)都是(shi)跳轉指令。有些(xie)時直接通(tong)(tong)過b指令實現(xian)的(de)(de)(de)(de),有些(xie)時通(tong)(tong)過修改pc值(zhi)實現(xian)的(de)(de)(de)(de)。這也(ye)就是(shi)剛(gang)(gang)剛(gang)(gang)我說到的(de)(de)(de)(de)"火箭"。跳轉的(de)(de)(de)(de)目的(de)(de)(de)(de)是(shi)跳到一(yi)個地(di)方對異常進行處(chu)理(li)。也(ye)就是(shi)我說到的(de)(de)(de)(de)到醫生(sheng)那里去"治療"。
我們以(yi)irq異常為例子,來說明我們需要干的事情
irq :
SUB LR,LR,#4 ;計(ji)算返回地址(zhi)
STMFD SP!,{R0-R3,LR} ;保存使用(yong)到的寄存器
干里你想干的事情
.....
LDMFD SP!,{R0-R3,PC}^ ;中(zhong)斷返(fan)回
注意(yi):當異常(chang)結束(shu)時,異常(chang)處理程序必(bi)須:
1.將LR中的值(zhi)減(jian)去偏(pian)移量后存入PC,偏(pian)移量根據(ju)異常(chang)的類型而有所不同(tong);
2.將(jiang)SPSR的值復制回CPSR;
3.清零中斷(duan)禁止標(biao)志(zhi)。
注(zhu):恢(hui)復(fu)CPSR的動作會將T、F和(he)I位自動恢(hui)復(fu)為異常發生(sheng)前的值。
哎,終于(yu)說完了異(yi)常(chang)。下面(mian)我們用一句話總結一下:異(yi)常(chang)產生需要(yao)保存現場(chang)(ARM核已經自(zi)動為我們做了),異(yi)常(chang)返回的(de)時候需要(yao)恢復(fu)現場(chang)(需要(yao)程(cheng)序(xu)員自(zi)動完成)。
下(xia)面我們來(lai)詳細說明異(yi)(yi)常(chang)產(chan)生(sheng)的原因,以及異(yi)(yi)常(chang)返回時,異(yi)(yi)常(chang)模式的lr應該保存的值是多(duo)少。后我們會以軟(ruan)中斷實驗,來(lai)給大家(jia)強化對(dui)異(yi)(yi)常(chang)的理解。
重要(yao)基礎(chu)知識:R15(PC)總是(shi)指(zhi)向“正(zheng)在(zai)取指(zhi)”的(de)(de)指(zhi)令(ling)(ling),而不是(shi)指(zhi)向“正(zheng)在(zai)執行”的(de)(de)指(zhi)令(ling)(ling)或正(zheng)在(zai)“譯碼”的(de)(de)指(zhi)令(ling)(ling)。一(yi)般來(lai)說,人們習慣性約定(ding)將“正(zheng)在(zai)執行的(de)(de)指(zhi)令(ling)(ling)作(zuo)為(wei)參考點”,稱之(zhi)為(wei)當前第(di)一(yi)條(tiao)指(zhi)令(ling)(ling),因此PC總是(shi)指(zhi)向第(di)三(san)條(tiao)指(zhi)令(ling)(ling)。當ARM狀(zhuang)態時,每條(tiao)指(zhi)令(ling)(ling)為(wei)4字節(jie)長(chang),所以PC始終指(zhi)向該指(zhi)令(ling)(ling)地址(zhi)加8字節(jie)的(de)(de)地址(zhi),即:PC值(zhi)=當前程序執行位置+8;
注(zhu)意:不管是幾級流(liu)(liu)水線都統一(yi)按照(zhao)三級流(liu)(liu)水線來分析,這一(yi)點已經(jing)向ARM官(guan)方求證過。
(1)快(kuai)速中斷異常
快(kuai)(kuai)速中斷請求(FIQ)適用于對一個突(tu)發事(shi)件的響應(ying),這得益于在ARM狀態中,快(kuai)(kuai)速中斷模式有8個專(zhuan)用的寄(ji)(ji)存器(qi)可用來滿(man)足(zu)寄(ji)(ji)存器(qi)保護的需要(這可以加速上下文切換的速度)。
不管異常入口是來自ARM狀態還是Thumb狀態,FIQ處理程序都會通過下面的指令從中斷返回(hui):
SUBS pc,R14_fiq,#4
在一(yi)個特權模式中(zhong),可以(yi)通過(guo)置(zhi)位CPSR中(zhong)的(de)F位來(lai)禁止FIQ異常。
(2)中(zhong)斷請求異常(chang)
中(zhong)斷(duan)請(qing)求(qiu)(IRQ)異常(chang)是(shi)一個(ge)(ge)由nIRQ輸入端(duan)的低電平所產生的正常(chang)中(zhong)斷(duan)(在(zai)具體的芯片(pian)中(zhong),nIRQ由片(pian)內外設拉低,nIRQ是(shi)內核的一個(ge)(ge)信(xin)號,對(dui)用戶不可(ke)見)。IRQ的優先級低于FIQ。對(dui)于FIQ序列它是(shi)被屏(ping)蔽的。任何(he)時候在(zai)一個(ge)(ge)特權模式下,都可(ke)通(tong)過置位CPSR中(zhong)的I 位來禁止IRQ。
不(bu)管異常入口(kou)是來(lai)自ARM狀(zhuang)(zhuang)態(tai)還是Thumb狀(zhuang)(zhuang)態(tai),FIQ處理程序都(dou)會通過執行下面的指令從中斷返回:
SUBS PC,R14_fiq,#4
分(fen)析IRQ 和(he) FIQ異常中斷處(chu)理的返回:
指令地址 對應于PC
A PC-8 執行(xing)此指令完成后(!)查詢IRQ及FIQ,如果有中(zhong)斷請(qing)求則產(chan)生中(zhong)斷.
A+4 PC-4
A+8 PC ;lr!
(此時PC的值已經更新,指向A+12.將(jiang)當前(qian)PC-4(即A+8)
保存到LR.返(fan)回時,要接著(zhu)執行A+4(LR-4)處(chu)的指令(ling),所以返(fan)回指令(ling)為
SUBS PC, LR,#4(PC=A+4=LR-4)
白(bai)話解釋(shi):對于普中斷(duan)和快中斷(duan)異常:
中斷必須在(zai)一條指(zhi)(zhi)(zhi)令執行(xing)完(wan)以后被(bei)檢測到,如正(zheng)在(zai)執行(xing)指(zhi)(zhi)(zhi)令甲時發生了中斷,不等指(zhi)(zhi)(zhi)令甲執行(xing)完(wan)是(shi)不
會處理該中斷的,發(fa)生異常時(shi)pc已經更新(A+12);
lr = pc – 4(這時(shi)處理器決(jue)定的,無法(fa)更改!)即A+8
返(fan)(fan)回(hui)后(hou),應(ying)執行被中斷(duan)而沒有執行的指令(上面(mian)的A+4),所以返(fan)(fan)回(hui)時,pc = lr-4
(3)中止
中止(zhi)發生在對存儲(chu)器的訪問不能(neng)完成時,中止(zhi)包含(han)兩種類型:
預(yu)取中(zhong)止(zhi) : 發生(sheng)在指令預(yu)取過程中(zhong)
數(shu)據中止 : 發生在(zai)對數(shu)據訪(fang)問時(shi)
A.預取中止
當(dang)發生預取(qu)中(zhong)止時,ARM核將(jiang)預取(qu)的指(zhi)(zhi)(zhi)令(ling)(ling)標(biao)記為無效,但(dan)在(zai)指(zhi)(zhi)(zhi)令(ling)(ling)達到流(liu)水線的執(zhi)行階段(duan)時才進(jin)入異(yi)常。如果指(zhi)(zhi)(zhi)令(ling)(ling)在(zai)流(liu)水線中(zhong)因為發生分支而(er)沒有被執(zhi)行,中(zhong)止將(jiang)不會發生。
在處(chu)理(li)中止的(de)原(yuan)因之后,不管處(chu)于哪種處(chu)理(li)器(qi)操作狀態,處(chu)理(li)程序(xu)都會執行(xing)下面的(de)指(zhi)令恢(hui)復(fu)PC和CPSR并重試被中止的(de)指(zhi)令:
SUBS PC,R14_abt,#4
分析指令預取中止異(yi)常中斷處理的返回:
指令地址
A PC-8 執行本指(zhi)令(ling)時發(fa)生異常,
A+4 PC-4 處(chu)理(li)器將(jiang)A+4(PC-4)保存到LR. ;lr!
A+8 PC
返(fan)回時,發生指令預(yu)取中止(zhi)的指令A(PC-8)處重新執(zhi)行,所以(yi)返(fan)回指令為
SUBS PC, LR,#4(PC=A=LR-4)
白話解(jie)釋(shi):對于預取指令(ling)中止異常:
發(fa)生預取指令(ling)異常(chang)時,是(shi)在執行時發(fa)生的異常(chang),pc未更新,即pc = A+8
lr = pc – 4(這時(shi)處(chu)理器決(jue)定的,無法更改!)即A+4
由于這(zhe)類異(yi)常返回后(hou)應重(zhong)新執行(xing)異(yi)常的那(nei)個指令(A),所(suo)以返回時,pc = lr-4
B.數據中止(zhi)
指(zhi)令地(di)址
A PC-8 本指令訪問有問題的(de)數據,產生中斷時,PC的(de)值(zhi)已經(jing)更新
A+4 PC-4 中斷發生時(shi)PC=A+12,處(chu)理(li)器將A+8(PC-4)保存到LR.
A+8 PC ;lr!
返(fan)回(hui)時,要返(fan)回(hui)到A處繼續執行,所以指令為SUBS PC, LR,#8.(PC=A=LR-8)
白(bai)話解釋:對于數據訪問中止異常:
發生數據訪(fang)問(wen)(wen)中止異(yi)常時(shi),是在執行時(shi)訪(fang)問(wen)(wen)數據錯誤導致的異(yi)常,pc已經更新,即pc = A+12
lr = pc – 4(這時處理器決定的,無(wu)法更(geng)改!)即A+8
由(you)于(yu)這類異(yi)常返(fan)回(hui)后應重新執行異(yi)常的(de)那(nei)個(ge)指(zhi)令(A),所(suo)以返(fan)回(hui)時,pc = lr-8
(4)軟件中斷指(zhi)令
所(suo)有的任務都(dou)是運行在用(yong)戶模(mo)(mo)式(shi)下(xia)的,因此任務只(zhi)能讀CPSR而不能寫SPSR。任務切(qie)換到(dao)特權模(mo)(mo)式(shi)下(xia)唯一(yi)(yi)的途徑就是使用(yong)一(yi)(yi)個SWI指令調用(yong),SWI指令強迫處(chu)理(li)器(qi)從用(yong)戶模(mo)(mo)式(shi)切(qie)換到(dao)SVC管(guan)理(li)模(mo)(mo)式(shi),并且IRQ自動關(guan)閉(bi),所(suo)以(yi)軟(ruan)件中斷方式(shi)常被用(yong)于系(xi)統調用(yong)。
(5)未(wei)定義指令異常(chang)
(1)當ARM在對一條(tiao)未(wei)定義指令進行譯碼時(shi),發(fa)現這是一條(tiao)自己(ji)和系(xi)統內任(ren)何協處理器都無法執(zhi)行的指令時(shi),就會(hui)發(fa)生未(wei)定義指令異常(chang);
(2)由于(yu)是在對未定(ding)義指令譯(yi)碼時(shi)發(fa)生異常,所(suo)以PC的值等于(yu)未定(ding)義指令的地址(zhi)+4(即(ji)剛(gang)好為中斷返(fan)回地址(zhi)),因此R14保存的值是 中斷返(fan)回地址(zhi) ,所(suo)以當異常要(yao)返(fan)回時(shi)可執行以下指令:
MOVS PC,R14_und
分析:SWI和和未定義指令異常(chang)中斷的返回(hui):
指令(ling)地址
A PC-8 當前指(zhi)令為SWI或(huo)未定(ding)義指(zhi)令 此時發(fa)生異常PC的值還沒有更新.
A+4 PC-4 中斷時(shi)處理器(qi)將PC-4保存到LR ;lr!
A+8 PC
返(fan)回時,從發生中斷的指(zhi)令(ling)A(PC-8)的下一條指(zhi)令(ling)A+4(PC-4)處開始執行,所以直接
把LR的值賦給PC就行(xing)了,具體指令為MOV PC,LR (PC=A+4=LR)
白話解釋:對于SWI和未定義指令異常:
發生異常時pc沒有更新(xin),根據ARM的(de)三級流(liu)水線(xian)原理,pc沒有更新(xin),仍然等于(A+8);
lr = pc – 4(這時處理器決定的,無法更改!)即(ji)A+4
由(you)于這(zhe)類異(yi)常返(fan)回(hui)后應執行下一條指(zhi)令(A+4),所以返(fan)回(hui)時,pc = lr即可
后(hou)我們來(lai)總結一下:
引起PC更(geng)新的(de)原因一種是數據中(zhong)止,還有就是中(zhong)斷(duan)了.
中斷(duan)必須是在一條(tiao)指令(ling)執行(xing)完畢后(hou)才(cai)能被檢(jian)測到,所(suo)以它中斷(duan)的只是還未執行(xing)的那條(tiao)指令(ling)(pc - 8),
所(suo)以(yi)pc = lr – 4;
與中斷相同(tong),SWI和未定義指(zhi)令異常也是(shi)返回到下一條指(zhi)令(pc - 4),只是(shi)他們(men)在(zai)執行(xing)時(shi),PC的(de)值并沒
有更新,所以pc = lr;
預取指令中止異常,也沒有發(fa)生pc更(geng)新(xin),但它還得重新(xin)執行(xing)發(fa)生異常的那條指令,所(suo)以pc = lr – 4;
數據訪問中止異常,發(fa)生(sheng)了pc更新,并且它(ta)也需要重新執行發(fa)生(sheng)異常的(de)那條指令,所(suo)以pc = lr – 8;
當多個異常同時發生時,一(yi)個固定的(de)優先(xian)級系統(tong)決定它們被(bei)處(chu)理的(de)順序(xu):

二、SWI 實驗
(1)swi 指令
SWI指(zhi)令用于產生軟(ruan)中斷,從而實現在從戶模(mo)式(shi)變(bian)換到(dao)(dao)(dao)管(guan)理模(mo)式(shi),并且將CPSR保存到(dao)(dao)(dao)管(guan)理模(mo)式(shi)的SPSR中,然后程序跳(tiao)轉到(dao)(dao)(dao)SWI異常入口。在其它模(mo)式(shi)下(xia)也可使(shi)用SWI指(zhi)令,處理器同樣地切換到(dao)(dao)(dao)管(guan)理模(mo)式(shi)。
該指令主要(yao)用于用戶程(cheng)序調用操(cao)作系(xi)(xi)統的系(xi)(xi)統服(fu)務,操(cao)作系(xi)(xi)統在(zai)SWI異(yi)常處(chu)理程(cheng)序中(zhong)進行相應的系(xi)(xi)統服(fu)務。
注意:
ARM 內核不提供(gong)直(zhi)接傳遞軟中(zhong)斷(SWI)號到處理程序的機制:
SWI 處(chu)理程序必(bi)須定位(wei)SWI 指令(ling)(ling),并(bing)提取(qu)SWI指令(ling)(ling)中的常(chang)數域(yu)
為此, SWI 處理(li)程(cheng)序必(bi)須確(que)定SWI 調用是在哪一(yi)種狀態(ARM/Thumb).
檢查 SPSR 的 T-bit
SWI 指令在ARM 狀(zhuang)態下在 LR-4 位置, Thumb 狀(zhuang)態下在 LR-2位置
SWI 指令按相應(ying)的格式(shi)譯碼:

例如:
SWI 13
思考,當軟中斷(duan)產(chan)生后(hou),怎么獲取它的(de)軟中斷(duan)號(hao)呢(ni)?
實驗(yan)的(de)核(he)心代碼如下:
software_interrupt:
@設置軟中斷(duan)所在模式的棧
ldr sp,=0x34000
@保存用到的寄存器
stmfd sp!,{r0-r2,lr}
@獲(huo)取swi指令對應的機器碼(ma)
ldr r0,[lr,#-4]
@獲取(qu)軟中斷(duan)號
bic r0,r0,#0xff000000
@調(diao)用C處理函數,求累加和
bl calc_sum
@獲(huo)得函(han)數返回值,存放在r1
mov r1,r0
@恢(hui)復現場,^表示目標寄(ji)存器是(shi)pc時(shi)(shi),傳遞數據給pc,同時(shi)(shi)更新(xin)CPSR
ldmfd sp!,{r0-r2,pc}^

