ARM基礎學習-SWI異常中斷處理

在ARM處理器中,我們常常使用SWI指令來產生一個軟中斷。軟中斷指令SWI指令中包含了一個24位的立即數,這個立即數指示了用戶請求的特定的SWI功能,即這個立即數表示的是SWI指令所想要觸發中斷的中斷號。

所以,當SWI指令觸發了一次異常後進入異常處理的程序時,異常程序必須要從SWI指令中提取出來中斷號,即提出出來SWI指令中低24位的值,從而得到用戶請求的特定的SWI功能。

SWI異常處理程序

通常情況下,SWI異常中斷處理函數分爲兩級,第一級的SWI處理函數用於從SWI指令中提取24位的立即數即中斷號,通第一級函數通過彙編語言、內嵌彙編來完成。第二級SWI異常中斷處理程序實現各個SWI的具體功能,第二級程序可以是彙編程序,也可以是C程序。
  
第一級SWI異常處理程序通過LR寄存器內容得到SWI指令地址,LR寄存器中保存的是該SWI指令的下一條指令的地址,並從存儲器中得到SWI指令編碼,從而提取出來24位中斷號。下面的例子顯示了提取中斷向量號的標準過程。

.SWI_Handler:
    STMFD sp!,{r0-r12,lr} ;保存寄存器
    LDR r0,[lr,#-4]   ;計算SWI指令地址
    BIC r0,r0,#0xff000000 ;提取指令編碼的後24位
    ;
    ; 提取出的中斷號放r0寄存器,函數返回
    ;
    LDMFD sp!, {r0-r12,pc}^ ;恢復寄存器

第二級中斷處理函數(根據提取的中斷向量號,跳轉到具體處理函數)卻可以使用C語言來完成。因爲第一級的中斷處理函數已經將中斷號提取到寄存器r0中,所以根據AAPCS函數調用規則,可以直接使用BL指令跳轉到C語言函數,而且中斷向量號作爲第一個參數被傳遞到C函數。


void C_SWI_handler (unsigned number)
{
    switch (number)
     {
      case 0 : /* SWI number 0 code */
      break;
      case 1 : /* SWI number 1 code */
      break;
      ...
      default : /* Unknown SWI - report error */
     }
}

另外,如果需要傳遞的參數多於1個,那麼可以使用堆棧,將堆棧指針作爲函數的參數傳遞給C類型的二級中斷處理程序,就可以實現在兩級中斷之間傳遞多個參數。

例如:

MOV r1, sp   ;將傳遞的第二個參數(堆棧指針)放到r1中
BL C_SWI_Handler ;調用C函數

相應的C函數的入口變爲:

void C_SWI_handler(unsigned number, unsigned *reg)

在2級中斷處理程序,可以通過下面的操作數讀取參數,這些參數是在SWI異常中斷產生時各寄存器的值,這些寄存器保存在SWI異常中斷的數據棧中:

value_in_reg_0 =reg [0];
value_in_reg_1 =reg [1];
value_in_reg_2 =reg [2];
value_in_reg_3= reg [3];

SWI異常中斷調用

(1) 在特權模式下調用SWI

比如在中斷模式下調用SWI,系統此時已經屬於特權模式,這是在調用SWI會破壞SPSR_svc和寄存器LR_svc,所以在調用SWI前保存SPSR_svc和寄存器LR_svc在數據棧中:

STMFD sp!,{r0-r3,r12,lr}

MOV r1,sp;
MRS  r0,spsr;
STMFD sp!,[r0];
...
SWI
...

LDMFD sp!,{r0};
MSR spsr_cf,r0;
LDMFD sp!, {r0-r3,r12,pc}^ ;

(2)應用程序中調用SWI

最簡單的是用匯編:

MOV r0,#100;
SWI 0x0;

C語言調用SWI比較複雜,因爲這時需要將一個C程序的子程序調用映射到一個SWI異常中斷程序,這些被映射的C語言子程序使用編譯器僞操作_SWI來聲明,如果該子程序需要的參數和返回結果只使用R0~R3寄存器,則該SWI可以編譯成inline,不需要使用子程序調用過程,否則編譯器需要用數據結構來返回參數,這時需要用僞操作_value_in_reg聲明該C語言程序;

需要安裝異常中斷處理程序到向量表中相對位置;

詳細參考ARM體系結構與編程P-272;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章