Exception Vector Table
當中斷發生時,CPU 會根據目前的 exception level 查找對應的中斷向量表 (VBAR_ELx
)。知道向量表在哪後,就可以根據中斷發生的類型執行對應的操作。
中斷發生的時機,可以是在 EL0 主動執行 svc
trap 到 EL1 (Synchronous),或是被 timer interrupt (IRQ) 打到,也會從 EL0 轉換到 EL1。
Exception Mechanism
當中斷發生時,會有以下流程:
- 將目前的 PSTAT 儲存在
SPSR_ELx
- 將 returned address 儲存在
ELR_ELx
- 關閉 interrupt (
PSTATE.{D,A,I,F}
are set to 1) - 若 exception 是 Synchronous exception 或是 SError interrupt,將 exception syndrome 保存在
ESR_ELx
- 轉換 EL 到目標的 EL,
pc
指到對應的中斷向量表
當中斷處理結束,執行 eret
回到中斷發生前的狀態:
pc
變回先前在ELR_ELx
儲存的值PSTATE
變回先前在SPSR_ELx
儲存的值
More details: Stack Pointer
當處在不同的 exception level 時,sp
這個暫存器會被當作是該 level sp 的別稱 (SP_ELx
的別稱)。可以使用 SPSel
在不同的 exception level 共享 SP_EL0
,但是通常不建議這樣做。
- 對於 EL0,僅能使用
SP_EL0
(簡稱為 EL0t) - 對於 EL1,可以選擇使用
SP_EL0
(簡稱為 EL1t),或者使用SP_EL1
(簡稱為 EL1h) - 對於 EL2,可以選擇使用
SP_EL0
(簡稱為 EL2t),或者使用SP_EL2
(簡稱為 EL2h) - 對於 EL3,可以選擇使用
SP_EL0
(簡稱為 EL3t),或者使用SP_EL3
(簡稱為 EL3h)
t: thread, h: handler
ELxt 與 ELxh 的區別在於是不是使用該 exception level 的 sp,t 代表使用 SP_EL0,h 代表使用該 exception level 自己的 sp
在 Exception Level Switch 設定 SPSR_EL1
與 SPSR_EL2
時,也會設定該 exception level 的 stack pointer (M[3:0]
欄位):
- 開機時處於 EL2,將
SPSR_EL2.M[3:0]
設定為 EL1h,執行eret
時回到 EL1 後,sp
即為SP_EL1
。 - 在處於 EL1 設定 EL0 時,將
SPSR_EL1.M[3:0]
設定為 EL0t,執行eret
時回到 EL0 後,sp
即為SP_EL0
。
Interrupts vs Exceptions
In ARM.v8 architecture, interrupts are part of a more general term: exceptions. There are 4 types of exceptions:
- Synchronous exception
- caused by the currently executed instruction
- IRQ (Interrupt Request)
- always asynchronous, which means that they have nothing to do with the currently executed instruction
- they are always not generated by the processor itself, but by external hardware
- FIQ (Fast Interrupt Request)
- for the purpose of prioritizing exceptions
- SError (System Error)
- asynchronous and are generated by external hardware
- always indicates some error condition
中斷向量表
定義 Vector Table,總共會有 16 個 Exception Handler 需要實作:4 種類型,每種類型都有 4 種不同的 exception handler (Sync, IRQ, FIQ, SError),以 EL1 的 Vector Table 為例:
- EL0_32
VBAR_EL1
+ 0x600
- EL0_64
VBAR_EL1
+ 0x400
- EL1h (SPSel = 1)
VBAR_EL1
+ 0x200
- EL1t (SPSel = 0)
VBAR_EL1
+ 0x0
注意每個 exception handler 需要對齊 0x80
exception_table.h
先定義一下 invalid 的編號,當有還沒有實作的 exception handler 被呼叫到時,會將編號當作參數傳入某個 function 進行錯誤輸出
|
|
exception_table.S
在進到 Exception Handler 時需要進行 context saving (kernel_entry
及 kernel_exit
這兩個 macro),避免 Exception Handler 覆寫先前的 Register 狀態。
|
|
目前只實作了 EL1h 與 EL0_64 的 Synchronous Interrupt (for system call) 及 IRQ Interrupt (for timer interrupt) 的 exception handler,當觸發時會跳到用 C 的 code。
|
|
start.S
在初始化到 EL1 時,將向量表的記憶體位址載入到 VBAR_EL1
|
|
panic.c
|
|
當發生 Exception 時怎麼知道會跳到哪個 level?
The Exception level that execution changes to, or remains in, on taking an exception, is called the target Exception level of the exception and:
- Every exception type has a target Exception level that is either:
- Implicit in the nature of the exception.
- Defined by configuration bits in the System registers.
- An exception cannot target the EL0 Exception level.
Synchronous exception 通常都有訂好 target exception level (e.g. svc
: EL0 -> EL1, hvc
: EL1 -> EL2)。
IRQ 可以通過設置不同 Register 來進行調整 (e.g. 設定 HCR_EL2.TGE
可以將 EL1 發生的 exception route 到 EL2),在實驗中我們都假設是由 EL1 來進行處理。