]> rtime.felk.cvut.cz Git - edu/osp-wiki.git/blob - cviceni/2.mdwn
use BusyBox 1_18_3 - b9348440b0491b479457b304754bca4840286f74 has problem with make...
[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 7. Pokud vše proběhlo správně, zobrazila se hláška
153
154         Please press Enter to activate this console.
155     
156    Po stisku Enteru se spustí shell a můžete začít pracovat ve
157    vašem právě vytvořeném systému.
158    
159 Možná vylepšení
160 ===============
161
162 Dále můžete provést drobná vylepšení vašeho systému, která vám mohou
163 zjednodušit další práci.
164
165 1. Můžete připojit souborový systém `/proc`, aby fungovaly příkazy
166    jako např. `ps` (výpis běžících procesů). Příkaz spusťte v
167    emulátoru, ne na vaší pracovní stanici.
168
169         mount -t proc none /proc
170
171 2. V RAM-disku můžete vytvořit soubor `/etc/init.d/rcS`, který bude
172    obsahovat příkazy, které budou spuštěny při bootu systému.
173
174         mkdir -p _install/etc/init.d
175         cat <<EOF > _install/etc/init.d/rcS
176         #!/bin/sh
177         mount -t proc none /proc
178         echo Nazdar!!!!
179         EOF
180         chmod +x _install/etc/init.d/rcS    # nastavení spustitelnosti
181
182    Nyní musíte znovu vytvořit RAM-disk a nabootovat.
183
184 Jaderné moduly
185 ==============
186
187 Jaderné moduly jsou přeložené kusy kódu, které lze za běhu nahrávat do
188 Linuxvého jádra. Pokud bychom chtěli nalézt analogickou věc v
189 uživatelském prostředí, pak by to byly *sdílené knihovny*. Jaderný
190 modul může obsahovat kód ovladače zařízení, podporu určitého
191 souborového systému, může přidávat do jádra nové funkce (např.
192 firewall) či sloužit jako knihovna pomocných funkcí pro jiné moduly
193 (např. libata).
194
195 Zdrojový kód jednoduchého jaderného modulu vypadá následovně: 
196
197     #include <linux/init.h>
198     #include <linux/module.h>
199     MODULE_LICENSE("Dual BSD/GPL");
200     
201     static int hello_init(void)
202     {
203         printk(KERN_ALERT "Hello, world\n");
204         return 0;
205     }
206     
207     static void hello_exit(void)
208     {
209         printk(KERN_ALERT "Goodbye, cruel world\n");
210     }
211     
212     module_init(hello_init);
213     module_exit(hello_exit);
214 *Příklad převzat z [LDD3][LDD3].*
215
216 Překlad modulu provedeme pomocí jednoduchého souboru Makefile, který
217 bude obsahovat jedinou řádku (zde předpokládáme, že výše uvedený
218 soubor se jmenuje **khello.c**):
219
220     obj-m = khello.o
221
222 Nyní stačí zavolat `make` se správnými parametry:
223
224     make -C /lib/modules/$(uname -r)/build M=$(pwd) modules
225
226 Tímto říkáme, že příkaz `make` načte `Makefile` z adresáře se
227 zdrojovými kódy aktuálně běžícího jádra (o který adresář se jedná
228 můžete zjistít pomocí `readlink -f /lib/modules/$(uname -r)/build`),
229 pomocí proměnné `M` řeknete, že se váš modul nachází v aktuálním
230 adresáři a slovo `modules` na konci znamená, že chcete, aby se
231 zkompilovaly pouze moduly.
232
233 Pokud vše dopadlo dobře, objevil se vám soubor `khello.ko`, což je
234 modul, který můžete zavést do jádra příkazem
235
236     insmod khello.ko
237
238
239
240 Zadání
241 ======
242
243 Vytvořte jednoduchý jaderný modul, který po zavedení do jádra vypíše
244 vaše jméno (objeví se ve výstupu `dmesg`). Jinak nemusí dělat nic.
245 Předveďte činnost vašeho modulu ve vámi vytvořeném systému běžícím v
246 emulátoru.
247
248 **Pozor:** V zadání je drobný chyták!
249
250 Kdo se bude nudit, může zkusit rozšířit modul tak, aby se jeho jméno
251 objevilo v souboru `/proc/myname` nebo vytvořit jednoduchý ovladač,
252 který bude vracet vaše jméno při čtení z `/dev/myname`. Návod najdete
253 v [tomto článku][henson_drivers] (strany 2 a 3).
254
255 Tipy a triky
256 ============
257
258 * Pro vyvolání určitého příkazu z historie můžete použít klávesu
259   `Ctrl-R` následovanou textem hledaného příkazu. Např:
260
261         <Ctrl-R>cpio<Enter>
262
263 * Pro rychlé kopírování textu mezi programy (např. příkazy z této stránky do shellu),
264   můžete použít prostřední tlačítko myši. Funguje to tak, že text označíte myší
265   (nemačkáte při tom Ctrl-C) a stiskem prostředního tlačítka myši v terminálovém
266   okně ho vložíte na příkazovou řádku shellu. Tím, že při tom nemusíte šahat na
267   klávesnici vám to půjde rychleji.
268
269 Reference
270 =========
271
272 * [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)
273 * [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)
274 * [Inside the Linux boot process](http://www.ibm.com/developerworks/linux/library/l-linuxboot/)  
275 * [The Linux Bootdisk HOWTO](http://www.tldp.org/HOWTO/Bootdisk-HOWTO/)  
276 * [Linux Loadable Kernel Module HOWTO](http://tldp.org/HOWTO/Module-HOWTO/)
277 * [Linux Device Drivers, Third Edition][LDD3]
278 * [Kbuild & modules](http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blob;f=Documentation/kbuild/modules.txt;hb=HEAD)
279 * [/dev/hello_world: A Simple Introduction to Device Drivers under Linux](henson_drivers)
280   
281 [LDD3]:http://lwn.net/Kernel/LDD3/
282 [henson_drivers]:http://linuxdevcenter.com/pub/a/linux/2007/07/05/devhelloworld-a-simple-introduction-to-device-drivers-under-linux.html