# Процесс загрузки: концептуальная модель ## Цепочка загрузки ``` Питание включено │ ▼ CPU reset vector (0xFFFFFFF0) │ ▼ UEFI firmware / BIOS │ ▼ Limine bootloader ─────────────────────────────┐ │ │ │ 1. Переводит CPU в 64-bit long mode │ │ 2. Настраивает page tables (identity map) │ │ 3. Загружает ядро по физическому адресу │ │ 4. Настраивает HHDM │ │ 5. Заполняет Limine requests │ │ 6. Передаёт управление на kmain │ │ │ ▼ │ kmain() (точка входа) │ │ │ ... инициализация ... │ │ │ ▼ │ HCF (останов CPU) ─────────────────────────────┘ ``` ## Limine Boot Protocol Elyz использует [Limine](https://github.com/limine-bootloader/limine) — современный bootloader с открытым исходным кодом. Статические `Limine requests` сообщают bootloader'у, что нужно ядру: | Request | Назначение | |---------|------------| | `FramebufferRequest` | Получить framebuffer для графического вывода | | `MemoryMapRequest` | Получить карту физической памяти | | `HhdmRequest` | Получить HHDM offset | | `ExecutableAddressRequest` | Получить физический/виртуальный адрес ядра | | `BaseRevision` | Проверить совместимость с Limine | ### Размещение в секциях Requests размещаются между специальными маркерами в секции `.data`: ```rust #[used] #[unsafe(link_section = ".requests_start_marker")] static _START_MARKER: RequestsStartMarker = RequestsStartMarker::new(); // ... все requests ... #[used] #[unsafe(link_section = ".requests_end_marker")] static _END_MARKER: RequestsEndMarker = RequestsEndMarker::new(); ``` Линкер скрипт сохраняет эти секции: ```ld .data : { *(.data .data.*) KEEP(*(.requests_start_marker)) KEEP(*(.requests)) KEEP(*(.requests_end_marker)) } :data ``` ## Точка входа — kmain Линкер скрипт: `ENTRY(kmain)`. ```rust #[unsafe(no_mangle)] unsafe extern "C" fn kmain() -> ! { ... } ``` Атрибуты: - `no_mangle` — сохраняет имя `kmain` (линкер ищет именно его). - `extern "C"` — C ABI (Linux x86-64 calling convention: RDI, RSI, ...). - `unsafe` — на этапе инициализации все операции потенциально опасны. - `-> !` — kmain никогда не возвращается (HALT). ## Build system ### GNUmakefile ```makefile KARCH ?= x86_64 RUST_TARGET ?= $(KARCH)-unknown-none RUST_PROFILE ?= dev all: RUSTFLAGS="-C relocation-model=static" \ cargo build --target $(RUST_TARGET) --profile $(RUST_PROFILE) cp target/$(RUST_TARGET)/$(RUST_PROFILE_SUBDIR)/kernel . ``` - `relocation-model=static`: ядро не использует динамическую перелокацию. - `--target x86_64-unknown-none`: bare-metal target (без ОС). - Результат копируется в `kernel/` (корень). ### build.rs — linker script ```rust fn main() { let arch = std::env::var("CARGO_CFG_TARGET_ARCH").unwrap(); println!("cargo:rustc-link-arg=-Tlinker-{arch}.ld"); println!("cargo:rerun-if-changed=linker-{arch}.ld"); } ``` Подставляет правильный linker script для архитектуры. ### rust-toolchain.toml ```toml [toolchain] channel = "nightly" targets = ["x86_64-unknown-none"] ``` Требуется nightly Rust из-за: - `#![no_std]`, `#![no_main]`. - `core::arch::global_asm!`, `core::arch::asm!`. - `const { ... }` в инициализации констант. ## Память: расположение после загрузки ``` Физическая память: ┌───────────────────────┐ 0x0 │ Reserved │ ├───────────────────────┤ │ Usable (free) │ ← входит в mmap entries ├───────────────────────┤ │ Kernel image │ ← загружен Limine ├───────────────────────┤ │ PMM metadata │ ← bitmap + ref_counts + L1 ├───────────────────────┤ │ ... (usable) │ └───────────────────────┘ max_addr Виртуальная память (Higher Half): 0xFFFF_8000_0000_0000 ─── HHDM (вся физическая память 1:1) 0xFFFF_9000_0000_0000 ─── Kernel heap (8 MiB) ```