====== 1. Mediul de dezvoltare pentru cod kernel ======
Vom face primi pași în investigarea nucleului Linux și ne vom acomoda cu infrastructura (minimalistă) de dezvoltare la nivelul nucleului. Infrastructura folosește o mașină virtuală [[http://wiki.qemu.org/Main_Page|QEMU]].
===== Subiecte abordate =====
* Ce este un kernel, care este rolul său? Ce este o imagine de kernel? Exemple.
* Pornirea (bootarea) sistemului
* Necesarul pentru a porni (boota) un mediu de dezvoltare: imagine de kernel, sistem de fișiere, set minimal de utilitare
* De ce folosim mașini virtuale?
* Folosirea mediulu de dezvoltare QEMU
* Opțiuni la bootarea nucleului
* Investigarea nucleului
* Comunicarea cu mediul de dezvoltare (minimalist) QEMU
===== Resurse utile =====
* http://wiki.qemu.org/Main_Page
* https://www.kernel.org/doc/Documentation/kernel-parameters.txt
* https://matt.ucc.asn.au/dropbear/dropbear.html
===== Exerciții =====
Arhiva de suport pentru exerciții se găsește [[http://koala.cs.pub.ro/training/res/linux-kernel-dev/arc/cap-01-tasks.zip|aici]]. Descărcați arhiva și apoi decomprimați-o folosind comanda
unzip cap-01-tasks.zip
==== Pornirea mediului QEMU ====
Pentru partea practică vom folosi mașina virtuală VirtualBox și o mașină virtuală (emulator) QEMU rulând în aceasta. Pentru aceasta vom intra în directorul ''linux-kernel-dev/qemu-vm/'' din mașina virtuală QEMU. Acest director conține o serie de script-uri pentru pornirea mașinii virtuale QEMU. Pe scurt, se construiește un sistem de fișiere virtual care este apoi folosit pentru pornirea mașinii virtuale.
Pentru pornirea mașinii virtuale folosim comanda
make
În urma rulării comenzii se deschide un prompt QEMU în care este pornită mașina virtuală.
Mașina virtuală ne va afișa un prompt de root în care putem include comenzi. Mașina virtuală conține un sistem de fișiere minimal cuprins din:
* imaginea de kernel
* busybox: un shell pentru sisteme embedded cuprinzând mai multe utilitare încorporate
* fișiere de configurare
În acest mod vom porni mereu mașina virtuală QEMU
Pentru oprirea mașinii virtuale folosim comanda ''poweroff'' în cadrul mașinii virtuale QEMU sau folosim combinația de taste ''Ctrl+c'' în fereastra din mașina virtuală VirtualBox în care am rulat comanda ''make''.
Ca să "intrați" în mediul QEMU dați click în cadrul ferestrei QEMU.
Ca să "ieșiți" din mediul QEMU apăsați pe ''Alt'' și ''Ctrl''.
==== Investigarea stării sistemului ====
Ca să aflăm informații, în mașina virtuală QEMU folosim comenzi precum cele de mai jos
uname -a
ps
dmesg
cat /proc/cmdline
Observați care este versiunea nucleului.
Observați că sunt doar procese shell pornite (restul sunt thread-uri kernel). Ca să parcurgeți diferitele procese shell folosiți combinațiile de taste ''Alt+F1'', ''Alt+F2'', ''Alt+F3'' etc.
Puteți observa că shell-ul folosit este ''busybox'' folosind comanda
ls -l /bin/sh
Puteți observa linia de comandă cu care a fost pornit nucleul (opțiunile nucleului). Acestea sunt cele introduse în fișierul ''Makefile'' cu ajutorul căruia pornim mașina virtuală QEMU.
Aceste comenzi le puteți rula și pe mașina virtuală VirtualBox. Ce versiune de nucleu are mașina virtuală VirtualBox? Ce shell folosește? Care este linia de comandă cu care a fost pornit nucleul mașinii virtuale VirtualBox?
==== Investigarea imaginii de kernel ====
Imaginea de kernel (fișierul imagine al nucleului) nu este disponibil în cadrul mașinii virtuale QEMU. Aceasta se găsește pe mașina virtuală indicată de link-urile simbolice ''bzImage'' și ''vmlinux''. Folosim comenzile ''ls'' și ''file'' pentru a investiga cele două imagini:
training@box:~/linux-kernel-dev/qemu-vm$ ls -lh /home/training/linux-kernel-dev/linux-3.13/arch/x86/boot/bzImage
-rw-r--r-- 1 training training 5.6M Feb 16 2014 /home/training/linux-kernel-dev/linux-3.13/arch/x86/boot/bzImage
itraining@box:~/linux-kernel-dev/qemu-vm$ file /home/training/linux-kernel-dev/linux-3.13/arch/x86/boot/bzImage
/home/training/linux-kernel-dev/linux-3.13/arch/x86/boot/bzImage: Linux kernel x86 boot executable bzImage, version 3.13.0 (ddvlad@doppleganger) #10 SMP Sun Feb 16 18:16:42 EET 20, RO-rootFS, swap_dev 0x5, Normal VGA
training@box:~/linux-kernel-dev/qemu-vm$ ls -lh /home/training/linux-kernel-dev/linux-3.13/vmlinux
-rwxr-xr-x 1 training training 223M Feb 16 2014 /home/training/linux-kernel-dev/linux-3.13/vmlinux
training@box:~/linux-kernel-dev/qemu-vm$ file /home/training/linux-kernel-dev/linux-3.13/vmlinux
/home/training/linux-kernel-dev/linux-3.13/vmlinux: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, BuildID[sha1]=2d1540041ec6cbf7edd08929364579e753537bac, not stripped
Ce puteți spune despre cele două fișiere? De ce este fișierul ''vmlinux'' atât de mare? Care este utilitatea acestui fișier?
Aplicați aceleași comenzi pe mașina virtuală VirtualBox, pe imaginea de kernel din ''/boot/''.
Folosiți comanda de mai jos pentru a afla simbolurile definite în fișierul ''vmlinux''
nm /home/training/linux-kernel-dev/linux-3.13/vmlinux | less
==== Urmărirea intrărilor din /proc/kallsyms ====
Informații despre simbolurile unui kernel aflat în rulare se găsesc în fișierul ''/proc/kallsyms'' pe care îl putem investiga folosind comanda
less /proc/kallsyms
Simbolurile (funcții și variabile) pe care nucleul le are definite sunt vizibile în fișierul ''/proc/kallsyms''. Acest fișier poate fi investigat pentru fiecare nucleu din fiecare mașină virtuală, atât cel de pe mașina virtuală QEMU, cât și cel de pe mașina virtuală VirtualBox.
De la ce adresă pornesc adresele din fișierele ''/proc/kallsyms'' din fiecare mașină virtuală?
==== Verificarea conectivității la rețea ====
Pentru a verifica legătura la rețea între mașina virtuală QEMU și sistemul pe care rulează (mașina virtuală VirtualBox) este folosită o interfață ''tap0''.
Dacă pe mașina virtuală VirtualBox interfața ''tap0'' este dezactivată, va trebui să o repornim.
Pentru a investiga aceste lucru, folosim comanda ''ip a s'' iar dacă output-ul este cel de mai jos (adică apare șirul ''DOWN''), atunci interfața este dezactivată
training@box:~/linux-kernel-dev/qemu-vm$ ip a s tap0
4: tap0: mtu 1500 qdisc pfifo_fast state DOWN group default qlen 500
link/ether 36:ec:be:96:ec:08 brd ff:ff:ff:ff:ff:ff
Dacă așa este cazul, atunci trebuie urmați pașii:
- Se oprește mașina virtuală QEMU folosind combinația de taste ''Ctrl+c''.
- Se șterge interfața ''tap0'' folosind comanda
sudo ip link del dev tap0
- Se repornește mașina virtuală QEMU folosind comanda
make
- Se verifică faptul că acum interfața ''tap0'' este activă folosind comanda
ip a s
Pentru a verifica conectivitatea se folosește comanda ''ping'' având ca adresă IP adresa celeilalte mașini virtuale. În fiecare mașină virtuală aflăm adresa IP folosind comanda ''ip a s'':
* Folosim pe mașina virtuală QEMU comanda
ip a s eth0
* Folosim pe mașina virtuală VirtualBox comanda
ip a s tap0
==== Vizualizarea mesajelor din kernel prin rețea ====
Atunci când avem conectivitate între două sisteme, putem configura modulul ''netconsole'' pe sistemul pe care dezvoltăm în nucleul Linux pentru a transmite mesaje de kernel în rețea.
Pe mașina virtuală QEMU modulul ''netconsole'' este deja configurat să transmită mesaje către adresa ''172.20.0.1'' pe portul UDP ''6666''. Puteți observa acest lucru în fișierul de startup ''/etc/rcS'' sau în mesajele de kernel vizibile cu ajutorul comenzii ''dmesg''.
Pentru a captura mesajele nucleului, pe mașina virtuală VirtualBox pornim un "seerver" UDP care asculta mesaje pe portul ''6666''. Folosim un alt tab de terminal și rulăm comanda
nc -lup 6666
Acum orice pornire a mașinii virtuale QEMU și orice mesaje furnizate de nucleul mașinii virtuale QEMU va fi capturat de serverul UDP.
Este foarte util să fie folosit un astfel de server pentru a captura mesaje. De multe ori fereastră mașinii virtuale QEMU e prea mică, sau se pierd informații, sau îngheață. Într-un ecran distinct, pe mașina virtuală VirtualBox, nu vor exista astfel de probleme.
==== Adăugarea unui fișier în mașina virtuală QEMU ====
În forma curentă mașina virtuală QEMU este destul de spartană și puțin dinamică. Avem nevoie de fișiere care să ne ofere funcționalități suplimentare. Vom folosi mașina virtuală VirtualBox pentru operații de compilare de module de kernel sau altele, iar fișierele rezultate vor forma apoi sistemul de fișiere al mașinii virtuale QEMU.
Pentru a obține fișiere pe mașina virtuală QEMU, acestea trebuie copiate în subdirectorul ''fsimg/'' din directorul de pornire al mașinii virtuale. Cel mai recomandat este să fie copiate în ''fsimg/root/''. Apoi se pornește mașina virtuală.
Doar ca exemplu să copiem fișierul ''/etc/protocols'' de pe mașina virtuală VirtualBox în directorul ''fsimg/root/''. Apoi pornim mașina virtuală QEMU folosind comanda ''make''. După pornire vom vedea că în directorul ''/root'' din cadrul mașinii virtuala QEMU avem fișierul ''protocols''.
Mașina virtuală QEMU se dorește a fi cât de simplă se poate pentru a putea fi pornită și oprită cât mai rapid. De aceea nu vom face compilări, editări sau schimbări în cadrul acesteia ci în cadrul mașinii virtuale VirtualBox. Urmând ca apoi să aducem acele fișiere în mașina virtuală QEMU și să o pornim cu acestea.
==== Folosirea netcat pentru comunicarea între mașini virtuale ====
Pentru a face ceva mai interesant, veți copia în mașina virtuală QEMU un fișier ''netcat'' compilat static.
Este vorba de fișierul ''nc-static'' din directorul ''/home/training/linux-kernel-dev/''. Copiați acest fișier în ''fsimg/root/programs/''.
O dată copiat acest utilitar static, îl puteți folosi pentru comunicare cu mașina virtuală VirtualBox. Porniți pe mașina virtuală QEMU un server care ascultă mesaje pe un port UDP. Iar apoi trimiteți un mesaj de pe mașina virtuală VirtualBox folosind tot ''netcat''.
La nevoie puteți transmite și fișiere în acest mod folosind comenzi de forma:
(receiver/server) netcat -u -l -p 12345 >
(sender/client) cat | ./nc-static -u 12345
unde '''' este numele fișierului (sau calea către fișier) iar '''' este adresa IP a a receiver-ului>
==== Folosirea unui client de SSH ====
Putem să folosim conexiune SSH pentru comunicarea între cele două mașini virtuale. O formă mai simplă este să folosim un client SSH pe mașina virtuală. Pentru aceasta găsiți în arhiva capitolului executabilul ''dbclient''.
Copiați executabilul ''dbclient'' pe mașina virtuală QEMU și apoi folosiți o comandă precum cea de mai jos pentru vă autentifica pe mașina virtuală VirtualBox
DROPBEAR_PASSWORD="training" ./dbclient -l training 172.20.0.1
În general, este de preferat o comunicare în celălalt sens, cu serverul SSH rulând pe mașina virtuală QEMU. Este nevoie de configuarea unui executabil static SSH pe mașina virtuală QEMU; se poate face acest lucru cu serverul [[https://matt.ucc.asn.au/dropbear/dropbear.html|dropbear]].
==== Alterarea opțiunilor de pornire a nucleului ====
Putem afecta modul în care se comportă nucleul prin alterarea opțiunilor de pornire a sa. Pentru aceasta edităm scriptul ''build-iso.sh'' și actualizăm intrarea ce definește linia de bootare (linia 146 din fișier). Astfel, pentru a face bootare //quiet// schimbăm linia din
append root=/dev/ram ro noquiet rdinit=/init initrd=ramdisk.gz debug apci=off noapic
în
append root=/dev/ram ro quiet rdinit=/init initrd=ramdisk.gz nodebug apci=off noapic
Mai sus am schimbat opțiunea ''noquiet'' în opțiunea ''quiet'' și ''debug'' în ''nodebug''.
Pornim mașina virtuală QEMU folosind comanda
make
La pornirea mașinii virtuale vom vedea reducerea drastică a mesajelor afișate de kernel.
==== Adăugarea unei opțiuni de bootare a nucleului ====
Urmăriți [[https://www.kernel.org/doc/Documentation/kernel-parameters.txt|opțiunile de bootare ale nucleului]] și dezactivați folosirea ''vdso''.
Pentru a verifica faptul că un proces folosește sau nu ''vdso'' urmăriți spațiul său de adresă folosind comanda
cat /proc/self/maps
În mapările afișate se va afla (sau nu) și ''vdso''.
==== [BONUS] Compilarea unui nou kernel ====
Compilați nucleul în directorul ''/home/training/linux-kernel-dev/linux-3.13''.
==== [BONUS] Rularea unui server SSH pe mașina virtuală QEMU ====
Folosiți sursele [[https://matt.ucc.asn.au/dropbear/dropbear.html|Dropbear]], compilați serverul și configurați-l pentru a funcționa pe mașina virtuală QEMU.
E foarte greu. Eu am încercat și nu am reușit. O să mai încerc. E recomandat să aveți acces la Internet ca să vă puteți documenta (acolo cât se poate) legat de ce aveți de făcut.