]> rtime.felk.cvut.cz Git - edu/osp-wiki.git/blob - cviceni/2.mdwn
lectures: minor update of link to LinuxDays 2023 presentation listing.
[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 Linuxové jádro 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. 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ů:
128
129    1. Pokud máte *rootovská* práva, použijte ke tvorbě RAM-disku
130       následující příkazy:
131
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
136
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].
140
141           (
142           cat <<EOF
143           dir /dev 755 0 0
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
150           dir /proc 755 0 0
151           dir /sys 755 0 0
152           EOF
153             
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"
157           ) > filelist
158             
159           gen_init_cpio filelist | gzip > ramdisk
160
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
165       `ramdisk`.
166
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      
168
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é
173    jádro z distribuce.
174    
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.
178
179 6. Bootování jádra s naším filesystémem (v softwarovém emulátoru
180    systému):
181
182    Na 64-bitovém systému spustíme emulátor následovně:
183
184        qemu-system-x86_64 -kernel /boot/vmlinuz-3.2.0-4-amd64 -initrd ramdisk
185
186    Na 32-bitovém systému použijte:
187
188        qemu-system-i386 -kernel /boot/vmlinuz-2.6.26-2-686 -initrd ramdisk
189
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:
194
195        kvm -kernel /boot/vmlinuz-3.2.0-4-amd64 -initrd ramdisk
196
197 [kvm]:http://www.linux-kvm.org/ 
198
199 7. Pokud vše proběhlo správně, zobrazila se hláška
200
201        Please press Enter to activate this console.
202     
203    Po stisku Enteru se spustí shell a můžete začít pracovat ve
204    vašem právě vytvořeném systému.
205    
206 Možná vylepšení
207 ===============
208
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.
211
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.
215
216        mount -t proc none /proc
217
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.
220
221        mkdir -p _install/etc/init.d
222        cat <<EOF > _install/etc/init.d/rcS
223        #!/bin/sh
224        mount -t proc none /proc
225        echo Nazdar!!!!
226        EOF
227        chmod +x _install/etc/init.d/rcS    # nastavení spustitelnosti
228
229    Nyní musíte znovu vytvořit RAM-disk a nabootovat.
230
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:
234
235        qemu -serial stdio ...
236
237    a jádru předáme parametr `console=ttyS0`
238
239        qemu -serial stdio -append console=ttyS0 ...
240
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:
244
245        qemu -net nic,vlan=0,model=ne2k_pci -net user,vlan=0 ...
246
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:
250
251        qemu -virtfs local,path=shared_dir_name,security_model=none,mount_tag=shared_tag ...
252
253    Adresářovou strukturu lze z vnitřního systému připojit následujícími
254    příkazy
255
256        modprobe virtio
257            modprobe virtio_ring
258            modprobe virtio_pci
259            modprobe 9pnet
260            modprobe 9pnet_virtio
261            modprobe 9p
262            mkdir -p /mnt/shareddir
263            mount -t 9p -o trans=virtio shared_tag /mnt/shareddir
264
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
268
269 Jaderné moduly
270 ==============
271
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
278 (např. libata).
279
280 Zdrojový kód jednoduchého jaderného modulu vypadá následovně: 
281
282     #include <linux/init.h>
283     #include <linux/module.h>
284     MODULE_LICENSE("Dual BSD/GPL");
285     
286     static int hello_init(void)
287     {
288         printk(KERN_ALERT "Hello, world\n");
289         return 0;
290     }
291     
292     static void hello_exit(void)
293     {
294         printk(KERN_ALERT "Goodbye, cruel world\n");
295     }
296     
297     module_init(hello_init);
298     module_exit(hello_exit);
299 *Příklad převzat z [LDD3][LDD3].*
300
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**):
304
305     obj-m = khello.o
306
307 Nyní stačí zavolat `make` se správnými parametry:
308
309     make -C /lib/modules/$(uname -r)/build M=$(pwd) modules
310
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.
317
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
320
321     insmod khello.ko
322
323
324
325 Zadání
326 ======
327
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`.
332
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í
337    příkazy:
338
339         echo Ahoj
340         strace echo Ahoj
341         ltrace echo Ahoj
342
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
346    emulátoru.
347    
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).
352
353 Tipy a triky
354 ============
355
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ř:
358
359       <Ctrl-R>cpio<Enter>
360
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.
366
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`).
374
375 Reference
376 =========
377
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)
389   
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
392
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
396 napsat. -->