Files
opencoreC/kernel/src/arch/idt.rs
T
RarDog eed05c1eca feat(boot+shell): add bootable disk image, unified scheduler and interactive user-space shell
- Implement Limine v8 boot protocol requests in dedicated PT_LOAD RW segment
- Configure IOPL=3 and SSE in arch setup for Ring 3 drivers and libc
- Unify scheduler context switching via switch_to and preempt_tick
- Support dual-source keyboard/serial input in sys_key_read
- Add automated 'make image' and 'make run' targets for instant QEMU launch
- Complete interactive UNIX-like shell (osh) with built-in commands & ramdisk
2026-09-02 19:47:57 +03:00

218 lines
7.6 KiB
Rust

//! Interrupt Descriptor Table (IDT) and Exception Handling
use crate::kprintln;
use crate::sched::SCHEDULER;
use crate::drivers::timer::send_eoi;
use core::mem::size_of;
#[repr(C, packed)]
#[derive(Clone, Copy)]
pub struct IdtEntry {
offset_low: u16,
selector: u16,
ist: u8,
type_attr: u8,
offset_mid: u16,
offset_high: u32,
_reserved: u32,
}
impl IdtEntry {
pub const fn missing() -> Self {
Self {
offset_low: 0,
selector: 0,
ist: 0,
type_attr: 0,
offset_mid: 0,
offset_high: 0,
_reserved: 0,
}
}
pub fn set_handler(&mut self, handler: u64, ist: u8, dpl: u8) {
self.offset_low = (handler & 0xffff) as u16;
self.selector = 0x08; // Kernel code segment
self.ist = ist & 0x7;
self.type_attr = 0x80 | ((dpl & 0x3) << 5) | 0x0E; // 64-bit Interrupt Gate Present
self.offset_mid = ((handler >> 16) & 0xffff) as u16;
self.offset_high = ((handler >> 32) & 0xffffffff) as u32;
self._reserved = 0;
}
}
#[repr(C, packed)]
struct IdtDescriptor {
limit: u16,
base: u64,
}
static mut IDT: [IdtEntry; 256] = [IdtEntry::missing(); 256];
extern "C" {
fn default_isr_stub();
fn timer_isr_entry();
fn keyboard_isr_entry();
}
// Global assembly ISR stub with vector ID pushed as separate stubs (0-31)
core::arch::global_asm!(
// With error code: CPU already pushed error_code, we push vector on top
".macro ISR_ERR_CODE num",
"isr_stub_\\num:",
"push \\num", // push vector number (error_code already on stack below)
"jmp default_isr_common",
".endm",
// Without error code: push dummy 0, then vector
".macro ISR_NO_ERR num",
"isr_stub_\\num:",
"push 0", // dummy error_code
"push \\num", // push vector number
"jmp default_isr_common",
".endm",
"ISR_NO_ERR 0", "ISR_NO_ERR 1", "ISR_NO_ERR 2", "ISR_NO_ERR 3",
"ISR_NO_ERR 4", "ISR_NO_ERR 5", "ISR_NO_ERR 6", "ISR_NO_ERR 7",
"ISR_ERR_CODE 8","ISR_NO_ERR 9", "ISR_ERR_CODE 10","ISR_ERR_CODE 11",
"ISR_ERR_CODE 12","ISR_ERR_CODE 13","ISR_ERR_CODE 14","ISR_NO_ERR 15",
"ISR_NO_ERR 16","ISR_ERR_CODE 17","ISR_NO_ERR 18","ISR_NO_ERR 19",
"ISR_NO_ERR 20","ISR_ERR_CODE 21","ISR_NO_ERR 22","ISR_NO_ERR 23",
"ISR_NO_ERR 24","ISR_NO_ERR 25","ISR_NO_ERR 26","ISR_NO_ERR 27",
"ISR_NO_ERR 28","ISR_NO_ERR 29","ISR_ERR_CODE 30","ISR_NO_ERR 31",
".global default_isr_stub",
"default_isr_stub:",
"push 0", // dummy error code
"push 255", // dummy vector
"jmp default_isr_common",
".global default_isr_common",
"default_isr_common:",
// Stack at this point (top to bottom):
// RSP+0: vector
// RSP+8: error_code
// RSP+16: RIP (pushed by CPU)
// RSP+24: CS
// RSP+32: RFLAGS
// RSP+40: RSP (if ring change)
// RSP+48: SS (if ring change)
"push rax", "push rcx", "push rdx",
"push rsi", "push rdi",
"push r8", "push r9", "push r10", "push r11",
"mov rdi, rsp",
"call raw_exception_handler",
"pop r11", "pop r10", "pop r9", "pop r8",
"pop rdi", "pop rsi",
"pop rdx", "pop rcx", "pop rax",
// skip vector + error_code from stack
"add rsp, 16",
"iretq"
);
pub unsafe fn init() {
let idt_ptr = core::ptr::addr_of_mut!(IDT) as *mut IdtEntry;
// Install per-vector stubs for exceptions 0-31
extern "C" {
fn isr_stub_0(); fn isr_stub_1(); fn isr_stub_2(); fn isr_stub_3();
fn isr_stub_4(); fn isr_stub_5(); fn isr_stub_6(); fn isr_stub_7();
fn isr_stub_8(); fn isr_stub_9(); fn isr_stub_10(); fn isr_stub_11();
fn isr_stub_12(); fn isr_stub_13(); fn isr_stub_14(); fn isr_stub_15();
fn isr_stub_16(); fn isr_stub_17(); fn isr_stub_18(); fn isr_stub_19();
fn isr_stub_20(); fn isr_stub_21(); fn isr_stub_22(); fn isr_stub_23();
fn isr_stub_24(); fn isr_stub_25(); fn isr_stub_26(); fn isr_stub_27();
fn isr_stub_28(); fn isr_stub_29(); fn isr_stub_30(); fn isr_stub_31();
}
let exception_stubs: [u64; 32] = [
isr_stub_0 as u64, isr_stub_1 as u64, isr_stub_2 as u64, isr_stub_3 as u64,
isr_stub_4 as u64, isr_stub_5 as u64, isr_stub_6 as u64, isr_stub_7 as u64,
isr_stub_8 as u64, isr_stub_9 as u64, isr_stub_10 as u64, isr_stub_11 as u64,
isr_stub_12 as u64, isr_stub_13 as u64, isr_stub_14 as u64, isr_stub_15 as u64,
isr_stub_16 as u64, isr_stub_17 as u64, isr_stub_18 as u64, isr_stub_19 as u64,
isr_stub_20 as u64, isr_stub_21 as u64, isr_stub_22 as u64, isr_stub_23 as u64,
isr_stub_24 as u64, isr_stub_25 as u64, isr_stub_26 as u64, isr_stub_27 as u64,
isr_stub_28 as u64, isr_stub_29 as u64, isr_stub_30 as u64, isr_stub_31 as u64,
];
for (i, &stub_addr) in exception_stubs.iter().enumerate() {
(*idt_ptr.add(i)).set_handler(stub_addr, 0, 0);
}
// Fill 32..255 with default stub
let stub_addr = default_isr_stub as *const () as usize as u64;
for i in 32..256usize {
(*idt_ptr.add(i)).set_handler(stub_addr, 0, 0);
}
// Set Timer Interrupt (Vector 32 / 0x20)
let timer_addr = timer_isr_entry as *const () as usize as u64;
(*idt_ptr.add(32)).set_handler(timer_addr, 0, 0);
// Set Keyboard Interrupt (Vector 33 / 0x21)
let kbd_addr = keyboard_isr_entry as *const () as usize as u64;
(*idt_ptr.add(33)).set_handler(kbd_addr, 0, 0);
let descriptor = IdtDescriptor {
limit: (size_of::<[IdtEntry; 256]>() - 1) as u16,
base: idt_ptr as u64,
};
core::arch::asm!("lidt [{0}]", in(reg) &descriptor, options(preserves_flags));
}
#[repr(C)]
pub struct ExceptionFrame {
// Stack layout when raw_exception_handler is called (low addr = top of stack):
// Pushed by default_isr_common: r11,r10,r9,r8,rdi,rsi,rdx,rcx,rax (in that push order)
pub r11: u64, pub r10: u64, pub r9: u64, pub r8: u64,
pub rdi: u64, pub rsi: u64, pub rdx: u64, pub rcx: u64, pub rax: u64,
// Pushed by per-vector stub (in push order: vector first on top)
pub vector: u64,
pub error_code: u64,
// Pushed by CPU hardware:
pub rip: u64,
pub cs: u64,
pub rflags: u64,
pub user_rsp: u64, // only present on ring transition
pub ss: u64,
}
#[no_mangle]
pub extern "C" fn raw_exception_handler(frame: *const ExceptionFrame) {
unsafe {
let v = (*frame).vector;
let ec = (*frame).error_code;
let rip = (*frame).rip;
let cs = (*frame).cs;
let rflags = (*frame).rflags;
let names = [
"#DE", "#DB", "NMI", "#BP", "#OF", "#BR", "#UD", "#NM",
"#DF", "CSO", "#TS", "#NP", "#SS", "#GP", "#PF", "RES",
"#MF", "#AC", "#MC", "#XM", "#VE", "#CP", "??" , "??" ,
"??" , "??" , "??" , "??" , "??" , "??" , "#SX", "??" ,
];
let name = if v < 32 { names[v as usize] } else { "IRQ" };
kprintln!("\n[EXCEPTION] Vec={} ({}) ErrCode={:#x} RIP={:#018x} CS={:#x} RFLAGS={:#x}",
v, name, ec, rip, cs, rflags);
if v == 14 {
let cr2: u64;
core::arch::asm!("mov {}, cr2", out(reg) cr2, options(nostack, preserves_flags));
kprintln!(" #PF CR2 (faulting address): {:#018x}", cr2);
}
if v < 32 {
kprintln!(" [HALT] Unrecoverable exception - CPU halted.");
loop { core::arch::asm!("cli; hlt", options(nostack, preserves_flags)); }
}
}
}
#[no_mangle]
pub extern "C" fn timer_interrupt_handler() {
unsafe {
send_eoi();
let sched = &mut *core::ptr::addr_of_mut!(SCHEDULER);
sched.preempt_tick();
}
}