Sestavení ovladače
Už máme první část kostry našeho modulu dskel hotovou, pojďme se proto naučit jak modul zkompilovat do podoby objektového souboru jádra.
Trocha teorie
Sestavení modulů (ovladačů) je pro jádro verze 2.6 snadnou záležitostí a to především díky systému sestavení jádra kbuild (kernel build system), který byl oproti jádru 2.4 značně přepracován.
Předtím než se pustíme do kompilace modulů jádra, je vhodné si ověřit, že máme k dispozici kbuildem podporovanou verzi kompilátoru a ostatních nástrojů včetně knihoven. Doporučené verze nástrojů jsou uvedeny v souboru /Documentation/changes, který je součástí zdrojových kódů jádra. Naše nástroje nesmí být starší, než je doporučeno, a občas mohou způsobovat problémy dokonce i výrazně novější nástroje. Ovšem v případě vývojových nástrojů dodávaných jako součást standardních linuxových distribucí nemusíme zpravidla nic řešit.
Postup sestavení modulů do jádra 2.6 vyžaduje, aby byly moduly jádra kompilované vůči kompletnímu stromu zdrojových kódů jádra, které musí být nakonfigurované a sestavené. Často se doporučuje nestahovat zdrojové kódy jádra od dodavatele linuxové distribuce, ale přímo z oficiálních stránek jádrahttp://www.kernel.org, protože pak si můžeme být jisti, že na původní jádro nejsou aplikovány žádné úpravy (patche).
Z vlastní zkušenosti mohu ale potvrdit, že uvedená podmínka - kompilace modulů vůči kompletnímu stromu jádra, které je už sestavené, není v případě jádra ze standardních distribucí tak striktní, jak se uvádí. Například v případě distribuce Debian 6.0 Squeeze si stačí stáhnout hlavičkové soubory jádraJe to balíček linux-headers-$(uname -r). Příkaz uname -r rozvine na verzi jádra a platformu. Celý příkaz pro instalaci hlavičkových souborů jádra by pak byl: apt-get install linux-headers-$(uname -r). a kompilovat modul vůči nim.
Zdrojové kódy modulu jádra můžeme umístit buď do stromu jádra nebo mimo něj. První varianta se používá v případě, kdy potřebujme, aby byl modul sestaven v rámci kompilace celého jádra, například kvůli tomu, že modul má být zakompilován do monolitu jádra. Druhá variantu použijeme tehdy, když chceme držet zdrojové kódy modulů odděleně od stromu jádra. Další text předpokládá druhou variantu.
K sestavení modulů potřebujeme samozřejmě soubor Makefile. Zde je na místě upozornit, že systém sestavení jádra kbuild využívá rozšířenou syntaxi programu GNU make a při sestavování modulu kbuild zasahuje do mechanismu zpracování souboru makefile. Což může být pro vývojáře znalé fungování make a makefile poněkud matoucí.
Pojďme si nyní projít makefile (výpis 11), který řídí sestavení pro našeho modulu dskel, jehož zdrojové kódy jsou umístěné mimo strom jádra.
1obj-m := dskel.o 2 3KDIR ?= /lib/modules/$(shell uname -r)/build 4PWD := $(shell pwd) 5 6all: 7 $(MAKE) -C $(KDIR) M=$(PWD) modules 8 9clean: 10 $(MAKE) -C $(KDIR) M=$(PWD) clean
Makefile je čten programem make nadvakrát. Nejprve je při zavolání programu make z příkazové řádky vyhodnocen řádek 6 - výchozí pravidlo. To způsobí nové rekurzivní volání programu make (řádek 7), kdy je make zároveň nastavena i cesta ke stromu jádra (proměnná KDIR), které systém právě používá. A zároveň i cesta zpět ke zdrojovým kódům modulu jádra (proměnná PWD). Toto druhé volání programu make vyhodnotí řádek 1, tj. zkompiluje modul vůči stromu jádra, který jsem uvedli v proměnné KDIR.
V případě, že se modul skládá z více souborů, tak je do procesu sestavení modulu přidáme vložením řádku:
dskel-y := dalsisoubor1.o dalsisoubor2.o
za řádek 1.
Pokud chceme modul kompilovat vůči jinému jádru, než které systém právě používá, změníme obsah proměnné KDIR. Buď při volání make z příkazové řádky nebo nastavením proměnné prostředí anebo změnou přímo v makefile.
Praktická ukázka
Takže jdeme na to - sestavíme si svůj první modul. Uvnitř adresáře se zdrojovým kódem modulu dskel zadáme příkaz:
$ make
a měli bychom vidět následující výpis (obrázek 1.5).
Po sestavení modulu jej můžeme zkusit zavést (jako uživatel root). Stále jsme v adresáři se zdrojovým kódem modulu, takže zadáme příkaz:
# insmod dskel.ko
Jádro nezobrazí žádnou zprávu, což je dobré znamení. Že je modul úspěšně zaveden, zjistíme z výpisu zavedených modulů příkazem:
# lsmod | grep dskel
kde si příkazem grep vyfiltrujeme jen informace o našem modulu. Náš modul by se měl také objevit v souboru /proc/devices, kde lze zároveň i zjistit, které hlavní číslo mu bylo jádrem přiděleno při registraci major-minor páru.
Uvedené příkazy včetně reakcí systému jsou ukázány na obrázku 1.6.