]> rtime.felk.cvut.cz Git - edu/osp-wiki.git/blob - cviceni/2.mdwn
64-bit QEMU variant after switching to 64-bit Squeeze
[edu/osp-wiki.git] / cviceni / 2.mdwn
1 [[!meta title="Embedded Linux"]]
2
3 [[!toc]]
4
5 Cíl cvičení
6 ===========
7
8 Open source projekty se často nepoužívají osamoceně, ale v kombinaci s
9 jinými OSS projekty, čímž vznikají tak tzv. OSS stacky. Asi
10 nejznámějším stackem je LAMP – Linux, Apache, MySQL, PHP. Na dnešním
11 cvičení se seznámíme s dalším, velmi často používaným, stackem
12 [Linux][kenrel] + [BusyBox][bb] (+[Dropbear][dropbear] SSH server).
13
14 [BusyBox][bb] je sada UNIXových uživatelských nástrojů (shell, editor,
15 utility jako ls, mkdir, …) zkompilovaná do jedné binárky. V kombinaci
16 s jádrem Linuxu tak dostáváme kompletní operační systém s poměrně
17 malými nároky na paměť. Díky tomu se tato kombinace často používá ve
18 vestavěných (embedded) aplikacích jako například
19 [WiFi routery či ADSL modemy][owrt].
20
21 V tomto cvičení si zkusíte vytvořit kompletní open source operační
22 systém z Linuxového jádra a uživatelského prostředí tvořeného právě
23 BusyBoxem. Dále si vyzkoušíte naprogramovat jednoduchý modul do jádra.
24
25 [kenrel]: http://kernel.org/
26 [bb]:http://busybox.net/
27 [owrt]:http://www.openwrt.org/
28 [dropbear]:http://matt.ucc.asn.au/dropbear/dropbear.html
29
30 Postup
31 ======
32
33 1. Stáhneme [zdrojové kódy][bbgit] projektu [BusyBox][bb]:
34
35         git clone git://busybox.net/busybox.git --reference /usr/src/busybox.git
36         cd busybox
37
38     Protože se jedná o aktuální vývojový snapshot, je možné, že se
39     při překladu, instalaci nebo používání vyskytne chyba. Naší výhodou
40     však je, že máme k dispozici kompletní historii projektu
41
42         qgit
43
44     a můžeme si vybrat verzi, kde se chyba nevyskytuje. Například
45
46         git checkout -f 1_18_3
47
48 [bbgit]:http://git.busybox.net/busybox/
49
50 2. Zkonfigurujeme jak chceme BusyBox přeložit. 
51
52         make menuconfig
53
54    Vystačíme s výchozí konfigurací, takže zvolit `Exit` a odpovědět
55    `Yes`, že chceme konfiguraci uložit.
56    
57 3. Kompilaci provedeme tradičně příkazem
58
59         make
60
61 4. Příkazem
62
63         make install
64
65     nainstalujeme busybox do adresáře `./_install`. Všimněte si, že se
66     tam nachází pouze jedna binárka `bin/busybox` a všechno ostatní
67     jsou pouze symbolické odkazy na tuto binárku.
68     
69     Protože neprovádíme tzv. *křížový překlad*, který je běžný pro v
70     případě vestavěných zařízení, můžeme výsledek hned otestovat
71     například spuštěním shellu: `./_install/bin/sh` (ukončíme ho např.
72     příkazem `exit`).
73     
74     V případě skutečného vestavěného systému bychom museli pokračovat
75     dál a busybox otestovat až po nabootování na cílovém hardwaru.
76
77 5. Pokud máte na vašem počítači práva superuživatele root, můžete
78    otestovat BusyBox v chroot prostředí, t.j. se stejným jádrem jako
79    právě běží na vašem počítači, ale se souborovým systémem tvořeným
80    pouze BusyBoxem:
81
82         # chroot _install /bin/sh
83
84    Fungovat to ale nebude, protože ke spuštění BusyBoxu jsou potřeba
85    knihovny, které v nejsou v adresáři `_install` dostupné.
86
87 6. Chybějící knihovny zjistíte příkazem
88
89         ldd _install/bin/busybox
90         
91    Tyto knihovny musíte nakopírovat do adresáře `_install`
92
93         mkdir _install/lib
94         cp /lib/i686/cmov/libm.so.6 /lib/i686/cmov/libc.so.6 /lib/ld-linux.so.2 _install/lib
95
96    Nyní už můžete spustit BusyBox v chroot prostředí.
97
98 5. Nejjednodušší možnost jak nabootovat do právě vytvořeného
99    uživatelského prostředí je uložit ho ve formátu pro Linuxový
100    startovací RAM-disk a nabootovat Linux s tímto RAM-diskem.
101    
102    Aby vše fungovalo jak má, kromě souborů v adresáři `_install` musí
103    RAM-disk obsahovat i někoik položek v adresáři `/dev` pro přístup k
104    virtuálním terminálům.
105
106    1. Pokud máte root práva, použijte ke tvorbě RAM-disku následující příkazy:
107
108             mkdir _install/{dev,etc,proc,sys}
109             sudo cp -a /dev/tty? _install/dev
110             ln -s bin/busybox _install/init
111             (cd _install; find . | cpio -o -H newc | gzip) > ramdisk
112
113    2. Bez rootovských práv můžete RAM-disk vytvořit pomocí nástoje
114       [gen_init_cpio][gic].
115
116             (
117             cat <<EOF
118             dir /dev 755 0 0
119             nod /dev/tty0 644 0 0 c 4 0
120             nod /dev/tty1 644 0 0 c 4 1
121             nod /dev/tty2 644 0 0 c 4 2
122             nod /dev/tty3 644 0 0 c 4 3
123             nod /dev/tty4 644 0 0 c 4 4
124             slink /init bin/busybox 700 0 0
125             dir /proc 755 0 0
126             dir /sys 755 0 0
127             EOF
128             
129             find _install -mindepth 1 -type d -printf "dir /%P %m 0 0\n"
130             find _install -type f -printf "file /%P %p %m 0 0\n"
131             find _install -type l -printf "slink /%P %l %m 0 0\n"
132             ) > filelist
133             
134             gen_init_cpio filelist | gzip > ramdisk
135
136 [gic]:http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blob;f=usr/gen_init_cpio.c;hb=HEAD      
137
138 5. **Jádro Linuxu**. Příprava jádra je téměř stejná jako u BusyBoxu:
139    stáhneme zdrojový kód, nakonfigurujeme a přeložíme. Vzhledem k
140    rozsáhlosti jádra (zkompilované zabere na disku cca 1 GB a překlad
141    trvá cca 20 minut) tyto kroky přeskočíme a použijeme již připravené
142    jádro z distribuce.
143    
144    Pokud byste si chtěli přeložit vlastní jádro, v následujícím
145    příkazu byste za parametrem *-kernel* uvedli cestu k vámi
146    zkompilovanému jádru.
147
148 6. Bootování jádra s naším filesystémem (v emulátoru):
149
150         qemu -kernel /boot/vmlinuz-2.6.26-2-686 -initrd ramdisk
151
152     Pokud systém nabízí hardwarovou podporu virtualizace, je výhodné
153     použít KVM, které pak běží rychleji
154
155         kvm -kernel /boot/vmlinuz-2.6.32-5-amd64 -initrd ramdisk
156
157     Na 64-bitovém systému může být potřeba použít příslušnou variantu QEMU
158
159         qemu-system-x86_64 -kernel /boot/vmlinuz-2.6.32-5-amd64 -initrd ramdisk
160
161 7. Pokud vše proběhlo správně, zobrazila se hláška
162
163         Please press Enter to activate this console.
164     
165    Po stisku Enteru se spustí shell a můžete začít pracovat ve
166    vašem právě vytvořeném systému.
167    
168 Možná vylepšení
169 ===============
170
171 Dále můžete provést drobná vylepšení vašeho systému, která vám mohou
172 zjednodušit další práci.
173
174 1. Můžete připojit souborový systém `/proc`, aby fungovaly příkazy
175    jako např. `ps` (výpis běžících procesů). Příkaz spusťte v
176    emulátoru, ne na vaší pracovní stanici.
177
178         mount -t proc none /proc
179
180 2. V RAM-disku můžete vytvořit soubor `/etc/init.d/rcS`, který bude
181    obsahovat příkazy, které budou spuštěny při bootu systému.
182
183         mkdir -p _install/etc/init.d
184         cat <<EOF > _install/etc/init.d/rcS
185         #!/bin/sh
186         mount -t proc none /proc
187         echo Nazdar!!!!
188         EOF
189         chmod +x _install/etc/init.d/rcS    # nastavení spustitelnosti
190
191    Nyní musíte znovu vytvořit RAM-disk a nabootovat.
192
193 Jaderné moduly
194 ==============
195
196 Jaderné moduly jsou přeložené kusy kódu, které lze za běhu nahrávat do
197 Linuxvého jádra. Pokud bychom chtěli nalézt analogickou věc v
198 uživatelském prostředí, pak by to byly *sdílené knihovny*. Jaderný
199 modul může obsahovat kód ovladače zařízení, podporu určitého
200 souborového systému, může přidávat do jádra nové funkce (např.
201 firewall) či sloužit jako knihovna pomocných funkcí pro jiné moduly
202 (např. libata).
203
204 Zdrojový kód jednoduchého jaderného modulu vypadá následovně: 
205
206     #include <linux/init.h>
207     #include <linux/module.h>
208     MODULE_LICENSE("Dual BSD/GPL");
209     
210     static int hello_init(void)
211     {
212         printk(KERN_ALERT "Hello, world\n");
213         return 0;
214     }
215     
216     static void hello_exit(void)
217     {
218         printk(KERN_ALERT "Goodbye, cruel world\n");
219     }
220     
221     module_init(hello_init);
222     module_exit(hello_exit);
223 *Příklad převzat z [LDD3][LDD3].*
224
225 Překlad modulu provedeme pomocí jednoduchého souboru Makefile, který
226 bude obsahovat jedinou řádku (zde předpokládáme, že výše uvedený
227 soubor se jmenuje **khello.c**):
228
229     obj-m = khello.o
230
231 Nyní stačí zavolat `make` se správnými parametry:
232
233     make -C /lib/modules/$(uname -r)/build M=$(pwd) modules
234
235 Tímto říkáme, že příkaz `make` načte `Makefile` z adresáře se
236 zdrojovými kódy aktuálně běžícího jádra (o který adresář se jedná
237 můžete zjistít pomocí `readlink -f /lib/modules/$(uname -r)/build`),
238 pomocí proměnné `M` řeknete, že se váš modul nachází v aktuálním
239 adresáři a slovo `modules` na konci znamená, že chcete, aby se
240 zkompilovaly pouze moduly.
241
242 Pokud vše dopadlo dobře, objevil se vám soubor `khello.ko`, což je
243 modul, který můžete zavést do jádra příkazem
244
245     insmod khello.ko
246
247
248
249 Zadání
250 ======
251
252 Vytvořte jednoduchý jaderný modul, který po zavedení do jádra vypíše
253 vaše jméno (objeví se ve výstupu `dmesg`). Jinak nemusí dělat nic.
254 Předveďte činnost vašeho modulu ve vámi vytvořeném systému běžícím v
255 emulátoru.
256
257 **Pozor:** V zadání je drobný chyták!
258
259 Kdo se bude nudit, může zkusit rozšířit modul tak, aby se jeho jméno
260 objevilo v souboru `/proc/myname` nebo vytvořit jednoduchý ovladač,
261 který bude vracet vaše jméno při čtení z `/dev/myname`. Návod najdete
262 v [tomto článku][henson_drivers] (strany 2 a 3).
263
264 Tipy a triky
265 ============
266
267 * Pro vyvolání určitého příkazu z historie můžete použít klávesu
268   `Ctrl-R` následovanou textem hledaného příkazu. Např:
269
270         <Ctrl-R>cpio<Enter>
271
272 * Pro rychlé kopírování textu mezi programy (např. příkazy z této stránky do shellu),
273   můžete použít prostřední tlačítko myši. Funguje to tak, že text označíte myší
274   (nemačkáte při tom Ctrl-C) a stiskem prostředního tlačítka myši v terminálovém
275   okně ho vložíte na příkazovou řádku shellu. Tím, že při tom nemusíte šahat na
276   klávesnici vám to půjde rychleji.
277
278 Reference
279 =========
280
281 * [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)
282 * [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)
283 * [Inside the Linux boot process](http://www.ibm.com/developerworks/linux/library/l-linuxboot/)  
284 * [The Linux Bootdisk HOWTO](http://www.tldp.org/HOWTO/Bootdisk-HOWTO/)  
285 * [Linux Loadable Kernel Module HOWTO](http://tldp.org/HOWTO/Module-HOWTO/)
286 * [Linux Device Drivers, Third Edition][LDD3]
287 * [Kbuild & modules](http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blob;f=Documentation/kbuild/modules.txt;hb=HEAD)
288 * [/dev/hello_world: A Simple Introduction to Device Drivers under Linux](henson_drivers)
289   
290 [LDD3]:http://lwn.net/Kernel/LDD3/
291 [henson_drivers]:http://linuxdevcenter.com/pub/a/linux/2007/07/05/devhelloworld-a-simple-introduction-to-device-drivers-under-linux.html