[[!meta title="Embedded Linux"]] [[!toc]] Aim of the Exercises ==================== The aim of this exercise is to practice building of the base system from open-source components presented during 2-nd lecture and motivate and practically introduce students for topics presented during 4-th lecture “*Linux kernel - beginning, development, components and device drivers; GNU libc and user space*”. If there are some steps or relations clear to you, we recommend you try Google to find information first and prepare to ask questions at the 4-th lecture. Open Source Software (OSS) projects are often not used alone but in combination with other OSS projects, resulting in the so-called OSS stacks or even distributions. Perhaps the best known is the LAMP stack - Linux, Apache, MySQL, PHP. In today's exercise you will learn and experiment with another, very often used, a stack of [Linux][kenrel] + [BusyBox][bb] (+[Dropbear][dropbear] SSH server). [BusyBox][bb] is a set of basic/standard UNIX utilities (shell, editor and such utilities as ls, mkdir, …) compiled into one binary. In combination with the Linux kernel it forms a complete minimal operating system with a relatively small footprint. Thanks to this combination is often used in embedded applications such as [WiFi routers and ADSL modems][owrt]. We try to create a complete open source operating system from the Linux kernel and user space environment consisting of just busybox during this exercise. Next, you try to program and load a simple module into the kernel. [kenrel]: http://kernel.org/ [bb]:http://busybox.net/ [owrt]:http://www.openwrt.org/ [dropbear]:http://matt.ucc.asn.au/dropbear/dropbear.html The Steps ========= 1. Download/clone [source code][bbgit] of [BusyBox][bb] project: git clone git://busybox.net/busybox.git --reference /usr/src/busybox.git cd busybox Because expanded source tree is a current development snapshot, it is quite possible that some problem is encountered during compilation, installing or use of the project. Our significant advantage is that cloned project repository contains whole project development history qgit and we can choose an older/stable version which is not affected by such problems. For example git checkout -f 1_18_3 [bbgit]:http://git.busybox.net/busybox/ 2. Next step is to configure BusyBox such way as intended. make menuconfig There is possibility to control build of many components but default configuration is suitable for our task. Selection of `Exit` and confirm by `Yes` to save configuration is enough for our case then. 3. Project is compiled by standard command make 4. Command make install installs busybox into local directory `./_install`. Notice, please, that there is only single binary executable file `bin/busybox` and all other directory contents are symbolic links to that binary file. Because we have not used *cross compilation*, which is quite often in case of build for embedded devices, it is possible to test functionality of our result of *native build* directly on build machine. The shell `./_install/bin/sh` can be run for example (it can be terminated by `exit` command). In the case of a real embedded system would have to go on and test the BusyBox after booting on the target hardware. 5. If you can use supervisor (root) rights on build system, then it is possible to test BusyBox in [chroot environment][chroot], i.e. with actual running kernel instance, but with minimal filesystem populated during BusyBox install: # chroot _install /bin/sh But you find that the attempt to execute BusyBox would fail, because there are necessary system libraries for default/non-static build of BusyBox and these libraries are not available in `_install` substree after chroot. [chroot]:http://en.wikipedia.org/wiki/Chroot 6. Chybějící knihovny zjistíte příkazem ldd _install/bin/busybox Tyto knihovny musíte nakopírovat do adresáře `_install`. Na 32-bitovém systému to může vypadat například takto: mkdir _install/lib cp /lib/i686/cmov/libm.so.6 /lib/i686/cmov/libc.so.6 /lib/ld-linux.so.2 _install/lib Na 64-bitovém systému jádro hledá pro dynamicky linkované programy "interpreter" `/lib64/ld-linux-x86-64.so.2` v adresáři `/lib64`. Vytvoříme ho jako symbolický odkaz na adresář `/lib` ( cd _install && ln -s lib lib64 ) 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ěkolik 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ástroje [gen_init_cpio][gic]. ( cat < filelist gen_init_cpio filelist | gzip > 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): Na 32-bitovém systému spustíme emulátor následovně: qemu -kernel /boot/vmlinuz-2.6.26-2-686 -initrd ramdisk Na 64-bitovém systému může být potřeba použít příslušnou variantu QEMU: qemu-system-x86_64 -kernel /boot/vmlinuz-2.6.32-5-amd64 -initrd ramdisk Pokud systém nabízí hardwarovou podporu virtualizace, je výhodné použít [KVM][kvm]. Výsledek pak běží rychleji. Například: kvm -kernel /boot/vmlinuz-2.6.32-5-amd64 -initrd ramdisk [kvm]:http://www.linux-kvm.org/ 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 Linuxové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 příkazu `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. * Pokud je Qemu spouštěný přes vzdálené připojení (např. server postel), je potřeba pro zobrazení emulované obrazovky spouštěného stroje buď provést protunelování X protokolu (`ssh -X`) nebo používat Qemu s emulací obrazovky v textovém režimu `qemu -curses`. Další možnost je emulovat HW bez grafické karty `qemu -nographic` a nastavit testovaný systém tak, aby systémová konzole směřovala na sériový port. 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