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 Pokud systém nabízí hardwarovou podporu virtualizace, je výhodné
153 použít KVM, které pak běží rychleji
155 kvm -kernel /boot/vmlinuz-2.6.32-5-amd64 -initrd ramdisk
157 Na 64-bitovém systému může být potřeba použít příslušnou variantu QEMU
159 qemu-system-x86_64 -kernel /boot/vmlinuz-2.6.32-5-amd64 -initrd ramdisk
161 7. Pokud vše proběhlo správně, zobrazila se hláška
163 Please press Enter to activate this console.
165 Po stisku Enteru se spustí shell a můžete začít pracovat ve
166 vašem právě vytvořeném systému.
171 Dále můžete provést drobná vylepšení vašeho systému, která vám mohou
172 zjednodušit další práci.
174 1. Můžete připojit souborový systém `/proc`, aby fungovaly příkazy
175 jako např. `ps` (výpis běžících procesů). Příkaz spusťte v
176 emulátoru, ne na vaší pracovní stanici.
178 mount -t proc none /proc
180 2. V RAM-disku můžete vytvořit soubor `/etc/init.d/rcS`, který bude
181 obsahovat příkazy, které budou spuštěny při bootu systému.
183 mkdir -p _install/etc/init.d
184 cat <<EOF > _install/etc/init.d/rcS
186 mount -t proc none /proc
189 chmod +x _install/etc/init.d/rcS # nastavení spustitelnosti
191 Nyní musíte znovu vytvořit RAM-disk a nabootovat.
196 Jaderné moduly jsou přeložené kusy kódu, které lze za běhu nahrávat do
197 Linuxvého jádra. Pokud bychom chtěli nalézt analogickou věc v
198 uživatelském prostředí, pak by to byly *sdílené knihovny*. Jaderný
199 modul může obsahovat kód ovladače zařízení, podporu určitého
200 souborového systému, může přidávat do jádra nové funkce (např.
201 firewall) či sloužit jako knihovna pomocných funkcí pro jiné moduly
204 Zdrojový kód jednoduchého jaderného modulu vypadá následovně:
206 #include <linux/init.h>
207 #include <linux/module.h>
208 MODULE_LICENSE("Dual BSD/GPL");
210 static int hello_init(void)
212 printk(KERN_ALERT "Hello, world\n");
216 static void hello_exit(void)
218 printk(KERN_ALERT "Goodbye, cruel world\n");
221 module_init(hello_init);
222 module_exit(hello_exit);
223 *Příklad převzat z [LDD3][LDD3].*
225 Překlad modulu provedeme pomocí jednoduchého souboru Makefile, který
226 bude obsahovat jedinou řádku (zde předpokládáme, že výše uvedený
227 soubor se jmenuje **khello.c**):
231 Nyní stačí zavolat `make` se správnými parametry:
233 make -C /lib/modules/$(uname -r)/build M=$(pwd) modules
235 Tímto říkáme, že příkaz `make` načte `Makefile` z adresáře se
236 zdrojovými kódy aktuálně běžícího jádra (o který adresář se jedná
237 můžete zjistít pomocí `readlink -f /lib/modules/$(uname -r)/build`),
238 pomocí proměnné `M` řeknete, že se váš modul nachází v aktuálním
239 adresáři a slovo `modules` na konci znamená, že chcete, aby se
240 zkompilovaly pouze moduly.
242 Pokud vše dopadlo dobře, objevil se vám soubor `khello.ko`, což je
243 modul, který můžete zavést do jádra příkazem
252 Vytvořte jednoduchý jaderný modul, který po zavedení do jádra vypíše
253 vaše jméno (objeví se ve výstupu `dmesg`). Jinak nemusí dělat nic.
254 Předveďte činnost vašeho modulu ve vámi vytvořeném systému běžícím v
257 **Pozor:** V zadání je drobný chyták!
259 Kdo se bude nudit, může zkusit rozšířit modul tak, aby se jeho jméno
260 objevilo v souboru `/proc/myname` nebo vytvořit jednoduchý ovladač,
261 který bude vracet vaše jméno při čtení z `/dev/myname`. Návod najdete
262 v [tomto článku][henson_drivers] (strany 2 a 3).
267 * Pro vyvolání určitého příkazu z historie můžete použít klávesu
268 `Ctrl-R` následovanou textem hledaného příkazu. Např:
272 * Pro rychlé kopírování textu mezi programy (např. příkazy z této stránky do shellu),
273 můžete použít prostřední tlačítko myši. Funguje to tak, že text označíte myší
274 (nemačkáte při tom Ctrl-C) a stiskem prostředního tlačítka myši v terminálovém
275 okně ho vložíte na příkazovou řádku shellu. Tím, že při tom nemusíte šahat na
276 klávesnici vám to půjde rychleji.
281 * [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)
282 * [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)
283 * [Inside the Linux boot process](http://www.ibm.com/developerworks/linux/library/l-linuxboot/)
284 * [The Linux Bootdisk HOWTO](http://www.tldp.org/HOWTO/Bootdisk-HOWTO/)
285 * [Linux Loadable Kernel Module HOWTO](http://tldp.org/HOWTO/Module-HOWTO/)
286 * [Linux Device Drivers, Third Edition][LDD3]
287 * [Kbuild & modules](http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blob;f=Documentation/kbuild/modules.txt;hb=HEAD)
288 * [/dev/hello_world: A Simple Introduction to Device Drivers under Linux](henson_drivers)
290 [LDD3]:http://lwn.net/Kernel/LDD3/
291 [henson_drivers]:http://linuxdevcenter.com/pub/a/linux/2007/07/05/devhelloworld-a-simple-introduction-to-device-drivers-under-linux.html