From c5a211db51503891bcefaeb3b02c03fb125d60a5 Mon Sep 17 00:00:00 2001 From: ParrotXray Date: Sat, 10 May 2025 21:47:46 +0800 Subject: [PATCH] add: Initialize the IDT table and add interrupt functions --- src/arch/x86/boot.S | 2 + src/hal/cpu.rs:Zone.Identifier | 0 src/kernel/asm/x86/gdt.rs | 10 +- src/kernel/asm/x86/idt.rs | 177 ++++++++++++++++++++++++++++++++ src/kernel/asm/x86/interrupt.rs | 14 +++ src/kernel/asm/x86/mod.rs | 3 +- src/kernel/kernel.rs | 16 ++- 7 files changed, 212 insertions(+), 10 deletions(-) delete mode 100644 src/hal/cpu.rs:Zone.Identifier create mode 100644 src/kernel/asm/x86/interrupt.rs diff --git a/src/arch/x86/boot.S b/src/arch/x86/boot.S index 51745b4..7f8cbd7 100644 --- a/src/arch/x86/boot.S +++ b/src/arch/x86/boot.S @@ -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 diff --git a/src/hal/cpu.rs:Zone.Identifier b/src/hal/cpu.rs:Zone.Identifier deleted file mode 100644 index e69de29..0000000 diff --git a/src/kernel/asm/x86/gdt.rs b/src/kernel/asm/x86/gdt.rs index 5a2d332..3c9a286 100644 --- a/src/kernel/asm/x86/gdt.rs +++ b/src/kernel/asm/x86/gdt.rs @@ -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(); diff --git a/src/kernel/asm/x86/idt.rs b/src/kernel/asm/x86/idt.rs index e69de29..b179a13 100644 --- a/src/kernel/asm/x86/idt.rs +++ b/src/kernel/asm/x86/idt.rs @@ -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) + ); + } +} \ No newline at end of file diff --git a/src/kernel/asm/x86/interrupt.rs b/src/kernel/asm/x86/interrupt.rs new file mode 100644 index 0000000..1e92df6 --- /dev/null +++ b/src/kernel/asm/x86/interrupt.rs @@ -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 {} +// } \ No newline at end of file diff --git a/src/kernel/asm/x86/mod.rs b/src/kernel/asm/x86/mod.rs index 6aed368..7a16afe 100644 --- a/src/kernel/asm/x86/mod.rs +++ b/src/kernel/asm/x86/mod.rs @@ -1,2 +1,3 @@ pub mod gdt; -pub mod idt; \ No newline at end of file +pub mod idt; +pub mod interrupt; \ No newline at end of file diff --git a/src/kernel/kernel.rs b/src/kernel/kernel.rs index 0c5490a..ae1d79c 100644 --- a/src/kernel/kernel.rs +++ b/src/kernel/kernel.rs @@ -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(); }