8. aCore - CPU 異常處理(1)
2020-05-31
其實, CPU 也是一台計算器.
它也會返回不同的異常, 最常見的如: 除零、溢位。
那麼我們怎麼利用到CPU 的這些信息呢?
在這之前, 我們看看我們可能會有甚麼信息。
https://wiki.osdev.org/Exceptions#Faults
其中最重要的:
- Page Fault: 寫到未划分的記憶體或者只讀記憶體.
- Invalid Opcode: 查無此opcode
- General Protection Fault: 包山包海的記體憶錯誤, 最常見是Segmentation fault, 也就是沒有讀取權限。
- Double Fault: 常有Exception 時, exception handler 會被叫起, 而如果exception handler 有Exception... 這就是不幸的Double Fault 了
- Triple Fault: Double Fault 會直接上交到CPU, CPU 會有Double fault 的處理函數, 而如果這個函數有錯誤, 這就無藥可救, 會導致電腦(OS)重啟。
那麼CPU 是怎麼把這些異常分類的呢?
我們有...
中斷描述表
中斷描述表 : Interrupt Descriptor Table (IDT)
它是一個16-byte 的描述規格。
Type| 名稱 | 描述
----|--------------------------|-----------------------------------
u16 | Function Pointer [0:15] | 函數位置(頭16bit)
u16 | GDT selector | 指寫何個全局描述符表(GDT) 的區段的(https://en.wikipedia.org/wiki/Global_Descriptor_Table)
u16 | Options | (如下)
u16 | Function Pointer [16:31] | 函數位置(中16bit)
u32 | Function Pointer [32:63] | 函數位置(尾16bit)
u32 | Reserved |
Option 中有
The options field has the following format:
Bits | 名稱 | 描述
------|-----------------------------------|-----------------------------------
0-2 | Interrupt Stack Table Index | 跳到IST 的第n 層(0 時當前位置)
3-7 | Reserved | 保留
8 | 0: Interrupt Gate, 1: Trap Gate | 當0 時, 中斷將不會發生
9-11 | must be one | checksum 用
12 | must be zero | checksum 用
13‑14 | Descriptor Privilege Level (DPL) | 執行這個handler function 的最低權限等級
15 | Present | 是否當前
Interrupt Stack Table (IST) , 中文是 中斷棧
。
就是在除錯時的, 函數調用的最低階狀態, 不同的CPU 架構有不同的棧結構。aCore 現時是在x86 架構上運行的。
當有異常時, CPU 大概會做下面的事:
- Register, instruction pointer 和 RFLAGS register, 三者入棧。
- 檢查 Interrupt Descriptor Table (IDT). 是哪一個entry. (e.g. 14 就是page fault)
- 這個entry 是當前的layer 嗎? 不是的話, 就Raise 一個Double Fault
- 如果bit40 是interrupt gate 的話, disable hardware interrupts (變成soft interrupt)
- 映射 GDT(https://en.wikipedia.org/wiki/Global_Descriptor_Table) 中的定義, 取後code segment的位置
- 跳到handler function
Rust 中有 內置可以讀取的IDT : https://docs.rs/x86_64/0.11.0/x86_64/structures/idt/struct.InterruptDescriptorTable.html
看源碼時 :
#[repr(C)]
pub struct InterruptDescriptorTable {
pub divide_by_zero: Entry<HandlerFunc>,
pub debug: Entry<HandlerFunc>,
pub non_maskable_interrupt: Entry<HandlerFunc>,
pub breakpoint: Entry<HandlerFunc>,
pub overflow: Entry<HandlerFunc>,
pub bound_range_exceeded: Entry<HandlerFunc>,
pub invalid_opcode: Entry<HandlerFunc>,
pub device_not_available: Entry<HandlerFunc>,
pub double_fault: Entry<HandlerFuncWithErrCode>,
pub invalid_tss: Entry<HandlerFuncWithErrCode>,
pub segment_not_present: Entry<HandlerFuncWithErrCode>,
pub stack_segment_fault: Entry<HandlerFuncWithErrCode>,
pub general_protection_fault: Entry<HandlerFuncWithErrCode>,
pub page_fault: Entry<PageFaultHandlerFunc>,
pub x87_floating_point: Entry<HandlerFunc>,
pub alignment_check: Entry<HandlerFuncWithErrCode>,
pub machine_check: Entry<HandlerFunc>,
pub simd_floating_point: Entry<HandlerFunc>,
pub virtualization: Entry<HandlerFunc>,
pub security_exception: Entry<HandlerFuncWithErrCode>,
// some fields omitted
}
會發覺它們都是(idt::Entry<F>
)[https://docs.rs/x86_64/0.11.0/x86_64/structures/idt/struct.Entry.html].
F
代表 handler function 的類型。