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

143 lines
4.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Прерывания
---
## 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) |