4.5 KiB
Управление памятью: концептуальная модель
Архитектурная философия
Управление памятью в Elyz построено как трёхуровневая иерархия, где каждый уровень решает свою задачу и взаимодействует с соседними через строго определённые интерфейсы.
Уровень 1: BitmapPMM (глобальный, физический)
│
│ предоставляет сырые фреймы
▼
Уровень 2: PMActor + BuddyAllocator (распределённый, физический)
│
│ управляет диапазонами, выдаёт под-диапазоны
▼
Уровень 3: AddressSpace (VMM) (виртуальный)
│
│ отображает физические фреймы в виртуальные адреса
▼
CPU (MMU, page tables)
Зачем три уровня?
-
BitmapPMM — глобальный аллокатор физических фреймов. Простой, надёжный, но неэффективный для частых alloc/free маленьких блоков. Используется для начальной загрузки и для Page Table страниц.
-
BuddyAllocator + PMActor — распределённая модель. Каждый актор управляет своим диапазоном физической памяти через buddy-алгоритм. Это даёт: (1) изоляцию — актор A не может истощить память актора B; (2) масштабирование — акторы могут работать параллельно; (3) предсказуемость — каждый актор знает свой лимит.
-
AddressSpace (VMM) — виртуальные адресные пространства. PML4, VMA-деревья, copy-on-write, lazy mapping. Использует PMM для аллокации Page Table страниц (через
pmm_allocвpaging.rs).
Разделение ответственности по файлам
| Файл | Компонент | Роль в абстракции |
|---|---|---|
address.rs |
PhysAddr / VirtAddr / HHDM | Базовые типы для адресов |
pmm.rs |
BitmapPMM | Глобальный менеджер физических фреймов |
buddy.rs |
BuddyAllocator | O(1) buddy allocator (intrusive list) |
pm_manages.rs |
PMActor + PMActorQueue | Актёр физической памяти + MPSC очередь |
pm_router.rs |
PMRouter | Lock-free маршрутизация запросов/ответов |
paging.rs |
PageTable | Аппаратные 4-уровневые page tables |
vmm.rs |
AddressSpace + VMA | Виртуальные адресные пространства |
allocator.rs |
SlabAllocator | Кучевой аллокатор (global_allocator) |
mod.rs |
Экспорт | Фасад подсистемы |
Поток данных: типичная аллокация
Процесс A хочет 16 страниц:
1. Код пользователя отправляет PMRequest::Allocate в PMActor через
PMRouter::alloc_channel() + actor.submit_request()
2. Когда актор получает CPU, process_messages() вызывает
buddy.alloc_pages(16)
3. BuddyAllocator находит блок порядка 4 (2^4 = 16) или больше,
разбивает его при необходимости
4. PMActor создаёт Capability с CapObject::Memory { phys, size_pages }
5. Ответ (PMResponse::Allocated) отправляется через PMRouter
6. Получатель может отобразить фреймы в своё AddressSpace через
map_region() или map_shared()
Поток данных: page fault
CPU ловит #PF (page fault):
1. interrupt.rs: rust_page_fault_handler() читает CR2
2. Получает блокировку KERNEL_SPACE
3. process_pending_revocations() — обрабатывает накопленные отзывы
4. handle_fault() проверяет: это COW? это lazy region?
5. Если COW — копируем страницу (copy-on-write)
6. Если lazy — alloc_frame() из PMM + map_page()
7. Если нераспознанный fault — KERNEL PANIC