1 [[!meta title="Embedded Linux"]]
8 Cílem tohoto cvičení je prakticky si procvičit informace probírané na
9 2. přednášce a motivovat vás ke 4. přednášce "*Linuxové jádro – vznik,
10 vývoj, skladba a ovladače; GNU libc a uživatelský prostor*". Pokud vám
11 nejsou jasné některé souvislosti, doporučujeme zkusit si informace
12 vygooglovat a připravit si otázky na 4. přednášku.
14 Open source software (OSS) projekty se často nepoužívají osamoceně,
15 ale v kombinaci s jinými OSS projekty, čímž vznikají tak tzv. OSS
16 stacky. Asi nejznámějším stackem je LAMP – Linux, Apache, MySQL, PHP.
17 Na dnešním cvičení se seznámíme s dalším, velmi často používaným,
18 stackem [Linux][] + [BusyBox][] (+[Dropbear][] SSH server).
20 [BusyBox][] je sada UNIXových uživatelských nástrojů (shell, editor,
21 utility jako ls, mkdir, …) zkompilovaná do jedné binárky. V kombinaci
22 s jádrem Linuxu tak dostáváme kompletní operační systém s poměrně
23 malými nároky na paměť. Díky tomu se tato kombinace často používá ve
24 vestavěných (embedded) aplikacích jako například
25 [WiFi routery či ADSL modemy][owrt].
27 V tomto cvičení si zkusíte vytvořit kompletní open source operační
28 Systém z Linuxového jádra a uživatelského prostředí tvořeného právě
29 BusyBoxem. Dále si vyzkoušíte naprogramovat jednoduchý modul do jádra.
31 [Linux]: http://kernel.org/
32 [BusyBox]:http://busybox.net/
33 [owrt]:http://www.openwrt.org/
34 [Dropbear]:http://matt.ucc.asn.au/dropbear/dropbear.html
39 1. Stáhneme [zdrojové kódy][bbgit] projektu [BusyBox][]:
41 git clone git://busybox.net/busybox.git --reference /usr/src/busybox.git
44 Protože se jedná o aktuální vývojový snapshot, je možné, že se
45 při překladu, instalaci nebo používání vyskytne chyba. Naší výhodou
46 však je, že máme k dispozici kompletní historii projektu
50 a můžeme si vybrat verzi, kde se chyba nevyskytuje. Například
52 git checkout -f 1_20_2
54 [bbgit]:http://git.busybox.net/busybox/
56 2. Zkonfigurujeme jak chceme BusyBox přeložit.
60 Vystačíme s výchozí konfigurací, takže zvolte `Exit` a odpovězte
61 `Yes`, že chcete konfiguraci uložit.
63 3. Kompilaci provedeme tradičně příkazem
71 nainstalujeme busybox do adresáře `./_install`. Všimněte si (`ls
72 -lR _install`), že se tam nachází pouze jedna binárka `bin/busybox`
73 a všechno ostatní jsou pouze symbolické odkazy na tuto binárku.
75 Protože neprovádíme tzv. *křížový překlad* (cross compilation),
76 který je běžný v případě vestavěných zařízení, můžeme výsledek
77 hned otestovat například spuštěním shellu: `./_install/bin/sh`
78 (ukončíme ho např. příkazem `exit`).
80 V případě skutečného vestavěného systému bychom museli pokračovat
81 dál a busybox otestovat až po nabootování na cílovém hardwaru.
83 5. Pokud máte na svém počítači práva uživatele `root`, můžete
84 otestovat BusyBox v [chroot prostředí][chroot], t.j. se stejným jádrem jako
85 právě běží na vašem počítači, ale se souborovým systémem tvořeným
88 # chroot _install /bin/sh
90 Fungovat to ale nebude, protože ke spuštění BusyBoxu jsou potřeba
91 knihovny, které v nejsou v adresáři `_install` dostupné.
93 [chroot]:http://en.wikipedia.org/wiki/Chroot
95 6. Knihovny, které `busybox` potřebuje ke svému běhu, zjistíte
98 ldd _install/bin/busybox
100 Na 32-bitovém systému to může vypadat například takto:
102 linux-gate.so.1 => (0xffffe000)
103 libm.so.6 => /lib/i686/cmov/libm.so.6 (0xf777c000)
104 libc.so.6 => /lib/i686/cmov/libc.so.6 (0xf7635000)
105 /lib/ld-linux.so.2 (0xf77aa000)
107 `linux-gate.so.1` (nebo `linux-vdso.so.1`) je virtuální knihovna,
108 kterou poskytuje jádro Linuxu, takže o tu se starat nemusíte.
109 Ostatní knihovny je potřeba nakopírovat do cílového systému
110 (adresáře `_install`) například následujícím způsobem:
113 cp /lib/i686/cmov/libm.so.6 /lib/i686/cmov/libc.so.6 /lib/ld-linux.so.2 _install/lib
115 Nezapomeňte, že v cílovém filesystému musí být i tzv. interpretr
116 (`ld-linux`), který je na **64-bitovém systému v adresáři
119 Nyní už můžete spustit BusyBox v chroot prostředí.
121 5. Nejjednodušší možnost jak nabootovat do právě vytvořeného
122 uživatelského prostředí je uložit ho ve formátu pro Linuxový
123 startovací RAM-disk a nabootovat Linux s tímto RAM-diskem.
125 Aby vše fungovalo jak má, kromě souborů v adresáři `_install` musí
126 RAM-disk obsahovat i několik položek v adresáři `/dev` pro přístup
127 k virtuálním terminálům.
129 1. Pokud máte root práva, použijte ke tvorbě RAM-disku následující příkazy:
131 mkdir _install/{dev,etc,proc,sys}
132 sudo cp -a /dev/tty? _install/dev
133 ln -s bin/busybox _install/init
134 (cd _install; find . | cpio -o -H newc | gzip) > ramdisk
136 2. Bez rootovských práv můžete RAM-disk vytvořit pomocí nástroje
137 [gen_init_cpio][gic].
142 nod /dev/tty0 644 0 0 c 4 0
143 nod /dev/tty1 644 0 0 c 4 1
144 nod /dev/tty2 644 0 0 c 4 2
145 nod /dev/tty3 644 0 0 c 4 3
146 nod /dev/tty4 644 0 0 c 4 4
147 slink /init bin/busybox 700 0 0
152 find _install -mindepth 1 -type d -printf "dir /%P %m 0 0\n"
153 find _install -type f -printf "file /%P %p %m 0 0\n"
154 find _install -type l -printf "slink /%P %l %m 0 0\n"
157 gen_init_cpio filelist | gzip > ramdisk
159 [gic]:http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blob;f=usr/gen_init_cpio.c;hb=HEAD
161 5. **Jádro Linuxu**. Příprava jádra je téměř stejná jako u BusyBoxu:
162 stáhneme zdrojový kód, nakonfigurujeme a přeložíme. Vzhledem k
163 rozsáhlosti jádra (zkompilované zabere na disku cca 1 GB a překlad
164 trvá cca 20 minut) tyto kroky přeskočíme a použijeme již připravené
167 Pokud byste si chtěli přeložit vlastní jádro, v následujícím
168 příkazu byste za parametrem *-kernel* uvedli cestu k vámi
169 zkompilovanému jádru.
171 6. Bootování jádra s naším filesystémem (v emulátoru):
173 Na 64-bitovém systému spustíme emulátor následovně:
175 qemu-system-x86_64 -kernel /boot/vmlinuz-2.6.32-5-amd64 -initrd ramdisk
177 Na 32-bitovém systému většinou stačí zkrácený název `qemu`:
179 qemu -kernel /boot/vmlinuz-2.6.26-2-686 -initrd ramdisk
181 Pokud systém nabízí hardwarovou podporu virtualizace, je výhodné
182 použít [KVM][kvm]. Výsledek pak běží rychleji. Například:
184 kvm -kernel /boot/vmlinuz-2.6.32-5-amd64 -initrd ramdisk
186 [kvm]:http://www.linux-kvm.org/
188 7. Pokud vše proběhlo správně, zobrazila se hláška
190 Please press Enter to activate this console.
192 Po stisku Enteru se spustí shell a můžete začít pracovat ve
193 vašem právě vytvořeném systému.
198 Dále můžete provést drobná vylepšení vašeho systému, která vám mohou
199 zjednodušit další práci.
201 1. Můžete připojit souborový systém `/proc`, aby fungovaly příkazy
202 jako např. `ps` (výpis běžících procesů). Příkaz spusťte v
203 emulátoru, ne na vaší pracovní stanici.
205 mount -t proc none /proc
207 2. V RAM-disku můžete vytvořit soubor `/etc/init.d/rcS`, který bude
208 obsahovat příkazy, které budou spuštěny při bootu systému.
210 mkdir -p _install/etc/init.d
211 cat <<EOF > _install/etc/init.d/rcS
213 mount -t proc none /proc
216 chmod +x _install/etc/init.d/rcS # nastavení spustitelnosti
218 Nyní musíte znovu vytvořit RAM-disk a nabootovat.
220 3. Zachytávání zpráv jádra spuštěného v emulátoru QEMU do souboru
221 je možné jejich přesměrování na virtuální sériový port.
222 Požadavek na jeho vytvoření se předá QEMU zadáním parametru
224 qemu -serial file:/tmp/virtual_guest.log ...
226 a jádro spustíme s parametrem `console=ttyS0`
228 qemu -serial file:/tmp/virtual_guest.log -append console=ttyS0 ...
230 4. Pokud chcete z vašeho systému komunikovat po síti, připojte ho na
231 vnější síť s využitím NAT na uživatelské úrovni:
233 qemu -net nic,vlan=0,model=ne2k_pci -net user,vlan=0 ...
235 5. Pokud QEMU nebo KVM podporuje vytvoření virtio sítě Plan9 a virtuálního
236 souborového systému, tak je možné propagovat do vnitřního systému
237 obsah adresáře hostitelského systému:
239 qemu -virtfs local,path=shared_dir_name,security_model=none,mount_tag=shared_tag ...
241 Adresářovou strukturu lze z vnitřního systému připojit následujícími
248 modprobe 9pnet_virtio
250 mkdir -p /mnt/shareddir
251 mount -t 9p -o trans=virtio shared_tag /mnt/shareddir
253 Další tipy a triky v oblasti virtualizace používané a odzkoušené zprávci
254 sítě na naší katedře nalezente na [Wiki Technické Podpory (support)][support-qemu].
255 [support-qemu]:http://support.dce.felk.cvut.cz/mediawiki/index.php/Kategorie:Virtualiza%C4%8Dn%C3%AD_stroje
260 Jaderné moduly jsou přeložené kusy kódu, které lze za běhu nahrávat do
261 Linuxového jádra. Pokud bychom chtěli nalézt analogickou věc v
262 uživatelském prostředí, pak by to byly *sdílené knihovny*. Jaderný
263 modul může obsahovat kód ovladače zařízení, podporu určitého
264 souborového systému, může přidávat do jádra nové funkce (např.
265 firewall) či sloužit jako knihovna pomocných funkcí pro jiné moduly
268 Zdrojový kód jednoduchého jaderného modulu vypadá následovně:
270 #include <linux/init.h>
271 #include <linux/module.h>
272 MODULE_LICENSE("Dual BSD/GPL");
274 static int hello_init(void)
276 printk(KERN_ALERT "Hello, world\n");
280 static void hello_exit(void)
282 printk(KERN_ALERT "Goodbye, cruel world\n");
285 module_init(hello_init);
286 module_exit(hello_exit);
287 *Příklad převzat z [LDD3][LDD3].*
289 Překlad modulu provedeme pomocí jednoduchého souboru Makefile, který
290 bude obsahovat jedinou řádku (zde předpokládáme, že výše uvedený
291 soubor se jmenuje **khello.c**):
295 Nyní stačí zavolat `make` se správnými parametry:
297 make -C /lib/modules/$(uname -r)/build M=$(pwd) modules
299 Tímto říkáme, že příkaz `make` načte `Makefile` z adresáře se
300 zdrojovými kódy aktuálně běžícího jádra (o který adresář se jedná
301 můžete zjisti pomocí `readlink -f /lib/modules/$(uname -r)/build`),
302 pomocí proměnné `M` řeknete, že se váš modul nachází v aktuálním
303 adresáři a slovo `modules` na konci znamená, že chcete, aby se
304 zkompilovaly pouze moduly.
306 Pokud vše dopadlo dobře, objevil se vám soubor `khello.ko`, což je
307 modul, který můžete zavést do jádra příkazem
316 Vytvořte jednoduchý jaderný modul, který po zavedení do jádra vypíše
317 vaše jméno (objeví se ve výstupu příkazu `dmesg`). Jinak nemusí dělat nic.
318 Předveďte činnost vašeho modulu ve vámi vytvořeném systému běžícím v
321 Kdo se bude nudit, může zkusit rozšířit modul tak, aby se jeho jméno
322 objevilo v souboru `/proc/myname` nebo vytvořit jednoduchý ovladač,
323 který bude vracet vaše jméno při čtení z `/dev/myname`. Návod najdete
324 v [tomto článku][henson_drivers] (strany 2 a 3).
329 * Pro vyvolání určitého příkazu z historie můžete použít klávesu
330 `Ctrl-R` následovanou textem hledaného příkazu. Např:
334 * Pro rychlé kopírování textu mezi programy (např. příkazy z této stránky do shellu),
335 můžete použít prostřední tlačítko myši. Funguje to tak, že text označíte myší
336 (nemačkáte při tom Ctrl-C) a stiskem prostředního tlačítka myši v terminálovém
337 okně ho vložíte na příkazovou řádku shellu. Tím, že při tom nemusíte šahat na
338 klávesnici vám to půjde rychleji.
340 * Pokud je Qemu spouštěný přes vzdálené připojení (např. server postel),
341 je potřeba pro zobrazení emulované obrazovky spouštěného stroje
342 buď provést protunelování X protokolu (`ssh -X`) nebo používat Qemu
343 s emulací obrazovky v textovém režimu `qemu -curses`. Další možnost
344 je emulovat HW bez grafické karty `qemu -nographic` a nastavit testovaný
345 systém tak, aby systémová konzole směřovala na sériový port
346 (`-append console=ttyS0`).
351 * [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)
352 * [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)
353 * [Inside the Linux boot process](http://www.ibm.com/developerworks/linux/library/l-linuxboot/)
354 * [The Linux Bootdisk HOWTO](http://www.tldp.org/HOWTO/Bootdisk-HOWTO/)
355 * [Linux Loadable Kernel Module HOWTO](http://tldp.org/HOWTO/Module-HOWTO/)
356 * [Linux Device Drivers, Third Edition][LDD3]
357 * [Kbuild & modules](http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blob;f=Documentation/kbuild/modules.txt;hb=HEAD)
358 * [/dev/hello_world: A Simple Introduction to Device Drivers under Linux](henson_drivers)
359 * [Rostislav Lisový: Diplomová práce - Rozšíření QEMU o podporu PCI I/O karty a tvorba ovladačů](http://rtime.felk.cvut.cz/hw/index.php/Humusoft_MF6xx)
360 * [Filip Navara: Diplomová práce - Rozšíření QEMU o podporu mikrokontroléru AT91SAM7X256](http://rtime.felk.cvut.cz/hw/index.php/AT91SAM7X256)
361 * [Aleš Kapica a další: Stránky o virtualizaci z oddělení IT K13135](https://support.dce.felk.cvut.cz/mediawiki/index.php/Kategorie:QEMU)
363 [LDD3]:http://lwn.net/Kernel/LDD3/
364 [henson_drivers]:http://linuxdevcenter.com/pub/a/linux/2007/07/05/devhelloworld-a-simple-introduction-to-device-drivers-under-linux.html
366 <!-- TODO pro pristi rok: At si najdou kde stahnout busybox sami.
367 Zakladni uloha jen za 3 body, za dalsi dva body uloha bez navodu: dame
368 jim binarku, ktera bude chctit sdilenou knihovnu a tu budou muset