Zajęcia 3: kompilacja jądra

Data: 14.03.2023

Materiały dodatkowe

Lektura

  • Kernel-HOWTO (niestety, przestarzałe)

  • Kernel-Build-HOWTO

  • /usr/src/linux/README

  • /usr/src/linux/Documentation/*

  • info grub

Przygotowanie źródeł jądra

  • Sklonować repozytorium gita z git.kernel.org (repozytorium linux/kernel/git/linux-stable) lub ściągniąć i rozpakować paczkę w wersji 6.7.6 z https://www.kernel.org/. W przypadku użycia gita, przejść na taga v6.7.6.

Informacje o wersjach jądra – X.Y.ZZ.ŹŹ(-abc)

Dawniej (wersje jądra przed 2.6)

Wówczas numery były postaci X.Y.ZZ(-abc).

Pierwsza liczba (X) – główny numer wersji, zmieniany przy radykalnych zmianach w budowie jądra. Pierwsze wersje Linuksa miały (krótko) numer 0, następnie przez długi czas 1; obecna główna wersja to 4.

Druga liczba (Y) – linia bądź seria jądra, parzyste liczby oznaczają wersję ‘stabilną’; nieparzyste – ‘rozwojową’. W wersjach rozwojowych testowane są nowe koncepcje, które później są ewentualnie przenoszone do wersji stabilnych. Wersje stabilne są też stale poprawiane, więc w pewnym sensie także się rozwijają.

Trzecia liczba (ZZ), to wersja jądra w danej linii, cały numer wyznacza ‘wydanie’ (release).

Dodatkowo, wydania mogą być oznaczane różnymi przyrostkami, przede wszystkim określającymi rodzaje łatek na nie nałożonych lub numer wersji testowej. Przyrostek “pre” oznacza wersję beta, np. 2.4.20pre7 oznacza 7 wersję beta kernela 2.4.20 . Po zakończeniu testowania ten kernel otrzyma numer 2.4.20, bądź przekształci się w 2.4.20pre8, jeżeli Linus nie zatwierdzi wersji jako oficjalnego wydania.

Zdarzają się też przyrostki oznaczające jądra tworzone równolegle do “oficjalnego” (zatwierdzanego przez Linusa Torvaldsa) jądra, np.:

  • arca – tworzone przez Andree Arcangeli,

  • ac – tworzone przez Alana Coxa, np. 2.0.36-ac12.

Numery wersji dla jądra 2.6 i 3+

Począwszy od serii 2.6 zrezygnowano z “dużych” serii rozwojowych o numerach nieparzystych na rzecz bardziej ciągłego rozwoju. W serii 2.6, numery wersji są postaci 2.6.XX.YY. Trzecia liczba (XX) oznacza wersję jądra w danej linii, jest ona zmieniana gdy dodane zostaną nowe sterowniki bądź nowa funkcjonalność. Nowe wydanie jądra różniące się od poprzedniego wyłącznie poprawkami błędów mają numer różniący się czwartą liczbą (YY). Oczywiście istnieją też jądra wydawane przez kogoś innego niż Linus Torvalds, zazwyczaj ich nazwa kończy się jakimś przyrostkiem.

W lipcu 2011 została wydana wersja 3.0, rozpoczynająca nową serię. W tej serii, numery wersji są postaci 3.XX.YY, gdzie XX i YY oznaczają to samo co w serii 2.6. Zmiana ta nie wiązała się z żadną nową funkcjonalnością, a z 20 rocznicą powstania Linuksa – wersja 3.0 nie różni się bardziej od 2.6.40 niż 2.6.40 od 2.6.39. Przejście na nowy system numeracji zostało przeprowadzone ze względu na nieadekwatność starego systemu do nowego modelu rozwoju jądra – numery wersji były po prostu za długie. Od tego czasu, główny numer wersji po prostu jest zwiększany, gdy numer drugorzędowy stanie się “dostatecznie duży” – nie ma to związku z funkcjonalnościami i ilością wprowadzonych zmian. W kwietniu 2015 została wydana wersja 4.0 (po wersji 3.19). W 2019 została wydana wersja 5.0 (https://lkml.org/lkml/2019/3/3/236).

Pobieranie źródeł jądra

Najprostszym sposobem zdobycia źródeł jądra jest pobranie skompresowanego pliku .tar ze strony http://kernel.org/, będącej oficjalnym archiwum wydań jądra. Oprócz kompletnych paczek ze źródłemi, publikowane są również łaty (pliki .patch), umożliwiające zaktualizowanie wcześniej ściągniętej paczki do nowszej wersji.

Trochę bardziej skomplikowanym, lecz znacznie elastyczniejszym sposobem zdobycia źródeł jest użycia gita. Pozwala to na pracę na najświeższym kodzie (nie zawartym jeszcze w żadnym oficjalnym wydaniu), a także niemal natychmiastowe przemieszczanie się między wszystkimi dotychczasowmi wersjami zawartymi w historii (od 2.6.12). Użycie gita jest też wymagane w przypadku wysyłania własnych zmian do włączenia do oficjalnej wersji jądra.

Istnieje wiele repozytoriów gita ze źródłami Linuksa – każdy podsystem jest rozwijany w swoim własnym repozytorium, które jest następnie łączone z głównym repozytorium, gdy nadchodzi czas na wydanie nowej wersji. Główne repozytorium, należące do Linusa Torvaldsa i używane jako podstawa do nowych wydań jądra, znajduje się pod adresem

git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git

Wszystkie “duże” wydania (2.6.XX, 3.XX, 4.XX) oraz wydania release candidate są w nim dostępne jako tagi (v2.6.27, v3.1-rc3, itd). Wydania będące poprawkami błędów (2.6.XX.YY, 3.XX.YY) są natomiast tworzone w osobnym repozytorium, dostępnym pod adresem

git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git

Jeśli chcemy pracować tylko nad zewnętrznymi modułami jądra, nie modyfikując istniejącego kodu, posiadanie kompletnych źródeł nie jest konieczne. Wystarczą nagłówki jądra, zainstalowane najczęściej w /usr/src/linux i podlinkowane w /lib/modules/<wersja>/build. Muszą to jednak być prawdziwe nagłówki jądra, a nie te przeznaczone do użytku przez libc. Wersja jądra, z której pochodzą te nagłówki musi się również dokładnie zgadzać z wersją jądra, pod którą będą używane skompilowane moduły. Niektóre dystrybucje pakują takie nagłówki w osobnej paczce, nazwanej np. linux-headers.

Dystrybucje często posiadają również źródła jądra w standardowym repozytorium pakietów – takie źródła zazwyczaj zawierają jednak łaty nakładane przez dystrybucję i nie są identyczne z oficjalnym wydaniem.

Nakładanie łat (patches) na źródła jądra

Zamiast pobierania całej nowej paczki z kodem jądra, można nałożyć łaty (pliki o nazwie np. patch-xx.xx.xx.gz) na stare źródła poleceniem patch, np.

cd /usr/src/linux
gzip -cd patch.xx.xx.xx.gz | patch -p1

Można też użyć do tego skryptu patch-kernel, znajdującego się w katalogu scripts (automatycznie aplikuje łaty znalezione w katalogu, z którego został wywołany).

Łaty ‘oficjalne’ o nazwie np. patch-2.6.17.14.gz działać będą z poprzednim wydaniem (względem nazwy określonej w nazwie patcha), czyli wspomniana łata działać będzie z jądrem 2.6.17.13. Łaty nieoficjalne (np. patch-2.6.11-ac4.gz) zazwyczaj odnoszą się to tego samego wydania co w nazwie.

Przed zainstalowaniem nowego jądra należy zapoznać się z plikiem Documentation/Changes, który zawiera wymagania odnośnie wersji kompilatora, zainstalowanych pakietów, wersji bibliotek, itp. i upewnić się, że stosowne wersje ma się zainstalowane.

Struktura źródeł jądra

Zawartość głównego katalogu

Documentation

katalog zawierający dokumentacje, w szczególności należy się zapoznać z plikiem CodingStyle

arch

kod źródłowy zależny od architektury procesora

block

funkcje warstwy urządzeń blokowych (ang. kernel block layer)

crypto

funkcje kryptograficzne (a także kompresja i dekompresja)

drivers

sterowniki urządzeń

firmware

kod pomocniczy ładowany przez niektóre sterowniki urządzeń na kontrolowane przez nie urządzenia

fs

systemy plików

include

pliki nagłówkowe

init

niezależna od platformy część inicjalizacji systemu

ipc

IPC (komunikacja międzyprocesowa System V)

kernel

rdzeń jądra – zarządzanie procesami, przerwania, DMA, czas

lib

procedury pomocnicze (np. wypisywanie na ekran, rozpakowywanie spakowanego jądra)

mm

zarządzanie pamięcią

net

protokoły sieciowe

samples

przykłady użycia niektórych wewnętrznych interfejsów jądra

scripts

skrypty (np. do konfiguracji)

security

kod związany z bezpieczeństwem (LSM – Linux Security Modules)

sound

sterowniki kart dźwiękowych oraz kod obsługujący dźwięk (ALSA)

usr

programy pomocnicze; aktualnie gen_init_cpio służący do tworzenia ramdysku ładowanego razem z jądrem systemu.

virt

kod związany z wirtualizacją (KVM)

arch – kod zależny od platformy sprzętowej

Kod dla procesorów Intela znajduje się w katalogu arch/x86. Istnieje możliwość skompilowania jądra dla innego procesora niż ten, na którym pracujemy, jakkolwiek wymaga to (poza źródłami Linuksa) także kompilatora dla danej platformy, działającego na naszym systemie (tzw. cross-compiler).

Nagłówki jądra

Jądro zawiera dwa zbiory nagłówków: wewnętrzne oraz nagłówki dla przestrzeni użytkownika. Nagłówki wewnętrzne są przeznaczone tylko do użytku przez sam kod jądra oraz moduły i są instalowane w /usr/src/linux (o ile w ogóle). Nagłówki dla przestrzeni użytkownika znajdują się w podkatalogach o nazwie uapi i są przeznaczone do użytku zarówno przez kod jądra, jak i przez programy użytkownika. Te nagłówki są instalowane w /usr/include. Ze względu na gwarancje kompatybilności interfejsów jądra, zainstalowana wersja nagłówków może być różna od wersji używanego jądra.

Wewnątrz źródeł jądra, nagłówki są porozrzucane po wielu katalogach:

  • include: główne nagłówki jądra

  • include/generated: główne nagłówki jądra, wygenerowane w czasie kompilacji

  • arch/<procesor>/include: nagłówki jądra specyficzne dla danej architektury

  • arch/<procesor>/include/generated

Z ważniejszych podkatalogów z nagłówkami należy wymienić asm, asm-generic oraz linux.

Konfiguracja jądra

Przed kompilacją, źródła jądra muszą zostać skonfigurowane za pomocą jednego z poniższych poleceń:

  • make config (wersja tekstowa, zadaje jedno pytanie na każdą opcję – niezalecane),

  • make menuconfig (ncurses),

  • make xconfig (X11),

  • make oldconfig (jak make config, ale aktualizuje konfigurację ze starej wersji jądra – pyta tylko o nowe opcje)

Najprostsza w obsłudze jest wersja menuconfig, bądź xconfig, choć w tej ostatniej częściej zdarzają się błędy.

Poniższe punkty opisują istotne elementy konfiguracji (tytuły odpowiadają elementom głównego menu w menuconfig).

Warning

Opcje jądra miewają dośc skomplikowane zależności, a programy konfigurujące nie pokazują opcji, które są wykluczone przez inne wybory (np. jeśli nie włączyliśmy wsparcia dla urządzeń typu virtio w opcjach wirtualizacji, w ogóle nie zobaczymy opcji wsparcia wirtualnej karty sieciowej virtio-net w opcjach sterowników sieci). Jeśli nie jesteśmy w stanie znaleźć poszukiwanej opcji tam, gdzie się jej spodziewamy, warto użyć funkcji wyszukiwania (wystarczy nacisnąć / w make menuconfig) – wyniki pokażą nam, gdzie opcja jest w drzewie wyborów oraz od jakich opcji zależy.

64-bit kernel

Wybiera, czy skompilowane jądro będzie działało w trybie 64-bitowym i zarazem pozwalało na uruchamianie 64-bitowych programów (uruchamianie 32-bitowych programów jest zawsze możliwe, chyba że jawnie wyrzucimy tą opcję w dalszej konfiguracji).

General setup

Ta część konfiguracji kontroluje kluczowe komponenty jądra systemu Linux. Najważniejsze opcje to:

  • ‘Support for paging of anonymous memory (swap)’ – obsługa pamięci wirtualnej na dysku

  • ‘System V IPC’ – obsługa komunikacji międzyprocesowej

  • ‘Initial RAM filesystem and RAM disk (initramfs/initrd) support’ – umożliwia wystartowanie Linuksa z ramdysku ładowanego przed uruchomieniem (np. przez GRUBa), co pozwala na załadowanie sterowników dla dysków czy systemów plików dostępnych tylko jako moduły lub też start systemu z urządzeń software-RAID.

  • ‘Initramfs source file(s)’ – lista plików do załączenia w ramdysku

  • ‘Embedded system’ – sama w sobie nic nie zmienia, ale powoduje pojawienie się opcji pozwalających na wyłączenie funkcjonalności zazwyczaj uznawanych za konieczne.

Enable loadable module support

Note

Moduł – część kodu jądra, która może być ładowana lub usuwana z jądra na życzenie. Wszystkie części jądra, które nie są potrzebne przy starcie systemu i nie są ciągle używane w trakcie pracy systemu powinny być skompilowane jako moduły. Nawet wiele części potrzebnych przy starcie systemu może być modułami, musimy tylko użyć ramdysku (initial ramdisk).

Konfiguruje wsparcie dla modułów jądra. W zależności od potrzeb, możemy włączyć lub wyłączyć ładowanie modułów (Enable loadable module support), umożliwić usuwanie modułów (Module unloading, Forced module unloading), umożliwić automatyczne ładowanie modułów przez kernel (Automatic kernel module loading) oraz umożliwić ładowanie modułów skompilowanych dla innych wersji jądra dzięki umieszczaniu w nich dodatkowych informacji o potrzebnych funkcjach (Module versioning support). Możemy też umieścić w każdym module sumę kontrolną (Source checksum for all modules).

Processor type and features

Umożliwia skonfigurowanie wsparcia i optymalizacji jądra dla danego procesora (Processor family) – w razie niepewności dla architektury i386 bezpiecznymi rozwiązaniami są 386 (zawsze) i 586 (dla procesorów od pentium w górę) bądź Pentium (dla procesorów Intela od pentium w górę). Uwaga – w przypadku wybrania nieprawidłowej wartości jądro może nie działać bądź działać błędnie. Inne ważne opcje dostępne w tym menu to:

  • ‘High Memory Support’ – wsparcie dla systemów z >1GB pamięci (tylko 32-bit),

  • ‘Math emulation’ – emulacja jednostki 387 dla starych procesorów bez FPU,

  • ‘MTRR (Memory Type Range Register) support’ – obsługa rejestrów dostępu do pamięci, umożliwiająca ustawienie szyny PCI/AGP w tryb “write-combining”, co może znacznie przyspieszyć aplikacje graficzne.

  • ‘Symetric multi-processing support’ – wsparcie dla wielu procesorów

  • ‘SMT (Hyperthreading) scheduler support’ – polepszenie właściwości planisty dla systemów z procesorem z obsługą HT.

  • ‘Preemption Model’ – pozwala wybrać, czy jądro może być wywłaszczane.

  • ‘Local APIC support on uniprocessors’ – wsparcie dla zaawansowanych kontrolerów przerwań dostępnych w nowszych płytach głównych. Opcja ta dostępna jest tylko, jeśli SMP jest wyłączone (dla systemów SMP APIC i tak zawsze jest włączone).

Power management and ACPI options

Wybór obsługiwanych metod oszczędzania energii – w tym obsługa ACPI oraz zmian prędkości procesora w trakcie działania systemu.

Bus options (PCI etc.)

Wybór obsługiwanych szyn systemowych oraz ich parametrów. Dla współczesnych komputerów warto skonfigurować obsługę szyny PCI.

Executable file formats / Emulations

Obsługa formatów plików wykonywalnych. Bez obsługi formatu ELF z tradycyjnymi dystrybucjami Linuksa zbyt wiele nie da się zrobić. W przypadku jądra 64-bitowego możemy tutaj włączyć lub wyłączyć obsługę 32-bitowych programów.

Networking support

Zazwyczaj nie daje się, całe szczęście, wyłączyć obsługi sieci (Networking support), bo bez tego niewiele by działało. Oprócz opisanego poniżej menu Networking options można tu skonfigurować obsługę różnych metod komunikacji - przez podczerwień, Bluetooth, Wi-Fi.

Networking options

Menu to zawiera konfigurację komponentów sieciowych i protokołów. Najważniejsze z nich to:

‘Packet socket’

bezpośredni dostęp do urządzeń sieciowych.

‘Unix domain sockets’

gniazda Unixowe, umożliwiające komunikację międzyprocesową w sposób zbliżony do komunikacji sieciowej. Gniazda takie są wykorzystywane np. przez X-Windows, PostgreSQL.

‘TCP/IP Networking’

obsługa protokołu TCP/IP – bardzo ważne. Ale trudne do niewybrania.

‘The IPv6 protocol’

obsługa nowej wersji protokołu TCP/IP. Obecnie jeszcze niekonieczna, ale za jakiś czas zapewne nie będzie się można bez tego obejść.

‘Network packet filtering framework (Netfilter)’

filtrowanie i modyfikowanie pakietów (firewall, NAT).

Device Drivers

Różne ustawienia dotyczące sterowników pogrupowane w wielu menu.

W przypadku budowania jądra na potrzeby zajęć najlepiej jest wybrać tylko niezbędne sterowniki – przyspieszy to znacząco proces budowy jądra.

Block devices

Najważniejsze opcje to:

‘Loopback device support’

pseudourządzenie umożliwiające stworzenie ‘urządzenia’ blokowego którego zawartość przechowywana jest w zwykłym pliku.

‘RAM block device support’

wsparcie dla RAM dysków.

‘Packet writing on CD/DVD media’

umożliwia zapis dysków CD/DVD

‘Virtio block driver’

wirtualizowane urządzenie blokowe o niskim narzucie

NVM Express block device

Wsparcie dla dysków SSD montowanych bezpośrednio na płycie głównej (złącze M.2).

SCSI device support

Włącza przede wszystkim obsługę magistrali SCSI, ale także umożliwia obsługę wielu innych rodzajów urządzeń blokowych używających emulacji SCSI (w tym SATA, ATA i USB). Do działania tych urządzeń należy włączyć opcje ‘SCSI disk support’, ‘SCSI CD-ROM support’, ‘SCSI generic support’. Dodatkowo w menu ‘SCSI low-level drivers’ można włączyć obsługę sprzętowego kontrolera SCSI (o ile takowy jest potrzebny/zainstalowany).

Serial ATA and Parallel ATA drivers (libata)

Obsługa urządzeń dyskowych ATA i SATA. Należy tu też wybrać posiadany kontroler ATA bądź SATA. Opcje ‘AHCI SATA Support’ oraz ‘Generic ATA support’ obsługują większość urządzeń, lecz mogą mieć mniejszą funkcjonalność niż specjalistyczny sterownik. Ten sterownik jest zrobiony na bazie warstwy SCSI – aby skorzystać z dysku bądź napędu optycznego, należy również włączyć wsparcie dla odpowiedniego typu urządzenia w menu SCSI.

Multiple devices driver support (RAID and LVM)

‘RAID support’

włącza obsługę programowego RAID, umożliwiającego wykorzystanie wielu dysków jako jeden, co może zwiększyć wydajność i bezpieczeństwo operacji dyskowych.

‘Device mapper support’

obsługa niskopoziomowego manadżera woluminów, z którego korzystają programy umożliwiającego definiowanie zbiorów urządzeń (volume group) a na nich logicznych dysków (woluminów) dla uproszczenia zarządzania dyskami w dużych systemach.

Opcja ‘RAID support’ przydatna jest także w systemach domowych, pod warunkiem posiadania co najmniej dwóch dysków twardych – w takiej sytuacji tryb RAID-0 umożliwia dwukrotny wzrost wydajności operacji dyskowych.

Network device support

Umożliwia kompilację sterownika karty sieciowej (‘Ethernet (10 or 100Mbit)’, ‘Ethernet (1000 Mbit)’), bezprzewodowej karty sieciowej (‘Wireless LAN’) i obslugę PPP (‘PPP (point-to-point protocol) support’), jak również wielu innych typów kart sieciowych oraz protokołów. Te cztery opcje jednak będą najczęściej wykorzystywane.

Input device support

Wsparcie (ogólne) dla urządzeń wejściowych. Jeżeli chcemy korzystać z myszki, klawiatury, joysticka lub podobnych urządzeń, należy włączyć tę opcję (szczęśliwie trudno ją wyłączyć) oraz odpowiedni moduł. Obsługa urządzeń wejściowych USB znajduje się w menu ‘HID Devices’ (patrz niżej).

Character devices

Najważniejsza opcja to ‘Virtual Terminal’, umożliwiająca korzystanie z konsoli Linuksa. Jest domyślnie niewidoczna i włączona (wyłączyć ją można tylko dla systemów wbudowanych). Można tu również włączyć obsługę portów szeregowych.

Graphics support

Wybór obsługiwanych urządzeń graficznych oraz w menu ‘Console display driver support’ obsługa konsoli. ‘VGA text console’ umożliwia obsługę konsoli na urządzeniu typu VGA. Znajdują się tu również przyspieszane sprzętowo sterowniki graficzne (Direct Rendering Manager).

Sourd card support

Wybór obsługiwanych systemów dźwiękowych oraz sterowników kart dźwiękowych. Zaleca się użycie systemu ALSA (Advanced Linux Sound Architecture).

HID support

Wsparcie dla urządzeń typu HID – przede wszystkim klawiatury i myszy podłączane przez USB.

USB support

Tu można wybrać obsługiwane chipsety oraz urządzenia podłączane przez magistralę USB. ‘USB Mass Storage support’ umożliwia korzystanie z urządzeń pamięci masowej, w tym dysków i pamięci flash. Wiele urządzeń USB znajduje się w innych kategoriach – np. karty sieciowe w ‘Network device support’.

Virtio drivers

Włącza wsparcie dla urządzeń virtio – wirtualnych urządzeń o małym narzucie, dostarczanych przez QEMU. Warto włączyć tą opcję, gdy kompilujemy jądro dla maszyny wirtualnej. Część sterowników virtio można znaleźć w innych miejscach (np. virtio network device jest wśród innych kart sieciowych).

Pozostałe sekcje ze sterownikami

W pozostałych menu można skonfigurować różnorakie urządzenia znajdujące się w systemie. Zazwyczaj można je spokojnie skompilować jako moduły, ponieważ nie są one potrzebne do startu systemu.

File systems

Umożliwia włączenie obsługi różnorakich systemów plików. Najważniejsze to system który używany jest na partycji startowej systemu (najczęściej ext4 bądź btrfs) – musi on być wkompilowany w jądro bądź załączony na ramdysku. Pozostałe systemy plików można skompilować jako moduły. Ważna jest również obsługa ‘Tmpfs virtual Memory file system support’, konieczne są ‘/proc’ oraz sysfs (wszystkie z ‘Pseudo filesystems’). ‘Filesystem in Userspace support’ to FUSE, pozwalający na używanie systemów plików działających w przestrzeni użytkownika. Pozostałe systemy plików można skompilować w zależności od potrzeb.

Kompilacja jądra – Kbuild

Kbuild jest systemem budowania Linuksa. Składa się on z odpowiednio przygotowanych Makefile’i.

Tak jak zawsze przy Makefile’ach używa się go następująco:

make <opcje> <cel> <opcjonalne zmienne dla Kbuild>

Użyteczną opcją do make jest -j<N> – spowoduje zrównoleglenie kompilacji aż do <N> procesów jednocześnie (proszę nie nadużywać tego na students).

make clean

Usuwa skompilowane pliki.

make bzImage

Kompiluje jądro i umieszcza je w katalogu arch/<architektura>/boot pod nazwa bzImage. Jądro tak utworzone jest skompresowane (rozpakowuje się przy starcie systemu).

make modules

Kompiluje części jądra, które skonfigurowaliśmy jako moduły. Następnie należy je zainstalować poleceniem make modules_install.

make all

Ma takie działanie, jak make bzImage razem z make modules.

make modules_install

Instaluje moduły do katalogu /lib/modules/<wersja>/ i wywołuje depmod w celu stworzenia informacji o zależnościach. Jeżeli podana jest zmienna INSTALL_MOD_PATH, instaluje w $INSTALL_MOD_PATH/lib/modules/<wersja>/.

make help

Pokazuje dostępne polecenia make.

make mrproper

Czyści dokładnie katalog ze źródłami (łącznie z konfiguracją!), usuwa też zależności, moduły, itp.

make prepare

Przygotowuje docelowy katalog do budowania. Szczególnie przydatne przy budowaniu w innym katalogu niż źródła.

make install

Instaluje jądro i dodaje je do konfiguracji bootloadera, nie zawsze działa zgodnie z oczekiwaniami.

make htmldocs

Kompiluje dokumentację w formacie DocBook do formatu HTML.

make pdfdocs

Kompiluje dokumentację w formacie DocBook do formatu PDF.

make rpm

Tworzy pakiet RPM z jądrem (przydatne w systemie RedHat).

Zmienne

Niektóre parametry kompilacji jądra można podawać przez zmienne programu make (dopisując ZMIENNA=wartość na koniec polecenia make). Te najważniejsze:

V=1

Verbose, Kbuild wypisze dokładniej co robi.

ARCH=<arch>

Wymuszenie architektury <arch>, np. i386.

EXTRA_CFLAGS=<flagi>

Podczas kompilacji, <flagi> będą dodane do wywołań gcc (użyteczne może być podanie -g, żeby mieć symbole).

INSTALL_MOD_PATH=<ścieżka>

Instaluje moduły w podanej lokalizacji.

O=<ścieżka>

Umieszcza pliki wynikowe w osobnym katalogu; po pierwszym wywołaniu make z tą opcją, następnie można używać make we wskazanym katalogu bez dodatkowych opcji (jest tam umieszczony odpowiedni Makefile).

Ćwiczenie

Skonfigurować i skompilować jądro i moduły, a następnie umieścic jądro w katalogu /boot.

Należy pamiętać o włączeniu wszystkich opcji koniecznych do wystartowania systemu, m.in.:

  • zaznaczyć 64-bit kernel

  • obsługa szyny PCI (Bus options -> PCI support)

  • obsługa formatu ELF (Exectable file formats -> Kernel support for ELF binaries)

  • obsługa virtio (Device drivers -> virtio -> PCI driver for virtio devices)

  • obsługa virtio balloon (Device drivers -> virtio -> Virtio balloon driver)

  • obsługa gniazd lokalnych (Network support -> Networking options -> Unix domain sockets)

  • obsługa protokołu IPv4 (Network support -> Networking options -> TCP/IP networking)

  • sterownik virtio block (Device drivers -> Block devices -> Virtio block driver)

  • sterownik virtio net (Device drivers -> Network device support -> Virtio network driver)

  • sterownik virtconsole (Device drivers -> Character devices -> Virtio console)

  • system plików ext4 (File systems -> The Extended 4 (ext4) filesystem)

  • system plików proc (File systems -> Pseudo filesystems -> /proc file system support)

  • system plików FUSE (File systems -> FUSE (Filesystem in Userspace) support)

Programy ładujące

Programy ładujące (bootloadery) ładują system operacyjny. Przy starcie komputera BIOS ładuje do pamięci MBR (master boot record) i przekazuje mu sterowanie. W MBR znajduje się tablica partycji i kod, który może być kodem ładującym system (np. kod ładujacy DOS). Ma on za zadanie załadowac boot sektor z odpowiedniej partycji i przekazac mu sterowanie. Jeśli jednak chcemy zorganizować współistnienie kilku systemów na jednym dysku, umieszczamy w MBR kod programu ładującego, który pozwala wybrać przy starcie, który boot sektor ma byc wczytany. Przykładami takich programów ładujących (dla systemu Linux na architekturze x86) są:

  • grub: pozwala na uruchamianie systemu z dysku twardego, bezpośrednio obsługuje szeroki zakres systemów plików i tablic partycji. Oprócz jądra systemu Linux wspiera również standard multiboot, FreeBSD/OpenBSD/NetBSD, oraz ładowanie innych bootloaderów (tzw. chain-loading). Posiada dość rozbudowaną linię poleceń pozwalającą m.in. na przeglądanie systemu plików i modyfikację linii poleceń uruchamianego jądra.

  • grub2: bardziej modularny i rozbudowany następca gruba, wypierający już oryginał.

  • syslinux: w zasadzie pakiet kilku lekkich bootloaderów:

    • syslinux: pozwala na uruchomienie systemu Linux z partycji dysku, rzadko stosowany.

    • isolinux: uruchamia system z płyt CD używających system plików ISO 9660.

    • pxelinux: uruchamia system przez sieć, używając środowiska PXE.

  • lilo: niegdyś bardzo popularny bootloader napisany dla systemu Linux, dziś już przestarzały

GRUB

GRUB dostępny jest poprzez dwa interfejsy: dający więcej możliwości interfejs linii komend bądź proste menu. Zwykle to drugie wystarcza. Po starcie, GRUB szuka pliku konfiguracyjnego. Jeśli go znajdzie, wyświetla pozycje z tego pliku (odpowiadające obrazom Linuksa bądź innym systemom) w formie pozycji menu. Pozycje menu można edytować (ale zmiany mają wpływ tylko na dane uruchomienie, nie są zapamiętywane) – przejście do trybu edycji odbywa się przez wciśnięcie ‘e’ (i w ten sposób być może da się naprawić błędy z pliku konfiguracyjnego). Z menu można również przejść do linii komend poprzez wciśnięcie ‘c’ (powrót przez ESC). Jeśli nasz GRUB jest chroniony hasłem, przejście do trybu edycji czy linii komend możliwe jest tylko po wcześniejszym naciśnięciu ‘p’ i wprowadzeniu hasła.

Plikiem konfiguracyjnym GRUB-a jest /etc/grub.conf. Plik składa się z wpisów dla kolejnych obrazów jądra czy innych systemów operacyjnych. Kolejne wpisy są numerowane poczynając od 0.

Najważniejszymi komendami wchodzącymi w skład wpisu są:

  • TITLE nazwa_obrazu – nazwa, która będzie widoczna w menu. Rozpoczyna wpis; wpis kończy się z końcem pliku lub z wystąpieniem kolejnej komendy title (zaczynającej następny wpis).

  • ROOT root_device – gdzie będziemy szukać obrazu.

  • ROOTNOVERIFY root_device – jak wyżej, ale urządzenie nie zostanie zamontowane, a komenda służy zwykle podaniu położenia innego boot loadera, co pozwala na tzw. chain-loading i ładowanie np. Windowsów.

  • KERNEL plik_z_obrazem [opcje_dla_jądra]

Istotnymi komendami wchodzącymi ponadto w skład grub.conf są:

  • DEFAULT=numer_wpisu – który wpis będzie wybrany domyślnie (jeśli nie jest podany, wybrany będzie wpis 0).

  • TIMEOUT=ile_sekund – GRUB będzie czekał ile_sekund na wybór systemu. Jeśli to nie nastąpi, zacznie ładować domyślny.

Znakiem # rozpoczynają się linie komentarza.

Plik grub.conf mógłby wyglądać np. tak:

# Note that you do not have to rerun grub after making changes to this file
# NOTICE:  You have a /boot partition.  This means that
#          all kernel and initrd paths are relative to /boot/, eg.
#          root (hd0,0)
#          kernel /vmlinuz-version ro root=/dev/hda2

default=1
timeout=3

title dos
    rootnoverify (hd0,0) # ustawia GRUB root device, bez montowania
    makeactive
    chainloader +1       # ładuje boot loader
title linux
        root (hd0,4)
        kernel /vmlinuz ro root=/dev/hda5 hdc=ide-scsi
title nowe
    root (hd0,4)
    kernel /vmlinuz-2.2.17 ro root=/dev/hda5 hdc=ide-scsi

GRUB 2

GRUB 2 jest następcą GRUBa, o większej modularności i funkcjonalności. Interfejs menu jest dość podobny do GRUBa, ale znacznie zmieniona została konfiguracja.

Plikiem konfiguracyjnym GRUBa 2 jest /boot/grub/grub.cfg, ale nie należy go modyfikować bezpośrednio – jest on generowany przez program grub-mkconfig na podstawie skryptów w katalogu /etc/grub.d i konfiguracji w pliku /etc/default/grub.

Dzięki skryptom konfiguracyjnym, nie trzeba ręcznie tworzyć wpisów konfigracyjnych dla każdego jądra – wystarczy umieścić jądro jako /boot/vmlinuz-<wersja>, a ewentualny initramfs jako /boot/initrd.img-<wersja>. Opcje przekazywane zainstalowanemu jądru można ustawić w pliku /etc/default/grub.

Po zmianie konfiguracji należy wydać polecenie:

grub-mkconfig -o /boot/grub/grub.cfg

Aby zainstalować GRUBa 2 po raz pierwszy należy wydać polecenie:

grub-install /dev/<dysk>

Ćwiczenie

  1. Zmodyfikować plik /etc/grub.conf, tak żeby umożliwiał załadowanie nowo stworzonego obrazu.

  2. Zrestartować komputer, poprosić bogów o wsparcie i uruchomić nowo utworzone jądro.