說到異常向量,會讓人聯想到中斷向量。其實,中斷是屬於異常的子集的,也就是說中斷其實是異常其中的一種。
回到異常向量,他其實是一張表格,每個格子里存放的是一個地址,或者是一個跳轉命令,不管是哪個,其目的都是讓PC跳轉到真正處理異常的代碼的地方。
以下是arm的異常向量表:
圖1
初步介紹完異常向量,就來對比下ARM的arm的7種工作模式:
圖2
User : 非特權模式,大部分任務執行在這種模式
FIQ : 當一個高優先級(fast) 中斷產生時將會進入這種模式
IRQ : 當一個低優先級(normal) 中斷產生時將會進入這種模式
Supervisor :當復位或軟中斷指令執行時將會進入這種模式
Abort : 當存取異常時將會進入這種模式
Undef : 當執行未定義指令時會進入這種模式
System : 使用和User模式相同寄存器集的特權模式
可以發現arm的7種工作模式其實是和arm的異常向量表有着一定的對應關系的。
接着來看ARM的一個非常重要的寄存器——CPSR程序狀態寄存器,如圖二所示:該寄存器在arm的任何工作模式中都存在,且是被所以工作模式共用的。
寄存器每一位的含義如下圖所示:
圖3
以上3者有着莫大的關聯,結合三者分析,就會明白很多東西。
其一、arm的7種工作模式,和異常向量表有着一定的對應關系。 如SVC模式下發生普通中斷(IRQ)arm自動切換到IRQ模式,進入IRQ模式后PC就會指向IRQ對應異常向量表,及0x18這個位置。
再比如復位時,就會進入svc模式,並且跳到Reset對應的異常向量表,及0x00位置(這也是為什么程序是從0x00開始執行的)
其二、工作模式的切換有主動和被動之分。上面所說的就是被動切換,他是隨着某種異常的發生而導致的切換。
主動切換,就要靠cpsr這個寄存器了。可以看到這個寄存器的末四位就是用來設定進入哪種模式的。
何時需要cpsr主動切換模式呢:
1、一開始就想進入某種模式。如:一開始設置所有模式下的sp地址。示例如下:
2、進入某種模式后,想切換到之前的模式。這個過程通常是通過讀回SPSR的值。示例如下:
接着,我們來區分異常和中斷的區別和聯系:
1、中斷可以看作是異常的一種情況。
2、中斷是可以屏蔽的,如通過cpsr寄存器的I位和F位分別屏蔽IRQ和FIQ。而異常是無法屏蔽的。
3、異常/中斷發生時,PC都會指向相應的向量表。異常的發生往往會導致模式的自動切換。
4、IRQ和其他模式稍有不同。因為被動切換到IRQ模式下的情況有很多種,換句話就是,很多種中斷,都會導致進入IRQ模式。進入IRQ模式還需要判斷是那種情況導致了中斷,所以IRQ往往還對應一張中斷向量表。(區分於異常向量表)相當於異常向量表的子級表。
最后看,在模式切換時,都發生了什么?
1、當模式發生切換時(主動或者被動),硬件會自動幫我們完成一些事情。然后還需要軟件完成一些事情。
做好這兩件事,就可以在模式之間切換而不會相互影響,當然對應程序員而言只需要做好后者。
2、硬件幫我們完成的事情,是在模式切換時隨之完成,而軟件要完成的任務,是在模式切換之后。這點需要十分注意!比如當前是SVC模式切換到IRQ模式。那么軟件需要完成的事情,是在當前IRQ模式下完成的。
3、那么硬件完成了什么事情,軟件又需要做什么呢?
3.1、硬件完成的事情有:
切換到新的模式后,用的就是當前模式下的sp以及lr,但是pc只有一個。由於硬件幫我們
完成的一些事。所以當前IRQ模式下的lr寄存器存放的其實是上個模式SVC的PC值。當前IRQ模式下的
SPSR寄存器存放的其實是上個模式SVC的CPSR值。這充分為返回上一個模式做好了准備。
3.2、所以軟件需要完成的任務有:
3.2.1、保存當前共用寄存器的值,(如SVC模式和IRQ模式共用r0~r12 以及r15及pc)到當前模式的棧內存。保證之前模式的值不被破壞。
這里CPSR雖然也是共用的,但是不用保存到棧中,這是因為硬件會自動把上個模式的CPSR保存到當前模式的SPSR。
而SPSR直到中斷返回,及切換到之前的模式才會用到。有點同學會問了,pc的值也會由硬件自動保存到lr,為什么還需要保存到棧中呢?這是因為lr和SPSR不同,在中斷執行的過程中,很可能需要使用lr,為了不把之前的pc值沖掉還是先將其發到棧中保存。
3.2.2、進入中斷處理函數。處理中斷。
3.2.3、中斷返回,將之前保存到棧里的值讀回,並SPSR的值賦值給CPSR實現主動切換到之前的模式。示例代碼:
最后,聊一個面試經常問的問題,FIQ相比IRQ,FIQ稱為快速中斷,IRQ稱為普通中斷。FIQ為什么比IRQ快!
我們可以結合圖1和圖2進行分析:
1、先看圖1,FIQ的異常向量地址為0x1C,位置處於最頂部,這就意味着,FIQ真正的異常處理代碼可以緊接着0x1C,及無需跳轉,不跳轉意味着無需打斷arm的流水線,所以可以提高中斷響應。
2、再看圖2,FIQ模式下具有更多的獨立寄存器,如r8~r14,這些寄存器都是FIQ模式下獨自享用的。這就意味着,當發生快速中斷,進行模式切換時,只有少量的寄存器需要備份到棧中,從而也能節省時間,提高中斷的響應速度。
以上兩點就是FIQ為什么比IRQ快的原因,別小看節省的這么一點點時間,有的時候就是這么“兵貴神速”。