frostbyte

Hobbystyczny kernel systemu operacyjnego na x86_64, w C i asemblerze. Bootuje przez Multiboot2, przechodzi w tryb 64-bit z własnymi tablicami stron, ma preempcyjny scheduler i uruchamia programy w ring 3 - realnie startuje w QEMU.

frostbyte
TL;DR

Jądro systemu operacyjnego napisane od zera - od bootloadera aż do uruchamiania własnych programów w trybie użytkownika. Startuje naprawdę, w QEMU.

Wprowadzenie

frostbyte to hobbystyczny kernel na x86_64, napisany w C i asemblerze. Celem nie było napisanie "systemu operacyjnego" w potocznym sensie, tylko przejście całej drogi, która zwykle jest ukryta: od momentu, w którym firmware oddaje sterowanie, aż do wykonania własnego programu w trybie użytkownika, odizolowanym od jądra.

To jeden z najbardziej bezlitosnych rodzajów projektu, jakie można sobie postawić. Nie ma tu bibliotek, które cokolwiek za ciebie załatwią, ani warstwy, która złapie błąd. Jest goły procesor, dokumentacja architektury i ty. Właśnie dlatego jest tak dobrą szkołą.

W zwykłym programie błąd jest lokalny: leci wyjątek, dostajesz stack trace, poprawiasz linijkę. W jądrze nie ma żadnej z tych wygód. Jeden zły bit w tablicy stron i maszyna po prostu się resetuje - bez komunikatu, bez logu, bez niczego. Debugowanie zamienia się w czytanie rejestrów i zgadywanie, który z ostatnich trzech ruchów był tym zabójczym.

Ta bezlitosność wymusza inny sposób pracy. Każdy krok trzeba domykać osobno i sprawdzać w izolacji, zanim dołoży się kolejny, bo inaczej nie da się odróżnić, która z dziesięciu zmian wywaliła całą maszynę. Dyscyplina nie jest tu cnotą, tylko warunkiem, żeby w ogóle ruszyć do przodu.

Od firmware do ring 3

Cała droga to sekwencja przejść między coraz wyższymi poziomami kontroli. Firmware ładuje jądro przez Multiboot2 i podaje mapę pamięci. Potem trzeba włączyć tryb 64-bit, co wymaga wcześniej wstępnego stronicowania. Następnie jądro przejmuje pamięć wirtualną na własnych tablicach stron, uruchamia scheduler przełączający zadania przerwaniem zegara, i dopiero na końcu skacze do ring 3.

1
Boot przez Multiboot2

bootloader ładuje jądro i przekazuje mapę pamięci.

2
Wejście w tryb 64-bit

włączenie long mode wymaga wcześniej wstępnego stronicowania.

3
Własne tablice stron

jądro przejmuje zarządzanie pamięcią wirtualną.

4
Preempcyjny scheduler

przerwanie zegara przełącza zadania, bez ich zgody.

5
Ring 3

skok do trybu użytkownika i uruchomienie pierwszego własnego programu.

Droga od zasilania do własnego programu

EtapCo się dziejeTryb
Multiboot2firmware oddaje sterowanie, jest mapa pamięciring 0
Long modewejście w tryb 64-bitring 0
Tablice stronjądro przejmuje pamięć wirtualnąring 0
Schedulerzegar przełącza zadania bez ich zgodyring 0
Ring 3pierwszy własny program, odcięty od jądraring 3

Debugowanie, gdy maszyna po prostu znika

Skoro błąd nie zostawia śladu, potrzebny był sposób, żeby jądro mogło cokolwiek powiedzieć, zanim ma sterownik ekranu. Rozwiązanie to QEMU z wyjściem na port szeregowy: jądro pisze logi tekstem na serial, a ten leci wprost do terminala. Dzięki temu widać ostatnią linijkę sprzed resetu, zamiast czarnego ekranu.

run.sh · bash
qemu-system-x86_64 \
  -cdrom frostbyte.iso \
  -m 512M \
  -serial stdio \
  -no-reboot -no-shutdown
!
Ostrzeżenie

W trybie jądra nie ma "prawie działa". Błąd w mapowaniu pamięci nie wywala funkcji - wywala całą maszynę. Dlatego każdy krok testowaliśmy osobno w emulatorze, zanim doszedł kolejny, a flagi no-reboot i no-shutdown pilnują, żeby maszyna zamarła na błędzie, a nie znikła w pętli restartów.

Efekt: system, który naprawdę startuje

Na wyjściu jest kernel, który realnie bootuje w QEMU i dochodzi do wykonania własnego programu w ring 3 - nie zatrzymuje się na wypisaniu "hello", tylko przechodzi całą drogę do trybu użytkownika. To projekt zbudowany po to, żeby zrozumieć komputer aż do samego dna, i doprowadzony do punktu, w którym to zrozumienie jest dowiedzione działaniem, a nie deklaracją.

Więcej projektów

Inne realizacje z tej samej kategorii - zobacz, jak podchodzimy do podobnych wyzwań.

Masz podobny projekt?

Napisz do nas - wycena jest bezpłatna i wraca w godzinę.