1 [[!meta title="Embedded Linux"]]
8 Open source projekty se často nepoužívají osamoceně, ale v kombinaci s
9 jinými OSS projekty, čímž vznikají tak tzv. OSS stacky. Asi
10 nejznámějším stackem je LAMP – Linux, Apache, MySQL, PHP. Na dnešním
11 cvičení se seznámíme s dalším, velmi často používaným, stackem
12 [Linux][kenrel] + [BusyBox][bb] (+[Dropbear][dropbear] SSH server).
14 [BusyBox][bb] je sada UNIXových uživatelských nástrojů (shell, editor,
15 utility jako ls, mkdir, …) zkompilovaná do jedné binárky. V kombinaci
16 s jádrem Linuxu tak dostáváme kompletní operační systém s poměrně
17 malými nároky na paměť. Díky tomu se tato kombinace často používá ve
18 vestavěných (embedded) aplikacích jako například
19 [WiFi routery či ADSL modemy][owrt].
21 V tomto cvičení si zkusíte vytvořit kompletní open source operační
22 systém z Linuxového jádra a uživatelského prostředí tvořeného právě
23 BusyBoxem. Dále si vyzkoušíte naprogramovat jednoduchý modul do jádra.
25 [kenrel]: http://kernel.org/
26 [bb]:http://busybox.net/
27 [owrt]:http://www.openwrt.org/
28 [dropbear]:http://matt.ucc.asn.au/dropbear/dropbear.html
33 1. Stáhneme [zdrojové kódy][bbgit] projektu [BusyBox][bb]:
35 git clone git://busybox.net/busybox.git --reference /usr/src/busybox.git
38 Protože se jedná o aktuální vývojový snapshot, je možné, že se
39 při překladu, instalaci nebo používání vyskytne chyba. Naší výhodou
40 však je, že máme k dispozici kompletní historii projektu
44 a můžeme si vybrat verzi, kde se chyba nevyskytuje. Například
46 git checkout -f 1_18_3
48 [bbgit]:http://git.busybox.net/busybox/
50 2. Zkonfigurujeme jak chceme BusyBox přeložit.
54 Vystačíme s výchozí konfigurací, takže zvolit `Exit` a odpovědět
55 `Yes`, že chceme konfiguraci uložit.
57 3. Kompilaci provedeme tradičně příkazem
65 nainstalujeme busybox do adresáře `./_install`. Všimněte si, že se
66 tam nachází pouze jedna binárka `bin/busybox` a všechno ostatní
67 jsou pouze symbolické odkazy na tuto binárku.
69 Protože neprovádíme tzv. *křížový překlad*, který je běžný pro v
70 případě vestavěných zařízení, můžeme výsledek hned otestovat
71 například spuštěním shellu: `./_install/bin/sh` (ukončíme ho např.
74 V případě skutečného vestavěného systému bychom museli pokračovat
75 dál a busybox otestovat až po nabootování na cílovém hardwaru.
77 5. Pokud máte na vašem počítači práva superuživatele root, můžete
78 otestovat BusyBox v chroot prostředí, t.j. se stejným jádrem jako
79 právě běží na vašem počítači, ale se souborovým systémem tvořeným
82 # chroot _install /bin/sh
84 Fungovat to ale nebude, protože ke spuštění BusyBoxu jsou potřeba
85 knihovny, které v nejsou v adresáři `_install` dostupné.
87 6. Chybějící knihovny zjistíte příkazem
89 ldd _install/bin/busybox
91 Tyto knihovny musíte nakopírovat do adresáře `_install`
94 cp /lib/i686/cmov/libm.so.6 /lib/i686/cmov/libc.so.6 /lib/ld-linux.so.2 _install/lib
96 Nyní už můžete spustit BusyBox v chroot prostředí.
98 5. Nejjednodušší možnost jak nabootovat do právě vytvořeného
99 uživatelského prostředí je uložit ho ve formátu pro Linuxový
100 startovací RAM-disk a nabootovat Linux s tímto RAM-diskem.
102 Aby vše fungovalo jak má, kromě souborů v adresáři `_install` musí
103 RAM-disk obsahovat i někoik položek v adresáři `/dev` pro přístup k
104 virtuálním terminálům.
106 1. Pokud máte root práva, použijte ke tvorbě RAM-disku následující příkazy:
108 mkdir _install/{dev,etc,proc,sys}
109 sudo cp -a /dev/tty? _install/dev
110 ln -s bin/busybox _install/init
111 (cd _install; find . | cpio -o -H newc | gzip) > ramdisk
113 2. Bez rootovských práv můžete RAM-disk vytvořit pomocí nástoje
114 [gen_init_cpio][gic].
119 nod /dev/tty0 644 0 0 c 4 0
120 nod /dev/tty1 644 0 0 c 4 1
121 nod /dev/tty2 644 0 0 c 4 2
122 nod /dev/tty3 644 0 0 c 4 3
123 nod /dev/tty4 644 0 0 c 4 4
124 slink /init bin/busybox 700 0 0
129 find _install -mindepth 1 -type d -printf "dir /%P %m 0 0\n"
130 find _install -type f -printf "file /%P %p %m 0 0\n"
131 find _install -type l -printf "slink /%P %l %m 0 0\n"
134 gen_init_cpio filelist | gzip > ramdisk
136 [gic]:http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blob;f=usr/gen_init_cpio.c;hb=HEAD
138 5. **Jádro Linuxu**. Příprava jádra je téměř stejná jako u BusyBoxu:
139 stáhneme zdrojový kód, nakonfigurujeme a přeložíme. Vzhledem k
140 rozsáhlosti jádra (zkompilované zabere na disku cca 1 GB a překlad
141 trvá cca 20 minut) tyto kroky přeskočíme a použijeme již připravené
144 Pokud byste si chtěli přeložit vlastní jádro, v následujícím
145 příkazu byste za parametrem *-kernel* uvedli cestu k vámi
146 zkompilovanému jádru.
148 6. Bootování jádra s naším filesystémem (v emulátoru):
150 qemu -kernel /boot/vmlinuz-2.6.26-2-686 -initrd ramdisk
152 7. Pokud vše proběhlo správně, zobrazila se hláška
154 Please press Enter to activate this console.
156 Po stisku Enteru se spustí shell a můžete začít pracovat ve
157 vašem právě vytvořeném systému.
162 Dále můžete provést drobná vylepšení vašeho systému, která vám mohou
163 zjednodušit další práci.
165 1. Můžete připojit souborový systém `/proc`, aby fungovaly příkazy
166 jako např. `ps` (výpis běžících procesů). Příkaz spusťte v
167 emulátoru, ne na vaší pracovní stanici.
169 mount -t proc none /proc
171 2. V RAM-disku můžete vytvořit soubor `/etc/init.d/rcS`, který bude
172 obsahovat příkazy, které budou spuštěny při bootu systému.
174 mkdir -p _install/etc/init.d
175 cat <<EOF > _install/etc/init.d/rcS
177 mount -t proc none /proc
180 chmod +x _install/etc/init.d/rcS # nastavení spustitelnosti
182 Nyní musíte znovu vytvořit RAM-disk a nabootovat.
187 Jaderné moduly jsou přeložené kusy kódu, které lze za běhu nahrávat do
188 Linuxvého jádra. Pokud bychom chtěli nalézt analogickou věc v
189 uživatelském prostředí, pak by to byly *sdílené knihovny*. Jaderný
190 modul může obsahovat kód ovladače zařízení, podporu určitého
191 souborového systému, může přidávat do jádra nové funkce (např.
192 firewall) či sloužit jako knihovna pomocných funkcí pro jiné moduly
195 Zdrojový kód jednoduchého jaderného modulu vypadá následovně:
197 #include <linux/init.h>
198 #include <linux/module.h>
199 MODULE_LICENSE("Dual BSD/GPL");
201 static int hello_init(void)
203 printk(KERN_ALERT "Hello, world\n");
207 static void hello_exit(void)
209 printk(KERN_ALERT "Goodbye, cruel world\n");
212 module_init(hello_init);
213 module_exit(hello_exit);
214 *Příklad převzat z [LDD3][LDD3].*
216 Překlad modulu provedeme pomocí jednoduchého souboru Makefile, který
217 bude obsahovat jedinou řádku (zde předpokládáme, že výše uvedený
218 soubor se jmenuje **khello.c**):
222 Nyní stačí zavolat `make` se správnými parametry:
224 make -C /lib/modules/$(uname -r)/build M=$(pwd) modules
226 Tímto říkáme, že příkaz `make` načte `Makefile` z adresáře se
227 zdrojovými kódy aktuálně běžícího jádra (o který adresář se jedná
228 můžete zjistít pomocí `readlink -f /lib/modules/$(uname -r)/build`),
229 pomocí proměnné `M` řeknete, že se váš modul nachází v aktuálním
230 adresáři a slovo `modules` na konci znamená, že chcete, aby se
231 zkompilovaly pouze moduly.
233 Pokud vše dopadlo dobře, objevil se vám soubor `khello.ko`, což je
234 modul, který můžete zavést do jádra příkazem
243 Vytvořte jednoduchý jaderný modul, který po zavedení do jádra vypíše
244 vaše jméno (objeví se ve výstupu `dmesg`). Jinak nemusí dělat nic.
245 Předveďte činnost vašeho modulu ve vámi vytvořeném systému běžícím v
248 **Pozor:** V zadání je drobný chyták!
250 Kdo se bude nudit, může zkusit rozšířit modul tak, aby se jeho jméno
251 objevilo v souboru `/proc/myname` nebo vytvořit jednoduchý ovladač,
252 který bude vracet vaše jméno při čtení z `/dev/myname`. Návod najdete
253 v [tomto článku][henson_drivers] (strany 2 a 3).
258 * Pro vyvolání určitého příkazu z historie můžete použít klávesu
259 `Ctrl-R` následovanou textem hledaného příkazu. Např:
263 * Pro rychlé kopírování textu mezi programy (např. příkazy z této stránky do shellu),
264 můžete použít prostřední tlačítko myši. Funguje to tak, že text označíte myší
265 (nemačkáte při tom Ctrl-C) a stiskem prostředního tlačítka myši v terminálovém
266 okně ho vložíte na příkazovou řádku shellu. Tím, že při tom nemusíte šahat na
267 klávesnici vám to půjde rychleji.
272 * [ramfs, rootfs and initramfs](http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blob;f=Documentation/filesystems/ramfs-rootfs-initramfs.txt;hb=HEAD)
273 * [Early userspace support](http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blob;f=Documentation/early-userspace/README;hb=HEAD)
274 * [Inside the Linux boot process](http://www.ibm.com/developerworks/linux/library/l-linuxboot/)
275 * [The Linux Bootdisk HOWTO](http://www.tldp.org/HOWTO/Bootdisk-HOWTO/)
276 * [Linux Loadable Kernel Module HOWTO](http://tldp.org/HOWTO/Module-HOWTO/)
277 * [Linux Device Drivers, Third Edition][LDD3]
278 * [Kbuild & modules](http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blob;f=Documentation/kbuild/modules.txt;hb=HEAD)
279 * [/dev/hello_world: A Simple Introduction to Device Drivers under Linux](henson_drivers)
281 [LDD3]:http://lwn.net/Kernel/LDD3/
282 [henson_drivers]:http://linuxdevcenter.com/pub/a/linux/2007/07/05/devhelloworld-a-simple-introduction-to-device-drivers-under-linux.html