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áhněte si zdrojové kódy z git repozitáře projektu [BusyBox][]
40 (adresu repozitáře si najděte sami).
45 Protože se jedná o aktuální vývojový snapshot, je možné, že se
46 při překladu, instalaci nebo používání vyskytne chyba. Naší výhodou
47 však je, že máme k dispozici kompletní historii projektu
51 a můžeme si vybrat verzi, kde se chyba nevyskytuje. Například
53 git checkout -f 1_22_0
55 2. Zkonfigurujeme jak chceme BusyBox přeložit.
59 Vystačíme s výchozí konfigurací, takže zvolte `Exit` a odpovězte
60 `Yes`, že chcete konfiguraci uložit.
62 3. Kompilaci provedeme tradičně příkazem
70 nainstalujeme busybox do adresáře `./_install`. Všimněte si (`ls
71 -lR _install`), že se tam nachází pouze jedna binárka `bin/busybox`
72 a všechno ostatní jsou pouze symbolické odkazy na tuto binárku.
74 Protože neprovádíme tzv. *křížový překlad* (cross compilation),
75 který je běžný v případě vestavěných zařízení, můžeme výsledek
76 hned otestovat například spuštěním shellu: `./_install/bin/sh`
77 (ukončíme ho např. příkazem `exit`).
79 V případě skutečného vestavěného systému bychom museli pokračovat
80 dál a busybox otestovat až po nabootování na cílovém hardwaru.
82 5. Pokud máte na svém počítači práva uživatele `root`, můžete
83 otestovat BusyBox v [chroot prostředí][chroot], t.j. se stejným jádrem jako
84 právě běží na vašem počítači, ale se souborovým systémem tvořeným
87 # chroot _install /bin/sh
89 Fungovat to ale nebude, protože ke spuštění BusyBoxu jsou potřeba
90 knihovny, které v nejsou v adresáři `_install` dostupné.
92 [chroot]:http://en.wikipedia.org/wiki/Chroot
94 6. Knihovny, které `busybox` potřebuje ke svému běhu, zjistíte
97 ldd _install/bin/busybox
99 Na 32-bitovém systému to může vypadat například takto:
101 linux-gate.so.1 => (0xffffe000)
102 libm.so.6 => /lib/i686/cmov/libm.so.6 (0xf777c000)
103 libc.so.6 => /lib/i686/cmov/libc.so.6 (0xf7635000)
104 /lib/ld-linux.so.2 (0xf77aa000)
106 `linux-gate.so.1` (nebo `linux-vdso.so.1`) je virtuální knihovna,
107 kterou poskytuje jádro Linuxu, takže o tu se starat nemusíte.
108 Ostatní knihovny je potřeba nakopírovat do cílového systému
109 (adresáře `_install`) například následujícím způsobem:
112 cp /lib/i686/cmov/libm.so.6 /lib/i686/cmov/libc.so.6 /lib/ld-linux.so.2 _install/lib
114 Nezapomeňte, že v cílovém filesystému musí být i tzv. interpretr
115 (`ld-linux`), který je na **64-bitovém systému v adresáři
118 Nyní už můžete spustit BusyBox v chroot prostředí.
120 5. Nejjednodušší možnost jak nabootovat do právě vytvořeného
121 uživatelského prostředí je uložit ho ve formátu pro Linuxový
122 startovací RAM-disk a nabootovat Linux s tímto RAM-diskem.
124 Aby vše fungovalo jak má, kromě souborů v adresáři `_install` musí
125 RAM-disk obsahovat i několik položek v adresáři `/dev` pro přístup
126 k virtuálním terminálům.
128 1. Pokud máte *rootovská* práva, použijte ke tvorbě RAM-disku
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 Nejprve vytvoříme seznam souborů (`filelist`), které má ramdisk
160 obsahovat. Nástroj `gen_init_cpio` pak podle toho seznamu
161 vytvoří obraz ramdisku, který "zazipujeme" příkazem `gzip` a
162 uložíme do souboru `ramdisk`.
164 [gic]:http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blob;f=usr/gen_init_cpio.c;hb=HEAD
166 5. **Jádro Linuxu**. Příprava jádra je téměř stejná jako u BusyBoxu:
167 stáhneme zdrojový kód, nakonfigurujeme a přeložíme. Vzhledem k
168 rozsáhlosti jádra (zkompilované zabere na disku cca 1 GB a překlad
169 trvá cca 20 minut) tyto kroky přeskočíme a použijeme již připravené
172 Pokud byste si chtěli přeložit vlastní jádro, v následujícím
173 příkazu byste za parametrem *-kernel* uvedli cestu k vámi
174 zkompilovanému jádru.
176 6. Bootování jádra s naším filesystémem (v emulátoru):
178 Na 64-bitovém systému spustíme emulátor následovně:
180 qemu-system-x86_64 -kernel /boot/vmlinuz-3.2.0-4-amd64 -initrd ramdisk
182 Na 32-bitovém systému většinou stačí zkrácený název `qemu`:
184 qemu -kernel /boot/vmlinuz-2.6.26-2-686 -initrd ramdisk
186 Pokud systém nabízí hardwarovou podporu virtualizace, je výhodné
187 použít [KVM][kvm]. Výsledek pak běží rychleji. Například:
189 kvm -kernel /boot/vmlinuz-3.2.0-4-amd64 -initrd ramdisk
191 [kvm]:http://www.linux-kvm.org/
193 7. Pokud vše proběhlo správně, zobrazila se hláška
195 Please press Enter to activate this console.
197 Po stisku Enteru se spustí shell a můžete začít pracovat ve
198 vašem právě vytvořeném systému.
203 Dále můžete provést drobná (či větší) vylepšení svého nového systému,
204 která vám mohou zjednodušit další práci.
206 1. Můžete připojit souborový systém `/proc`, aby fungovaly příkazy
207 jako např. `ps` (výpis běžících procesů). Příkaz spusťte
208 v emulátoru, ne na vaší pracovní stanici.
210 mount -t proc none /proc
212 2. V RAM-disku můžete vytvořit soubor `/etc/init.d/rcS`, který bude
213 obsahovat příkazy, které budou spuštěny při bootu systému.
215 mkdir -p _install/etc/init.d
216 cat <<EOF > _install/etc/init.d/rcS
218 mount -t proc none /proc
221 chmod +x _install/etc/init.d/rcS # nastavení spustitelnosti
223 Nyní musíte znovu vytvořit RAM-disk a nabootovat.
225 3. Zachytávání zpráv jádra spuštěného v emulátoru QEMU do souboru.
226 Zprávy jádra je možné přesměrovat na virtuální sériový port a
227 odtamtud pak například na standardní výstup:
229 qemu -serial stdio ...
231 a jádru předáme parametr `console=ttyS0`
233 qemu -serial stdio -append console=ttyS0 ...
235 4. Pokud chcete z vašeho systému komunikovat po síti, připojte ho na
236 vnější síť pomocí <abbr title="Network Address
237 Translation">NAT</abbr> na uživatelské úrovni:
239 qemu -net nic,vlan=0,model=ne2k_pci -net user,vlan=0 ...
241 5. Pokud QEMU nebo KVM podporuje vytvoření virtio sítě Plan9 a virtuálního
242 souborového systému, tak je možné propagovat do vnitřního systému
243 obsah adresáře hostitelského systému:
245 qemu -virtfs local,path=shared_dir_name,security_model=none,mount_tag=shared_tag ...
247 Adresářovou strukturu lze z vnitřního systému připojit následujícími
254 modprobe 9pnet_virtio
256 mkdir -p /mnt/shareddir
257 mount -t 9p -o trans=virtio shared_tag /mnt/shareddir
259 Další tipy a triky v oblasti virtualizace používané a odzkoušené zprávci
260 sítě na naší katedře nalezente na [Wiki Technické Podpory (support)][support-qemu].
261 [support-qemu]:http://support.dce.felk.cvut.cz/mediawiki/index.php/Kategorie:Virtualiza%C4%8Dn%C3%AD_stroje
266 Jaderné moduly jsou přeložené kusy kódu, které lze za běhu nahrávat do
267 Linuxového jádra. Pokud bychom chtěli nalézt analogickou věc v
268 uživatelském prostředí, pak by to byly *sdílené knihovny*. Jaderný
269 modul může obsahovat kód ovladače zařízení, podporu určitého
270 souborového systému, může přidávat do jádra nové funkce (např.
271 firewall) či sloužit jako knihovna pomocných funkcí pro jiné moduly
274 Zdrojový kód jednoduchého jaderného modulu vypadá následovně:
276 #include <linux/init.h>
277 #include <linux/module.h>
278 MODULE_LICENSE("Dual BSD/GPL");
280 static int hello_init(void)
282 printk(KERN_ALERT "Hello, world\n");
286 static void hello_exit(void)
288 printk(KERN_ALERT "Goodbye, cruel world\n");
291 module_init(hello_init);
292 module_exit(hello_exit);
293 *Příklad převzat z [LDD3][LDD3].*
295 Překlad modulu provedeme pomocí jednoduchého souboru Makefile, který
296 bude obsahovat jedinou řádku (zde předpokládáme, že výše uvedený
297 soubor se jmenuje **khello.c**):
301 Nyní stačí zavolat `make` se správnými parametry:
303 make -C /lib/modules/$(uname -r)/build M=$(pwd) modules
305 Tímto říkáme, že příkaz `make` načte `Makefile` z adresáře se
306 zdrojovými kódy aktuálně běžícího jádra (o který adresář se jedná
307 můžete zjisti pomocí `readlink -f /lib/modules/$(uname -r)/build`),
308 pomocí proměnné `M` řeknete, že se váš modul nachází v aktuálním
309 adresáři a slovo `modules` na konci znamená, že chcete, aby se
310 zkompilovaly pouze moduly.
312 Pokud vše dopadlo dobře, objevil se vám soubor `khello.ko`, což je
313 modul, který můžete zavést do jádra příkazem
322 1. Stáhněte si [[tento program|magic]] ([[32-bitová verze|magic32]]) a
323 zprovozněte ho ve vámi vytvořeném systému. Zprovoznění znamená, že
324 po spuštění program nevypíše žádnou chybu. Nezapomeňte nastavit
325 práva pro spouštění příkazem `chmod +x`.
327 Ke zjištění případným problémů by se vám mohly hodit příkazy
328 `strace` a `ltrace`. Ten prvý vypisuje všechna systémová volání
329 vyvolaná daným programem a druhý vypisuje jaké funkce ze sdílených
330 knihoven program volá. Zkuste si například spustit následující
337 2. Vytvořte jednoduchý jaderný modul, který po zavedení do jádra vypíše
338 vaše jméno (objeví se ve výstupu příkazu `dmesg`). Jinak nemusí dělat nic.
339 Předveďte činnost vašeho modulu ve vámi vytvořeném systému běžícím v
342 Kdo se bude nudit, může zkusit rozšířit modul tak, aby se jeho jméno
343 objevilo v souboru `/proc/myname` nebo vytvořit jednoduchý ovladač,
344 který bude vracet vaše jméno při čtení z `/dev/myname`. Návod najdete
345 v [tomto článku][henson_drivers] (strany 2 a 3).
350 * Pro vyvolání určitého příkazu z historie můžete použít klávesu
351 `Ctrl-R` následovanou textem hledaného příkazu. Např:
355 * Pro rychlé kopírování textu mezi programy (např. příkazy z této stránky do shellu),
356 můžete použít prostřední tlačítko myši. Funguje to tak, že text označíte myší
357 (nemačkáte při tom Ctrl-C) a stiskem prostředního tlačítka myši v terminálovém
358 okně ho vložíte na příkazovou řádku shellu. Tím, že při tom nemusíte šahat na
359 klávesnici vám to půjde rychleji.
361 * Pokud je Qemu spouštěný přes vzdálené připojení (např. server postel),
362 je potřeba pro zobrazení emulované obrazovky spouštěného stroje
363 buď provést protunelování X protokolu (`ssh -X`) nebo používat Qemu
364 s emulací obrazovky v textovém režimu `qemu -curses`. Další možnost
365 je emulovat HW bez grafické karty `qemu -nographic` a nastavit testovaný
366 systém tak, aby systémová konzole směřovala na sériový port
367 (`-append console=ttyS0`).
372 * [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)
373 * [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)
374 * [Inside the Linux boot process](http://www.ibm.com/developerworks/linux/library/l-linuxboot/)
375 * [The Linux Bootdisk HOWTO](http://www.tldp.org/HOWTO/Bootdisk-HOWTO/)
376 * [Linux Loadable Kernel Module HOWTO](http://tldp.org/HOWTO/Module-HOWTO/)
377 * [Linux Device Drivers, Third Edition][LDD3]
378 * [Kbuild & modules](http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blob;f=Documentation/kbuild/modules.txt;hb=HEAD)
379 * [/dev/hello_world: A Simple Introduction to Device Drivers under Linux](henson_drivers)
380 * [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)
381 * [Filip Navara: Diplomová práce - Rozšíření QEMU o podporu mikrokontroléru AT91SAM7X256](http://rtime.felk.cvut.cz/hw/index.php/AT91SAM7X256)
382 * [Aleš Kapica a další: Stránky o virtualizaci z oddělení IT K13135](https://support.dce.felk.cvut.cz/mediawiki/index.php/Kategorie:QEMU)
384 [LDD3]:http://lwn.net/Kernel/LDD3/
385 [henson_drivers]:http://linuxdevcenter.com/pub/a/linux/2007/07/05/devhelloworld-a-simple-introduction-to-device-drivers-under-linux.html
387 <!-- TODO pro pristi rok: Pokud i tohle bude moc jednoduché:
388 Zakladni uloha jen za 3 body, za dalsi dva body uloha bez navodu: dame
389 jim binarku, ktera bude chctit sdilenou knihovnu a tu budou muset