Laborator Extra - Compilarea kernel-ului

Compilarea kernel-ului Linux

Principalul motiv pentru care se dorește compilarea kernel-ului este adaptarea acestuia la un anumit sistem cu scopul creșterii performanțelor, adaptare care de obicei constă în:

  • utilizarea unor opțiuni de compilare prin care arhitectura procesorului este folosită la maxim (ex: alegerea tipului de procesor - implicit se folosește un procesor generic gen i386)
  • activarea/dezactivarea suportului pentru anumite componente hardware sau software (ex: selectarea anumitor driver-e, selectarea unor anumite protocoale de comunicatie)

În cazul kernel-ului Linux, suportul pentru hardware/software poate să fie:

  • built-in - suportul este inclus direct în imaginea (fisierul) kernel-ului
  • sub forma de module de kernel - suportul se găsește în fișiere separate care se încarcă on-demand

Deși adăugarea funcționalităților în kernel poate duce la creșterea eficienței în anumite subsisteme, acest lucru poate avea ca și consecință îngreunarea sistemului în ansamblu (bloated), lucru nerecomandat.

Majoritatea distribuțiilor includ în kernel numai suportul pentru componentele critice, fără de care sistemul de operare nu poate funcționa. Restul componentelor sunt compilate sub forma de module, module care sunt încărcate în funcție de hardware-ul/necesitățile fiecărui sistem/utilizator.

Există și situații în care kernel-ul care vine cu o anumită distribuție este mai vechi sau nu are compilat suportul pentru o anumită componentă. De asemenea, compilarea unui kernel optimizat este des întalnită pe sistemele care ruleaza server-e unde se dorește exploatarea la maxim a resurselor sistemului.

Pentru a putea efectua modificări de tipul celor mentionate mai sus, trebuie inițial efectuată configurarea kernel-ului. După această etapă se poate porni compilarea kernel-ului și a modulelor de kernel.

Pregătire

Cerințe hardware și software

Înaintea compilării kernel-ului trebuie verificat dacă sistemul satisface cerințele hardware și software.

Din punct de vedere hardware:

  • deși un sistem Linux minimal poate rula în sisteme cu puțină memorie RAM, cerințele minime pentru o distribuție Linux, în momentul de față, variază în jurul valorilor de 128-256 MB RAM.
  • în funcție de opțiunile alese pentru compilare, spațiul ocupat pe disc poate depăși valoarea de 500 MB - în aceste condiții, se recomandă un minim de 1 GB liber pe hard-disk-ul pe care se realizează compilarea.

Timpul de compilare variază în funcție de numărul de componente activate pentru compilare în momentul configurării.

Compilarea se poate realiza pe un sistem mai puternic urmând ca apoi să se mute pachetul ce conține kernel-ul pe sistemul destinație.

Cerințele software pentru kernel-ul de compilat se găsesc precizate în fișierul Documentation/Changes din cadrul surselor:

o  Gnu C                  3.2                     # gcc --version
o  Gnu make               3.79.1                  # make --version
o  binutils               2.12                    # ld -v
o  util-linux             2.10o                   # fdformat --version
o  module-init-tools      0.9.10                  # depmod -V
o  e2fsprogs              1.29                    # tune2fs
o  jfsutils               1.1.3                   # fsck.jfs -V
o  reiserfsprogs          3.6.3                   # reiserfsck -V 2>&1|grep reiserfsprogs
o  xfsprogs               2.6.0                   # xfs_db -V
o  pcmciautils            004                     # pccardctl -V
o  quota-tools            3.09                    # quota -V
o  PPP                    2.4.0                   # pppd --version
o  isdn4k-utils           3.1pre1                 # isdnctrl 2>&1|grep version
o  nfs-utils              1.0.5                   # showmount --version
o  procps                 3.2.0                   # ps --version
o  oprofile               0.9                     # oprofiled --version
o  udev                   081                     # udevinfo -V
o  grub                   0.93                    # grub --version

Observații:

  • cerințele de mai sus sunt valabile pentru versiunea de kernel 2.6.31.6.
  • utilitarele e2fsprogs, jfsutils, reiserfsprogs, xfsprogs sunt folosite pentru sistemul de fișiere asociat
  • PPP și isdn4k-utils sunt necesare numai dacă legăturile sistemului la Internet sunt de tip PPP sau ISDN.

Ce hardware există în sistem?

Un kernel compilat poate oferi suport doar pentru hardware-ul utilizatorului, micșorând astfel dimensiunea imaginii obținute. De asemenea, cunoașterea hardware-ului în sistem este necesară pentru un kernel mai rapid și alegerea opțiunilor de compilare și a driver-elor de dispozitiv corecte. Informații despre controller-ele Ethernet, VGA, placa de sunet se află cu ajutorul comenzii lspci (din pachetul pciutils):

# lspci
00:00.0 Host bridge: VIA Technologies, Inc. K8M800 Host Bridge
00:00.1 Host bridge: VIA Technologies, Inc. K8M800 Host Bridge
00:00.2 Host bridge: VIA Technologies, Inc. K8M800 Host Bridge
00:00.3 Host bridge: VIA Technologies, Inc. K8M800 Host Bridge
00:00.4 Host bridge: VIA Technologies, Inc. K8M800 Host Bridge
00:00.7 Host bridge: VIA Technologies, Inc. K8M800 Host Bridge
00:01.0 PCI bridge: VIA Technologies, Inc. VT8237 PCI bridge [K8T800/K8T890 South]
00:0a.0 Ethernet controller: Linksys, A Division of Cisco Systems [AirConn] ...

Tipul procesorului se află cu ajutorul procfs (montat în /proc).

# cat /proc/cpuinfo
processor       : 0
vendor_id       : AuthenticAMD
cpu family      : 15
model           : 28
model name      : Mobile AMD Sempron(tm) Processor 2800+
stepping        : 0
cpu MHz         : 1601.122
cache size      : 256 KB
fdiv_bug        : no
hlt_bug         : no
f00f_bug        : no
coma_bug        : no
fpu             : yes
fpu_exception   : yes
cpuid level     : 1
wp              : yes
flags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr ...
bogomips        : 3205.53

Obținerea surselor

Sursele de kernel de Linux pot fi obținute din pachete specifice distribuției sau pot fi descărcate sursele oficiale ale lui Linus Torvalds.

În cazul în care se alege varianta folosirii surselor oficiale, se recomandă folosirea unui mirror din Romania.

Sursele kernel-ului se găsesc în subdirectorul /pub/linux/kernel/v2.6 (pentru versiunea 2.6). Se poate folosi http sau ftp pentru obținerea surselor:

# cd /usr/src
# wget ftp://ftp.idilis.lkams.kernel.org/pub/linux/kernel/v2.6/linux-2.6.24.2.tar.gz

Se dezarhivează sursele. Se recomandă crearea unei legături simbolice cu numele linux către directorul ce contine sursele.

# cd /usr/src
# tar xzf linux-2.6.24.2.tar.gz
# ln -s linux-2.6.24.2 linux
# ls -l
total 40924
lrwxrwxrwx  1 root src        14 2008-02-19 13:52 linux -> linux-2.6.24.2
drwxrwxrwx 19 root root     4096 2008-02-16 19:21 linux-2.6.24.2
-rw-r--r--  1 root src  41853865 2008-02-16 19:28 linux-2.6.24.2.tar.gz

Kernel-ul compilat de pe mașina virtuală de Linux disponibilă este un kernel versiunea 2.6.31.6.

Configurare

Partea de configurare este partea cea mai importantă a procesului de compilare. În cadrul acesteia se decide ce caracteristici vor fi incluse în noul kernel; sunt necesare cunoștințe ale hardware-ului sistemului și ale facilităților dorite.

Procesul de configurare era unul destul de dificil de realizat la primele versiuni, însa acest lucru s-a schimbat odată cu introducerea unor interfețe care folosesc X Window sau ncurses. Pentru verificarea opțiunilor posibile de compilare se poate rula comanda:

# make help
Cleaning targets:
  clean           - remove most generated files but keep the config
  mrproper        - remove all generated files + config + various backup files

Configuration targets:
  config          - Update current config utilising a line-oriented program
  menuconfig      - Update current config utilising a menu based program
  xconfig         - Update current config utilising a QT based front-end
  gconfig         - Update current config utilising a GTK based front-end
  oldconfig       - Update current config utilising a provided .config as base
  randconfig      - New config with random answer to all options
  defconfig       - New config with default answer to all options
  allmodconfig    - New config selecting modules when possible
  allyesconfig    - New config where all options are accepted with yes
  allnoconfig     - New config where all options are answered with no
  ...

Pentru utilizarea unei interfețe text-based (ncurses), va trebui instalat pachetul libncurses-dev. Pentru utilizarea unei interfețe folosind front-end GTK (de obicei într-un desktop environment GNOME) vor trebui instalate pachetele libgtk2.0-dev și libglade2.0-dev. Pentru QT va trebui instalat pachetul libqt4-dev.

Avantajul folosirii interfetei ncurses este faptul că este relativ ușor de utilizat și nu necesită prezenta unui mediu grafic.

În cazul în care sursele conțineau o configurație anterioară care nu mai este dorită, va trebui rulată una dintre comenzile:

# make clean
# make mrproper

Rularea uneia dintre comenzile:

# make menuconfig
# make gconfig
# make xconfig

rezultă în afișarea unui meniu. Acesta conține mai multe intrări de configurare (General setup, Networking, Device drivers, File systems, etc.) care pot fi utilizate pentru configurări ale unui subdomeniu. Acestea pot conține, la rândul lor, alte subdomenii de configurare.

O opțiune finită de configurare (spre exemplu Device Drivers → Block Devices → Normal floppy disk support) poate prezenta utilizatorului trei optiuni de configurare:

  • absența completă din kernel-ul finit (se apasa <N>)
  • compilarea acesteia în cadrul imaginii de kernel (built-in) (se apasa <Y>)
  • compilarea acesteia sub forma de modul de kernel (se apasa <M>)

Compilarea built-in înseamnă introducerea codului obiect asociat opțiunii în imaginea de kernel care va rezulta. Compilarea în forma de modul de kernel înseamnă că pentru activarea acelei facilități, kernel-ul va încărca modulul (codul obiect asociat) și îl va descărca atunci când nu are nevoie de el. Kernel-ul este astfel extensibil și pentru adăugarea anumitor facilități nu este nevoie de recompilare. Pentru lucrul cu module de kernel vor trebui adăugate opțiunile din Loadable module support (Enable loadable module support).

Multe opțiuni nu vor fi încorporate în cadrul kernel-ului întrucât nu sunt necesare. Altele pot fi compilate numai built-in. Opțiunile care suportă varianta modul de kernel sau built-in se recomandă a fi compilate ca module de kernel pentru a fi încărcate la nevoie. Pe procesoarele moderne, timpul în care se încarcă/descarcă module este suficient de mic încat compilarea ca modul de kernel sau built-in să nu afecteze performanța.

O opțiune utilă este precizarea unei versiuni locale pentru kernel, astfel încât acesta să fie identificat; exista posibilitatea compilării aceleiași versiuni de kernel pentru scopuri distincte; oferirea unei versiuni locale generează o versiune de kernel unică.

Precizarea tipului de procesor și a arhitecturii este un pas necesar pentru a crea un kernel eficient. Majoritatea opțiunilor țin de preferințele utilizatorilor (desi probabil multi vor alege suport de networking, sunet etc.) sau de hardware-ul existent.

Dacă se dorește crearea unui kernel pentru dezvoltare (development) atunci vor trebui activate opțiunile din Kernel hacking; acestea oferă informații de debug suplimentare, cu dezavantajul unui kernel mai mare și mai lent.

Configurația este salvată în cadrul fișierului .config din directorul rădăcină al surselor. Este indicat să se realizeze un backup al acestui fișier înainte de configurare pentru a avea o configurație sigură la care să se revină în cazul apariției de probleme.

initrd - ramdisk-ul inițial

initrd (initial ramdisk) este un sistem de fișiere temporar având ca suport memoria RAM (ramdisk) care este folosit la pornirea sistemului (booting). Initrd este folosit pentru a încărca driver-ele necesare încărcării sistemului de fișiere rădăcina.

Motivația folosirii initrd este flexibilitatea. Distributiile Linux au un kernel generic Linux care trebuie să boot-eze de pe sisteme cu hardware diferit. Kernel-ul inclus trebuie să fie modular, nefiind posibilă compilarea statică a tuturor opțiunilor fără a mări semnificativ imaginea kernel-ului. Este, în consecinta, necesar să se cunoască la booting locația sistemului de fișiere rădăcină și ce driver-e vor trebui încărcate în kernel. Această problemă este rezolvată prin introducerea initrd ca pas intermediar în pasul de boot-ing. Acesta actioneaza ca un sistem de fisiere rădăcină temporar. Conținutul acestui sistem rădăcină este dat de imaginea de initrd.

De obicei, compilarea unui kernel pentru un sistem dat nu necesită utilizarea initrd, deoarece se cunoaste hardware-ul existent și sistemul de fisiere utilizat. Pentru a se evita utilizarea initrd, vor trebui compilate în imaginea de kernel (built-in) driver-ele de hard-disk, SCSI (dacă există) și de sisteme de fișiere. Daca aceste driver-e ar fi compilate ca module atunci ar trebui încărcate de pe hard-disk, făra însă a putea accesa hard-disk-ul (din lipsa driver-elor). În această situație se foloseste initrd. Driver-ele în cauză se găsesc în:

  • Device Drivers → ATA/ATAPI/MFM/RLL support - de obicei trebuie compilate built-in driverele IDE specifice hardware-ului folosit pentru a putea beneficia de modurile Ultra DMA. Daca nu, se pot pune driverele generice (generic/default IDE chipset support și Generic PCI IDE Chipset Support)
  • Device Drivers → SCSI device support
  • File systems (va trebui configurat ca built-in suportul pentru sistemul de fișiere rădăcină)

Pentru utilizarea initrd este necesar pachetul initrd-tools.

(re)denumirea versiunii de kernel

Înainte de compilare, este indicat să se creeze un indicator unic pentru imaginea de kernel creată. Aceasta se poate realiza completând campul EXTRAVERSION din Makefile-ul kernelului. Se poate seta acest camp la orice șir de caractere.

Compilare

Faza de compilare presupune obținerea imaginii de kernel și compilarea modulelor de kernel. Acest lucru se realizează prin intermediul a doua comenzi:

# make bzImage
# make modules

Prima comandă creează o imagine de kernel comprimată. Acest pas poate dura de la câteva minute până la câteva zeci, depinzând de configurația hardware. După încheiere, imaginea comprimată se regasește în arch/i386/boot/bzImage (pentru o arhitectura x86).

A doua comandă compilează modulele care pot fi încărcate de kernel. Acest pas poate dura de câteva ori mai mult decât pasul precedent. Fișierele obiect ce reprezintă modulele (cu extensia .ko) rezidă în directoarele asociate, urmând a fi instalate.

Instalare

Instalarea presupune copierea imaginii de kernel și a modulelor in locurile prevăzute și configurarea bootloader-ului pentru a boot-a noul kernel. Acest pas se leagă de directorul /boot unde se găsesc toate fișierele importante.

Instalare imagine kernel

Imaginea de kernel și fișierele asociate sunt copiate în directoarele necesare cu ajutorul comenzii make install.

Pașii executați prin intermediul comenzii make install sunt detaliați mai jos.

Imaginea de kernel va trebui copiată în /boot:

# cd /usr/src/linux
# cp arch/x86/boot/bzImage /boot/vmlinuz-2.6.24.2mykernel

(șirul mykernel este folosit pentru identificarea imaginii de kernel; poate coincide cu versiunea locală precizată la configurare)

În plus față de imaginea de kernel, se recomandă copierea fișierului de configurare și a tabelei de simboluri.

# cd /usr/src/linux
# cp .config /boot/config-2.6.24.2mykernel
# cp System.map /boot/System.map-2.6.24.2mykernel

Instalare module de kernel

Instalarea modulelor de kernel se realizează prin intermediul comenzii:

# make modules_install

Modulele sunt instalate in /lib/modules/2.6.24.2mykernel.

Daca s-a configurat sistemul pentru a folosi initrd, va trebui creată imaginea de ramdisk. Pentru aceasta se ruleaza comanda:

# cd /boot
# mkinitramfs -o /boot/initrd.img-2.6.24.2mykernel 2.6.24.2mykernel

Comanda va inspecta directorul /lib/modules/2.6.24.2mykernel si va crea imaginea de ramdisk corespunzatoare.

Configurare GRUB

Dupa instalarea imaginii de kernel și a modulelor de kernel va trebui configurat bootloader-ul pentru a ști de unde să incarce imaginea la pornirea sistemului.

Vom presupune configurarea GRUB (GRand Unified Bootloader), în detrimentul LILO (LInux LOader), pentru că este mai răspăndit. Configurări pentru LILO se pot găsi și in link-urile de mai jos.

Există două versiuni majore de GRUB, 1 și 2. Mai departe ne vom ocupa de configurare GRUB2.

Pentru a adăuga o intrare în meniul GRUB-ului se editează fișierul /etc/grub.d/40_custom și apoi se rulează comanda:

# update-grub

Un exemplu de configurare este prezentat în continuare:

[...]

menuentry "Linux" {
    set root=(hd0,1)
    linux /boot/vmlinuz-2.6.24.2mykernel root=/dev/sda1
    initrd /boot/initrd.img-2.6.24.2mykernel
}

Opțiunea initrd poate fi omisă în cazul în care nu s-a configurat un ramdisk inițial.

Repornire sistem

Pentru rularea noului kernel, va trebui repornit sistemul și optat pentru noul kernel din meniul bootloader-ului.

ATENTIE: Se recomandă păstrarea fostului kernel, în cazul în care apar probleme la noul kernel compilat. Probleme pot aparea din neincluderea driver-elor necesare în cazul în care nu se folosește initrd, omiterea driver-ului de sistem de fișiere necesar etc.

E posibil sa avem la dispoziție un kernel care ruleaza dar caruia ii lipsesc funcționalitați (de exemplu networking), pentru ca s-a omis compilarea driver-elor pentru placa de rețea. În acest caz se poate recompila kernel-ul pentru introducerea noilor funcționalități. Noua compilare va dura mai puțin în cazul în care modificările sunt minime.

O metoda de troubleshooting este compararea unei configurații functionale cu cea curentă prin inspecția fișierelor .config asociate.

Compilarea kernel-ului Windows

În cadrul Windows Academic Program există posibilitatea accesului la codul sursa a kernel-ului de Windows NT, prin intermediul inițiativei Windows Research Kernel (WRK).

Codul sursă prezintă componentele cele mai importante din cadrul nuclelui (managementul memoriei, procese, thread-uri, scheduling, I/O manager) și poate fi folosit și modificat în scopuri non-comerciale. Se pot astfel urmări diversele mecanisme de implementare și design care stau la baza kernel-ului și se pot testa diverse alte soluții prin modificarea surselor. Accesul la sursele kernel-ului este limitat, anumite subdomenii (cum ar fi networking-ul) fiind absente.

Accesul la codul sursă pentru nucleul de Windows NT înseamna posibilitatea de modificare a acestuia și, evident, de compilare a kernel-ului și de boot-are. Sursele sunt accesibile prin intermediul imaginii de CD pusă la dispoziție de Microsoft în cadrul inițiativei WRK.

Din păcate, kernel-ul de Windows nu vine cu opțiuni de configurare, astfel încat procesul se rezumă la rularea comenzii de compilare și la instalarea noului kernel. Dacă se dorește un tip special de funcționalitate vor trebui alterate sursele.

De asemenea, kernel-ul poate fi compilat numai pe un sistem Windows 2003 SP1 sau Windows XP x64. Versiunea curentă (WRK-1.2) nu poate fi compilată pe un sistem Windows XP x86. Sursele sunt disponibile în directorul C:\cygwin\home\Administrator\so2\WRK\ din cadrul mașinii virtuale de Windows.

Etapele de compilare sunt prezentate și în fișierul README.txt din rădăcina surselor.

Compilare

Pentru compilarea surselor se parcurg următorii pași (vom utiliza de acum inainte %wrk% ca rădăcina surselor de kernel de Windows):

C:\>set wrk=C:\cygwin\home\Administrator\so2\WRK\WRK-v1.2
C:\>set arch=x86
C:\>set path=%wrk%\tools\%arch%;%path%
C:\>cd %wrk%\base
C:\cygwin\home\Administrator\so2\WRK\WRK-v1.2\base>cd ntos
C:\cygwin\home\Administrator\so2\WRK\WRK-v1.2\base\ntos>nmake -nologo %arch%=

Imaginea de kernel obținută se va regăsi în %wrk%\base\ntos\BUILD\EXE și va purta numele wrkx86.exe pentru un sistem cu arhitectura x86. Imaginea obținută este doar nucleul; modulele de kernel folosite vor fi cele existente în sistem în acel moment.

Instalare

Procesul de instalare presupune copierea imaginii kernel-ului în %SystemRoot%\system32:

C:\>copy %wrk%\base\ntos\BUILD\EXE\wrkx86.exe %SystemRoot%\system32\

Totuși, în afara imaginii de kernel, va trebui precizată imaginea de HAL (Hardware Abstraction Layer) care va fi utilizată. Va trebui gasită imaginea corecta de HAL; există trei imagini de HAL disponibile in %wrk%\WS03SP1HALS\x86. Pentru a afla care imagine este cea corectă va trebui utilizat linker-ul (folosind comanda link și analizată imaginea de HAL existentă în acest moment în sistem).

C:\>"C:\Program Files\Microsoft Visual Studio 8\VC\vcvarsall.bat"
Setting environment for using Microsoft Visual Studio 2005 x86 tools.
C:\>link -dump -all %SystemRoot%\system32\hal.dll | findstr pdb
  80011530: 68 61 6C 2E 70 64 62 00 00 00 00 00 00 00 00 00  hal.pdb.........
    42435B3A cv           20 00001518      918    Format: RSDS, {2ECB059A-3F06-4
285-8E30-3FDE64119692}, 1, hal.pdb

Motivul pentru care în ieșirea comenzii nu apare șirul halaacpi.dll este că a fost dezactivat ACPI pe mașina virtuală de Windows 2003.

Asocierea dintre ieșirea comenzii de mai sus și imaginile disponibile în %wrk%\WS03SP1HALS\x86 este (după cum este precizat și în README.txt):

    halacpi.dll  -> halacpim.dll
    halaacpi.dll -> halmacpi.dll
    halapic.dll  -> halmps.dll

De obicei, imaginea căutată va fi halmacpi.dll.

Imaginea corectă de HAL va fi copiată tot în %SystemRoot%\system32:

C:\>copy %wrk%\WS03SP1HALS\x86\halmacpi\halmacpi.dll %SystemRoot%\System32\

Configurare boot.ini

Pentru a boota proaspătul kernel va trebui adaugată o intrare în C:\boot.ini, fișierul de configurare pentru loader-ul de Windows NT. Se recomandă copierea unei linii de bootare existente și modificarea ei pentru a boota noul kernel și noua imagine de HAL, ca mai jos:

[boot loader]
timeout=30
default=multi(0)disk(0)rdisk(0)partition(1)\WINDOWS
[operating systems]
multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Windows Server 2003, Standard"
/fastdetect /NoExecute=OptOut
multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Windows Server 2003, Standard - WRK-1.2
compiled kernel" /kernel=wrkx86.exe /hal=halmacpi.dll /fastdetect /NoExecute=OptOut

Pentru vizualizarea boot.ini în Windows Explorer, va trebui să accesați Tools → Folder Options → View → Hide protected operating system files (Recommended). Fișierul este implicit read-only; pentru editare va trebui să anulați această opțiune. Alternativ puteți face acest lucru din linia de comanda:

C:\>attrib -h -s -r boot.ini

După configurarea boot.ini, sistemul poate boota în noul kernel compilat.

so2/laboratoare/lab_compilare.txt · Last modified: 2013/05/24 13:38 by ghennadi.procopciuc
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0