aboutsummaryrefslogtreecommitdiff
path: root/src/arch
diff options
context:
space:
mode:
authorTianhao Wang <shrik3@mailbox.org>2024-04-18 02:29:44 +0200
committerTianhao Wang <shrik3@mailbox.org>2024-06-11 15:16:34 +0200
commit4c7dec80c02db70d9592bbe91f00145c0eb7a40e (patch)
tree6889539f2bb88aafe22fe076e83fcf67afc66b67 /src/arch
parent9ffe5da010790ca8751e132841352c9543d06c5c (diff)
interrupt: add rust binding for idt
Diffstat (limited to 'src/arch')
-rw-r--r--src/arch/x86_64/asm/vectors.s28
-rw-r--r--src/arch/x86_64/interrupt/mod.rs79
-rw-r--r--src/arch/x86_64/interrupt/pic_8259.rs2
3 files changed, 89 insertions, 20 deletions
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);