rustubs/arch/x86_64/interrupt/
idt.rs

1use crate::defs::HWDefs::*;
2use crate::io::*;
3use crate::ExternSyms::{idt, idt_descr, vectors_start};
4use core::arch::asm;
5use core::slice;
6
7/// initialize the idt: we reserved space for idt in assembly code (and linker
8/// script) we write contents to them now. One purpose is to save binary space.
9/// This also allows more flexibility for some interrupt handlers (e.g. when
10/// they needs a dedicated stack...)
11#[inline(always)]
12pub fn init() {
13	println!("[init] idt: vectors_start: 0x{:x}", vectors_start as usize);
14
15	let gate_descriptors: &mut [GateDescriptor64] = unsafe {
16		slice::from_raw_parts_mut(idt as *mut GateDescriptor64, IDT_CAPACITY)
17	};
18
19	// write to idt
20	for i in 0..IDT_VALID {
21		let offset = vectors_start as usize + (i * VECTOR_SIZE);
22		gate_descriptors[i].set_default_interrupt(offset as u64);
23	}
24	let offset_inv: usize = vectors_start as usize + (IDT_VALID * VECTOR_SIZE);
25	for i in IDT_VALID..IDT_CAPACITY {
26		gate_descriptors[i].set_default_interrupt(offset_inv as u64);
27	}
28	// set idtr
29	unsafe { asm! ("lidt [{}]", in(reg) idt_descr) }
30}
31
32/// ```text
33/// <pre>
34/// [0 :15]  addr[0:15]
35/// [16:31]  segment selector: must point to valid code segment in GDT
36/// [32:39]  ist: index into Interrupt Stack Table; only lower 3 bit used,
37///          other bits are reserved to 0
38/// [40:47]  attrs: attributes of the call gate:
39///          [0:3]    - Gate Type: 0xe for interrupt and 0xf for trap
40///          [ 4 ]    - Res0
41///          [5:6]    - DPL: allowed privilege levels (via INT)
42///          [ 7 ]    - Present (Valid)
43/// [48:63] - addr[16:31]
44/// [64:95] - addr[32:63]
45/// ```
46#[repr(C)]
47#[repr(packed)]
48struct GateDescriptor64 {
49	pub offset_1: u16,
50	pub selector: u16,
51	pub ist: u8,
52	pub attrs: u8,
53	pub offset_2: u16,
54	pub offset_3: u32,
55	res0: u32, // [96:127]
56}
57
58// TODO expand interface for idt entry, if needed.
59impl GateDescriptor64 {
60	#[inline(always)]
61	fn set_offset(&mut self, offset: u64) {
62		self.offset_1 = (offset & 0xffff) as u16;
63		self.offset_2 = ((offset & 0xffff0000) >> 16) as u16;
64		self.offset_3 = ((offset & 0xffffffff00000000) >> 32) as u32;
65	}
66	/// selector = 0; present; type = interrupt;
67	fn set_default_interrupt(&mut self, offset: u64) {
68		self.set_offset(offset);
69		self.selector = 0x8 * 2;
70		self.attrs = 0x8e;
71		self.ist = 0;
72		self.res0 = 0;
73	}
74}