5.4 KiB
5.4 KiB
Процесс загрузки: концептуальная модель
Цепочка загрузки
Питание включено
│
▼
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 — современный bootloader с открытым исходным кодом.
Статические Limine requests сообщают bootloader'у, что нужно ядру:
| Request | Назначение |
|---|---|
FramebufferRequest |
Получить framebuffer для графического вывода |
MemoryMapRequest |
Получить карту физической памяти |
HhdmRequest |
Получить HHDM offset |
ExecutableAddressRequest |
Получить физический/виртуальный адрес ядра |
BaseRevision |
Проверить совместимость с Limine |
Размещение в секциях
Requests размещаются между специальными маркерами в секции .data:
#[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();
Линкер скрипт сохраняет эти секции:
.data : {
*(.data .data.*)
KEEP(*(.requests_start_marker))
KEEP(*(.requests))
KEEP(*(.requests_end_marker))
} :data
Точка входа — kmain
Линкер скрипт: ENTRY(kmain).
#[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
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
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
[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)