# Адресация и трансляция: `address.rs` ## Концептуальная модель В x86-64 MMU транслирует виртуальные адреса (48 бит, канонические) в физические (до 52 бит) через 4-уровневую иерархию page tables. Ядро использует **Higher-Half Direct Map (HHDM)** — область виртуальной памяти, где вся физическая память отображена 1:1 с фиксированным смещением. ``` Физический адрес 0x0 │ │ + HHDM_OFFSET (например, 0xFFFF8000_0000_0000) ▼ Виртуальный адрес 0xFFFF8000_0000_0000 ``` ## Физический адрес: `PhysAddr(pub u64)` Представляет собой физический адрес. Это **newtype** над `u64` — строгая типизация предотвращает случайное смешивание физических и виртуальных адресов. **Методы:** - `to_virt()` — преобразует в виртуальный адрес через HHDM: `VirtAddr(self.0 + HHDM_OFFSET)` - `is_aligned()` — проверка выравнивания на 4KiB - `align_down()` / `align_up()` — выравнивание вниз/вверх до границы 4KiB ## Виртуальный адрес: `VirtAddr(pub u64)` **Методы:** - `to_phys()` — обратное преобразование: вычитает HHDM, возвращает `None` если адрес ниже HHDM (не канонический для физической памяти) - `as_ptr()` — получить `*const T` (для чтения) - `as_mut_ptr()` — получить `*mut T` (для записи) ## HHDM Offset: глобальное состояние ```rust static HHDM_OFFSET: AtomicU64 = AtomicU64::new(0); ``` - `init_hhdm(offset: u64)` — вызывается в `kmain()` сразу после получения ответа от bootloader'а. Сохраняет offset через `Ordering::Release`. - `get_hhdm() -> u64` — читает offset через `Ordering::Relaxed` (высокая производительность, на этой архитектуре атомарность гарантирована). ### Почему Atomic? HHDM инициализируется однократно до включения прерываний и создания дополнительных потоков. Atomic гарантирует, что даже если в будущем инструкции будут переупорядочены, значение будет видно всем ядрам. ## Код и абстракция ```rust // address.rs (полный код) static HHDM_OFFSET: AtomicU64 = AtomicU64::new(0); pub fn init_hhdm(offset: u64) { HHDM_OFFSET.store(offset, Ordering::Release); // ^ Release: все предыдущие записи становятся видимы для // всех acquire-операций на HHDM_OFFSET } pub fn get_hhdm() -> u64 { HHDM_OFFSET.load(Ordering::Relaxed) // ^ Relaxed: в однопоточном контексте и при инициализации // до включения прерываний это безопасно и максимально быстро } #[repr(transparent)] pub struct PhysAddr(pub u64); // ^ repr(transparent): гарантирует, что PhysAddr имеет то же // представление в памяти, что и u64 — важно для FFI и передачи // в ассемблерные инструкции (mov cr3, rax) impl PhysAddr { pub fn to_virt(self) -> VirtAddr { VirtAddr(self.0 + get_hhdm()) // ^ Концептуально: физический адрес + HHDM смещение даёт // виртуальный адрес, по которому этот физический фрейм // отображён в higher half } } impl VirtAddr { pub fn as_mut_ptr(self) -> *mut T { self.0 as *mut T // ^ Прямая интерпретация числа как указателя. // Безопасность на стороне вызывающего кода. } } ``` ## Где используется - `PhysAddr::to_virt()` — в `paging.rs` для доступа к Page Table entries, в `pmm.rs` для обнуления фреймов, в `buddy.rs` для intrusive list. - `VirtAddr::as_mut_ptr()` — в `paging.rs` для создания ссылок на PTE. - `init_hhdm()` — в `kmain()` при старте. - `get_hhdm()` — в `lapic.rs` для вычисления LAPIC_base.