Files
Elyz/kernel/docs/interrupts.md
2026-07-06 00:25:49 +03:00

4.3 KiB
Raw Blame History

Прерывания


IDT (Interrupt Descriptor Table)

Файл: src/cpu/idt.rs

IdtEntry — #[repr(C, packed)]

Структура записи IDT (x86-64):

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)]

struct IdtPtr {
    limit: u16,  // размер IDT - 1
    base: u64,   // адрес IDT
}

Загружается инструкцией lidt.

InterruptDescriptorTable

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

pub static mut IDT: InterruptDescriptorTable;

Константы

TLB_SHOOTDOWN_VECTOR: u8 = 0xFD

Ассемблерные заглушки (global_asm!)

page_fault_stub

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

save all registers
call rust_tlb_shootdown_handler
restore all registers
iretq

init_idt()

  • Устанавливает вектор 14 → page_fault_stub
  • Устанавливает вектор TLB_SHOOTDOWN_VECTORtlb_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).

Константы

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)