čtvrtek 30. července 2009

Linux Kernel: Jak zkompilovat jaderný modul

Kompilace programů ze zdrojových kódů je činnost ke které se většina uživatelů příliš nemá, či je to dokonce přímo odrazuje. A to právem. Uživatel by se v ideálním případě s tímto slovem ani setkat neměl a to nemluvě o kompilaci jádra. Bohužel, svět není ideální a tak se občas naskytnou důvody si čas od času trošku zakompilovat. K zamyšlení ovšem je, za se do takové situace uživatel vůbec dostane. Vzhledem k mé vrozené lenosti a tendencím si věci příliš zjednodušovat, předpokládejme, že nedostane.

Tak tedy po tom, co jsem ze sebe smyl povinnost vysvětlovat pojem kompilace a její užitečnost můžeme se pustit rovnýma nohama do toho. Řeč bude o kompilace jaderného modulu. Může jít o modul jakéhokoli projektu, který se prozatím nedostal, a snad ani nikdy nedostane do jádra, modul, který již součástí jádra je, ale váš distributor se jej rozhodl nezahrnout a nebo poslední a pro mne ta nejzajímavější možnost, modul se nachází ve stromě staging a nebyl zakompilován (což je prozatím většina).

Trocha teorie o tom co to vlastně ten staging tree je k nalezení na stránkách kerneltrap.org. V podstatě jde o ovladače, které se prozatím nedostaly do hlavního stromu jádra, ale mají na to jisté ambice. Tento strom byl do jádra vpraven s vydáním 2.6.28 a klade si za cíl vylepšit (již tak velmi dobrou) situací ovladačů v jádře. Jelikož co je v jádře to je na očích jeho vývojářů a co je na očích vývojářů jádra má většinou tendence vzkvétat. No...dobře možná troch přeháním, ale znáte to, je lepší být in, než out.

První co budete muset provést je rozhodnout se proti jakému jádru budete chtít modul zkompilovat. Většina lidí zřejmě sáhne po distribučním jádře v takové verzi, která je momentálně aktuální a kterou má nainstalovanou. Je to dobrá volba, pokud chcete použít modul na svém počítači. Zdrojáky jádra (toho aktuálního) pak můžete jednoduše získat z vašeho repozitáře (předpokládám Debian, nebo některou jeho mutaci například Ubuntu) :

apt-get source linux-image-$(uname -r)
# ke kompilaci budete potřebovat také tyto balíčky
apt-get install libncurses5-dev fakeroot wget bzip2
Příkaz uname -r samozřejmě doplní označení aktuálně použitého jádra a nemusí to tedy přepisovat. Celý tento příkaz můžete samozřejmě spustit jako root, ale lepší je se privilegií zbavit a pracovat po obyčejným uživatelem, což je mimochodem při kompilaci vždy dobrá volba. Práva roota totiž nejsou zapotřebí.

Za zmínku stojí fakt, že jádro disponuje schopností zkontrolovat modul při zavádění, zda byl opravdu sestaven oproti stejné verzi jádra (za předpokladu že byla tato schopnost zakompilována). Není tedy možné zavést modul do jádra, do kterého prostě nepatří. (To ovšem není zcela přesné viz dále).

Než se pustíte do samotné kompilace budete zřejmě potřebovat pár věcí :

aptitude install 

Jakmile jsou zdrojáky staženy můžete je s klidným srdcem rozbalit. Teď přichází na řadu příprava pro kompilaci modulu. V prvé řadě je třeba nastavit zdrojáky tak, abychom vůbec mohli modul zkompilovat. Pokud se module nalézá v jádře, jednoduše spustíme
make menuconfig
počkáme až se provedou přípravy a následném menu vybereme a zaškrtneme modul který budeme chtít kompilovat. Nastavení uložíte jako .config.

Nyní je potřeba připravit jádro na kompilaci modulu. Obojí může trochu trvat. Pro ty kteří vlastní více procesorových jader (poznáme v /proc/cpuinfo) má make parametr -j který spustí více souběžných procesů. Více informací hledejte v man make.

make prepare
make modules_prepare

Původně jsem předpokládal, že v tomhle bodě již můžu začít s kompilací. Ovšem výsledkem by byl nepoužitelný modul. Důvodem je výše zmiňovaná kontrola kompatibility Modversions. Zjednodušeně, jak jsem to pochopil já, slouží verzování modulu k tomu, aby bylo možno zavádět do jádra binární moduly sestavené pro jiné jádro, ovšem v případě, že se nezměnilo API jaderných funkcí, které modul používá. Funguje to tak, že každému exportovanému symbolu z jádra je přiřazen určitý kontrolní součet. Podobně je to s prototypy a definicemi symbolů v modulu a pokud tyto součty navzájem souhlasí, je možné modul bezpečně zavést.

V mém případě jsem ale modul zkompiloval bez vytvoření Module.symvers, což mělo za následek odmítnutí modulu, jelikož distribuční jádro Ubuntu je zkompilováno s podporou verzování modulů a toto verzování vyžaduje. Vše napravíte následujícím příkazem. Který soubor Module.symvers vytvoří.

make bzImage
Může to chvilku trvat, takže opět doporučuji majitelům vícejádrových procesorů parametr -j. Pokud se vám něco nepovedlo, nebo potřebujete začít znova, zdrojáky zaručeně pročistí Mr. Proper :)
make mrproper
make help   # pro výpis použití

Posledním krokem je pak kompilace samotného modulu. To již netrvá tak dlouho a výsledkem je použitelný modul, který můžete zavést jednoduše pomocí insmod.

make M=/cesta/k/modulu/ke/kompilaci   # např drivers/staging/cokoli

V tomto krátkém článku jsem se snažil shrnout jednoduchý a vcelku univerzální postup jak si zkompilovat modul do svého jádra. Existuje samozřejmě řada jiných možností a internet se těmito návody jenom hemží, ale tento postup se mi nejednou osvědčil i tam, kde ostatní selhali.Ovšem na druhou stranu, nekamenujte mne když něco nepůjde jak má, chyba je pravděpodobně ve vašem přijímači:) - ale klidně můžete napsat o radu, pokud toho budu schopen rád poradím. A nejen to, ještě raději se i přiučím, proto pokud máte faktické připomínky k tomuto článku, prosím neváhejte a napište mi a pokusíme se uvést věci na pravou míru.

Zajímavé odkazy: