1use super::IsaInterrupt;
2use crate::{cpu, segment};
3use mycelium_util::{bits, fmt};
4
5#[repr(C)]
6#[repr(align(16))]
7pub struct Idt {
8 pub(crate) descriptors: [Descriptor; Self::NUM_VECTORS],
9}
10
11#[derive(Copy, Clone, Eq, PartialEq)]
12#[repr(C)]
13pub struct Descriptor {
14 offset_low: u16,
15 segment: segment::Selector,
16 ist_offset: u8,
17 attrs: Attrs,
18 offset_mid: u16,
19 offset_hi: u32,
20 _zero: u32,
21}
22
23mycelium_util::bits::bitfield! {
24 #[derive(Eq, PartialEq)]
25 pub struct Attrs<u8> {
26 pub const GATE_KIND: GateKind;
27 pub const IS_32_BIT: bool;
28 pub const RING: cpu::Ring;
29 const _PAD = 1;
30 pub const PRESENT: bool;
31 }
32}
33
34impl Descriptor {
35 pub const fn null() -> Self {
36 Self {
37 offset_low: 0,
38 segment: segment::Selector::null(),
39 ist_offset: 0,
40 attrs: Attrs::null(),
41 offset_mid: 0,
42 offset_hi: 0,
43 _zero: 0,
44 }
45 }
46
47 pub(crate) fn set_handler(&mut self, handler: *const ()) -> &mut Self {
48 self.segment = segment::Selector::current_cs();
49 let addr = handler as u64;
50 self.offset_low = addr as u16;
51 self.offset_mid = (addr >> 16) as u16;
52 self.offset_hi = (addr >> 32) as u32;
53 self.attrs
54 .set_present(true)
55 .set_32_bit(true)
56 .set_gate_kind(GateKind::Interrupt);
57 self
58 }
59
60 pub(crate) fn set_ist_offset(&mut self, ist_offset: u8) -> &mut Self {
64 self.ist_offset = ist_offset;
65 self
66 }
67
68 #[inline]
70 #[must_use]
71 pub fn attrs_mut(&mut self) -> &mut Attrs {
72 &mut self.attrs
73 }
74}
75
76#[derive(Debug, Eq, PartialEq, Copy, Clone)]
77#[repr(u8)]
78pub enum GateKind {
79 Interrupt = 0b0000_0110,
80 Trap = 0b0000_0111,
81 Task = 0b0000_0101,
82}
83
84impl bits::FromBits<u8> for GateKind {
85 const BITS: u32 = 3;
86 type Error = &'static str;
87
88 fn try_from_bits(bits: u8) -> Result<Self, Self::Error> {
89 match bits {
90 bits if bits == Self::Interrupt as u8 => Ok(Self::Interrupt),
91 bits if bits == Self::Trap as u8 => Ok(Self::Trap),
92 bits if bits == Self::Task as u8 => Ok(Self::Task),
93 _ => Err("unknown GateKind pattern, expected one of [110, 111, or 101]"),
94 }
95 }
96
97 fn into_bits(self) -> u8 {
98 self as u8
99 }
100}
101
102impl Idt {
105 pub const NUM_VECTORS: usize = 256;
106
107 pub const DIVIDE_BY_ZERO: usize = 0;
109
110 pub const DEBUG: usize = 1;
111
112 pub const NMI: usize = 2;
114
115 pub const BREAKPOINT: usize = 3;
116
117 pub const OVERFLOW: usize = 4;
118
119 pub const BOUND_RANGE_EXCEEDED: usize = 5;
120
121 pub const INVALID_OPCODE: usize = 6;
122
123 pub const DEVICE_NOT_AVAILABLE: usize = 7;
125
126 pub const DOUBLE_FAULT: usize = 8;
128
129 pub const COPROCESSOR_SEGMENT_OVERRUN: usize = 9;
132
133 pub const INVALID_TSS: usize = 10;
134
135 pub const SEGMENT_NOT_PRESENT: usize = 11;
136
137 pub const STACK_SEGMENT_FAULT: usize = 12;
138
139 pub const GENERAL_PROTECTION_FAULT: usize = 13;
140
141 pub const PAGE_FAULT: usize = 14;
142
143 pub const X87_FPU_EXCEPTION: usize = 16;
144
145 pub const ALIGNMENT_CHECK: usize = 17;
146
147 pub const MACHINE_CHECK: usize = 18;
148
149 pub const SIMD_FLOATING_POINT: usize = 19;
150
151 pub const VIRTUALIZATION_EXCEPTION: usize = 20;
152
153 pub const SECURITY_EXCEPTION: usize = 30;
154
155 pub const DOUBLE_FAULT_IST_OFFSET: usize = 4;
157
158 pub const MAX_CPU_EXCEPTION: usize = Self::SECURITY_EXCEPTION;
159
160 pub const ISA_BASE: usize = 0x20;
162
163 pub const LOCAL_APIC_TIMER: usize = (Self::NUM_VECTORS - 2);
171
172 pub const LOCAL_APIC_SPURIOUS: usize = (Self::NUM_VECTORS - 1);
180
181 pub const PIC_BIG_START: usize = Self::ISA_BASE;
189
190 pub const PIC_LITTLE_START: usize = Self::ISA_BASE + 8;
198 pub const fn new() -> Self {
201 Self {
202 descriptors: [Descriptor::null(); Self::NUM_VECTORS],
203 }
204 }
205
206 pub fn register_isa_isr(&mut self, irq: IsaInterrupt, isr: *const ()) {
209 let vector = irq as usize + Self::ISA_BASE;
210 self.register_isr(vector, isr);
211 }
212
213 pub fn register_isr(&mut self, vector: usize, isr: *const ()) {
214 let descr = self.descriptors[vector].set_handler(isr);
215 if vector == Self::DOUBLE_FAULT {
216 descr.set_ist_offset(Self::DOUBLE_FAULT_IST_OFFSET as u8);
217 }
218 tracing::debug!(vector, ?isr, ?descr, "set ISR");
219 }
220
221 pub fn load(&'static self) {
222 unsafe {
223 self.load_raw()
226 }
227 }
228
229 pub unsafe fn load_raw(&self) {
233 let ptr = cpu::DtablePtr::new_unchecked(self);
234 tracing::debug!(?ptr, "loading IDT");
235 cpu::intrinsics::lidt(ptr);
236 tracing::debug!("IDT loaded!");
237 }
238}
239
240impl Default for Idt {
241 fn default() -> Self {
242 Self::new()
243 }
244}
245
246impl fmt::Debug for Idt {
247 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
248 let Self { descriptors } = self;
249 let descriptors = descriptors[..]
250 .iter()
251 .filter(|&descr| descr != &Descriptor::null())
252 .enumerate()
253 .map(|(i, descr)| (fmt::hex(i), descr));
254 f.debug_map().entries(descriptors).finish()
255 }
256}
257
258impl fmt::Debug for Descriptor {
261 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
262 let Self {
263 offset_low,
264 segment,
265 ist_offset,
266 attrs,
267 offset_mid,
268 offset_hi,
269 _zero: _,
270 } = self;
271 f.debug_struct("Descriptor")
272 .field("offset_low", &format_args!("{offset_low:#x}"))
273 .field("segment", segment)
274 .field("ist_offset", &format_args!("{ist_offset:#x}"))
275 .field("attrs", attrs)
276 .field("offset_mid", &format_args!("{offset_mid:#x}"))
277 .field("offset_high", &format_args!("{offset_hi:#x}"))
278 .finish()
279 }
280}
281
282impl Attrs {
285 pub const fn null() -> Self {
286 Self(0)
287 }
288
289 pub fn gate_kind(&self) -> GateKind {
290 self.get(Self::GATE_KIND)
291 }
292
293 pub fn is_32_bit(&self) -> bool {
294 self.get(Self::IS_32_BIT)
295 }
296
297 pub fn is_present(&self) -> bool {
298 self.get(Self::PRESENT)
299 }
300
301 pub fn ring(&self) -> cpu::Ring {
302 self.get(Self::RING)
303 }
304
305 pub fn set_gate_kind(&mut self, kind: GateKind) -> &mut Self {
306 self.set(Self::GATE_KIND, kind)
307 }
308
309 pub fn set_32_bit(&mut self, is_32_bit: bool) -> &mut Self {
310 self.set(Self::IS_32_BIT, is_32_bit)
311 }
312
313 pub fn set_present(&mut self, present: bool) -> &mut Self {
314 self.set(Self::PRESENT, present)
315 }
316
317 pub fn set_ring(&mut self, ring: cpu::Ring) -> &mut Self {
318 self.set(Self::RING, ring)
319 }
320}
321
322#[cfg(test)]
323mod tests {
324 use super::*;
325
326 #[test]
327 fn idt_entry_is_correct_size() {
328 use core::mem::size_of;
329 assert_eq!(size_of::<Descriptor>(), 16);
330 }
331
332 #[test]
333 fn attrs_pack_specs() {
334 Attrs::assert_valid()
335 }
336
337 #[test]
338 fn idt_attrs_are_correct() {
339 let mut present_32bit_interrupt = Attrs::null();
340 present_32bit_interrupt
341 .set_present(true)
342 .set_32_bit(true)
343 .set_gate_kind(GateKind::Interrupt);
344 println!("{present_32bit_interrupt}");
345 assert_eq!(
354 present_32bit_interrupt.0, 0b1000_1110,
355 "\n attrs: {present_32bit_interrupt:#?}",
356 );
357 }
358
359 #[test]
360 fn idt_entry_is_correct() {
361 let mut idt_entry = Descriptor::null();
362 idt_entry.set_handler(0x1234_8765_abcd_fdec as *const ());
363
364 let idt_bytes = unsafe { core::mem::transmute::<&Descriptor, &[u8; 16]>(&idt_entry) };
365
366 let expected_idt: [u8; 16] = [
367 0xec, 0xfd, 0x33, 0x00, 0x00, 0x8e, 0xcd, 0xab, 0x65, 0x87, 0x34, 0x12, 0x00, 0x00, 0x00, 0x00,
374 ];
375
376 assert_eq!(idt_bytes, &expected_idt, "\n entry: {idt_entry:#?}",);
377 }
378}