Exception in MIPS

介紹

分支、跳轉、異常(包括硬體中斷)是三種改變控制流的事件。

同步異常是指程式執行到固定位置必定觸發且每次現象一致的異常,如算術溢出異常、未定義指令異常、缺頁異常等。

非同步異常與當前執行程式無關,如I/O請求、記憶體錯誤、電源不穩定等。硬體中斷是一種非同步異常。

異常發生時,當前執行程式被中斷,CPU跳轉到對應的異常處理函數執行,異常處理完畢之後,繼續執行被中斷程式。

異常處理函數入口必須要保存被中斷任務上下文,這樣才能從異常返回。任務上下文包括CPU暫存器值、返回地址和棧頂指針等,通常是保存到記憶體中,那麼就需要一個暫存器用來保存該記憶體段的基地址。MIPS預留了$k0和$k1兩個暫存器,異常處理函數每次都會直接改寫$k0和$k1暫存器值,這就意味著,正常運行的程式如果使用$k0或者$k1暫存器會導致不可預期的結果。

異常處理機制

MIPS的異常處理、MMU、Cache都是由CP0協處理器控制,CP0隻能在內核態操作。

CP0暫存器使用下述指令操作:

異常處理相關CP0暫存器如下:

BadVAddr暫存器

保存異常發生時的記憶體地址(虛擬地址), 比如非對齊訪問異常;

Cause暫存器

IP0~1表示軟中斷,IP2~7表示硬體中斷類型,ExcCode表示異常類型,ExcCode 0表示中斷。

ExcCode

Status暫存器

IM2~7為1表示使能對應中斷,為0表示去使能;

IEc即當前中斷模式,為1表示使能中斷,為0表示禁用所有中斷;

KUc即當前工作模式,為1表示User模式,為0表示Kernel模式;

IEp和KUp表示異常發生前的中斷模式和工作模式;

IEo和KUo表示再之前的狀態;

上述三組狀態依次覆蓋。

EPC暫存器

使用jal跳轉指令時,發生了兩件事情:

1)跳轉到jal指定的地址執行

2)返回地址保存到$ra暫存器

但是當異常發生時,CPU跳轉到一個固定的地址執行,即異常向量表。此時,返回地址不能保存在$ra暫存器中,因為它會覆蓋$ra暫存器值,因此MIPS將異常返回地址保存在EPC暫存器中。

 從異常返回

無延遲槽時

mfc0 $k0, $14 # get EPC in $k0
rfe # return from exception
jr $k0 # replace PC with the return address

有延遲槽時

mfc0 $k0, $14 # get EPC in $k0
addiu $k0, 4 # make sure it points to next instruction
rfe # return from exception
jr $k0 # replace PC with the return address

異常處理函數

當異常發生時,CPU會進入Kernel模式,同時禁用所有中斷(CPU硬體實現,軟體不可控)。

禁用中斷的原因是異常處理函數首先需要保存處理器狀態,隨後才能處理中斷。具體為:

1)確定異常類型,並保存相關資訊(如EPC、Cause、Status暫存器值)

2)保存異常上下文,即所有CPU暫存器值

禁用中斷並不代表不處理中斷,只是延遲處理。當異常處理函數中使能中斷,或者異常處理函數返回時,CPU會馬上處理被Pending的中斷(長時間Pending會丟失中斷),跳轉到中斷處理函數處理。

如果異常處理函數可以在很短時間內執行完畢,那麼,不需要在異常處理函數中使能中斷,異常返回時CPU會使能中斷。這也意味著,異常處理函數中不需要保存異常上下文,如EPC、Cause、Status暫存器值,但是仍然需要保存除$k0和$k1以外的通用暫存器值。

異常嵌套

異常處理函數執行時,中斷被禁用,但是不代表CPU不會被trap。當異常處理函數本身出現異常時,仍然會觸發異常。

參考文獻

Exception in MIPS

Tags: