[[!meta title="Embedded Linux"]] [[!toc]] Cíl cvičení =========== Open source projekty se často nepoužívají osamoceně, ale v kombinaci s jinými OSS projekty, čímž vznikají tak tzv. OSS stacky. Asi nejznámějším stackem je LAMP – Linux, Apache, MySQL, PHP. Na dnešním cvičení se seznámíme s dalším, velmi často používaným, stackem [Linux][kenrel] + [BusyBox][bb] (+[Dropbear][dropbear] SSH server). [BusyBox][bb] je sada UNIXových uživatelských nástrojů (shell, editor, utility jako ls, mkdir, …) zkompilovaná do jedné binárky. V kombinaci s jádrem Linuxu tak dostáváme kompletní operační systém s poměrně malými nároky na paměť. Díky tomu se tato kombinace často používá ve vestavěných (embedded) aplikacích jako například [WiFi routery či ADSL modemy][owrt]. V tomto cvičení si zkusíte vytvořit kompletní open source operační systém z Linuxového jádra a uživatelského prostředí tvořeného právě BusyBoxem. Dále si vyzkoušíte naprogramovat jednoduchý modul do jádra. [kenrel]: http://kernel.org/ [bb]:http://busybox.net/ [owrt]:http://www.openwrt.org/ [dropbear]:http://matt.ucc.asn.au/dropbear/dropbear.html Postup ====== 1. Stáhneme [zdrojové kódy][bbgit] projektu [BusyBox][bb]: git clone git://busybox.net/busybox.git --reference /usr/src/busybox.git cd busybox [bbgit]:http://git.busybox.net/busybox/ 2. Zkonfigurujeme jak chceme BusyBox přeložit. make menuconfig Vystačíme s výchozí konfigurací, takže zvolit `Exit` a odpovědět `Yes`, že chceme konfiguraci uložit. 3. Kompilaci provedeme tradičně příkazem make 4. Příkazem make install nainstalujeme busybox do adresáře `./_install`. Všimněte si, že se tam nachází pouze jedna binárka `bin/busybox` a všechno ostatní jsou pouze symbolické odkazy na tuto binárku. Protože neprovádíme tzv. *křížový překlad*, který je běžný pro v případě vestavěných zařízení, můžeme výsledek hned otestovat například spuštěním shellu: `./_install/bin/sh` (ukončíme ho např. příkazem `exit`). V případě skutečného vestavěného systému bychom museli pokračovat dál a bysybox otestovat až po nabootování na cílovém hardwaru. 5. Pokud máte na vašem počítači práva superuživatele root, můžete otestovat BusyBox v chroot prostředí, t.j. se stejným jádrem jako právě běží na vašem počítači, ale se souborovým systémem tvořeným pouze BusyBoxem: # chroot _install /bin/sh Fungovat to ale nebude, protože ke spuštění BusyBoxu jsou potřeba knihovny, které v nejsou v adresáři `_install` dostupné. 6. Chybějící knihovny zjistíte příkazem ldd _install/bin/busybox Tyto knihovny musíte nakopírovat do adresáře `_install` mkdir _install/lib cp /lib/i686/cmov/libm.so.6 /lib/i686/cmov/libc.so.6 /lib/ld-linux.so.2 _install/lib Nyní už můžete spustit BusyBox v chroot prostředí. 5. Nejjednodušší možnost jak nabootovat do právě vytvořeného uživatelského prostředí je uložit ho ve formátu pro Linuxový startovací RAM-disk a nabootovat Linux s tímto RAM-diskem. Aby vše fungovalo jak má, kromě souborů v adresáři `_install` musí RAM-disk obsahovat i někoik položek v adresáři `/dev` pro přístup k virtuálním terminálům. 1. Pokud máte root práva, použijte ke tvorbě RAM-disku následující příkazy: mkdir _install/{dev,etc,proc,sys} sudo cp -a /dev/tty? _install/dev ln -s bin/busybox _install/init (cd _install; find . | cpio -o -H newc | gzip) > ramdisk 2. Bez rootovských práv můžete RAM-disk vytvořit pomocí nástoje [gen_init_cpio][gic]. ( cat < filelist gen_init_cpio filelist > ramdisk [gic]:http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blob;f=usr/gen_init_cpio.c;hb=HEAD 5. **Jádro Linuxu**. Příprava jádra je téměř stejná jako u BusyBoxu: stáhneme zdrojový kód, nakonfigurujeme a přeložíme. Vzhledem k rozsáhlosti jádra (zkompilované zabere na disku cca 1 GB a překlad trvá cca 20 minut) tyto kroky přeskočíme a použijeme již připravené jádro z distribuce. Pokud byste si chtěli přeložit vlastní jádro, v následujícím příkazu byste za parametrem *-kernel* uvedli cestu k vámi zkompilovanému jádru. 6. Bootování jádra s naším filesystémem (v emulátoru): qemu -kernel /boot/vmlinuz-2.6.26-2-686 -initrd ramdisk 7. Pokud vše proběhlo správně, zobrazila se hláška Please press Enter to activate this console. Po stisku Enteru se spustí shell a můžete začít pracovat ve vašem právě vytvořeném systému. Možná vylepšení =============== Dále můžete provést drobná vylepšení vašeho systému, která vám mohou zjednodušit další práci. 1. Můžete připojit souborový systém `/proc`, aby fungovaly příkazy jako např. `ps` (výpis běžících procesů). Příkaz spusťte v emulátoru, ne na vaší pracovní stanici. mount -t proc none /proc 2. V RAM-disku můžete vytvořit soubor `/etc/init.d/rcS`, který bude obsahovat příkazy, které budou spuštěny při bootu systému. mkdir -p _install/etc/init.d cat < _install/etc/init.d/rcS #!/bin/sh mount -t proc none /proc echo Nazdar!!!! EOF chmod +x _install/etc/init.d/rcS # nastavení spustitelnosti Nyní musíte znovu vytvořit RAM-disk a nabootovat. Jaderné moduly ============== Jaderné moduly jsou přeložené kusy kódu, které lze za běhu nahrávat do Linuxvého jádra. Pokud bychom chtěli nalézt analogickou věc v uživatelském prostředí, pak by to byly *sdílené knihovny*. Jaderný modul může obsahovat kód ovladače zařízení, podporu určitého souborového systému, může přidávat do jádra nové funkce (např. firewall) či sloužit jako knihovna pomocných funkcí pro jiné moduly (např. libata). Zdrojový kód jednoduchého jaderného modulu vypadá následovně: #include #include MODULE_LICENSE("Dual BSD/GPL"); static int hello_init(void) { printk(KERN_ALERT "Hello, world\n"); return 0; } static void hello_exit(void) { printk(KERN_ALERT "Goodbye, cruel world\n"); } module_init(hello_init); module_exit(hello_exit); *Příklad převzat z [LDD3][LDD3].* Překlad modulu provedeme pomocí jednoduchého souboru Makefile, který bude obsahovat jedinou řádku (zde předpokládáme, že výše uvedený soubor se jmenuje khello.c): obj-m = khello.o Nyní stačí zavolat `make` se správnými parametry: make -C /lib/modules/$(uname -r)/build M=$(pwd) modules Tímto říkáme, že příkaz `make` načte `Makefile` z adresáře se zdrojovými kódy aktuálně běžícího jádra (o který adresář se jedná můžete zjistít pomocí `readlink -f /lib/modules/$(uname -r)/build`), pomocí proměnné `M` řeknete, že se váš modul nachází v aktuálním adresáři a slovo `modules` na konci znamená, že chcete, aby se zkompilovaly pouze moduly. Pokud vše dopadlo dobře, objevil se vám soubor `khello.ko`, což je modul, který můžete zavést do jádra příkazem insmod khello.ko Zadání ====== Vytvořte jednoduchý jaderný modul, který po zavedení do jádra vypíše vaše jméno (objeví se ve výstupu `dmesg`). Jinak nemusí dělat nic. Předveďte činnost vašeho modulu ve vámi vytvořeném systému běžícím v emulátoru. Kdo se bude nudit, může zkusit rozšířit modul tak, aby se jeho jméno objevilo v souboru `/proc/myname` nebo vytvořit jednoduchý ovladač, který bude vracet vaše jméno při čtení z `/dev/myname`. Návod najdete v [tomto článku][henson_drivers] (strany 2 a 3). Tipy a triky ============ * Pro vyvolání určitého příkazu z historie můžete použít klávesu `Ctrl-R` následovanou textem hledaného příkazu. Např: cpio * Pro rychlé kopírování textu mezi programy (např. příkazy z této stránky do shellu), můžete použít prostřední tlačítko myši. Funguje to tak, že text označíte myší (nemačkáte při tom Ctrl-C) a stiskem prostředního tlačítka myši v terminálovém okně ho vložíte na příkazovou řádku shellu. Tím, že při tom nemusíte šahat na klávesnici vám to půjde rychleji. Reference ========= * [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) * [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) * [Inside the Linux boot process](http://www.ibm.com/developerworks/linux/library/l-linuxboot/) * [The Linux Bootdisk HOWTO](http://www.tldp.org/HOWTO/Bootdisk-HOWTO/) * [Linux Loadable Kernel Module HOWTO](http://tldp.org/HOWTO/Module-HOWTO/) * [Linux Device Drivers, Third Edition][LDD3] * [Kbuild & modules](http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blob;f=Documentation/kbuild/modules.txt;hb=HEAD) * [/dev/hello_world: A Simple Introduction to Device Drivers under Linux](henson_drivers) [LDD3]:http://lwn.net/Kernel/LDD3/ [henson_drivers]:http://linuxdevcenter.com/pub/a/linux/2007/07/05/devhelloworld-a-simple-introduction-to-device-drivers-under-linux.html