1. 程式人生 > >mips下的異常、中斷

mips下的異常、中斷

什麼是異常

在mips中,中斷、陷阱、系統呼叫和任何可以中斷程式正常執行流的情況都稱異常

1. 外部事件  ——中斷

2. 記憶體翻譯異常

3. 其他不太常見的核心修改的程式條件

4. 程式或硬體探測到的錯誤

5. 資料完整性錯誤

6. 系統呼叫和陷入

精確異常

在執行流程中沒有任何多餘效應的異常。即當異常發生時,在受害指令之前的指令被完全執行,而受害指令及後面的指令還沒開始執行(注:說受害指令及後面的指令還沒做任何事情是不對的,實際上受害指令是處於其指令週期的第三階段剛完成,即ALU階段剛完成)。精確異常有有助於保證軟體設計上不受硬體實現的影響。

CP0中的EPC暫存器用於指向異常發生時指令跳轉前的執行位置,一般是受害指令地址。當異常時,是返回這個地址繼續執行。但如果受害指令在分支延遲槽中,則會硬體自動處理使EPC往回指一條指令,即分支指令。在重新執行分支指令時,分支延遲槽中的指令會被再執行一次。

精確異常的實現對流水線的流暢性是有一定的影響的,如果異常太多,系統執行效率就會受到影響。

異常

常規異常一般為軟體的異常,而中斷一般為硬體異常,中斷可以是晶片內部,也可以是晶片外部觸發產生。

異常發生時,跳轉前最後被執行的指令是其MEM階段剛好被執行完的那條指令。受害指令是其ALU階段剛好執行完的那條指令。

Ø 使用者特權地址的TLB重填

TLB硬體上只存在儲存一定數目的地址轉換條目,在執行一個虛擬記憶體的OS的系統中,如果如果程式得以充分的執行,應用程式就會很容易碰到一個虛擬地址在TLB中沒有的情況,一個TLB不匹配的事件就發生了。異常產生後硬體幫助異常處理程式在大約13個時鐘週期內完成TLB重填。

Ø 64位地址空間的TLB重填

為了充分利用64位CPU的地址空間,地址轉換用了一套略為不同的暫存器佈局和不同的TLB重填例程,叫做XTLB重填。

Ø 非快取的異常入口點

出於對異常處理效能的考慮,訪問中斷入口地址時都要經過快取,但是在系統啟動期間,上電或重啟時快取未經初始化不能使用。因此,在早期啟動期間訪問不需要經過快取,CP0暫存器中有個模式位SR(BEV)將異常處理入口定位於非快取的、啟動安全的kseg1記憶體區域。

Ø 奇偶/ECC校驗錯誤

Mips32cpu可以檢查到資料錯誤,這是不管SR(BEV)的狀態,快取錯誤的異常入口都在非快取區域kseg1記憶體區域。

Ø 重啟

MIPS系統把重啟看作一個不可迴歸的異常來處理。
          冷啟動:CPU硬體完全被重新配置,軟體重新載入;
           熱啟動:軟體完全重新初始化;

Ø 中斷

異常向量

所有的異常入口點都位於MIPS記憶體對映中不需要地址轉換的區域——非快取的kseg1段和快取的kseg0段。當SR(BEV)置位時,非快取的異常入口時固定的,但是當SR(BEV)清零時,EBase暫存器可以通過程式設計一起移動所有的異常入口到其他地址。

高優先順序異常有:冷啟動、熱重啟、非遮蔽中斷,

TLB 重填(32 位模式),

xTLB 重填(64 位模式),cache 錯誤,其他異常。

高優先順序異常入口地址有以下五個:

優先順序異常入口

異常型別 

正常執行(BEV 為 0)

 啟動(BEV 為 1)

冷啟動、熱重啟、非遮蔽中斷

0x BFC0 0000

0x BFC0 0000

TLB 重填

0x 8000 0000

0x BFC0 0200

xTLB 重填 

0x 8000 0080

0x BFC0 0280

cache 錯誤

0x A000 0100

0x BFC0 0300

 其他

0x 8000 0180 

0x BFC0 0380

狀態暫存器(SR)

BEV=1 :非快取異常處理入口固定定位於非快取的、啟動安全的kseg1記憶體區域

BEV=0 :異常處理入口不固定,通過EBase暫存器可以程式設計移動,系統正常執行時為0

MIPS 下 TLB、Cache 都要 OS 參與管理,在其啟動時 OS 尚未接管系統,這個時候不採用 TLB、Cache 機制是很重要的。

冷啟動、熱重啟、非遮蔽中斷的入口地址始終位於 0x BFC0 0000

其他異常類入口(一般稱為通用異常入口) CPU 內部異常或者外部中斷髮生時, CPU 硬體設定 CAUSE 暫存器的 ExcCode( CAUSE6: 2) 位後,就跳轉到該異常入口。 ExcCode 位段用來描述通用異常型別, 5 位,故而可以描述 2^5 = 32 個異常型別。

1. 高優先順序異常入口初始化

通用異常入口初始化,位於:[ arch/mips/kernel/traps. c]

void __init trap_init( )cache 錯誤入口初始化,位於:[ arch/mips/mm/c-r4k. c]

void __init r4k_cache_init( )

2. 通用異常處理表初始化

CAUSE 暫存器的 ExcCode 索引一張通用異常處理表 exception_handlers它定義於:

arch/mips/kernel/traps. c]void __init trap_init( void)

異常初始化

1. EPC被置為被中斷的PC

2. 如果中斷模式是相容模式的話(普便情況),則vector offset = 0x180.

3. 如果Status[EXL] == 1,offset = 0x180,並且EPC不變

4. 如果是TLB refill,offset = 0x0000000,如果是其它異常,則是0x180。這裡強調一下是,mips R2後中斷有幾種模式,不同的模式它的入口還不同。

5. 如果Status[BEV] == 1,BASE會到0xBFC00200,否則就BASE會是0x80000000,當然在MIPS32 R2後,我們設定了EBASE暫存器,這可以讓使用者選擇中斷後跳轉的指令,這與R1就不同了,它固定在0x80000000處。為了向後相容,EBASE預設情況下,它就是0x80000000處。

6. 設定cause[extcode]為異常號,中斷為0

7. Status[EXL] = 0,這個值會產生很大的影響,它會無視Status[IE,KSU]位,而強制處於核心態和關中斷狀態。這樣做的原因是為了我們有足夠的時間去儲存現場。

8. 最近PC會跑去base+offset的地方。

異常處理

異常產生

                      EPC指向異常位置

1. 設定EPC指向迴歸的位置;

2. 設定SR(EXL)強迫CPU進入kernel態,並禁止所有中斷響應。

3. 設定Cause暫存器,以使軟體可以得到異常的型別資訊;還有其它一些暫存器在某些異常時 會被設定;

4.  CPU開始從異常入口取指令,然後以後的所有事情都交由軟體處理了。

          k0和k1暫存器用於儲存異常處理函式的地址。
          異常處理函式執行完成後,會回到異常分配函式那去,在異常分配函式裡,有一個eret指令,用於迴歸原來被中斷的程式繼續執行;eret指令會原子性地把中斷響應開啟(置SR(EXL)),並把狀態級由kernel轉到user級,並返回原地址繼續執行

中斷

MIPS CPU有8個獨立的中斷位(在Cause暫存器中),其中,6個為外部中斷,2個為內部中斷(可由軟體訪問)。一般來說,片上的時鐘計數/定時器,會連線到一個硬體位上去。

Ø 全域性中斷使能位SR(IE)必須置1,否則沒有中斷響應。

Ø 設定SR(EXL)(異常級別)和SR(ERL)(錯誤級別)位(任何異常之後會立即設定這二者之一)將阻止中斷。

Ø 狀態暫存器裡有8個單獨的中斷遮蔽位SR(IM),每個對應Cause暫存器的一箇中斷位。要使能某個中斷,其對應的遮蔽位SR(IM)必須置為1。

         中斷處理程式也是用通用異常入口。

中斷的響應:

handle_int   ->plat_irq_dispatch->do_IRQ(irq)->generic_handle_irq -> __do_IRQ()

1. 假如Gpio中斷,系統產生中斷,通過在 CPU 的中斷引腳上,引起異常。

2. CPU 自動設定 CAUSE  ExcCode 位為 0 IP5 x並跳轉到通用異常入口0x 80000180

3. 位於通用異常入口處的簡單異常處理程式,根據 ExcCode 的值索引異常處理表(exception_handlers) 獲取到 0 號異常的處理程式是 handle_int並跳轉過去

4.  handle_int 根據 CAUSE  IP 位的值跳轉到相關的中斷plat_irq_dispatch;通過簡單的計算得到中斷號,進而調 do_IRQ 進入相應的中斷處理程式。

啟動

CPU重啟和異常幾乎相同,但重啟不會返回到被中斷的程式。利用一般異常的機制,EPC就指向重啟被偵測到時正在執行的那條指令,大多數暫存器的值會被保留。然而,重啟打斷了正常的操作、正在進行裝載的一個暫存器,或者正在進行儲存或重填的快取單元,此時重啟也許會被忽略。

利用重啟時儲存起來的狀態可以做一些有用的宕機後的除錯。

啟動順序:

1. 跳轉到主ROM程式碼。

2. 將狀態暫存器設定成為某種已知的有意義的狀態,從現在開始,可以對非快取記憶體區域進行存取操作。

3. 在初始化並且對RAM空間的完整性進行快速自檢前,啟動程式碼只能使用暫存器。

4. 對控制檯埠和診斷暫存器配置,以輸出初始化過稱中的問題

5. 分配堆疊,設定足夠多的暫存器,通用標準的C程式碼

6. 初始化快取