Od włączenia zasilania do działającej przestrzeni użytkownika — oprogramowanie układowe (firmware), program ładujący (bootloader), inicjalizacja jądra i init. Koncentracja na x86-64 i UEFI, z uwagami dotyczącymi BIOS/MBR tam, gdzie to istotne.
Gdy procesor wychodzi ze stanu resetu, zaczyna wykonywanie od stałego adresu fizycznego. W architekturze x86-64 jest to 0xFFFFFFF0 — 16-bajtowy "wektor resetu", który natychmiast przeskakuje do pamięci ROM oprogramowania układowego.
Nowoczesne systemy używają UEFI. Wykonanie przechodzi przez trzy fazy przed wywołaniem programu ładującego system operacyjny:
| SEC (Bezpieczeństwo) | Działa całkowicie w pamięci podręcznej jako RAM (CAR). Weryfikuje obraz PEI, ustanawia minimalne zaufane środowisko. |
| PEI (Inicjalizacja Pre-EFI) | Inicjuje pamięć DRAM, podstawy chipsetu i wszelki kod specyficzny dla układu. Tworzy listę bloków przekazywania (Hand-Off Block - HOB), która jest przekazywana dalej. |
| DXE (Wykonanie Sterownika) | Pełne środowisko UEFI. Ładuje sterowniki z woluminu firmware'u, uruchamia PCIe, pamięć masową i USB. Tworzy Tablicę Systemową EFI (EFI System Table) widoczną dla późniejszych etapów. |
| BDS (Wybór Urządzenia Rozruchowego) | Ocenia kolejność rozruchu w NVRAM, lokalizuje aplikację EFI (\EFI\BOOT\BOOTX64.EFI lub ścieżkę specyficzną dla dystrybucji) i przekazuje jej kontrolę. |
db. Shim (shimx64.efi) to standardowy pierwszy etap dla dystrybucji — niesie własny podpis akceptowany przez klucze Microsoftu, a następnie weryfikuje bootloader za pomocą własnej bazy danych MOK.
BIOS ładuje pierwsze 512 bajtów dysku rozruchowego (MBR) pod adres fizyczny 0x7C00 i przeskakuje do niego. Kod MBR lokalizuje partycję rozruchową za pomocą tablicy partycji i ładuje program ładujący drugiego etapu. Wszystko to dzieje się w 16-bitowym trybie rzeczywistym bez abstrakcji sprzętowej.
Dominującym bootloaderem w systemach Linux x86-64 jest GRUB2. Plik binarny EFI grubx64.efi jest ładowany bezpośrednio przez BDS jako aplikacja EFI; działa w 64-bitowym trybie EFI z pełnym dostępem do Usług Rozruchowych UEFI.
/boot/grub/grub.cfg (lub /boot/grub2/grub.cfg). Analizuje bloki menuentry w celu wyświetlenia menu rozruchowego./boot, zanim uruchomi się jakikolwiek sterownik systemu operacyjnego.linux z konfiguracji i wszelkich edycji wprowadzonych w menu. Staje się to ciągiem parametrów jądra w /proc/cmdline.ExitBootServices(), aby zakończyć Usługi Rozruchowe UEFI, konstruuje blok informacyjny protokołu rozruchowego systemu Linux (Linux Boot Protocol) i przeskakuje do punktu wejścia jądra.GRUB umieszcza strukturę struct boot_params pod znanym adresem i przekazuje ją do jądra. Zawiera ona mapę pamięci (tablica E820), wskaźnik do wiersza poleceń, adres i rozmiar initrd, informacje o trybie wideo oraz dane specyficzne dla EFI.
0x000 screen_info
0x040 apm_bios_info
0x090 hdr ← setup_header (magiczna liczba 0xAA55, wersja protokołu itp.)
0x1E8 e820_entries
0x2D0 e820_table[128]
... efi_info ← Mapa pamięci EFI, wskaźnik do tablicy systemowej
CONFIG_EFI_STUB. systemd-boot (lub dowolny program ładujący EFI) ładuje vmlinuz bezpośrednio jako plik binarny EFI, przekazując parametry przez EFI LoadOptions. Nie jest potrzebna oddzielna ścieżka kodu dla bootloadera.
Plikiem na dysku jest vmlinuz — samorozpakowujące się archiwum. Nazwa pochodzi od virtual memory Linux; sufiks z wskazuje na kompresję (historycznie gzip, obecnie często zstd lub lz4 w zależności od konfiguracji dystrybucji).
| Nagłówek bzImage | Pierwsze ~512 bajtów. Zawiera setup_header z magiczną liczbą 0x53726448 ("HdrS"), wersję protokołu, wskazówki dotyczące adresu ładowania oraz przesunięcie/rozmiar ładunku (payload). |
| Kod konfiguracyjny trybu rzeczywistego | Historycznie działał w trybie 16-bitowym; w przypadku protokołu rozruchowego ≥ 2.02 i nowoczesnego bootloadera, jest on całkowicie omijany — bootloader używa bezpośrednio 32/64-bitowych punktów wejścia. |
| Skompresowany ładunek | Rzeczywisty plik binarny jądra, skompresowany. Poprzedzony niewielkim kodem źródłowym (stubem) dekompresora. |
Kontrola przechodzi do stuba dekompresora w arch/x86/boot/compressed/head_64.S. Tworzy on minimalną tablicę stron, przełącza w tryb long mode, jeśli jeszcze w nim nie jest, dekompresuje obraz jądra do pamięci (zwykle pod adres 0x1000000) i przeskakuje do nieskompresowanego wejścia jądra — startup_64 w arch/x86/kernel/head_64.S.
CONFIG_RANDOMIZE_BASE, dekompresor wywołuje oprogramowanie układowe, aby uzyskać losowe przesunięcie fizyczne przed umieszczeniem jądra. Końcowy adres ładowania jest zapisywany i używany do naprawienia wszelkich absolutnych odniesień przed skokiem do właściwego jądra.
Po dojściu do startup_64, jądro wykonuje własny kod bez systemu operacyjnego pod spodem. Stan sprzętu jest nadal w dużej mierze taki, jak pozostawiło go oprogramowanie układowe / bootloader.
startup_64 |
Konfiguruje wczesne tablice stron (mapowania tożsamości + mapowania jądra). Czyści sekcję BSS. Wywołuje x86_64_start_kernel(). |
x86_64_start_kernel |
Naprawia rejestr CR3, aby wskazywał na prawdziwy PGD jądra. Przechodzi do wywołania start_kernel() w init/main.c. |
start_kernel() |
Główny punkt wejścia w języku C. Wykonuje setki wywołań inicjujących w określonej kolejności. Nigdy nie powraca. |
memblock) na alokator bliźniaczy (alokator stron). Inicjuje kmalloc/slab.kernel_init (pid 1) oraz kthreadd (pid 2). CPU 0 staje się wątkiem bezczynnym.Gdy główny procesor rozruchowy (BSP - Bootstrap Processor) zakończy start_kernel(), wysyła sekwencje INIT-SIPI-SIPI przez LAPIC, aby obudzić procesory aplikacyjne (AP - Application Processors). Każdy AP wykonuje start_secondary(), inicjuje własny stan dla każdego CPU i dołącza do kolejki uruchamiania planisty. W nowoczesnych jądrach proces ten jest kontrolowany przez mechanizm hotplug dla CPU.
# logiczne CPU i mapowanie
$ lscpu --extended
# domeny planisty (topologia NUMA/cache widziana przez jądro)
$ cat /sys/kernel/debug/sched/domains/cpu0/domain0/name
Jądro nie może zamontować prawdziwego głównego systemu plików bez sterowników, które same w sobie mogą być modułami jądra przechowywanymi w tym systemie plików (kontroler dysku, LUKS, LVM, sieć). initramfs rozwiązuje ten problem jajka i kury.
Skompresowanym (gzip/lz4/zstd) archiwum CPIO przekazywanym do jądra przez bootloader za pomocą pól initrd_start / initrd_size w boot_params. Jądro rozpakowuje je do instancji tmpfs i montuje jako początkowy katalog główny (/).
initrd był obrazem urządzenia blokowego montowanym jako ramdisk (wymagał sterownika systemu plików i stałego rozmiaru). initramfs to archiwum CPIO rozpakowywane bezpośrednio do tmpfs — tańsze, bez stałego rozmiaru, bez dodatkowej warstwy systemu plików. Nowoczesne jądra używają initramfs; termin "initrd" jest potocznie używany dla obu tych rozwiązań.
Archiwum zawiera minimalny główny system plików wystarczający do zlokalizowania i zamontowania prawdziwego katalogu głównego (root):
systemd lub dracut/mkinitcpio.Po zamontowaniu prawdziwego urządzenia głównego (zazwyczaj w /sysroot), proces init initramfs wywołuje switch_root /sysroot /sbin/init — sekwencję wywołań systemowych, która przenosi montowanie, wykonuje chroot oraz uruchamia przez exec końcowy plik binarny init. Przestrzeń tmpfs środowiska initramfs zostaje zwolniona.
# lista zawartości
$ lsinitrd /boot/initramfs-$(uname -r).img # dracut/Fedora
$ lsinitcpio /boot/initramfs-linux.img # mkinitcpio/Arch
# ręczne rozpakowanie (dostosuj do typu kompresji)
$ mkdir /tmp/ir && cd /tmp/ir
$ file /boot/initramfs-$(uname -r).img # sprawdzenie kompresji
$ zstdcat /boot/initramfs-$(uname -r).img | cpio -idm
PID 1 w ostatecznym rootfs to system init. Jest on przodkiem wszystkich procesów przestrzeni użytkownika i nigdy nie może zostać zakończony. W zdecydowanej większości obecnych dystrybucji Linuksa jest to systemd.
default.target |
Zazwyczaj połączony dowiązaniem symbolicznym z graphical.target lub multi-user.target. Definiuje zbiór jednostek, które muszą być aktywne. |
| Graf jednostek | systemd buduje graf zależności ze wszystkich plików jednostek w /lib/systemd/system/ oraz /etc/systemd/system/. Krawędzie to Requires=, Wants=, Before=, After=. |
| Aktywacja równoległa | Jednostki o spełnionych zależnościach są aktywowane współbieżnie. Aktywacja przez gniazdo D-Bus oraz jednostki urządzeń (.device poprzez udev) pozwalają na opóźnione uruchamianie (lazy-start) usług. |
| Wczesne cele | sysinit.target → basic.target → network.target → multi-user.target / graphical.target. Każdy z nich stanowi punkt synchronizacji. |
sysinit.target. Zbiera logi z bufora kołowego jądra oraz ze wszystkich późniejszych usług./dev, stosuje reguły udev, emituje jednostki urządzeń./etc/modules-load.d/./usr/lib/tmpfiles.d/ (np. /run, /tmp)./etc/fstab. Zależy od systemd-fsck@.service w celu sprawdzania systemu plików.getty@.service. Wyświetla monit o logowanie na konsoli wirtualnej.# Ogólne zestawienie czasu rozruchu
$ systemd-analyze
# Czasy dla poszczególnych jednostek (od najwolniejszej)
$ systemd-analyze blame
# Ścieżka krytyczna przez graf zależności
$ systemd-analyze critical-chain
# Pełny graf zależności jednostek (renderowany przez dot)
$ systemd-analyze dot | dot -Tsvg > boot.svg
# Bufor kołowy jądra z tego rozruchu
$ journalctl -k -b 0
# Wszystkie komunikaty z fazy initramfs
$ journalctl -b 0 -o short-monotonic | head -200
/boot/vmlinuz-* | Skompresowany obraz jądra ładowany przez bootloader. |
/boot/initramfs-*.img | Archiwum CPIO initramfs (nazewnictwo dracut; initramfs-linux.img na Arch). |
/boot/grub/grub.cfg | Wygenerowana konfiguracja GRUB2. Nie edytuj bezpośrednio; wygeneruj ponownie za pomocą grub-mkconfig. |
/proc/cmdline | Wiersz poleceń jądra przekazywany przez bootloader. |
/proc/1/exe | Dowiązanie symboliczne do pliku binarnego init (potwierdza, czym jest PID 1). |
/sys/firmware/efi | Obecne tylko przy rozruchu UEFI. Zawiera zmienne EFI oraz informacje o usługach środowiska wykonawczego. |
/sys/firmware/acpi | Tablice ACPI udostępniane przez jądro. acpidump służy do ich ekstrakcji. |
/sys/kernel/boot_params | Surowa struktura boot_params widziana przez jądro (dostępna z CONFIG_BOOT_CONFIG). |
/etc/systemd/system/ | Lokalne pliki jednostek i nadpisania (wyższy priorytet niż /lib/systemd/system/). |
/etc/fstab | Tabela montowania systemu plików używana przez systemd-fstab-generator do tworzenia jednostek montowania. |
root= | Główne urządzenie (Root). Akceptuje /dev/sdXN, UUID=, PARTUUID=, LABEL=. |
rootflags= | Opcje montowania dla głównego systemu plików. |
init= | Zastąpienie PID 1. Np. init=/bin/bash dla powłoki awaryjnej. |
rd.break | Przejście do powłoki wewnątrz initramfs przed wykonaniem switch_root (dracut). |
systemd.unit= | Rozruch do określonego celu, np. rescue.target lub emergency.target. |
nomodeset | Wyłącza KMS; jądro pozostaje w trybie bufora ramki (framebuffer) VESA/EFI. Przydatne przy debugowaniu sterowników GPU. |
iommu=off | Wyłącza IOMMU. Istotne przy debugowaniu problemów z DMA. |
loglevel= | Poziom szczegółowości (verbosity) wczesnych komunikatów printk (0–7). Domyślnie zazwyczaj 4 (KERN_WARNING). |
earlyprintk= | Kieruje wczesne dane wyjściowe jądra na port szeregowy lub konsolę EFI, zanim uruchomiony zostanie bufor ramki. |