1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
|
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")]
extern "C" fn interrupt_gate(slot: u16) {
interrupt_disable();
// NOTE: the interrupt handler should NEVER block on a lock; in this case
// the CGA screen is protected by a spinlock. The lock holder will never be
// 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 0x{:x}", slot);
interrupt_enable();
}
#[inline(always)]
pub fn interrupt_enable() {
unsafe {
asm!("sti");
}
}
#[inline(always)]
pub fn interrupt_disable() {
unsafe {
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();
}
|