# Прерывания --- ## IDT (Interrupt Descriptor Table) **Файл**: `src/cpu/idt.rs` ### IdtEntry — `#[repr(C, packed)]` Структура записи IDT (x86-64): ```rust struct IdtEntry { offset_low: u16, // адрес обработчика [15:0] selector: u16, // селектор кода (0x28 — kernel CS) ist: u8, // Interrupt Stack Table index type_attr: u8, // тип шлюза, DPL, Present offset_mid: u16, // адрес обработчика [31:16] offset_high: u32, // адрес обработчика [63:32] ignore: u32, // резерв (0) } ``` - `new()` — все поля нули - `set_handler(handler: u64, selector: u16, flags: u8)` — устанавливает адрес и флаги. Принудительно ставит Present (0x80) в flags. ### IdtPtr — `#[repr(C, packed)]` ```rust struct IdtPtr { limit: u16, // размер IDT - 1 base: u64, // адрес IDT } ``` Загружается инструкцией `lidt`. ### InterruptDescriptorTable ```rust struct InterruptDescriptorTable { entries: [IdtEntry; 256], // 256 векторов } ``` - `set_handler(vector, handler: u64)` — устанавливает обработчик на вектор. Селектор: `0x28` (kernel code), flags: `0x8E` (32-bit interrupt gate, ring 0, present). - `load()` — `unsafe fn`: вызывает `lidt` с `&self`. --- ## Обработчики прерываний **Файл**: `src/cpu/interrupts.rs` ### Глобальная IDT ```rust pub static mut IDT: InterruptDescriptorTable; ``` ### Константы `TLB_SHOOTDOWN_VECTOR: u8 = 0xFD` ### Ассемблерные заглушки (global_asm!) #### `page_fault_stub` ```asm save all registers (push rax, rcx, rdx, rbx, rbp, rsi, rdi, r8-r15) mov rdi, [rsp + 15*8] ; error code из стека → 1-й аргумент call rust_page_fault_handler restore all registers add rsp, 8 ; убрать error code iretq ``` #### `tlb_shootdown_stub` ```asm save all registers call rust_tlb_shootdown_handler restore all registers iretq ``` ### `init_idt()` - Устанавливает вектор 14 → `page_fault_stub` - Устанавливает вектор `TLB_SHOOTDOWN_VECTOR` → `tlb_shootdown_stub` - `IDT.load()` ### `process_deferred_mmu_events()` Лочит `KERNEL_SPACE`, вызывает `process_pending_revocations()` — дренаж очереди отзыва. ### `rust_page_fault_handler(error_code: u64)` `#[unsafe(no_mangle)] pub extern "C" fn` 1. Читает CR2 (адрес fault) 2. Из error_code: бит 1 = write, бит 0 = present 3. **Сначала** `process_deferred_mmu_events()` — обработка ревокаций до захвата VMM (deadlock prevention) 4. Лочит `KERNEL_SPACE`, вызывает `handle_fault(virt_addr, write)` 5. При неудаче: паника с деталями (address, read/write, present, error_code) 6. При успехе: возврат — инструкция будет перезапущена ### `rust_tlb_shootdown_handler()` 1. `handle_tlb_shootdown_ipi()` — локальный сброс TLB 2. `send_eoi()` — подтверждение LAPIC --- ## Local APIC **Файл**: `src/cpu/lapic.rs` Драйвер Local APIC (Advanced Programmable Interrupt Controller). ### Константы ```rust LAPIC_DEFAULT_BASE = 0xFEE0_0000 // стандартный MMIO адрес LAPIC LAPIC_EOI = 0x0B0 // End-Of-Interrupt регистр LAPIC_ICR_LOW = 0x300 // Interrupt Command Register (low) ``` ### `LAPIC_VIRT_BASE: AtomicU64` Кэшированный виртуальный адрес LAPIC MMIO (HHDM + default base). ### Функции | Функция | Описание | |---|---| | `init(hhdm_offset)` | Вычисляет и сохраняет `LAPIC_VIRT_BASE = 0xFEE0_0000 + hhdm_offset` | | `current_core_id() -> u32` | CPUID leaf 1, EBX[31:24] — Initial APIC ID | | `write_lapic_reg(offset, value)` | Volatile write u32 в LAPIC MMIO | | `send_eoi()` | `write_lapic_reg(LAPIC_EOI, 0)` — подтверждение прерывания | | `broadcast_ipi_exclude_self(vector)` | IPI всем остальным ядрам через ICR (destination shorthand = 10b = all except self) |