# Interrupt Descriptor Table: `idt.rs` ## Аппаратная модель IDT (Interrupt Descriptor Table) — это таблица из 256 entry (по 16 байт каждая), которая сообщает CPU, куда передавать управление при прерываниях и исключениях. ``` IDT: ┌──────┬──────────────────────────────────────────────────────┐ │ 0 │ #DE — Divide Error │ │ 1 │ #DB — Debug │ │ 2 │ #NMI — Non-Maskable Interrupt │ │ 3 │ #BP — Breakpoint │ │ 4 │ #OF — Overflow │ │ 5 │ #BR — Bound Range Exceeded │ │ 6 │ #UD — Undefined Opcode │ │ 7 │ #NM — Device Not Available │ │ 8 │ #DF — Double Fault │ │ 9 │ #MF — Coprocessor Segment Overrun │ │ 10 │ #TS — Invalid TSS │ │ 11 │ #NP — Segment Not Present │ │ 12 │ #SS — Stack-Segment Fault │ │ 13 │ #GP — General Protection Fault │ │ 14 │ #PF — Page Fault │ │ 15-31│ Reserved / CPU exceptions │ │ 32-255│ User-defined (hardware interrupts) │ └──────┴──────────────────────────────────────────────────────┘ ``` Загрузка IDT: инструкция `lidt [idtr_ptr]`, где `idtr_ptr` — это 6-байтовая структура `IdtPtr`: ``` IdtPtr: ┌──────────┬──────────┐ │ limit:16 │ base:48 │ └──────────┴──────────┘ ``` ## IdtEntry — 16-байтовая запись ```rust #[repr(C, packed)] pub struct IdtEntry { offset_low: u16, // Бит 0:15 адреса обработчика selector: u16, // Селектор сегмента кода (0x28 для ядра) ist: u8, // Interrupt Stack Table type_attr: u8, // Тип вентиля + флаги offset_mid: u16, // Бит 16:31 адреса обработчика offset_high: u32, // Бит 32:63 адреса обработчика ignore: u32, // Зарезервировано } ``` **type_attr:** - Бит 7: Present (должен быть 1) - Бит 6-5: DPL (Descriptor Privilege Level) - Бит 4: Reserved (0) - Бит 3-0: Gate Type (0xE = Interrupt Gate, 0xF = Trap Gate) `set_handler(handler, selector, flags)`: ```rust pub fn set_handler(&mut self, handler: u64, selector: u16, flags: u8) { self.offset_low = handler as u16; self.selector = selector; self.ist = 0; self.type_attr = flags | 0x80; // Present bit forced on self.offset_mid = (handler >> 16) as u16; self.offset_high = (handler >> 32) as u32; } ``` ## InterruptDescriptorTable — 256 entry ```rust pub struct InterruptDescriptorTable { entries: [IdtEntry; 256], // 256 × 16 = 4096 байт } ``` **Методы:** - `set_handler(vector, handler)` — устанавливает обработчик с селектором 0x28 (GDT code segment) и type_attr 0x8E (Interrupt Gate, Ring 0, Present). - `load()` — `lidt` инструкция. ```rust pub unsafe fn load(&'static self) { let ptr = IdtPtr { limit: (size_of::() - 1) as u16, // 4095 base: self as *const _ as u64, }; asm!("lidt [{}]", in(reg) &ptr); } ``` ## Глобальная IDT ```rust pub static mut IDT: InterruptDescriptorTable = InterruptDescriptorTable::new(); ``` `static mut` — потому что IDT модифицируется в ранней инициализации, до включения прерываний. Потенциально может быть заменён на `static` с `UnsafeCell`. ## Детали конфигурации - **Selector**: `0x28` — это GDT entry для ring 0 code segment (дескриптор 5, 5 × 8 = 0x28). Селектор сегмента кода в long mode. - **Type 0x8E**: `1000_1110` = бит 7 (Present) + бит 3:0 = 1110 (Interrupt Gate, 32-bit). В 64-bit режиме все вентили — 64-bit, флаг 0xE остаётся корректным. - **IST**: 0 — не используем Interrupt Stack Table (один стек для всех обработчиков).