add: Initialize the IDT table and add interrupt functions

This commit is contained in:
ParrotXray 2025-05-10 21:47:46 +08:00
parent 27568f5b5f
commit c5a211db51
7 changed files with 212 additions and 10 deletions

View File

@ -39,6 +39,8 @@
// lgdt (%esp)
// addl $0x6, %esp
call _load_idt
/* processing register (CS, ES, SS, DS, FS, GS) */
movw $0x10, %cx /* 0x10 in binary representation is 0001 0000. If you right-shift this number by 3 bits, you will get 0000 0010, so the index is 2. */
movw %cx, %es

View File

@ -39,11 +39,11 @@ pub const SEG_CODE_EXRDC: u64 = 0x0E; // Execute/Read, conforming
#[allow(dead_code)]
pub const SEG_CODE_EXRDCA: u64 = 0x0F; // Execute/Read, conforming, accessed
const NULL_SELECTOR: SegmentSelector = SegmentSelector::new(0, Ring::Ring0);
const KERNEL_CODE_SELECTOR: SegmentSelector = SegmentSelector::new(1, Ring::Ring0);
const KERNEL_DATA_SELECTOR: SegmentSelector = SegmentSelector::new(2, Ring::Ring0);
const USER_CODE_SELECTOR: SegmentSelector = SegmentSelector::new(3, Ring::Ring3);
const USER_DATA_SELECTOR: SegmentSelector = SegmentSelector::new(4, Ring::Ring3);
pub const NULL_SELECTOR: SegmentSelector = SegmentSelector::new(0, Ring::Ring0);
pub const KERNEL_CODE_SELECTOR: SegmentSelector = SegmentSelector::new(1, Ring::Ring0);
pub const KERNEL_DATA_SELECTOR: SegmentSelector = SegmentSelector::new(2, Ring::Ring0);
pub const USER_CODE_SELECTOR: SegmentSelector = SegmentSelector::new(3, Ring::Ring3);
pub const USER_DATA_SELECTOR: SegmentSelector = SegmentSelector::new(4, Ring::Ring3);
#[no_mangle]
pub static NULL_SEL: u16 = NULL_SELECTOR.bits();

View File

@ -0,0 +1,177 @@
// src/kernel/asm/x86/idt.rs
use core::mem;
use core::ptr;
use x86::dtables::{DescriptorTablePointer, lidt};
use x86::segmentation::{self, SegmentSelector, Descriptor, SystemDescriptorTypes32, DescriptorBuilder, BuildDescriptor};
use x86::Ring;
use x86::irq::{self, EXCEPTIONS};
use x86::segmentation::GateDescriptorBuilder;
use x86::segmentation::TaskGateDescriptorBuilder;
// 中斷處理常數
pub const IDT_ENTRY_COUNT: usize = 256;
// IDT 表
#[no_mangle]
pub static mut _IDT: [Descriptor; IDT_ENTRY_COUNT] = [Descriptor::NULL; IDT_ENTRY_COUNT];
// IDT 表大小限制
#[no_mangle]
pub static mut _IDT_LIMIT: u16 = (mem::size_of::<[Descriptor; IDT_ENTRY_COUNT]>() - 1) as u16;
// 內核代碼段選擇子
pub const KERNEL_CS: SegmentSelector = SegmentSelector::new(1, Ring::Ring0);
// 異常/中斷處理函數類型
pub type InterruptHandler = extern "C" fn() -> ();
pub type ExceptionHandlerWithErrorCode = extern "C" fn(error_code: u32) -> ();
// 設置中斷處理函數
#[no_mangle]
pub fn set_interrupt_handler(vector: u8, handler: InterruptHandler) {
unsafe {
// 使用 DescriptorBuilder 正確地構建中斷描述符
let desc = segmentation::DescriptorBuilder::interrupt_descriptor(KERNEL_CS, handler as u32)
.present() // 必須設置存在位!
.dpl(Ring::Ring0)
.finish();
_IDT[vector as usize] = desc;
}
}
// 設置陷阱處理函數
#[no_mangle]
pub fn set_trap_handler(vector: u8, handler: InterruptHandler) {
unsafe {
// 使用 DescriptorBuilder 正確地構建陷阱描述符
let desc = segmentation::DescriptorBuilder::trap_gate_descriptor(KERNEL_CS, handler as u32)
.present() // 必須設置存在位!
.dpl(Ring::Ring0)
.finish();
_IDT[vector as usize] = desc;
}
}
#[no_mangle]
pub fn set_task_gate(vector: u8, tss_selector: SegmentSelector) {
unsafe {
// 使用 DescriptorBuilder 建立任務門描述符
let desc = segmentation::DescriptorBuilder::task_gate_descriptor(tss_selector)
.present() // 必須設置存在位
.dpl(Ring::Ring0) // 設置特權級,通常為 Ring 0
.finish();
_IDT[vector as usize] = desc;
}
}
// 初始化 IDT
#[no_mangle]
pub fn _init_idt() {
// 初始化所有條目為 NULL
unsafe {
for i in 0..IDT_ENTRY_COUNT {
_IDT[i] = Descriptor::NULL;
}
}
}
// 載入 IDT
#[no_mangle]
pub fn _load_idt() {
unsafe {
_init_idt();
let idtr = DescriptorTablePointer {
limit: _IDT_LIMIT,
base: ptr::addr_of!(_IDT) as *const _,
};
lidt(&idtr);
setup_idt();
}
}
// 除零錯誤處理函數
#[no_mangle]
pub extern "C" fn divide_error_handler() {
let ex = &EXCEPTIONS[irq::DIVIDE_ERROR_VECTOR as usize];
crate::println!("CPU Exception: {} ({})", ex.mnemonic, ex.description);
crate::println!("Type: {}, Source: {}", ex.irqtype, ex.source);
loop {}
}
// 頁錯誤處理函數
#[no_mangle]
pub extern "C" fn page_fault_handler() {
let cr2: u32;
unsafe {
cr2 = x86::controlregs::cr2() as u32;
}
let ex = &EXCEPTIONS[irq::PAGE_FAULT_VECTOR as usize];
crate::println!("CPU Exception: {} ({})", ex.mnemonic, ex.description);
crate::println!("Fault address: 0x{:x}", cr2);
loop {}
}
// 通用保護錯誤處理函數
#[no_mangle]
pub extern "C" fn general_protection_handler() {
let ex = &EXCEPTIONS[irq::GENERAL_PROTECTION_FAULT_VECTOR as usize];
crate::println!("CPU Exception: {} ({})", ex.mnemonic, ex.description);
loop {}
}
// 默認中斷處理函數
#[no_mangle]
pub extern "C" fn default_interrupt_handler() {
crate::println!("Unhandled interrupt!");
loop {}
}
// 為 CPU 所有異常設置處理函數
#[no_mangle]
pub fn setup_idt() {
// 設置典型的異常處理函數
set_interrupt_handler(irq::DIVIDE_ERROR_VECTOR, divide_error_handler);
set_interrupt_handler(irq::DEBUG_VECTOR, default_interrupt_handler);
set_interrupt_handler(irq::NONMASKABLE_INTERRUPT_VECTOR, default_interrupt_handler);
set_interrupt_handler(irq::BREAKPOINT_VECTOR, default_interrupt_handler);
set_interrupt_handler(irq::OVERFLOW_VECTOR, default_interrupt_handler);
set_interrupt_handler(irq::BOUND_RANGE_EXCEEDED_VECTOR, default_interrupt_handler);
set_interrupt_handler(irq::INVALID_OPCODE_VECTOR, default_interrupt_handler);
set_interrupt_handler(irq::DEVICE_NOT_AVAILABLE_VECTOR, default_interrupt_handler);
set_interrupt_handler(irq::DOUBLE_FAULT_VECTOR, default_interrupt_handler);
set_interrupt_handler(irq::COPROCESSOR_SEGMENT_OVERRUN_VECTOR, default_interrupt_handler);
set_interrupt_handler(irq::INVALID_TSS_VECTOR, default_interrupt_handler);
set_interrupt_handler(irq::SEGMENT_NOT_PRESENT_VECTOR, default_interrupt_handler);
set_interrupt_handler(irq::STACK_SEGEMENT_FAULT_VECTOR, default_interrupt_handler);
set_interrupt_handler(irq::GENERAL_PROTECTION_FAULT_VECTOR, general_protection_handler);
set_interrupt_handler(irq::PAGE_FAULT_VECTOR, page_fault_handler);
// 設置其餘中斷為默認處理函數
for i in 32..IDT_ENTRY_COUNT as u8 {
set_interrupt_handler(i, default_interrupt_handler);
}
crate::println!("IDT initialized with {} entries", IDT_ENTRY_COUNT);
}
// 實現對中斷的測試函數
pub fn test_divide_by_zero() {
crate::println!("Testing divide by zero exception...");
unsafe {
core::arch::asm!(
"mov $0, %eax",
"mov $1, %ecx",
"div %eax",
options(att_syntax)
);
}
}

View File

@ -0,0 +1,14 @@
use core::mem;
use core::ptr;
use x86::segmentation::{SegmentSelector, Descriptor};
use x86::Ring;
use x86::irq::{self, PageFaultError, EXCEPTIONS};
use crate::{print, println};
// #[no_mangle]
// pub extern "C" fn divide_error_handler() {
// let ex = &EXCEPTIONS[irq::DIVIDE_ERROR_VECTOR as usize];
// println!("CPU Exception: {} ({})", ex.mnemonic, ex.description);
// println!("Type: {}, Source: {}", ex.irqtype, ex.source);
// loop {}
// }

View File

@ -1,2 +1,3 @@
pub mod gdt;
pub mod idt;
pub mod idt;
pub mod interrupt;

View File

@ -40,16 +40,24 @@ pub extern "C" fn _kernel_main() {
let mut brand_buffer = [0u8; 64];
println!("{}", cpu::cpu_get_brand(&mut brand_buffer));
unsafe {
core::arch::asm!(
"movl $0, %eax",
"movl $0, %ebx",
"divl %ebx",
options(att_syntax)
);
}
cpu::cpu_enable_interrupts();
// unsafe {
// core::arch::asm!(
// "movl $0, %eax",
// "movl $0, %ebx",
// "divl %ebx",
// "int $0",
// options(att_syntax)
// );
// }
loop {
cpu::cpu_idle();
}