Linux Kernel

Jiří Slabý, xslaby@fi.muni.cz


Obsah


Historie

Linus Torvalds napsal linux 0.01 v roce 1991 se slovy:

Hello everybody out there using minix -

I'm doing a (free) operating system (just a hobby, won't be big and
professional like gnu) for 386(486) AT clones.

Od té doby se linux změnil, stal se velkým a profesionálním pro nejen x86 mašiny, do dnešní podoby – linux řady 2.6, o které je tento referát.

Jedna z verzí vzniku jména linux (ISBN 0-7382-0333-5):

“Linux was my working name,” Linus says, “but if I actually used it as the
official one, people would think that I was an egomaniac and wouldn't take it
seriously. So I chose this very bad name: Freax” - free + freak + x. “Sick, I
know.” Ari Lemmke, who ran the FTP site (myslí se funet.fi),
decided he didn't like the Freax label, so he used the working name instead.

Trvalo dlouhou dobu, než vznikla 1. opravdu multiplatformní, funkční řada 2.x.


Současnost

Nynější jádra jsou číslována trochu odlišně od starších, nedávno doznalo číslování malých změn. Ještě na začátku května popisoval číslování Linus takto:

- 2.6.<even>: even at all levels, aim for having had minimally intrusive
patches leading up to it (timeframe: a week or two)
- 2.6.<odd>: still a stable kernel, but accept bigger changes leading up
to it (timeframe: a month or two).
- 2.<odd>.x: aim for big changes that may destabilize the kernel for
several releases (timeframe: a year or two)
- <odd>.x.x: Linus went crazy, broke absolutely _everything_, and rewrote
the kernel to be a microkernel using a special message-passing version
of Visual Basic. (timeframe: "we expect that he will be released from
the mental institution in a decade or two").

Dnes si ale můžete v archivu jader všimnout, že existují i jádra 2.x.y.z, kde z je nějaké malé číslo. Takové verze jádra obsahují malé změny, které bylo nutné opravit třeba kvůli funkčnosti. Souběžně jsou vytvářeni kandidáti na další uvolnění celku – 2.x.(y+1)-rcz jádra. Po dostatečném testování se uvolní jádro 2.x.(y+1) a dále zase jeho podverze a -rc na další verzi.
Očekávaná verze 2.6.14, je „sudá” a Linus slibuje větší stabilitu, měla by vyjít během 14 dní.

Stažení, dekomprimace archívu

Nejnovější jádra lze získat z odkazů kernel.org. Od doby vzniku po současnost se vytvořilo mnoho obrazů primárního ftp serveru, odkud je možné jádro získat, mezi ně patří i naše fakulta, na adrese ftp.muni.cz, resp. ftp.linux.cz. Další možností je použít rsync a git/cogito (můžu doporučit, jsou to nástroje typu CVS, SVN).

Po stažení jádra jej můžeme dekomprimovat standardní cestou:

tar jxf linux-verze.tar.bz2

která nám vytvoří v pracovním adresáři adresář s rozbaleným, novým, jádrem.


Verze jádra, patchování

Tím, že jsme stáhli a rozbalili jádro, máme vanilla verzi, kterou vydává Linus a má číslovaní popsané výše. S malým zpožděním se k vanilla jádrům (a jejich -rc) vydávají patche, které spravují různí lidé. Mezi nejpoužívanější mezi kernel hackery patří -mm jádro vydávané Andrew Mortonem (akpm@osdl.org). Další je -ac vydávané chlapíkem s červeným (RedHat) klouboukem, Alanem Coxem. Mezi ty méně známé patří -gh (nebo -gk?), které vydává Greg Kroah-Hartmann a další (-ck, -rt, …).

Důležité jsou také -git patche, což jsou snapshoty z git databáze, ve které se jádro vyvíjí.

Pokud chcete nebo potřebujete nějaký patch, stáhněte jej, rozbalte a změňte pracovní adresář do jádra, na jehož verzi se dá patch aplikovat. Poté stačí:

patch -p1 -i <cesta k patchi>

Patche na vanilla jádra se aplikují na poslední 2.x.y stabilní verzi před patchem. Pokud si nejste jisti, na co se dá patch aplikovat, je nejlepší spustit něco podobného jako grep '+++ b/Makefile' -A10 patch. Řádky začínající - jsou stará verze, + potom nová (kterou známe z názvu patche).

Nezapomínejte, že patch(1) má parametr --dry-run.


Konfigurace

Jak lze v
make help

vidět, je možné využít několik rozhraní pro konfiguraci. To nejjednodušší je textové (make config), kde odpovídáte na otázky stiskem y, n, m nebo ? pro nápovědu. Další, textové, tentokrát ale s výběrem v menu je

make menuconfig
Jste-li zastánci klikacích nástrojů, zvolíte
make xconfig nebo make gconfig
které jsou postavené na gtk a qt designu.

Jak nastavit nové jádro?

To je asi nejčastější otázka, kterou není lehké zodpovědět. Nejlépe je najít konfigurační soubor odpovídající mé konfiguraci, tedy aspoň přibližně, někde na Internetu (nejčastější zbůsob tvorby jádra pro notebooky, kde jsou konfigurace u jednotlivých modelů podobné). Pokud je hledání takové konfigurace neúspěšné, přijdou na řadu nástroje, z nichž lze současně používané ovladače vyčíst. Jednak můžeme zjistit aktuálně načtené moduly pomocí lsmod(8), jednak využijeme výstup dmesg(8) současného jádra, v neposlední řadě můžeme zjistit typ HW pomocí lspci(8). V žádném případě není dobré brát konfiguraci z distribučních jader. Systém vám sice bude fungovat, ale jádro bude obrovské a všechny ovladače budou jako moduly, což ubírá na rychlosti.

Pokud již známe konfiguraci, stačí zaškrtat v konfigurační utilitě odpovídající ovladače. Není na škodu zakompilovat config.gz do jádra, což se stalo novinkou v jednom z posledních jader, to pro pozdější účely – kompilace novějšího jádra.

Tím jsem se dostal k další vymoženosti, kterou je

make oldconfig

který provedeme po upgradu jádra, popřípadě jeho napatchování. Konfigurátor se zeptá pouze na rozdílné věci, ty stejné použije z předchozího konfiguračního souboru .config, který se hledá buď v adresáři se zdrojovými kódy, nebo v adresáři nastaveným pomocí O=.

V neposlední řadě je třeba zmínit možnost O=<cesta>, čímž řekneme překladači, aby adresář se zdrojovými kódy zůstal nezměněn, naproti tomu, vše potřebné ke kompilaci a vytvoření výsledného obrazu se bude ukládat do <cesta>.

V adresáři je také možné provést

make clean nebo make mrproper

což vyčistí náš strom od přeložených věcí, v druhém případě i s konfiguračím souborem. Ve starších verzích jádra bylo nutné spouštět clean prakticky před každou kompilací. V jádře 2.6 jsou závislosti vyřešeny daleko lépe a nutné to (v 97,283 %) není. Minulostí je také make dep, který řešil závislosti ve starých jádrech.

Konfigurační řádka může tedy vypadat takto:

make menuconfig
nebo
mkdir ../xyz && make O=../xyz xconfig

Module or not to module?

Modul je soubor s příponou .ko, do jádra se vloží příkazem insmod(8) s cestou, popřípadě sofistikovanějším modprobe(8), který nahraje i moduly, na kterých ten námi požadovaný závisí. Moduly podporují i parametry, o této možnosti se můžete více dočíst v manuálové stránce. Po odstranění závislostí (např. zastavením síťového rozhraní, odmountováním disku) lze zase modul odebrat příkazem rmmod(8). Jako modul se doporučuje kompilovat věci jednak nestabilní (při pádu je jádro stále schopné běhu), jednak ty málo používané, např. wi-fi. modinfo(8) potom vypisuje informace o modulu včetně možných parametrů.

Významné volby nastavení

Při samotné konfiguraci je dobré (ne vždy nutné k běhu; generic drivery sice fungují, ale bez HW akcelerace) dát do jádra ovladače odpovídající přímo HW.

Možnosti, u kterých si nejste jisti ani po přečtení nápovědy, nechejte nastavené tak, jak radí v nápověde (např. If unsure, say N.).

Přeji příjemně strávené hodiny u konfigurace, neboť to je většinou věc, která trvá na svém prvním jádře nejdéle.


Překlad, instalace

To první je věc jednoduchá na provedení, složitější na čas. Pro překlad v podstatě stačí příkaz

make <O=…> all modules_install

all znamená přeložit vše, tedy vytvořit obraz i moduly (viz make help|grep ^*).
modules_install zkopíruje moduly do /lib/modules/x/ a vytvoří závislosti. x vyjadřuje verzi jádra, v novějších jádrech může také obsahovat řetězec popisující aktuální snapshot z databáze.

Tím jsme odbyli i první fázi instalace – moduly. Nyní je třeba nastavit systém tak, aby akceptoval a spustil naše nové jádro. Důležité je nakopírovat jádro tam, kde ho bude moci přečíst námi používaný zavaděč. Na většině systémů by to měl být adresář /boot. Provedeme tedy něco jako

cp <`…' z O=…>/arch/<naše architektura>/boot/bzImage /boot/<cokoliv>

kde cokoliv je většinou vmlinuz-<verze jádra>, avšak např. vyznavači powerpc mají raději vmlinux-<verze>. Dále je nutné upravit konfiguraci zavaděče a pokud budeme chtít použít initramdisk, tak vytvořit i jej pomocí mkinitrd(8), pidinávod zde.

Celý proces instalace za nás může udělat /sbin/kernelinstall, který spustíme pomocí make <O=…> install, pokud ho distribuce obsahuje.

To je celý proces, po rebootu by mělo jádro fungovat (v některých případech nebude, čtěte časté chyby).

Parametry jádra

Některé nedostatky/přebytky lze doladit parametry jádra, jejichž neúplný výčet je v Documentation/kernel-parameters.txt. Pro přesný výčet je nejlepší se vždy podívat do zdrojových kódů (i v případě, že vám nějaký parametr nefunguje).
K těm základním patří root=, init=, ro, rw, které po řadě nastavují kořenový svazek, program, který se má spustit jako init, mountování kořenového svazku jen pro čtení a pro zápis v ranné fázi, distribuční skripty popř. později provedou přemountování do rw.

System.map

Je soubor, který se kopíruje také do /boot a neobsahuje nic jiného, než tabulku převádějící adresy na symboly.
Ve většině případů je System.map linkem na nějaký System.map-verze.

Na dobře nastaveném jádře by kompilace neměla přesáhnout půl hodiny (v závislosti na procesoru, samozřejmě). Nezapomínejte na přepínač -j, který umí make(1).


Krátké shrnutí

Aneb jak to všechno udělat ve zkratce a neztratit body.
verze=2.6.13 # například
wget ftp://ftp.muni.cz/pub/linux/kernel/v2.6/linux-$verze.tar.bz2
tar jxf linux-$verze.tar.bz2
mkdir build
cd linux-$verze
make O=../build menuconfig
make O=../build -j3 all
make O=../build modules_install
cp ../build/arch/i386/boot/bzImage /boot/vmlinuz-verze
vim /boot/grub/menu.lst # přidat záznam a nahradit LABEL= /DEV/...
# mount --move ... [viz časté chyby], pokud je třeba
reboot
Jak jednoduché…

Dokumentace

Soubory s dokumentací jsou umístěny v adresáři Documentation jádra. Nachází se zde i soubor 00-INDEX, ve kterém je stručný popis (téměř) všech souborů z tohoto adresáře.

Pro zasvěcenější stojí za zmínku ManagementStyle, CodingStyle (ten je pro všechny, každý správný céčkař by se měl těmito radami řídit), SubmittingDrivers a SubmittingPatches. Dále je možné generovat DocBook nápovědu k API, která je stále ve vývoji, takže spousta věcí chybí, tak, že zadáte make htmldocs (xmldocs, psdocs, pdfdocs, mandocs). V adresáři Documentation/DocBook by poté měly být vygenerované soubory s příponou, kterou požadujete.


Bugzilla, LKML

Jako každý rozsáhlý projekt, i Linux má své vši. Pokud se vám podaří na nějakou přijít, nebo lépe, vyřešit ji, podělte se s ostatními. Bugy můžete zadávat na bugzilla.kernel.org, což je všeobecně známý, ucelený systém na bugtracking. Popřípadě můžete poslat patch, který vyhovuje CodingStyle na linux-kernel@vger.kernel.org s CC lidem, kteří mají odpovídající úsek na starost (viz MAINTAINERS v adresáři jádra), popřípadě na akpm, pokud není možné nalézt odpovídající osobu (ovladač není pod správou).


Časté chyby

Některé distribuce mají vanilla jádro upravené tak, aby fungovaly některé věci:

Vanilla jádro nepodporuje LABEL pro nastavení kořenového svazku. Je tedy nutné nastavit konkrétní /dev/[hs]d* svazek.

Jádro skončí s chybou nemožnosti namountovat svazek. (hned po zavaděči) Někdy je příčína v tom, že udev vytváří speciální soubory až je jádro načtené (protože je to user-level démon), ale jádro před tím potřebuje /dev/console a /dev/null. V tom případě je nutné tyto soubory vytvořit:

mkdir /tmp/dev
mount --move /dev /tmp/dev # to funguje jen na jádře 2.6, se staršími si musíte poradit jinak
cd /dev
mknod initctl p
mknod console c 5 1
mknod null 1 3
mknod zero 1 5
for cnt in 0 1 2 3 4 5 6 7 8; do
	mknod tty$cnt c 4 $cnt
done

V /dev by se měly objevit speciální soubory, které jsme vytvořili a můžeme přesunout udev dev zpět do /dev příkazem mount --move /tmp/dev /dev.

Jádro skončí s chybou nemožnost namountovat kořenový svazek. (těsně před načtením a spuštěním initu) Většinou jste zapomněli dát nějaký ovladač přímo do jádra. Pokud nepoužíváte initramdisk, musí být filesystém kořenového svazku a ovladač řadiče disku v jádře! Zkuste číst generovaný text při startu systému, jestli opravdu jádro našlo váš disk (Ctrl+S, Ctrl+Q funguje i zde).

Některé z těhto věcí jsem zachytil na diskuzích před delší dobou, zdroje už bohužel nevím (je možné, že zdrojem byly i stránky Fedory).


Ostatní (nelinuxová) jádra

Zkompilovat na míru lze i jiná jádra. Např. NetBSD, FreeBSD (ssys.*). NetBSD se konfiguruje editací textového souboru, pomocí utility config(8) se vytvoří adresář, ve kterém se překládá – spustí se make dep a make. Hotové jádro se uloží do souboru netbsd, který lze bootovat jako kernel ze zavaděče. [pro získání představy, jak to chodí v jiných jádrech].


kernel.org – domovská stránka jádra Linuxu
fakultní zrcadlo
mkinitrd – jak na to
Linux Device Drivers – kromě toho, jak psát ovladače jsou zde dobré připomínky a páky, které lze na jádro použít


Podobných návodů je na Internetu jistě spousta, já jsem se pokusil zachytit mé zkušenosti, které doufám pomohou. Přeji hodně štěstí při kompilaci jader.
Aktuální verzi bude možné najít zde. Následující sekce je (v tomto předmětu) spíše pro zajímavost.


A jak to všechno funguje? (jen tak na okraj)

Téměř v každém adresáři je soubor Makefile, jako v každém projektu. Před samotnou konfigurací jádra se zkompiluje vámi zadaný konfigurátor nad TUI/GUI, který jste vybrali. Pod ním existuje řada funkcí, které parsují .config, Kconfig, zapisují konfiguraci jako definice do hlavičkových souborů a mnoho dalších. Nikomu nic nebrání v tom napsat vlastní royhraní, které bude volat funkce a bude postavené nad jeho oblíbeným prostředí (třeba konfigurovat jádro psaním kódu v base64).

Zmínil jsem soubor Kconfig, není jeden, ale téměř v každém adresáři jako Makefile. V něm jsou texty, odpovídající každému ovladači a také obsahují nastavení, jak se mají chovat funkce pod konfigurátorem, jak mají řešit závislosti, co mají vybrat, když zvolíte nějaký ovladač, co vám nedovolí vybrat, když nemáte v jádře něco jiného a pod.

Po uložení je vygenerován jednak soubor, podle kterého se orientuje make a překládá jen to, co jste zvolili a jednak hlavičkový soubor, který obsahuje tytéž informace, podle kterých jsou nastaveny podmínky ve zdrojových kódech (např. pokud máte procfs, vytvoří tam ovladač svůj adresář).

Samozřejmě podle vybrané architektury se vytvoří adresář include2 a v něm jsou odkazy na hlavičkové soubory závislé na architektuře, aby mohl developer jednoduše udělat #include <asm/cokoliv.h>.

To je v podstatě vše, v Makefiles jsou skupiny -m, -y a -n odpovídající modulu, do jádra, nebo vůbec ne. Potom se čistým jazykem c, resp. zašpiněným gcc (jiným překladačem jádro nepřeložíte) verze aspoň 2.9x, překládá -m a -y; -m se potom linkuje do samostatného .ko, -y v každém adresáři do built-in.o, všechny nejnadřazenější built-iny do monolitu spolu se zaváděcí oblastí. Monolit se může zmenšit kompresí (z Image, nebo big z Image). K dispozici vám také zůstane vmlinux, což je nekomprimovaná verze, kterou můžete spolu s /proc/kcore předhodit gdb (a vytisknout si třeba jiffiesp jiffies).