]> rtime.felk.cvut.cz Git - edu/osp-wiki.git/blob - cviceni/2.mdwn
Simek Adam -- test
[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áhněte si zdrojové kódy z git repozitáře projektu [BusyBox][]
40    (adresu repozitáře si najděte sami).
41
42        git clone ...
43        cd busybox
44
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
48
49        gitk
50
51     a můžeme si vybrat verzi, kde se chyba nevyskytuje. Například
52
53        git checkout -f 1_22_0
54
55 2. Zkonfigurujeme jak chceme BusyBox přeložit. 
56
57        make menuconfig
58
59    Vystačíme s výchozí konfigurací, takže zvolte `Exit` a odpovězte
60    `Yes`, že chcete konfiguraci uložit.
61    
62 3. Kompilaci provedeme tradičně příkazem
63
64        make
65
66 4. Příkazem
67
68        make install
69
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.
73     
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`).
78     
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.
81
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
85    pouze BusyBoxem:
86
87        # chroot _install /bin/sh
88
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é.
91    
92 [chroot]:http://en.wikipedia.org/wiki/Chroot
93
94 6. Knihovny, které `busybox` potřebuje ke svému běhu, zjistíte
95    příkazem
96
97        ldd _install/bin/busybox
98
99    Na 32-bitovém systému to může vypadat například takto:
100
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)
105
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:
110
111        mkdir _install/lib
112        cp /lib/i686/cmov/libm.so.6 /lib/i686/cmov/libc.so.6 /lib/ld-linux.so.2 _install/lib
113
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
116    `/lib64`**.
117
118    Nyní už můžete spustit BusyBox v chroot prostředí.
119
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.
123    
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.
127
128    1. Pokud máte *rootovská* práva, použijte ke tvorbě RAM-disku
129       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       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`.
163
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      
165
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é
170    jádro z distribuce.
171    
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.
175
176 6. Bootování jádra s naším filesystémem (v emulátoru):
177
178    Na 64-bitovém systému spustíme emulátor následovně:
179
180        qemu-system-x86_64 -kernel /boot/vmlinuz-3.2.0-4-amd64 -initrd ramdisk
181
182    Na 32-bitovém systému většinou stačí zkrácený název `qemu`:
183
184        qemu -kernel /boot/vmlinuz-2.6.26-2-686 -initrd ramdisk
185
186    Pokud systém nabízí hardwarovou podporu virtualizace, je výhodné
187    použít [KVM][kvm]. Výsledek pak běží rychleji. Například:
188
189        kvm -kernel /boot/vmlinuz-3.2.0-4-amd64 -initrd ramdisk
190
191 [kvm]:http://www.linux-kvm.org/ 
192
193 7. Pokud vše proběhlo správně, zobrazila se hláška
194
195        Please press Enter to activate this console.
196     
197    Po stisku Enteru se spustí shell a můžete začít pracovat ve
198    vašem právě vytvořeném systému.
199    
200 Možná vylepšení
201 ===============
202
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.
205
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.
209
210        mount -t proc none /proc
211
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.
214
215        mkdir -p _install/etc/init.d
216        cat <<EOF > _install/etc/init.d/rcS
217        #!/bin/sh
218        mount -t proc none /proc
219        echo Nazdar!!!!
220        EOF
221        chmod +x _install/etc/init.d/rcS    # nastavení spustitelnosti
222
223    Nyní musíte znovu vytvořit RAM-disk a nabootovat.
224
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:
228
229        qemu -serial stdio ...
230
231    a jádru předáme parametr `console=ttyS0`
232
233        qemu -serial stdio -append console=ttyS0 ...
234
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:
238
239        qemu -net nic,vlan=0,model=ne2k_pci -net user,vlan=0 ...
240
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:
244
245        qemu -virtfs local,path=shared_dir_name,security_model=none,mount_tag=shared_tag ...
246
247    Adresářovou strukturu lze z vnitřního systému připojit následujícími
248    příkazy
249
250        modprobe virtio
251            modprobe virtio_ring
252            modprobe virtio_pci
253            modprobe 9pnet
254            modprobe 9pnet_virtio
255            modprobe 9p
256            mkdir -p /mnt/shareddir
257            mount -t 9p -o trans=virtio shared_tag /mnt/shareddir
258
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
262
263 Jaderné moduly
264 ==============
265
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
272 (např. libata).
273
274 Zdrojový kód jednoduchého jaderného modulu vypadá následovně: 
275
276     #include <linux/init.h>
277     #include <linux/module.h>
278     MODULE_LICENSE("Dual BSD/GPL");
279     
280     static int hello_init(void)
281     {
282         printk(KERN_ALERT "Hello, world\n");
283         return 0;
284     }
285     
286     static void hello_exit(void)
287     {
288         printk(KERN_ALERT "Goodbye, cruel world\n");
289     }
290     
291     module_init(hello_init);
292     module_exit(hello_exit);
293 *Příklad převzat z [LDD3][LDD3].*
294
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**):
298
299     obj-m = khello.o
300
301 Nyní stačí zavolat `make` se správnými parametry:
302
303     make -C /lib/modules/$(uname -r)/build M=$(pwd) modules
304
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.
311
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
314
315     insmod khello.ko
316
317
318
319 Zadání
320 ======
321
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`.
326
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í
331    příkazy:
332
333         echo Ahoj
334         strace echo Ahoj
335         ltrace echo Ahoj
336
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
340    emulátoru.
341    
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).
346
347 Tipy a triky
348 ============
349
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ř:
352
353       <Ctrl-R>cpio<Enter>
354
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.
360
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`).
368
369 Reference
370 =========
371
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)
383   
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
386
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
390 napsat. -->