]> rtime.felk.cvut.cz Git - edu/osp-wiki.git/blob - cviceni/2.mdwn
5c607790bdcfac72868996826636092cf354d5e4
[edu/osp-wiki.git] / cviceni / 2.mdwn
1 [[!meta title="Embedded Linux"]]
2
3 [[!toc]]
4
5 Cíl cvičení
6 ===========
7
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.
13
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).
19
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].
26
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.
30
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
35
36 Postup
37 ======
38
39 1. Stáhneme [zdrojové kódy][bbgit] projektu [BusyBox][]:
40
41        git clone git://busybox.net/busybox.git --reference /usr/src/busybox.git
42        cd busybox
43
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
47
48        gitk
49
50     a můžeme si vybrat verzi, kde se chyba nevyskytuje. Například
51
52        git checkout -f 1_20_2
53
54 [bbgit]:http://git.busybox.net/busybox/
55
56 2. Zkonfigurujeme jak chceme BusyBox přeložit. 
57
58        make menuconfig
59
60    Vystačíme s výchozí konfigurací, takže zvolte `Exit` a odpovězte
61    `Yes`, že chcete konfiguraci uložit.
62    
63 3. Kompilaci provedeme tradičně příkazem
64
65        make
66
67 4. Příkazem
68
69        make install
70
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.
74     
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`).
79     
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.
82
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
86    pouze BusyBoxem:
87
88        # chroot _install /bin/sh
89
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é.
92    
93 [chroot]:http://en.wikipedia.org/wiki/Chroot
94
95 6. Knihovny, které `busybox` potřebuje ke svému běhu, zjistíte
96    příkazem
97
98        ldd _install/bin/busybox
99
100    Na 32-bitovém systému to může vypadat například takto:
101
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)
106
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:
111
112        mkdir _install/lib
113        cp /lib/i686/cmov/libm.so.6 /lib/i686/cmov/libc.so.6 /lib/ld-linux.so.2 _install/lib
114
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
117    `/lib64`**.
118
119    Nyní už můžete spustit BusyBox v chroot prostředí.
120
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.
124    
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.
128
129    1. Pokud máte root práva, použijte ke tvorbě RAM-disku následující příkazy:
130
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
135
136    2. Bez rootovských práv můžete RAM-disk vytvořit pomocí nástroje
137       [gen_init_cpio][gic].
138
139           (
140           cat <<EOF
141           dir /dev 755 0 0
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
148           dir /proc 755 0 0
149           dir /sys 755 0 0
150           EOF
151             
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"
155           ) > filelist
156             
157           gen_init_cpio filelist | gzip > ramdisk
158
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      
160
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é
165    jádro z distribuce.
166    
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.
170
171 6. Bootování jádra s naším filesystémem (v emulátoru):
172
173    Na 64-bitovém systému spustíme emulátor následovně:
174
175        qemu-system-x86_64 -kernel /boot/vmlinuz-2.6.32-5-amd64 -initrd ramdisk
176
177    Na 32-bitovém systému většinou stačí zkrácený název `qemu`:
178
179        qemu -kernel /boot/vmlinuz-2.6.26-2-686 -initrd ramdisk
180
181    Pokud systém nabízí hardwarovou podporu virtualizace, je výhodné
182    použít [KVM][kvm]. Výsledek pak běží rychleji. Například:
183
184        kvm -kernel /boot/vmlinuz-2.6.32-5-amd64 -initrd ramdisk
185
186 [kvm]:http://www.linux-kvm.org/ 
187
188 7. Pokud vše proběhlo správně, zobrazila se hláška
189
190        Please press Enter to activate this console.
191     
192    Po stisku Enteru se spustí shell a můžete začít pracovat ve
193    vašem právě vytvořeném systému.
194    
195 Možná vylepšení
196 ===============
197
198 Dále můžete provést drobná vylepšení vašeho systému, která vám mohou
199 zjednodušit další práci.
200
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.
204
205        mount -t proc none /proc
206
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.
209
210        mkdir -p _install/etc/init.d
211        cat <<EOF > _install/etc/init.d/rcS
212        #!/bin/sh
213        mount -t proc none /proc
214        echo Nazdar!!!!
215        EOF
216        chmod +x _install/etc/init.d/rcS    # nastavení spustitelnosti
217
218    Nyní musíte znovu vytvořit RAM-disk a nabootovat.
219
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
223
224        qemu -serial file:/tmp/virtual_guest.log ...
225
226    a jádro spustíme s parametrem `console=ttyS0`
227
228        qemu -serial file:/tmp/virtual_guest.log -append console=ttyS0 ...
229
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:
232
233        qemu -net nic,vlan=0,model=ne2k_pci -net user,vlan=0 ...
234
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:
238
239        qemu -virtfs local,path=shared_dir_name,security_model=none,mount_tag=shared_tag ...
240
241    Adresářovou strukturu lze z vnitřního systému připojit následujícími
242    příkazy
243
244        modprobe virtio
245            modprobe virtio_ring
246            modprobe virtio_pci
247            modprobe 9pnet
248            modprobe 9pnet_virtio
249            modprobe 9p
250            mkdir -p /mnt/shareddir
251            mount -t 9p -o trans=virtio shared_tag /mnt/shareddir
252
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
256
257 Jaderné moduly
258 ==============
259
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
266 (např. libata).
267
268 Zdrojový kód jednoduchého jaderného modulu vypadá následovně: 
269
270     #include <linux/init.h>
271     #include <linux/module.h>
272     MODULE_LICENSE("Dual BSD/GPL");
273     
274     static int hello_init(void)
275     {
276         printk(KERN_ALERT "Hello, world\n");
277         return 0;
278     }
279     
280     static void hello_exit(void)
281     {
282         printk(KERN_ALERT "Goodbye, cruel world\n");
283     }
284     
285     module_init(hello_init);
286     module_exit(hello_exit);
287 *Příklad převzat z [LDD3][LDD3].*
288
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**):
292
293     obj-m = khello.o
294
295 Nyní stačí zavolat `make` se správnými parametry:
296
297     make -C /lib/modules/$(uname -r)/build M=$(pwd) modules
298
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.
305
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
308
309     insmod khello.ko
310
311
312
313 Zadání
314 ======
315
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
319 emulátoru.
320
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).
325
326 Tipy a triky
327 ============
328
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ř:
331
332       <Ctrl-R>cpio<Enter>
333
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.
339
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`).
347
348 Reference
349 =========
350
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)
362   
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
365
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
369 napsat. -->