Hlavní navigace

Kompilace jádra: cesta za nepodporovaným hardwarem

13. 7. 2012
Doba čtení: 9 minut

Sdílet

Vlastní jádro na desktopovém počítači ztratilo smysl před dlouhou dobou. Výkon i kapacita paměti je dnes taková, že není potřeba odstraňovat nepotřebné moduly, a když se do toho pustíte, jen stěží poznáte, že se něco změnilo. Existují ale i situace, kdy se bez kompilace jádra neobejdete. Třeba podpora nového hardwaru.

Linux je známý tím, že podpora většiny současného hardwaru se nachází přímo v jádře, a tak když koupíte novou webovou kameru nebo třeba řadič disku, nemusíte do mechaniky strkat CD od výrobce nebo hledat ovladač někde na webu. To sebou nese i nějaké problémy, a to především otevřenost jádra v kontrastu s uzavřeností výrobců. Někteří se smíří s tím, že pokud chtějí, aby byl jejich hardware používán v Linuxu, tak otevřenou trochu kódu a podporu do něj přidají. Jiní neberou Linux jako populární platformu a neočekávají, že by ho jejich zákazníci používali. Pro takový hardware pak dělá ovladače komunita na základě tzv. reverse engineeringu, kdy se sleduje komunikace mezi ovladačem a hardwarem na podporované platformně a pak se vývojáři snaží tuto komunikaci napodobit ve svém linuxovém ovladači.

Za podporu hardwaru

Bohužel se stane, že narazíte na hardware, který podporován není a v takovém případě je jen otázkou náhody, jestli se vám ho podaří rozjet nebo ne. Ještě před týdnem bych řekl, že už jsou pryč doby, kdy se muselo linuxové jádro kompilovat kvůli nějakému konkrétnímu hardwaru. Pak jsem narazil na WiFi kartu TL-WN751ND, která mě vrátila zpět do reality. Tato karta využívá svobodný ovladač ath9k, který se v jádře nachází už několik let. Není to žádná novinka, ale pouze PCI varianta TL-WN781ND. Na našem trhu se nachází někdy od začátku tohoto roku a díky sběrnici se stala nekompatibilní s již existujícím ovladačem. Aby karta fungovala správně, musel jsem udělat malou úpravu jádra, která se navíc objevila teprve nedávno. Bez úpravy po několika sekundách zamrzl systém, což u čerstvě vybalené karty dokáže vzbudit pochyby. Kdyby se mi stejný problém stal po přechodu z jiného operačního systému, kde vše fungovalo, jen těžko bych hledal příčinu a stálo by mě to spoustu času. Naštěstí jsem nemusel pochybovat, jaký hardware problém způsobuje, a začal jsem hledat řešení.

Stejný problém řešilo více uživatelů, a jak bylo řečeno, týká se pouze PCI varianty této karty. PCIe varianta se prodává za stejnou cenu a díky modernější sběrnici vám bude fungovat hned po připojení. Problém je popsaný v bugu #42903 na bugzilla.kernel.org. Nejsem vývojář jádra, ale z dostupných informací jsem pochopil, že karta nemá ráda, když se do ní zapisuje a zároveň se z ní čte, k čemuž může dojít na systémech s více procesory. Řešení je jednoduché, stačí zapnout serializaci operací týkajících se karty. Podobné řešení v ovladači ath9k už pro dva chipsety je, takže stačí jenom přidat identifikátor, což je několik málo bytů. Je škoda, když karta nejede kvůli několika bytům. Bohužel, úprava zdrojového kódu je v tomto případě triviální, ale dostat změnu do binární podoby už chce trochu času, znalostí a trpělivosti.

Bug byl založen 11.3.2012 a řešení se pod ním objevilo 18.6.2012, tedy po nějakých třech měsících. Opravující patch se dostane do jádra 3.5, takže ve většině dalších verzí populárních distribucí bude karta fungovat bez problémů. Jenže kartu mám teď a další verze distribucí budou až někdy kdoví kdy. Když se dostanete do stejného problému ať už s touto WiFi kartou nebo s jiným hardwarem a podaří se vám najít patch, který problém opravuje, máte dvě možnosti:

  • Když je patch už zahrnut v novém a stabilním jádře, můžete přejít na něj
  • Když existuje patch, ale ten ještě není v jádře a není důvod ho nenasadit, můžete si zkompilovat jádro vlastní

V prvním případě můžete využít možností, které nabízí vaše distribuce. Pro Ubuntu jsou nová jádra k dispozici třeba na kernel.ubuntu.com. Kompilace vlastního jádra je ovšem sázka na jistotu a dá vám prostor pro další změny. Zjistěte si také, jak se na patch tváří ostatní uživatelé, zda jim nepřinesl nějaký jiný problém nebo zda nevyžaduje nějakou konkrétní verzi jádra.

Tento článek bude hodně Ubuntu a Debian centrický a zaměřen spíše na začátečníky, kteří se nebojí sáhnout trochu hlouběji. Pokročilí uživatelé v něm třeba také najdou něco nového. Na Ubuntu a Debian se zaměřuji ze třech důvodů. Ubuntu, jeho varianty a Debian jsou skupinou distribucí s velkou základnou uživatelů. Obě distribuce každý den používám a mám s nimi větší zkušenosti než s ostatními. Posledním důvodem je, že se v obou distribucích jádro kompiluje velmi dobře a po zadání jednoho příkazu vám vypadnou balíčky, které stačí nainstalovat jako každé jiné, čímž odpadnou další kroky instalace nového jádra, viz. dále. Navíc se přímo v repositáři nachází zdrojové kódy s distribučními úpravami, ke kterým sedne jako ulitá již existující jaderná konfigurace.

Začínáme

Zdrojové kódy jádra najdeme na kernel.org, kde si můžeme vybrat hned z několika aktuálně podporovaných verzí. Na desktopu nic nezkazíte, když si vyberete nejnovější stabilní verzi (aktuálně 3.4.4). Jádrům z kernel.org se říká vanilla. Než si nějaké vyberete, zvažte, zda opravdu vanilla jádro potřebujete, například kvůli podpoře vašeho hardwaru v novější verzi a podobně. Od vašeho distributora totiž máte k dispozici konfigurační soubor, ve kterém je napsané, co má vaše jádro obsahovat. Když přejdete na jinou verzi, můžete tento soubor použít také, ale chybějící volby je pak lepší doplnit pomocí „make oldconfig“, což už vyžaduje zkušenosti. Nelze na to napsat univerzální návod, protože se volby mění s každou verzí. Proto pokud můžete, sáhněte spíše po zdrojovém kódu jádra vaší distribuce, v Ubuntu a Debianu se schovává v balíčku linux-source.

$ sudo apt-get install linux-source 

Po instalaci se vám v systému objeví soubor /usr/src/linux-source-3.2.0.tar.bz2. Sice jde o symlink na skutečné umístění, ale to nám vadit nemusí. Soubor překopírujeme někam, kde je dostatek místa (~10 GB) a rozbalíme.

# tar xf linux-source-3.2.0.tar.bz2 

Po rozbalení se objeví adresář linux-source-3.2.0. Teď nadešel čas pro aplikování patche, který přidá chybějící podporu pro náš hardware. Někdy jsou patche krátké, v mém případě to byl:

561c561
<             ((AR_SREV_9160(ah) || AR_SREV_9280(ah)) &&
---
>           ((AR_SREV_9160(ah) || AR_SREV_9280(ah) || AR_SREV_9287(ah)) && 

Patche mohou mít různé formáty, přičemž tento není zrovna nejvhodnější, protože neobsahuje název souboru, kterého se týká. Ten je uveden až v diskusi. Nicméně z těch čtyřech řádků lze snadno pochopit, že řádek ((AR_SREV_9160(ah) || AR_SREV_9280(ah)) && se má nahradit ((AR_SREV_9160(ah) || AR_SREV_9280(ah) || AR_SREV_9287(ah)) &&. Změnu jsem tedy provedl ručně.

Když narazíte na patch získaný pomocí „diff -Naur“, což je nejčastější formát, stačí ho nahrát do adresáře se zdrojovým kódem a zavolat:

# patch -p0 < muj_patch.diff 

Parametrem -p říkáme, kolik částí cesty se má v patchi odstranit. Nejlépe když si to ukážeme na příkladu.

--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -532,7 +532,8 @@ static int __ath9k_hw_init(struct ath_hw *ah)

        if (ah->config.serialize_regmode == SER_REG_MODE_AUTO) {
                if (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCI ||
-                   (AR_SREV_9280(ah) && !ah->is_pciexpress)) {
+                   ((AR_SREV_9160(ah) || AR_SREV_9280(ah)) &&
+                    !ah->is_pciexpress)) {
                        ah->config.serialize_regmode =
                                SER_REG_MODE_ON;
                } else { 

Tohle je patch, který byl vložen do ath9k před dvěma lety a pro dvě karty zapíná serializaci. Když na něj použijeme -p0, bude program patch hledat soubor ./a/drivers/net/wireless/at­h/ath9k/hw.c, pokud použijeme -p1, bude hledat ./drivers/net/wireless/at­h/ath9k/hw.c, což je cesta, kterou potřebujeme.

Tímto způsobem lze do jádra přidat kromě podpory hardwaru i další vlastnosti, ale na desktopu není zas tolik příležitostí. Nakonec zkopírujeme konfiguraci aktuálně běžícího jádra do adresáře s novým jádrem:

# cp /boot/config-`uname -a | awk '{print $3}'` linux-source-3.2.0/.config 

Máme-li hotovo, je potřeba nainstalovat pár balíčků, bez kterých se kompilace neobejde:

# apt-get install kernel-package libncurses5-dev fakeroot wget bzip2 build-essential udev 

Máte-li zvídavou povahu a chcete si jádro upravit tak, aby bylo menší, mělo méně modulů a možná dosáhnout i nějaké optimalizace, tak v adresáři s jádrem můžete spustit:

# make menuconfig 

Objeví se vám menu, kde si vyberete části, které chcete mít ve svém jádře zahrnuté. Je to téma na celý seriál a navíc se volby s každou verzí trochu mění, takže uvedu jen odkaz na video, kde Rudolf Marek ukazuje, na co si dát pozor. I když je to video z roku 2005 a je na něm popisováno jádro 2.6.12, najdete tam spoustu informací, které platí i dnes. Pokud jádro trochu osekáte, bude jeho kompilace trvat kratší dobu a nebude potřebovat tolik místa. Kompilace čistého jádra z Ubuntu zabere si vezme přibližně 8 GB prostoru na disku.

V případě, že používáte konfiguraci, která patří staršímu jádru než to, co chcete kompilovat, nic nezkazíte, když spustíte:

# make oldconfig 

Jak je zmíněno výše, zeptá se vás skript na volby, které nejsou v použitém konfiguráku k nalezení, ale nové jádro je obsahuje. Pokud si nejste jistí, můžete vsadit na výchozí hodnoty.

Nyní zbývá poslední krok a to spustit kompilaci. V Ubuntu a Debianu je to zjednodušené díky balíčku kernel-package. Ten obsahuje skripty, které téměř vše udělají za nás. V adresáři se zdrojovým kódem tedy spustíme:

# make-kpkg clean
# time make-kpkg --initrd --append-to-version=-custom kernel_image kernel_headers 

Program time nám na konci řekne, jak dlouho operace trvala a make-kpkg udělá vše potřebné, aby se jádro zkompilovalo a na konci vypadly dva deb balíčky. Jeden bude obsahovat vlastní jádro a druhý hlavičkové soubory, které mohou vyžadovat některé uzavřené ovladače (NVIDIA například). Za označení verze je možné dát vlastní suffix, který bude v tomto případě -custom. Balíčky najdeme o adresář výš a stačí je nainstalovat například takto:

bitcoin_skoleni

# dpkg -i linux-headers-3.2.19-custom_3.2.19-custom-10.00.Custom_amd64.deb linux-image-3.2.19-custom_3.2.19-custom-10.00.Custom_amd64.deb 

Že vám z celého procesu vypadnou dva balíčky, je velmi důležité pro majitele grafických karet s uzavřenými ovladači nebo třeba pro uživatele VirtualBoxu. V obou případech se kompilují jaderné moduly a tím, že jádro nainstalujete jako balíček, dostane slovo framework DKMS, který se o vše potřebné s moduly třetích stran postará, resp. je pro nové jádro zkompiluje během instalace balíčku. Navíc se jádro přidá automaticky do GRUBu, takže instalací balíčků vše končí, můžete svůj stroj restartovat a nabootovat do svého nového jádra.

Shrnutí

Určitě nejde o úplně pohodlný postup a někdo už se určitě chystá v diskusi argumentovat, jak by se to na Windows nestalo. Je potřeba mít na paměti, že do Linuxu se ovladače dostávají jiným způsobem, který umí uživatele od nějakých ovladačů úplně oddělit. Na Windows má zase výrobce jednodušší možnost, jak ovladač k uživateli dostat. Ta je z části dána zvykem než nějakým systémem – nemám ovladač, tak mrknu na web výrobce. Ani jeden způsob distribuce není ideální a mohu jmenovat problémy s různým hardwarem na obou stranách barikády. Je třeba brát také v potaz, že běžný uživatel by si neměl svůj počítač spravovat sám, stejně jako si sám nespravuje své auto, takže pohodlí instalace nějakého hardwaru nemusí mít takovou váhu.

Autor článku

Adam Štrauch je redaktorem serveru Root.cz a svobodný software nasazuje jak na desktopech tak i na routerech a serverech. Ve svém volném čase se stará o komunitní síť, ve které je již přes 100 členů.