diff options
| author | Tianhao Wang <shrik3@mailbox.org> | 2024-04-18 02:29:44 +0200 |
|---|---|---|
| committer | Tianhao Wang <shrik3@mailbox.org> | 2024-06-11 15:16:34 +0200 |
| commit | 4c7dec80c02db70d9592bbe91f00145c0eb7a40e (patch) | |
| tree | 6889539f2bb88aafe22fe076e83fcf67afc66b67 | |
| parent | 9ffe5da010790ca8751e132841352c9543d06c5c (diff) | |
interrupt: add rust binding for idt
| -rw-r--r-- | boot/startup-x86_64.s | 36 | ||||
| -rw-r--r-- | src/arch/x86_64/asm/vectors.s | 28 | ||||
| -rw-r--r-- | src/arch/x86_64/interrupt/mod.rs | 79 | ||||
| -rw-r--r-- | src/arch/x86_64/interrupt/pic_8259.rs | 2 | ||||
| -rw-r--r-- | src/lib.rs | 8 |
5 files changed, 93 insertions, 60 deletions
diff --git a/boot/startup-x86_64.s b/boot/startup-x86_64.s index 610d7ca..5413a80 100644 --- a/boot/startup-x86_64.s +++ b/boot/startup-x86_64.s @@ -161,10 +161,6 @@ clear_bss: inc rdi cmp rdi, ___BSS_END__ jne clear_bss - - ; initialize IDT and PICs - call setup_idt - fninit ; activate FPU init_sse: @@ -182,38 +178,6 @@ init_sse: cli ; Usually we should not get here. hlt -; -; Interrupt handling -; - - -; -; Relocating of IDT entries and setting IDTR -; - -setup_idt: - mov rax, vectors_start - - ; bits 0..15 -> ax, 16..31 -> bx, 32..64 -> edx - mov rbx, rax - mov rdx, rax - shr rdx, 32 - shr rbx, 16 - - mov r10, idt ; pointer to the actual interrupt gate - mov rcx, 255 ; counter -.loop: - add [r10+0], ax - adc [r10+6], bx - adc [r10+8], edx - add r10, 16 - dec rcx - jge .loop - - lidt [idt_descr] - ret - - [SECTION .data] ; diff --git a/src/arch/x86_64/asm/vectors.s b/src/arch/x86_64/asm/vectors.s index c3fa12f..ba5fb87 100644 --- a/src/arch/x86_64/asm/vectors.s +++ b/src/arch/x86_64/asm/vectors.s @@ -9,29 +9,21 @@ ; ; Interrupt descriptor table with 256 entries ; TODO: use a interrupt stack instead of the current stack. -; -idt: -%macro idt_entry 1 - dw (wrapper_%1 - wrapper_0) & 0xffff ; offset 0 .. 15 - dw 0x0000 | 0x8 * 2 ; selector points to 64-bit code segment selector (GDT) - dw 0x8e00 ; 8 -> interrupt is present, e -> 80386 32-bit interrupt gate - dw ((wrapper_%1 - wrapper_0) & 0xffff0000) >> 16 ; offset 16 .. 31 - dd ((wrapper_%1 - wrapper_0) & 0xffffffff00000000) >> 32 ; offset 32..63 - dd 0x00000000 ; reserved -%endmacro -%assign i 0 -%rep 256 -idt_entry i -%assign i i+1 -%endrep +idt: +; reserve space for 256x idt entries (16 bytes each) +resb 16 * 256 idt_descr: dw 256*8 - 1 ; 256 entries dq idt -; template for header for each interrupt-handling routine +; NOTE: vectors MUST have fixed instruction length currently aligned to 16 +; bytes. DO NOT modify the wrapper, instead change the wrapper_body if needed. +; if the vector has to be modified into more than 16 bytes, +; arch::x86_64:: interrupt::_idt_init() must be modified accordingly %macro wrapper 1 +align 16 wrapper_%1: push rbp mov rbp, rsp @@ -46,8 +38,8 @@ wrapper_%1: vectors_start: %assign i 0 %rep 256 -wrapper i -%assign i i+1 + wrapper i + %assign i i+1 %endrep ; common handler body diff --git a/src/arch/x86_64/interrupt/mod.rs b/src/arch/x86_64/interrupt/mod.rs index 410996a..ce87e89 100644 --- a/src/arch/x86_64/interrupt/mod.rs +++ b/src/arch/x86_64/interrupt/mod.rs @@ -2,6 +2,58 @@ pub mod pic_8259; pub mod pit; use crate::io::*; use core::arch::asm; +use core::slice; + +// number of entries in IDT +pub const IDT_CAPACITY: usize = 256; +// size of interrupt handler wrapper routine (vector) +pub const VECTOR_SIZE: u64 = 16; +extern "C" { + fn vectors_start(); + fn idt(); + fn idt_descr(); +} + +// x86_64 gate descriptor (idt entry) format +// [0 :15] addr[0:15] +// [16:31] segment selector: must point to valid code segment in GDT +// [32:39] ist: index into Interrupt Stack Table; only lower 3 bit used, +// other bits are reserved to 0 +// [40:47] attrs: attributes of the call gate: +// [0:3] - Gate Type: 0xe for interrupt and 0xf for trap +// [ 4 ] - Res0 +// [5:6] - DPL: allowed privilege levels (via INT) +// [ 7 ] - Present (Valid) +// [48:63] - addr[16:31] +// [64:95] - addr[32:63] +#[repr(C)] +pub struct GateDescriptor64 { + pub offset_1: u16, + pub selector: u16, + pub ist: u8, + pub attrs: u8, + pub offset_2: u16, + pub offset_3: u32, + res0: u32, // [96:127] +} + +// TODO expand interface for idt entry, if needed. +impl GateDescriptor64 { + #[inline(always)] + pub fn set_offset(&mut self, offset: u64) { + self.offset_1 = (offset & 0xffff) as u16; + self.offset_2 = ((offset & 0xffff0000) >> 16) as u16; + self.offset_3 = ((offset & 0xffffffff00000000) >> 32) as u32; + } + /// selector = 0; present; type = interrupt; + pub fn set_default_interrupt(&mut self, offset: u64) { + self.set_offset(offset); + self.selector = 0x8 * 2; + self.attrs = 0x8e; + self.ist = 0; + self.res0 = 0; + } +} #[no_mangle] #[cfg(target_arch = "x86_64")] @@ -12,7 +64,7 @@ extern "C" fn interrupt_gate(slot: u16) { // able to release the lock if the interrupt handler blocks on it. Try // spamming the keyboard with the following line of code uncommented: it // will deadlock! - // println!("interrupt received {:x}", slot); + // println!("interrupt received 0x{:x}", slot); interrupt_enable(); } @@ -29,3 +81,28 @@ pub fn interrupt_disable() { asm!("cli"); } } + +#[inline(always)] +fn _idt_init() { + unsafe { + println!("[init] idt: vectors_start: 0x{:x}", vectors_start as usize); + } + + let gate_descriptors: &mut [GateDescriptor64] = + unsafe { slice::from_raw_parts_mut(idt as *mut GateDescriptor64, 256) }; + + // write to idt + for i in 0..IDT_CAPACITY { + let offset: u64 = vectors_start as u64 + (i as u64 * VECTOR_SIZE); + gate_descriptors[i].set_default_interrupt(offset); + } + // set idtr + unsafe { asm! ("lidt [{}]", in(reg) idt_descr) } +} + +pub fn init() { + // init idt + _idt_init(); + // init pic + pic_8259::_init(); +} diff --git a/src/arch/x86_64/interrupt/pic_8259.rs b/src/arch/x86_64/interrupt/pic_8259.rs index 969e8d1..d40d5ba 100644 --- a/src/arch/x86_64/interrupt/pic_8259.rs +++ b/src/arch/x86_64/interrupt/pic_8259.rs @@ -15,7 +15,7 @@ impl PicDeviceInt { // init must be called before interrupt is enabled. // TODO: turn pic into a singleton struct -pub fn init() { +pub fn _init() { outb(0x20, 0x11); outb(0xa0, 0x11); outb(0x21, 0x20); @@ -8,11 +8,11 @@ mod ds; mod io; mod machine; mod mm; +use arch::x86_64::interrupt; use arch::x86_64::interrupt::pic_8259; use arch::x86_64::interrupt::pic_8259::PicDeviceInt; use core::panic::PanicInfo; use machine::cgascr::CGAScreen; -use machine::interrupt; use crate::machine::key::Modifiers; @@ -26,11 +26,11 @@ fn panic(info: &PanicInfo) -> ! { #[no_mangle] pub extern "C" fn _entry() -> ! { // init code - pic_8259::init(); - pic_8259::allow(PicDeviceInt::KEYBOARD); - interrupt::interrupt_enable(); io::set_attr(0x1f); io::clear(); + interrupt::init(); + pic_8259::allow(PicDeviceInt::KEYBOARD); + interrupt::interrupt_enable(); println!("--RuStuBs--"); println!(" _._ _,-'\"\"`-._ ~Meow"); println!(" (,-.`._,'( |\\`-/|"); |
