KAPITOLA 9 Moduly jádra Linuxu V předchozích dvou kapitolách jste zjistili, jak probíhá vývojový proces pro linuxové jádro. Seznámili jste se s vývojovou komunitou upstreamu jádra a zjistili jste, že projekt jádra se nachází v neustálém vývoji. Tato devátá kapitola má za úkol položit základy, které jsou nezbytné pro skutečné vytváření vašich vlastních modulů jádra. Tyto moduly jsou často označovány jako ovladače jádra, protože většina modulů je určena pro podporu specifických zařízení. Už jste napsali jednoduchý modul jádra nazvaný plp v kapitole sedm. Tento jednoduchý natažitelný modul prostě vytiskl pozdrav do kernel buffer ringu (zobrazený pomocí příkazu dmesg) a demonstroval základní koncepty psaní modulů, bez hlubšího záběru. Tato kapitola vychází z příkladu předchozí kapitoly a uvádí daleko víc konceptů, které budete potřebovat při psaní skutečných modulů jádra pro reálné uživatele. Ne všechen vývoj jádra ovšem probíhá ve formě modulů třetí strany. Existuje mnoho částí jádra, které nelze modifikovat pomocí samotných natažitelných modulů, protože vyžadují změny v kódu jádra namísto jednoduchého načtení příslušného modulu. Protože v této kapitole poprvé okusíte příchuť vývoje jádra ve formě natažitelných modulů, nemusíte mít strach, že bychom na konci této kapitoly rovnou přešli k úpravám základních algoritmů jádra. Abyste něco takového mohli provádět, budete muset získat ještě velké množství vědomostí, protože se jedná o opravdu složitou látku, která se nedá naučit za týden.
Jak moduly pracují Jádro Linuxu je schopno rozšíření za běhu pomocí natažitelných modulů. Dynamicky načítané moduly linuxového jádra (neboli LKM, Linux Kernel Modules) jsou velmi podobné ovladačům, které můžete získat pro Microsoft Windows, některé proprietární systémy UNIX (jako například Sun Solaris) nebo Mac OS X. LKM jsou zkompilovány pro konkrétní sadu zdrojů jádra a částečně linkovány do souboru objektu modulu, který má příponu .ko. Tyto soubory jsou načteny do běžícího jádra Linuxu prostřednictvím speciálních systémových volání.
300
Kapitola 9 – Moduly jádra Linuxu
Když je modul načten do jádra, jádro pro něj alokuje dostatek paměti a extrahuje informace ze sekce "modinfo" ELF1, která byla přidána k modulu během kompilace, aby mohly být splněny požadavky daného modulu. V době načtení je modul konečně linkován k exportovaným verzím funkcí běžícího jádra, k nimž se vztahují jeho závislosti a veřejně exportované symboly modulu se stanou součástí běžícího jádra. Tohle znamená, že modul se stane částí jádra. 1
Jak už bylo vysvětleno v kapitole 2, Linux široce využívá binární formát ELF jako de facto standard pro všechny uživatelské programy (a nahrazuje zastaralý formát a.out). Formát ELF specifikuje standardní kontejner pro binární data (včetně programů), která jsou rozdělena do mnoho různých sekcí.
V tuto chvíli nepochybně ve vašem systému využíváte některé natažitelné moduly jádra, protože jádro vašeho Linuxu bylo určitě zkompilováno tak, aby tyto natažitelné moduly podporovalo (pokud používáte nějakou standardní distribuci Linuxu). Vás systém má tudíž načteno několik modulů, aby bylo možné podporovat hardware detekovaný při startu počítače. Tyto moduly byly načteny automatickým správcem zařízení jako je například udev (který spravuje nejenom souborový systém v /dev, ale také načtené moduly pro nově detekovaná zařízení). Seznam aktuálně načtených modulů si můžete prohlédnout pomocí příkazu lsmod: $ /sbin/lsmod Module
Size
Used by
procfs
1732
0
char
2572
0
raw
7328
0
tun
9600
0
snd_rtctimer
2636
0
vmnet
35172
13
vmmon
111244
0
capability
3336
0
commoncap
5504
1
thermal
11272
0
fan
3588
0
button
5200
0
processor
19712
1
ac
3652
0
battery
7876
0
8250_pnp
8640
0
8250
25492
3
8250_pnp
serial_core
18944
1
8250
floppy
59972
0
pcspkr
1860
0
rtc
10868
1
usbnet
14024
0
capability
thermal
snd_rtctimer
Linux PROFESIONÁLNĚ – programování aplikací sd_mod
16704
2
eth1394
18376
0
ohci1394
33268
0
ieee1394
292568
2
emu10k1_gp
3072
0
ehci_hcd
32008
0
usb_storage
64128
1
scsi_mod
94760
2
ohci_hcd
19652
0
via686a
16712
0
i2c_isa
3968
1
uhci_hcd
31504
0
usbcore
120452
6
parport_pc
38276
0
parport
33608
1
shpchp
44512
0
pci_hotplug
11780
1
tsdev
6336
0
md_mod
64916
0
dm_mod
54552
0
psmouse
36420
0
ide_cd
38212
0
cdrom
37152
1
snd_cmipci
32288
1
gameport
12808
3
emu10k1_gp,snd_cmipci
snd_opl3_lib
9472
1
snd_cmipci
snd_mpu401_uart
6720
1
snd_cmipci
snd_emu10k1_synth
7040
0
snd_emux_synth
36160
1
snd_emu10k1_synth
snd_seq_virmidi
6464
1
snd_emux_synth
snd_seq_midi_emul
6784
1
snd_emux_synth
snd_seq_oss
32960
0
snd_seq_midi
7328
0
snd_seq_midi_event
6400
3
snd_seq_virmidi,snd_seq_oss,snd_seq_midi
snd_seq
50512
8
snd_emux_synth,snd_seq_virmidi,
eth1394,ohci1394
sd_mod,usb_storage
via686a usbnet,ehci_hcd,usb_storage,ohci_hcd,uhci_hcd parport_pc shpchp
ide_cd
snd_seq_midi_emul,snd_seq_oss, snd_seq_midi,snd_seq_midi_event snd_emu10k1
119652
5
snd_emu10k1_synth
snd_rawmidi
21600
4
snd_mpu401_uart,snd_seq_virmidi, snd_seq_midi,snd_emu10k1
snd_seq_device
7628
8
301
snd_opl3_lib,snd_emu10k1_synth, snd_emux_synth,snd_seq_oss,snd_seq_midi,
302
Kapitola 9 – Moduly jádra Linuxu snd_seq,snd_emu10k1,snd_rawmidi
snd_ac97_codec
94304
1
snd_emu10k1
snd_pcm_oss
50784
1
snd_mixer_oss
17728
3
snd_pcm_oss
snd_pcm
83460
4
snd_cmipci,snd_emu10k1,snd_ac97_codec,
snd_timer
22404
5
snd_ac97_bus
2176
1
snd_ac97_codec
snd_page_alloc
8904
2
snd_emu10k1,snd_pcm
snd_util_mem
3776
2
snd_emux_synth,snd_emu10k1
snd_hwdep
7840
3
snd_opl3_lib,snd_emux_synth,snd_emu10k1
snd
47844
20 snd_cmipci,snd_opl3_lib,snd_mpu401_uart,
snd_pcm_oss snd_rtctimer,snd_opl3_lib,snd_seq, snd_emu10k1,snd_pcm
snd_emux_synth,snd_seq_virmidi,snd_seq_oss, snd_seq,snd_emu10k1,snd_rawmidi, snd_seq_device,snd_ac97_codec, snd_pcm_oss,snd_mixer_oss,snd_pcm, snd_timer,snd_hwdep soundcore
8224
4
snd
r128
46912
1
drm
68308
2
r128
agpgart
29592
1
drm
8139too
23424
0
mii
5120
1
8139too
Jak sami vidíte, výstup je docela rozsáhlý a to se jedná o docela obyčejnou pracovní stanici. Výstup příkazu lsmod ukazuje, že v tomto linuxovém systému je načteno celkem 77 modulů. Některé z těchto modulů nemají jiné moduly, které by používaly jejich symboly exportované do jmenného prostoru jádra (znak nula ve třetím sloupci), zatímco jiné vytvářejí komplexní hierarchie zásobníků modulů – podívejte se například na ovladač zvuku ALSA, který poskytuje podporu pro dvě nainstalované zvukové karty (Creative Labs emu10k chipset a C-Media cmpci chipset) nebo na několik nainstalovaných USB modulů.
Rozšíření jmenného prostoru jádra Natažitelné moduly jádra Linuxu často exportují nové funkce pro použití jinými částmi jádra (dále v této kapitole se dozvíte, jak tato činnost probíhá). Tyto nové symboly budou zobrazeny uvnitř procfs prostřednictvím /proc/kallsyms (pokud vaše jádro obsahuje podporu pro toto sestavení) společně s adresami nových symbolů, které byly přidány do obrazu jádra. Zde je výpis z běžícího jádra pro /proc/kalsyms. Nejprve začátek tabulky symbolů: $ cat /proc/kallsyms | head c0100220 T _stext
Linux PROFESIONÁLNĚ – programování aplikací
303
c0100220 t rest_init c0100220 T stext c0100270 t do_pre_smp_initcalls c0100280 t run_init_process c01002b0 t init c0100430 t try_name c0100620 T name_to_dev_t c01008e0 t calibrate_delay_direct c0100a60 T calibrate_delay
A nyní následující spodní část tabulky symbolů jádra. Protože nové symboly jsou vždy přidávány na konec tabulky, můžete v tomto výstupu vidět několik symbolů modulů (jméno modulu je vypsáno v hranatých závorkách – v tomto případě pro správu zařízení MII Ethernet): $ cat /proc/kallsyms | tail e0815670 T mii_check_media
[mii]
e08154f0 T mii_check_gmii_support
[mii]
c023d900 U capable
[mii]
e0815600 T mii_check_link
[mii]
c011e480 U printk
[mii]
e08155a0 T mii_nway_restart
[mii]
c032c9b0 U netif_carrier_off
[mii]
e0815870 T generic_mii_ioctl
[mii]
c032c970 U netif_carrier_on
[mii]
e0815000 T mii_ethtool_gset
[mii]
Jak už jsme si uvedli výše, natažitelné moduly jsou uvedeny na konci výpisu tabulky se symboly jádra, přičemž jejich jméno je uvedeno v hranatých závorkách (viz [mii]). Také je snadno rozeznáte podle adresy v prvním sloupci výpisu. Protože jádro Linuxu je obvykle linkováno tak, aby běželo z 3 GB virtuální paměti, vestavěné symboly se objevují s malým offsetem nad 3 GB (0xc0000000). Načtené moduly ovšem existují v paměti, která je alokována pro jádro – v tomto případě nad 0xe0000000. To proto, že paměť pro moduly je alokována jádrem za běhu. Tento příklad byl záměrně upraven tak, aby vám dával větší smysl. Jádro obsahuje moduly, které nejsou šířeny pod licencí GPL, a jež jsou načteny výhradně kvůli podpoře oblíbeného komerčního produktu sloužícího k vytvoření virtuálního stroje. Stejná situace nastává v případě moderních grafických chipsetů. Vývojářská komunita ovšem nesnáší všechny moduly, které nejsou šířeny pod GPL, takže abyste mohli získat požadovanu podporu od vývojářské komunity, měli byste takové moduly odstranit z vašeho testovacího stroje.
304
Kapitola 9 – Moduly jádra Linuxu
Garance kompatibility modulů? Neexistuje! Na rozdíl od jiných operačních systémů Linux záměrně neposkytuje nějaký standardizovaný model ovladače, který byste mohli použít jako vzor při kompilaci vašich vlastních modulů za účelem dosažení kompatibility mezi aktuální verzí linuxového systému a budoucími verzemi. To znamená, že Linux je optimalizován pro případy, ve kterých je vždy dostupný zdrojový kód modulu (což by normálně mělo platit, protože mnoho lidí považuje moduly ovladačů, jež nejsou šířeny pod GPL licencí, za omezování práv vývojářů jádra, takže při psaní vašich modulů vám příliš nedoporučujeme experimentovat s binárními ovladači). Všeobecně byste neměli předpokládat, že moduly, které byly zkompilovány pro váš konkrétní linuxový systém, budou ve zkompilované binární formě běžet i na nějakých jiných linuxových strojích. Tyto moduly budou obvykle před svým spuštěním vyžadovat novou kompilaci ze zdrojů daného linuxového stroje. Existují ovšem významné výjimky – jádra dodavatelů Linuxu jsou často kompatibilní s jinými.
Nalezení kvalitní dokumentace Jedním z největších problémů, kterému musí čelit noví vývojáři pro Linux (a zvláště noví vývojáři pro jádro), je nalezení kvalitní API dokumentace pro každou z mnoha stovek a tisíců funkcí, s nimiž musí pracovat, aby využili možnosti, jež jsou jim nabízeny linuxovým jádrem. Pokud každodenně nepracujete s jádrem Linuxu, nedá se předpokládat, že byste pro tuto chvíli měli nějaké extra znalosti, takže práce s dobrou dokumentací bude nepostradatelnou součástí vaší práce. Jak jistě tušíte, problém spočívá v tom, že neexistuje dostatek kvalitní dokumentace. Linux se neustále vyvíjí, takže i dobrá dokumentace může být zastaralá již v okamžiku, kdy ji čtete. Povšimněte si, že autoři této knihy se ani nepokoušejí napsat dokumentaci k jádru Linuxu, takže tato kniha se spíše snaží vysvětlit povahu jádra a nabídnout příklady, které názorně demonstrují koncepty, jež můžete sami použít. Hlavními zdroji dokumentace ohledně vytváření nových modulů jádra jsou tak již existující moduly jádra2. 2
To znamená linuxové jádro, které je dostupné na adrese http://www.kernel.org.
Manuálové stránky jádra Linuxu Situace ovšem není tak špatná, jak by se mohlo zdát z předchozích odstavců. Existuje totiž jeden dobrý zdroj dokumentace k API – manuálové stránky jádra Linuxu. Tato dokumentace se snaží být za všech okolnosti co nejvíce aktuální a je dostupná na webu kernel.org, společně s mnoha jinými zdroji: http://www.kernel.org/pub/linux/docs/manpages. Tyto manuálové stránky si můžete ze zdrojových souborů jádra klidně vybudovat i sami. Stačí použít cíl mandocs příkazu make:
Linux PROFESIONÁLNĚ – programování aplikací
305
$ make mandocs MAN Documentation/DocBook/usb.9 Writing struct_usb_ctrlrequest.9 for refentry Writing struct_usb_host_endpoint.9 for refentry Writing struct_usb_interface.9 for refentry etc.
Vytvořené manuálové stránky pro jádro následně nainstalujte prostřednictvím cíle installmandocs příkazu make, aby mohly být dostupné pro příkaz man. Vaše linuxová distribuce může obsahovat balíčky s již vybudovanou verzí těchto manuálových stránek pro jádro Linuxu (společně s obvyklými manuálovými stránkami Linuxu), takže možná ani nebudete muset provádět jejich budování. Pokud máte distribuci Debian či Ubuntu (nebo distribuci odvozenou z nich), zkuste se po těchto balíčcích podívat.
A zde je jednoduchá ukázka, jak si můžete na vašem systému vyvolat manuálovou stránku pro funkci vmalloc(), která slouží pro alokaci paměti jádra. $ man vmalloc VMALLOC(9) LINUX VMALLOC(9) NAME vmalloc - allocate virtually contiguous memory SYNOPSIS void * vmalloc (unsigned long size); ARGUMENTS size allocation size DESCRIPTION Allocate enough pages to cover size from the page level allocator and map them into contiguous kernel virtual space. For tight cotrol over page level allocator and protection flags use __vmalloc instead. DESCRIPTION Allocate enough pages to cover size from the page level allocator and map them into contiguous kernel virtual space. For tight control over page level allocator and protection flags use __vmalloc instead. Kernel Hackers Manual July 2006 VMALLOC(9)
Tyto manuálové stránky vám budou pravděpodobně velmi užitečné, až začnete pracovat s linuxovým jádrem. Pokud máte odpovídající znalosti, nezapomeňte pomoci ostatním zdokumentovat ty části jádra, kde nedostatek informací způsobuje bolení hlavy mnoha vývojářům. Pokud každý vývojář pomůže zdokumentovat alespoň nějaký kousek chybějící části, bude vývoj jádra pro ostatní vývojáře mnohem méně komplikovanější.
306
Kapitola 9 – Moduly jádra Linuxu
Psaní modulů jádra Linuxu V kapitole 7 jsme vám na velmi jednoduchém příkladu předvedli ukázku vývoje pro jádro. Tento příklad předvedl, jak jsou kompilovány moduly jádra a jak jsou načteny do (binárně kompatibilního) běžícího jádra. Pomocí funkce jádra printk() mohl modul provádět zápis do logu při svém načtení či uvolnění z paměti jádra. V tomto okamžiku byste měli znát základní proces kompilace jádra a kompilaci modulů pro jádro. Pokud jste kapitolu 7 z nějakého důvodu vynechali, podívejte se zpět a ujistěte se, že těmto popsaným postupům rozumíte. Tato kapitola se bude věnovat základům psaní užitečných modulů jádra a bude se vás snažit vybavit schopností samostatně získat nové znalosti prostřednictvím dalších dostupných zdrojů. V rozsahu této jedné kapitoly bohužel není možné popsat všechny možné problémy, na které můžete narazit při vytváření kódu jádra (na něco takového by pravděpodobně nestačila ani celá kniha), nicméně informace, jež zde naleznete, byste měli být schopni vcelku bez problémů využít ve vaší programátorské praxi (za předpokladu, že budete studovat existující zdrojové kódy a používat už dříve zmiňovanou dokumentaci pro vytváření kompletních modulů linuxového jádra). Vaše programování by nemělo spočívat pouze ve vývoji natažitelných modulů, které budou drženy mimo hlavní linii vývoje Linuxu. Linux jako takový je mnohem více než jádro, pro které vytváříte ovladače – je to celá komunita. Vaším cílem by vždy mělo být dostat nový kód co nejdříve do hlavní vývojové linie jádra. Je možné, že při vaší vývojářské práci zjistíte, že některé věci, které si přejete udělat, nelze implementovat pomocí modulů, protože vyžadují změny v základním kódu samotného jádra. To je ovšem problematika, které se tato kniha specificky nevěnuje, protože změny základního kódu s sebou nesou obrovské množství otázek, jejichž zodpovězení je lepší nechat na větších znalcích z této oblasti.
Než začnete S odpovídajícím vývojovým a testovacím prostředím jste se seznámili v kapitole 7. Pamatujte si, že i ti nejzkušenější linuxoví odborníci dělají chyby, dopouštějí se různých překlepů, či provádějí jiné činnosti, které mají za následek destabilizaci jejich testovacího prostředí. Jakmile ztratíte přehled o ukazatelích a jiných zdrojích uvnitř jádra, jsou pro vás ztraceny navždy. Při zápisu dat do paměti můžete také omylem odstranit celý obsah paměti RAM, takže už vám nic nebude stát v cestě. Pokud budete testovat kód jádra na stejném počítači, na kterém provádíte jeho vývoj, s velkou pravděpodobností nakonec skončíte s ošklivými pády systému a neustálým rebootováním, takže něco takového prostě nedělejte. Pro testování vašeho kódu si pro začátek obstarejte nějaký starší, nicméně stále funkční stroj, který je určen na vyhození. Pokud budete později potřebovat pro váš vývoj nějaký specifický hardware, nezapomeňte ho přidat k vhodnému počítači. Důrazně vám radíme, abyste na vašem vývojovém stroji používali síťové sdílení pro rychlé zpřístupnění jádra a modulů vašemu testovacímu počítači – pro další podrobnosti se podívejte do online nápovědy. A na závěr tohoto úvodního textu musíme zmínit jeden důležitý bod, který vyžaduje neustálé opakování – nikdy nepředpokládejte, že váš testovací stroj bude stabilní.
Linux PROFESIONÁLNĚ – programování aplikací
307
Základní požadavky modulů Každý modul jádra Linuxu vyžaduje definovaný vstupní a výstupní bod. Tyto dva body popisují funkce, které budou volány při načtení a uvolnění modulu z paměti. Každý modul by navíc měl specifikovat svého autora, číslo verze a poskytnout stručný popis služeb, které zpřístupňuje, aby uživatelé, administrátoři a vývojáři mohli rychle získat představu o účelu zkompilovaných modulů prostřednictvím standardních utilit, jako například modinfo (viz kapitola 7 a 8). A zde je příklad holého minima pro natažitelný modul, který může být zkompilován: /* * plp_min.c - Minimal example kernel module. */ #include
#include #include /* function prototypes */ static int __init plp_min_init(void); static void __exit plp_min_exit(void); /* * plp_min_init: Load the kernel module into memory */ static int __init plp_min_init(void) { printk("plp_min: loaded"); return 0; } /* * plp_min_exit: Unload the kernel module from memory */ static void __exit plp_min_exit(void) { printk("plp_min: unloading"); } /* declare init/exit functions here */ module_init(plp_min_init); module_exit(plp_min_exit); /* define module meta data */ MODULE_AUTHOR("Jon Masters <[email protected]>"); MODULE_DESCRIPTION("A minimal module stub"); MODULE_ALIAS("minimal_module"); MODULE_LICENSE("GPL"); MODULE_VERSION("0:1.0");
308
Kapitola 9 – Moduly jádra Linuxu
Tento modul zkompilujte obvyklým způsobem: $ make –C 'uname –r'/build modules M=$PWD
A následně se podívejte na výstup z běžícího příkazu modinfo použitého na tento modul: $ /sbin/modinfo plp_min.ko filename:
plp_min.ko
author:
Jon Masters <[email protected]>
description:
A minimal module stub
alias:
minimal_module
license:
GPL
version:
0:1.0
vermagic:
2.6.15.6 preempt K7 gcc-4.0
depends: srcversion:
295F0EFEC45D00AB631A26C
Povšimněte si, že verze modulu je zobrazena společně s vygenerovaným kontrolním součtem. Zvykněte si vždy přidávat k vašim modulům verzi, aby vývojáři, kteří budou později balíčkovat vaše moduly, mohli používat nástroje jako modinfo pro automatické získání těchto informací.
module.h Všechna linuxová jádra musí obsahovat společně s dalšími hlavičkovými soubory, které používají. Module.h definuje řadu maker, která jsou používána kompilačním systémem jádra pro přidání nezbytných metadat ke zkompilovaným souborům modulů. Když si prohlédnete vygenerované zdrojové soubory v C, které končí na .mod.c, a jež vznikly během kompilace, můžete získat představu o tom, jakým způsobem jsou tato makra používána. Následující tabulka popisuje některá speciální hlavičková makra a funkce, jež jsou dostupné. Makra a funkce, které jsou uvedeny v této tabulce, by měly být použity v každém modulu vždy, když je to vhodné. Obvykle jsou vloženy na konec zdrojového kódu modulu. makro/funkce
Popis
MODULE_ALIAS (_alias)
Poskytuje alias pro uživatelský prostor. Dovoluje nástrojům, které načítají a uvolňují moduly, rozpoznat alias. Modul intel-agp (stejně jako mnoho ovladačů pro PCI) specifikuje řadu identifikátorů PCI zařízení, které jsou podporovány ovladačem, a jež mohou nástroje uživatelského prostoru použít pro automatické nalezení ovladače: MODULE_ALIAS ("pci:v00001106d00000314sv *sd*bc06sc00i00*")