Kompilace Linuxového a BSD jádra

referát do P090

Václav Lorenc

Ústav výpočetní techniky, Masarykova univerzita v Brně

Obsah
1. Proč kompilovat jádro?
2. Linuxové jádro
2.1. Zdrojové texty
2.2. Konfigurace jádra
2.3. Vlastní kompilace
2.4. Instalace, LILO, Grub, ...
2.5. Poznámky
3. Jádro (Free|Open|Net)BSD
3.1. GENERIC vs. LINT
3.2. Moduly na BSD

1. Proč kompilovat jádro?

Za jakých okolností je vlastně vhodné si kompilovat jádro? Je to vůbec vhodné, nebo jsou lepší jádra dodaná z distribucí?

Každá linuxová distribuce v sobě nějaké linuxové jádro obsahuje. Čím novější distribuce, tím (obvykle) novější jádro, vyladěnější, lepší, s podporou dalších zařízení či technologií. Ale ani při nejlepší vůli se nedá do jádra dostat vše – některé ovladače jsou proprietární a dodávané pouze poté, co za ně zaplatíte, jiné se nedostaly do vybrané verze jádra a je nutné je sehnat jinde, příp. v dané distribuci na podporu vašeho zařízení zapomněli. A nemusí se jednat jen o ovladač zařízení, ale např. i o lepší bezpečnostní model celého jádra nebo o takovou „drobnost“, jakou je jádro překompilované pro váš konkrétní procesor.

Právě v takových případech je nezbytné buď sehnat upravené jádro již překompilované, nebo si je zkompilovat vlastními silami...


2. Linuxové jádro

2.1. Zdrojové texty

První problém, na který je možné narazit, je problém sehnání zdrojových textů.

Jak už jsem nastínil, v každé distribuci je jádro již dodané, jak v podobě binárních souborů, tak i s možností nainstalovat si zdrojové texty, ze kterých bylo získáno. Jenže není zdroj jako zdroj...

Distribuční jádra jsou nezřídka bohatší na ovladače, stabilnější, zkrátka upravená někým, kdo distribuci připravoval a dal si záležet, aby bylo co nejlepší. Naproti tomu tzv. vanilla kernel, např. ze stránek www.kernel.org, tedy původní čisté jádro, je přímým produktem skupiny vývojářů jádra. I ti své práci jistě rozumí. Takže jak se rozhodnout?

Odpověď není úplně jednoduchá, hodně záleží na tom, proč si přejete jádro kompilovat. Jde-li vám o lepší využití vašeho procesoru nebo o zapnutí podpory zařízení, která již v jádře je, doporučuji jádra z distribuce. Jejich autoři si s nimi dali hodně práce a vědí, proč přidávali to či ono vylepšení, příp. některé věci naopak rušili. Distribuční jádra mají snad jen jednu nevýhodu – špatně se do nich přidávají kusy zdrojových textů, které se do jádra nedostaly, ve formě tzv. patchů (český termín zní „záplata“, osobně raději používám onen příšerně počeštěný anglický termín). Jedná se v podstatě o soubor změn proti původnímu zdrojovému stromu. A v tom je právě onen pověstný zakopaný pes – distribuční jádra mají díky velkému množství jiných patchů zdrojový strom odlišný od původního, další patche je tedy nutné upravovat, aby se vůbec daly aplikovat. A některé by mohly nadělat více škody než užitku...

Příklad aplikace patche do zdrojového stromu jádra:


	patch -p0 < nejaky_uzasny_patch.diff
      

Případem, kdy je vhodné vzít čisté zdrojové texty, jsou např. bezpečnostní subsystémy. Ty se dodávají prozatím ve formě patchů, do stabilních verzí jádra nepronikly. A díky tomu, že modifikují bezpečnost linuxového jádra takříkajíc „od podlahy“, mění ve zdrojovém stromu poměrně velký počet souborů.


2.2. Konfigurace jádra

Asi nejnáročnější část celé kompilace jádra je konfigurace toho, co se má přikompilovat a jak...

Nejprve by se možná slušelo vysvětlit poznámku „jak“. Linuxové jádro není ani mikrojádrem, ani vyloženě jádrem monolitickým, dokáže používat tzv. moduly. Při rozhodování o tom, co je vlastně vhodné do našeho jádra přidat, je vhodné řešit i otázku, zda-li ona část má být v jádře k dispozici po celou dobu jeho běhu, či zda docela stačí, aby se zavedla až v okamžiku, kdy to bude třeba. Dobrým příkladem může být modul na souborový systém ISO9660, používaný na klasických CD-ROM médiích. Tento modul je zapotřebí mít v jádře jenom tehdy, pracuje-li se s CD-ROM mechanikou, v opačném případě pouze zbytečně zabírá místo. Existuje i další možnost využití modulů – máte-li Linux na své pracovní stanici, může se vám stát, že budete měnit hardware. V tom případě vám díky předpřipraveným modulům může jádro najít nová zařízení, nakonfigurovat je a staré ovladače nepoužívat – a to bez nutnosti další rekompilace jádra.

Jak už to bývá, moduly nemají jenom výhodné vlastnosti. Z těch negativních stojí za zmínku potenciální nebezpečnost zavádění binárních modulů přímo do jádra pod oprávněním jádra, dále tu jsou pak vyšší paměťové nároky na jednotlivé moduly a vyšší režie při jejich přidávání a rušení. Na specializovaných serverech se často používá monolitické jádro, kdy se do jádra ani podpora modulů nekompiluje. Zároveň je také nutné upozornit, že bez dalších prostředků také není vhodné mít ovladač pro řadič disků a pro kořenový souborový systém jako modul, jádro by totiž nemělo možnost tyto moduly načíst a použít! Je to řešitelné, ale popis řešení by byl nad rámec tohoto článku.

Obvykle se zdrojové soubory nacházejí v adresáři /usr/src/, příp. přímo /usr/src/linux. Vlastní konfiguraci je možné provést několika způsoby, každý se vyznačuje určitými výhodami a nevýhodami:

  • make config je metodou pro drsné a ostřílené typy, kteří se strohého a nekamarádského prostředí nezaleknou. Tato volba se vyptává na každou konfigurační položku a příp. dovoluje vypsat nápovědu k těm, ke kterým existuje. Její výhodou je téměř nulová závislost na dalších knihovnách.

  • make menuconfig již oplývá značnou dávkou komfortu, dle mého názoru naprosto postačující. Používá textové menu, pomocí kterého je možné vybrat položky, určit typ jejich kompilace (přímo nebo modul) a zobrazit k nim nápovědu. Vyžaduje knihovnu pro práci s textovým terminálem.

  • make xconfig spustí grafickou konfiguraci. Zapotřebí jsou jednak knihovny pro X11, funkční X11 server a také jazyk Tcl/Tk. Pohodlí proti textovému rozhraní nejspíš žádné.

  • make oldconfig je poměrně rozumná volba, pokud máte konfigurační soubor ze staršího jádra a chtěli byste tuto konfiguraci přenést i do jádra novějšího – tento příkaz se vás vyptá pouze na položky, které v nové verzi přibyly.

  • Existuje ještě jedna možnost, vhodná pro rychlé úpravy již stávajících konfigurací a je určena těm, kteří jsou již opravdu znalí – přímá editace souboru .config v adresářovém stromu zdrojových textů jádra. V tomto souboru není ani minimální nápověda o jednotlivých položkách, pro člověka neznalého by mohla mít přímá editace neblahé následky.


2.3. Vlastní kompilace

As easy as it gets...

Vlastní kompilace už je potom poměrně jednoduchá, stačí na přikazovou řádku napsat následující posloupnost příkazů


	make dep clean bzImage modules
      
a nechat proběhnout kompilační proces. make dep zjistí závislosti jednotlivých souborů, které se při kompilaci použijí, make clean vyčistí adresářový podstrom od souborů z předchozích kompilací (přikompilováváte-li nový modul k jádru, které jste si už kompilovali, je možné tuto část vynechat, podstatně se zrychlí čas kompilace). make bzImage je příkazem pro kompilaci jádra a následnou komprimaci pomocí bzipu, kvůli výsledné velikosti, a konečně make modules spustí kompilaci modulů.

Na multiprocesorových strojích je možné ještě použít přepínač -j N, kde N se liší podle počtu procesorů, není vhodné překračovat více než jejich dvojnásobek. make potom rozloží kompilaci mezi více procesorů, což znatelně urychluje překlad:


	make -j 4 bzImage modules
      

Jednou z voleb, kterou je ještě možné použít, je make mrproper, který pročistí adresářový strom od zbytečného balastu předchozích kompilací. Pozor! Smaže i konfigurační soubor .config, který jste si předtím pracně stvořili!


2.4. Instalace, LILO, Grub, ...

...aneb konec korunuje dílo

Po úspěšné kompilaci obvykle následuje instalace nového jádra, aby bylo možné je vyzkoušet. V nejjednodušším případě k tomu stačí příkaz


	make install modules_install
      
který se postará jak o instalaci nového jádra (nakopírování obvykle do adresáře /boot nebo přímo do /), tak i o překopírování zkompilovaných modulů (do adresáře /lib/modules/verze_jádra). V některých distribucích dokáže provést i akce nezbytné pro to, aby si i bootloader zjistil pozici nového jádra na disku.

Čerstvě překompilované jádro se na architektuře i386 nachází v adresáři /usr/src/linux/arch/i386/boot/, na jiné platformě bude i386 nahrazeno jejím označením.

V pozici zavaděčů jádra (bootmanagerů, bootloaderů, jak je libo) se v Linuxu dají objevit zhruba dva programy – LILO a GRUB. Oba se neustále vyvíjí, Lilo má podstatně delší historii, ještě donedávna bývalo jediným zavaděčem ve většině distribucí. Při instalaci nového jádra je vhodné (a v podstatě nutné) vždy spustit program lilo, aby zavaděč zjistil novou pozici jádra na souborovém systému.

GRUB je proti tomu novější, s Lilem nemá společného (krom vykonávané funkce) nic, v době bootu již rozumí některým souborovým systémům, dokáže nabootovat široké spektrum operačních systémů, umožňuje editaci bootovacích příkazů, má výstup na seriovou konzoli... Právě pro svou flexibilitu a rozsáhlé možnosti se začíná stávat defaultním zavaděčem novějších verzí známých distribucí.


2.5. Poznámky

  • Jak už bylo uvedeno, není vhodné kompilovat do modulů úplně vše (někdy se brání i jádro samo). Pokud byste dospěli k názoru, že bez zcela modulárního jádra žít nelze, doporučují k pátrání klíčové slovo initrd.

  • Pro práci s moduly slouží příkazy lsmod, modprobe, depmod, insmod, rmmod... První tři jsou obvykle nejpoužívanější.

  • Při kompilaci jádra je dobré dbát na to, aby byl nastaven správný cílový procesor, příp. nižší, než na kterém dané jádro pojede.

  • Editací souboru Makefile je možné pomocí nastavení proměnné EXTRAVERSION připojit k aktuální verzi jádra libovolný řetězec (slouží k odlišení různých jader stejné verze).


3. Jádro (Free|Open|Net)BSD

3.1. GENERIC vs. LINT

Život je změna...

Co člověka zvyklého na poměrně přívětivou linuxovou instalaci jádra zarazí, je už skutečnost, že v adresáři /usr/src/ je příliš mnoho dalších adresářů. Navíc tam není žádný podadresář BSD nebo kernel, po chvíli zoufalého bloudění je však možné narazit v adresáři /usr/src/sys/i386/conf na dva soubory, které se týkají konfigurace jádra. K nim není žádný make menuconfig. Nic. Jen soubory GENERIC a LINT se zákeřně smějí na zoufalého uživatele, kterému dochází skutečnost, že editace textových souborů je zjevně jediným způsobem, jak si nakonfigurovat své jádro pod BSD systémy.

Strašil-li jsem však v minulé části s tím, že linuxový .config je soubor s nulovým obsahem komentářů, je to v BSD systémech naštěstí jinak. Ne-li oba, pak alespoň LINT obsahuje ke každé položce poměrně rozsáhlou nápovědu, která dává poměrně hezký přehled o tom, co by daná položka mohla dělat.

Proč jsou tu ale tyto dva soubory? LINT je soubor, který obsahuje všechny konfigurační volby pro dané jádro. GENERIC pak obsahuje volby, které byly použity pro vygenerování defaultního jádra dané distribuce BSD. Osobně volím způsob, kdy si GENERIC překopíruji do vlastního souboru, ten otevřu, zároveň si otevřu i soubor LINT a pokud najdu volbu, která by byla pro mé nové jádro vhodná, povolím ji v mém novém konfiguračním souboru.

Jak tento soubor s konfigurací použít dál? config <můj soubor>. Ten vygeneruje všechny potřebné volby a na závěr vypíše, do jakého adresáře je nutné se přepnout dál. Poté už je postup v leccčems podobný tomu linuxovému:


	make depend; make kernel
      
následované případným make install.


3.2. Moduly na BSD

Tady je situace také odlišná od Linuxu – ač se při zadávání konfigurace nezadává, jak danou položku přikompilovat, platí jednoduchá zásada. Cokoliv se nepřikompiluje přímo do jádra (a není tedy v povoleno v souboru, který se předhodí configu), se stává automaticky modulem. Na závěr kompilace tedy dostáváte jádro, které přímo obsahuje vše, co jste chtěli, plus sadu modulů, které obsahují zbytek. Hezké v tom, že nemůžete zapomenout na modul, který byste museli později přikompilovávat, nepříjemné z hlediska délky kompilace.