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 Linuxové jádro 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. V závislosti na vašem oprávnění můžete
127 RAM-disk vytvořit jedním z následujících způsobů:
129 1. Pokud máte *rootovská* práva, použijte ke tvorbě RAM-disku
132 mkdir _install/{dev,etc,proc,sys}
133 sudo cp -a /dev/tty? _install/dev
134 ln -s bin/busybox _install/init
135 (cd _install; find . | cpio -o -H newc | gzip) > ramdisk
137 2. Bez rootovských práv můžete RAM-disk vytvořit pomocí nástroje
138 [gen_init_cpio][gic]. Pokud program nemáte na svém počítači,
139 zkompilujte si ho ze [zdrojových kódů][gic].
144 nod /dev/tty0 644 0 0 c 4 0
145 nod /dev/tty1 644 0 0 c 4 1
146 nod /dev/tty2 644 0 0 c 4 2
147 nod /dev/tty3 644 0 0 c 4 3
148 nod /dev/tty4 644 0 0 c 4 4
149 slink /init bin/busybox 700 0 0
154 find _install -mindepth 1 -type d -printf "dir /%P %m 0 0\n"
155 find _install -type f -printf "file /%P %p %m 0 0\n"
156 find _install -type l -printf "slink /%P %l %m 0 0\n"
159 gen_init_cpio filelist | gzip > ramdisk
161 Výše uvedené příkazy fungují následovně: Nejprve vytvoříme
162 seznam souborů (`filelist`), které má ramdisk obsahovat. Nástroj
163 `gen_init_cpio` pak podle toho seznamu vytvoří obraz ramdisku,
164 který "zazipujeme" příkazem `gzip` a uložíme do souboru
167 [gic]:http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blob;f=usr/gen_init_cpio.c;hb=HEAD
169 5. **Jádro Linuxu**. Příprava jádra je téměř stejná jako u BusyBoxu:
170 stáhneme zdrojový kód, nakonfigurujeme a přeložíme. Vzhledem k
171 rozsáhlosti jádra (zkompilované zabere na disku cca 1 GB a překlad
172 trvá cca 20 minut) tyto kroky přeskočíme a použijeme již připravené
175 Pokud byste si chtěli přeložit vlastní jádro, v následujícím
176 příkazu byste za parametrem *-kernel* uvedli cestu k vámi
177 zkompilovanému jádru.
179 6. Bootování jádra s naším filesystémem (v softwarovém emulátoru
182 Na 64-bitovém systému spustíme emulátor následovně:
184 qemu-system-x86_64 -kernel /boot/vmlinuz-3.2.0-4-amd64 -initrd ramdisk
186 Na 32-bitovém systému použijte:
188 qemu-system-i386 -kernel /boot/vmlinuz-2.6.26-2-686 -initrd ramdisk
190 Pokud systém nabízí hardwarovou podporu virtualizace, je výhodné
191 použít virtualizační nástroj [KVM][kvm]. Výsledek pak běží
192 rychleji. KVM vychází z qemu a má tudíž téměř stejné parametry
193 příkazové řádky. Například:
195 kvm -kernel /boot/vmlinuz-3.2.0-4-amd64 -initrd ramdisk
197 [kvm]:http://www.linux-kvm.org/
199 7. Pokud vše proběhlo správně, zobrazila se hláška
201 Please press Enter to activate this console.
203 Po stisku Enteru se spustí shell a můžete začít pracovat ve
204 vašem právě vytvořeném systému.
209 Dále můžete provést drobná (či větší) vylepšení svého nového systému,
210 která vám mohou zjednodušit další práci.
212 1. Můžete připojit souborový systém `/proc`, aby fungovaly příkazy
213 jako např. `ps` (výpis běžících procesů). Příkaz spusťte
214 v emulátoru, ne na vaší pracovní stanici.
216 mount -t proc none /proc
218 2. V RAM-disku můžete vytvořit soubor `/etc/init.d/rcS`, který bude
219 obsahovat příkazy, které budou spuštěny při bootu systému.
221 mkdir -p _install/etc/init.d
222 cat <<EOF > _install/etc/init.d/rcS
224 mount -t proc none /proc
227 chmod +x _install/etc/init.d/rcS # nastavení spustitelnosti
229 Nyní musíte znovu vytvořit RAM-disk a nabootovat.
231 3. Zachytávání zpráv jádra spuštěného v emulátoru QEMU do souboru.
232 Zprávy jádra je možné přesměrovat na virtuální sériový port a
233 odtamtud pak například na standardní výstup:
235 qemu -serial stdio ...
237 a jádru předáme parametr `console=ttyS0`
239 qemu -serial stdio -append console=ttyS0 ...
241 4. Pokud chcete z vašeho systému komunikovat po síti, připojte ho na
242 vnější síť pomocí <abbr title="Network Address
243 Translation">NAT</abbr> na uživatelské úrovni:
245 qemu -net nic,vlan=0,model=ne2k_pci -net user,vlan=0 ...
247 5. Pokud QEMU nebo KVM podporuje vytvoření virtio sítě Plan9 a virtuálního
248 souborového systému, tak je možné propagovat do vnitřního systému
249 obsah adresáře hostitelského systému:
251 qemu -virtfs local,path=shared_dir_name,security_model=none,mount_tag=shared_tag ...
253 Adresářovou strukturu lze z vnitřního systému připojit následujícími
260 modprobe 9pnet_virtio
262 mkdir -p /mnt/shareddir
263 mount -t 9p -o trans=virtio shared_tag /mnt/shareddir
265 Další tipy a triky v oblasti virtualizace používané a odzkoušené zprávci
266 sítě na naší katedře nalezente na [Wiki Technické Podpory (support)][support-qemu].
267 [support-qemu]:http://support.dce.felk.cvut.cz/mediawiki/index.php/Kategorie:Virtualiza%C4%8Dn%C3%AD_stroje
272 Jaderné moduly jsou přeložené kusy kódu, které lze za běhu nahrávat do
273 Linuxového jádra. Pokud bychom chtěli nalézt analogickou věc v
274 uživatelském prostředí, pak by to byly *sdílené knihovny*. Jaderný
275 modul může obsahovat kód ovladače zařízení, podporu určitého
276 souborového systému, může přidávat do jádra nové funkce (např.
277 firewall) či sloužit jako knihovna pomocných funkcí pro jiné moduly
280 Zdrojový kód jednoduchého jaderného modulu vypadá následovně:
282 #include <linux/init.h>
283 #include <linux/module.h>
284 MODULE_LICENSE("Dual BSD/GPL");
286 static int hello_init(void)
288 printk(KERN_ALERT "Hello, world\n");
292 static void hello_exit(void)
294 printk(KERN_ALERT "Goodbye, cruel world\n");
297 module_init(hello_init);
298 module_exit(hello_exit);
299 *Příklad převzat z [LDD3][LDD3].*
301 Překlad modulu provedeme pomocí jednoduchého souboru Makefile, který
302 bude obsahovat jedinou řádku (zde předpokládáme, že výše uvedený
303 soubor se jmenuje **khello.c**):
307 Nyní stačí zavolat `make` se správnými parametry:
309 make -C /lib/modules/$(uname -r)/build M=$(pwd) modules
311 Tímto říkáme, že příkaz `make` načte `Makefile` z adresáře se
312 zdrojovými kódy aktuálně běžícího jádra (o který adresář se jedná
313 můžete zjisti pomocí `readlink -f /lib/modules/$(uname -r)/build`),
314 pomocí proměnné `M` řeknete, že se váš modul nachází v aktuálním
315 adresáři a slovo `modules` na konci znamená, že chcete, aby se
316 zkompilovaly pouze moduly.
318 Pokud vše dopadlo dobře, objevil se vám soubor `khello.ko`, což je
319 modul, který můžete zavést do jádra příkazem
328 1. Stáhněte si [[tento program|magic]] ([[32-bitová verze|magic32]]) a
329 zprovozněte ho ve vámi vytvořeném systému. Zprovoznění znamená, že
330 po spuštění program nevypíše žádnou chybu. Nezapomeňte nastavit
331 práva pro spouštění příkazem `chmod +x`.
333 Ke zjištění případným problémů by se vám mohly hodit příkazy
334 `strace` a `ltrace`. Ten prvý vypisuje všechna systémová volání
335 vyvolaná daným programem a druhý vypisuje jaké funkce ze sdílených
336 knihoven program volá. Zkuste si například spustit následující
343 2. Vytvořte jednoduchý jaderný modul, který po zavedení do jádra vypíše
344 vaše jméno (objeví se ve výstupu příkazu `dmesg`). Jinak nemusí dělat nic.
345 Předveďte činnost vašeho modulu ve vámi vytvořeném systému běžícím v
348 Kdo se bude nudit, může zkusit rozšířit modul tak, aby se jeho jméno
349 objevilo v souboru `/proc/myname` nebo vytvořit jednoduchý ovladač,
350 který bude vracet vaše jméno při čtení z `/dev/myname`. Návod najdete
351 v [tomto článku][henson_drivers] (strany 2 a 3).
356 * Pro vyvolání určitého příkazu z historie můžete použít klávesu
357 `Ctrl-R` následovanou textem hledaného příkazu. Např:
361 * Pro rychlé kopírování textu mezi programy (např. příkazy z této stránky do shellu),
362 můžete použít prostřední tlačítko myši. Funguje to tak, že text označíte myší
363 (nemačkáte při tom Ctrl-C) a stiskem prostředního tlačítka myši v terminálovém
364 okně ho vložíte na příkazovou řádku shellu. Tím, že při tom nemusíte šahat na
365 klávesnici vám to půjde rychleji.
367 * Pokud je Qemu spouštěný přes vzdálené připojení (např. server postel),
368 je potřeba pro zobrazení emulované obrazovky spouštěného stroje
369 buď provést protunelování X protokolu (`ssh -X`) nebo používat Qemu
370 s emulací obrazovky v textovém režimu `qemu -curses`. Další možnost
371 je emulovat HW bez grafické karty `qemu -nographic` a nastavit testovaný
372 systém tak, aby systémová konzole směřovala na sériový port
373 (`-append console=ttyS0`).
378 * [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)
379 * [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)
380 * [Inside the Linux boot process](http://www.ibm.com/developerworks/linux/library/l-linuxboot/)
381 * [The Linux Bootdisk HOWTO](http://www.tldp.org/HOWTO/Bootdisk-HOWTO/)
382 * [Linux Loadable Kernel Module HOWTO](http://tldp.org/HOWTO/Module-HOWTO/)
383 * [Linux Device Drivers, Third Edition][LDD3]
384 * [Kbuild & modules](http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blob;f=Documentation/kbuild/modules.txt;hb=HEAD)
385 * [/dev/hello_world: A Simple Introduction to Device Drivers under Linux](henson_drivers)
386 * [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)
387 * [Filip Navara: Diplomová práce - Rozšíření QEMU o podporu mikrokontroléru AT91SAM7X256](http://rtime.felk.cvut.cz/hw/index.php/AT91SAM7X256)
388 * [Aleš Kapica a další: Stránky o virtualizaci z oddělení IT K13135](https://support.dce.felk.cvut.cz/mediawiki/index.php/Kategorie:QEMU)
390 [LDD3]:http://lwn.net/Kernel/LDD3/
391 [henson_drivers]:http://linuxdevcenter.com/pub/a/linux/2007/07/05/devhelloworld-a-simple-introduction-to-device-drivers-under-linux.html
393 <!-- TODO pro pristi rok: Pokud i tohle bude moc jednoduché:
394 Zakladni uloha jen za 3 body, za dalsi dva body uloha bez navodu: dame
395 jim binarku, ktera bude chctit sdilenou knihovnu a tu budou muset