feat: docs & ARCH 2.2, 2.3, 2.4

This commit is contained in:
Faynot
2026-07-07 16:40:41 +03:00
parent c092a81331
commit 1bfde637d0
50 changed files with 5113 additions and 1823 deletions

View File

@@ -0,0 +1,200 @@
# Обработчики прерываний и исключений: `interrupts.rs`
## Концептуальная модель
Файл объединяет **обработчики исключений** (таблицу IDT) и
**межпроцессорные прерывания** (TLB shootdown). Это связующий слой
между аппаратурой (CPU exceptions, APIC) и программными подсистемами
(VMM, Memory).
## Структура обработчика (stub + Rust handler)
Каждый обработчик состоит из двух частей:
1. **Сборочный stub** (global_asm): сохраняет контекст, вызывает
Rust-функцию, восстанавливает контекст, iretq.
2. **Rust handler**: собственно обработка.
```
Пример: Page Fault
[stack]
page_fault_stub: error_code ← CPU пушет
push rax ...регистры...
push rcx
...
mov rdi, [rsp + 15*8] ← error_code как аргумент
call rust_page_fault_handler ← вызов Rust
pop r15 восстановление
...
pop rax
add rsp, 8 ← убираем error_code
iretq ← возврат
```
## Exception stubs (макрос)
```rust
macro_rules! exception_stub {
($name:ident, $handler:ident) => {
concat!(
".global ", stringify!($name), "\n",
stringify!($name), ":\n",
"push rax\npush rcx\n...push r15\n", // сохранение
"mov rdi, [rsp + 15*8]\n", // error_code
"call ", stringify!($handler), "\n",
"pop r15\n...pop rax\n", // восстановление
"add rsp, 8\n", // очистка error_code
"iretq\n",
)
};
}
```
Используется для:
- `page_fault_stub``rust_page_fault_handler` (вектор 14)
- `gpf_stub``rust_gpf_handler` (вектор 13)
- `double_fault_stub``rust_double_fault_handler` (вектор 8)
## TLB shootdown stub
```rust
global_asm!(
"tlb_shootdown_stub:",
"push rax\npush rcx\n...", // сохранение
"call rust_tlb_shootdown_handler",
"pop r15\n...pop rax\n", // восстановление
"iretq"
);
```
## Early handlers — для начальной загрузки
До того как VMM и slab allocator готовы, ядро не может обрабатывать
сложные исключения. Для векторов 0-31 генерируются ранние заглушки.
### Генерация (макрос `.altmacro`)
```asm
.macro early_stub vec
.globl early_handler_\vec
.balign 16
early_handler_\vec:
push 0 /* dummy error code (если нет аппаратного) */
push \vec /* номер вектора */
jmp early_common
.endm
```
`early_stub 0`..`early_stub 31` генерирует 32 обработчика.
### `early_common`
```asm
early_common:
push rax\npush rcx\n... // сохранение всех GP-регистров
mov rdi, [rsp + 15*8] // vector number
mov rsi, [rsp + 16*8] // error code (или dummy 0)
call rust_early_exception_handler
// never returns
```
### `rust_early_exception_handler(vector, error_code)`
```rust
pub extern "C" fn rust_early_exception_handler(vector: u64, _error_code: u64) -> ! {
serial::write_global(format_args!(
"\n!!! EARLY EXCEPTION !!! vector={} error_code={:#x}\nCPU halted.\n",
vector, _error_code
));
loop { asm!("cli; hlt"); }
}
```
Всегда HALT — раннее исключение фатально.
## init_early_exceptions() — настройка IDT для ранней загрузки
```rust
pub fn init_early_exceptions() {
let idt = addr_of_mut!(IDT);
// Устанавливаем early_handler_N для векторов 0-31
for (v, &handler) in early_handlers.iter().enumerate() {
(*idt).set_handler(v as u8, handler);
}
// Переопределяем критические:
(*idt).set_handler(8, double_fault_stub); // #DF
(*idt).set_handler(13, gpf_stub); // #GPF
(*idt).set_handler(14, page_fault_stub); // #PF
(*idt).set_handler(TLB_SHOOTDOWN_VECTOR, tlb_shootdown_stub);
let ptr: &'static IDT = &*addr_of!(IDT);
ptr.load(); // lidt
}
```
## init_idt() — перезагрузка после полной инициализации
```rust
pub fn init_idt() {
// Переустанавливаем только Page Fault и TLB Shootdown
// (их обработчики уже переключились на VMM-aware версии)
let idt = addr_of_mut!(IDT);
(*idt).set_handler(14, page_fault_stub);
(*idt).set_handler(TLB_SHOOTDOWN_VECTOR, tlb_shootdown_stub);
let ptr: &'static IDT = &*addr_of!(IDT);
ptr.load();
}
```
## Обработчики исключений
### `rust_page_fault_handler(error_code)`
```rust
pub extern "C" fn rust_page_fault_handler(error_code: u64) {
let fault_addr: u64;
asm!("mov {}, cr2", out(reg) fault_addr); // читаем CR2
let write = (error_code & 0x2) != 0; // fault на запись?
let present = (error_code & 0x1) != 0; // PTE был PRESENT?
let mut vmm_guard = KERNEL_SPACE.lock();
if let Some(space) = vmm_guard.as_mut() {
space.process_pending_revocations(); // обрабатываем отзывы
match space.handle_fault(fault_addr, write) {
Ok(_) => {} // обработано: iretq retry
Err(e) => panic!(...), // необработанный fault
}
} else {
panic!("Page fault before KERNEL_SPACE!");
}
}
```
### `rust_gpf_handler(error_code)` и `rust_double_fault_handler(error_code)`
Оба — HALT с сообщением.
## TLB Shootdown обработчик
```rust
pub extern "C" fn rust_tlb_shootdown_handler() {
crate::mem::vmm::handle_tlb_shootdown_ipi();
crate::cpu::lapic::send_eoi(); // подтверждаем LAPIC прерывание
}
```
### Тайминги и безопасность
- TLB shootdown — IPI, требует минимальной задержки.
- Все операции в `handle_tlb_shootdown_ipi` — простые и быстрые.
- LAPIC EOI отправляется сразу после локального TLB flush.
## Константы
```rust
pub const TLB_SHOOTDOWN_VECTOR: u8 = 0xFD;
```
Вектор 0xFD (253) — в диапазоне пользовательских прерываний (32-255),
намеренно далеко от системных векторов 0-31.