Ricompilare il kernel di Linux

Sul blog di Elettronica Open Source puoi leggere non solo tutti gli articoli Premium riservati agli abbonati Platinum 2.0 e inseriti nella rivista Firmware 2.0 (insieme ad articoli tecnici, progetti, approfondimenti, news, tutorial a puntate e molto altro) ma anche gli articoli della Rubrica Firmware Reload. In questa Rubrica del blog abbiamo raccolto gli articoli tecnici della vecchia rivista cartacea Firmware, che contengono argomenti e temi evergreen per Professionisti, Makers, Hobbisti e Appassionati di elettronica. A volte, per integrare le nostre modifiche o aggiungere un nuovo driver, può essere necessario ricompilare il kernel di Linux o di una sua distribuzione embedded. In questo articolo vedremo quali sono le attività necessarie per raggiungere questo traguardo.

Introduzione

Ricompilare il kernel di Linux non è un’attività difficile o impossibile per l’utente medio, ma è altrettanto certo che, per il buon esito di questo lavoro, dobbiamo conoscere quantomeno in modo discreto il funzionamento di un sistema basato su Unix, per utilizzarne i diversi tool indispensabili. Per prima cosa dobbiamo procurarci una versione del kernel utile ai nostri scopi e installare il suo codice sorgente in una posizione ben definita, ovvero in /usr/src/linux. Solo successivamente, potremo iniziare ad avviare le procedure di compilazione/linker per ottenere l’immagine binaria da caricare sul nostro target. È comunque doveroso far notare che, dato che la comunità rilascia in continuazione nuove versioni del kernel per sopperire a nuove funzionalità o sistemare varie lacune o bachi software, dovremo, prima di prendere visione di una particolare versione, verificare che quella che intendiamo utilizzare risponda pienamente alle nostre esigenze.

SISTEMIAMO IL NOSTRO CONFIG

Per prima cosa dobbiamo sistemare il nostro config file, ossia il nostro kernel configuration dove dovremo specificare i moduli da noi utilizzati e inserirli nella nostra lista di compilazione. Per questa ragione, per raggiungere questa esigenza, dovremo utilizzare il comando di *nix make con le opzioni corrette. Il nostro Makefile include diversi target, ossia opzioni di compilazione, quali config, menuconfig, xconfig, oldconfig, gconfig, e config. Con l’opzione config, ovvero make config, si abilita la creazione del file .config in una modalità testo dove ogni singola opzione di compilazione è presentata come una domanda, alla quale l’utente è invitato a confermare o negare in modo manuale attraverso l’interfaccia a schermo: si suggerisce di utilizzare questa modalità solo qualora non si disponga di un classico schermo full-screen. In questo modo:

[root@example]# make config
rm -f include/asm
( cd include ; ln -sf asm-i386 asm)
/bin/sh scripts/Configure arch/i386/
config.in
#
# Using defaults found in .config
#
*
* Code maturity level options
*
Prompt for development and/or incomplete
code/drivers (CONFIG_EXPERIMENTAL)
[N/y/?] n
*
* Loadable module support
*
Enable loadable module support (CONFIG_MODULES) [Y/n/?] y
Set version information on all module symbols (CONFIG_MODVERSIONS)
[Y/n/?]

Un approccio di questo tipo è limitativo perché, oltre a incidere sulla flessibilità, ci costringe a seguire una lista predeterminata senza la possibilità di bypassare una scelta. Al contrario, con make menuconfig l’approccio è di tipo “text-based”. Grazie a questa particolare opzione è possibile selezionare una lista di kernel che possono essere compilati in base ad ogni singola configurazione possibile: l’utente può scegliere il noto code maturity level, il tipo di processore da utilizzare con le librerie annesse, oltre alle differenti “loadable module support”. In altre parole, con il comando make menuconfig l’utente può selezionare una particolare configurazione ricorrendo alla keypad insieme al tasto return, si ha la possibilità di selezionare un particolare submenu. Un’altra possibilità è di ricorrere a “xconfig”, in altre parole make xconfig. Per utilizzare questa scelta bisogna, però, disporre di un ambiente grafico del tipo X Windows System: il comando, al fine di utilizzare xconfig, crea un file di configurazione, al pari delle precedenti possibilità, il .config. Una volta lanciato il comando, il sistema operativo apre una finestra e, grazie alla presenza di una GUI, attraverso l’interazione con una classica interfaccia grafica, può ottenere un file di configurazione, permettendo di intervenire sulle opzioni del kernel. Un’ulteriore possibilità è “oldconfig”.

Con questa si ottiene un file di configurazione del kernel in assenza di una esplicita presenza del file .config nella distribuzione che si intende utilizzare: questa particolare scelta è stata pensata per realizzare un nuovo kernel in quelle distribuzioni che risultano un pò datate. Con il comando make oldconfig si crea un default file .config, ecco perché il suo uso diventa necessario qualora non si disponga di un file di questo tipo. In questo modo si garantisce, comunque, una certa flessibilità a qualsiasi lavoro di riconfigurazione del kernel; infatti, è così possibile utilizzare una delle altre opzioni del comando di Makefile per mettere a punto il contenuto dello stesso file .config: si utilizza make oldconfig comando per creare un file .config che si basa su un file .config personalizzato da una versione precedente del kernel. Ad esempio, si potrebbe avere un file .config anche personalizzato per un kernel 2.2 su una macchina specifica. Quando si aggiorna il kernel, si copia il vecchio file .config nella cartella usr/src/linux e si deve lanciare il comando make oldconfig. Il nuovo .config è creato così in modo automatico, in base ai requisiti previsti dalla configurazione del file precedente. Può però capitare che, durante la procedura automatica, il processo presenti delle domande specifiche alle quali non era stato possibile rispondere in modo diretto e trasparente: queste possono riguardare problematiche sulla creazione di eventuali nuovi moduli nel kernel aggiornato. Anche questo comando è di tipo “text-based” allo scopo di essere utilizzato su terminali un pò datati che non supportano schermi full-screen. A questo punto, non rimane altro che descrivere per sommi capi make gconfig. Con make gconfig si crea un file .config in un ambiente di lavoro dove si utilizza la modalità grafica GTK. Possiamo, senza dubbio, affermare che questa sessione di lavoro è simile a quella precedente in modalità grafica X Windows: anche in questo caso, il sistema apre una nuova sessione di lavoro per definire il proprio .config file.

RICOMPILIAMO IL KERNEL

Una volta ottenuto il nostro file, per procedere alla ricompilazione del kernel dobbiamo rimuovere un precedente .config file. Anche questa operazione, al pari di quelle precedenti, deve essere svolta con il comando make del nostro Makefile ma con l’opzione clean.

make clean

Una volta che siamo sicuri di aver eliminato una precedente sessione di lavoro, dobbiamo entrare nel vivo del nostro lavoro decidendo di generare un nuovo kernel per la nostra architettura definita in precedenza. Per fare questo dobbiamo ricorrere sempre al comando make scegliendo il tipo di immagine binaria che intendiamo generare. Ci sono diverse possibilità e una di queste è di sicuro:

make bzImage

Con questo comando si ottiene una versione compressa dell’immagine del kernel. L’utente ha anche la possibilità di compilare e organizzare moduli addizionali con l’uso del comando make modules e make modules_install. Non solo, è anche possibile decidere, in qualsiasi momento, di annullare una sessione di lavoro con make clean. Il riquadro 1 mostra il risultato dell’azione “make clean” propedeutica a “make bzImage”. Al termine di make clean è così possibile attivarsi per creare l’immagine del kernel, e nel nostro caso compresso: l’immagine della versione del nostro kernel sarà messa in esecuzione al termine della sessione di boot di Linux. È bene ricordare che ci sono due possibilità, o due tipologie di immagine del kernel compresso, come bzImage e zImage: per ottenerle occorre semplicemente intervenire sugli argomenti di make, nel nostro caso scegliamo di utilizzare make bzImage: questa variante compila il kernel di Linux e pone l’immagine finale nella cartella usr/src/linux/arch/i386/boot posizionata nell’alberatura del codice sorgente (vedi Riquadro 2). Al termine di questa sessione di lavoro dobbiamo ancora compiere due azioni: da una parte è necessario compilare i nostri moduli che avevamo selezionato in .config e, in ultima istanza, dobbiamo procedere alla loro installazione. Nel primo passaggio dobbiamo, al solito, invocare il comando make modules (vedi Riquadro 3), mentre nell’ultimo passaggio, make modules_install, posizioniamo questi moduli nella loro corretta locazione organizzati in /lib/modules (Riquadro 4): con quest’ultima operazione si conclude il nostro lavoro sul kernel di Linux.

INSTALLIAMO IL NOSTRO KERNEL

Dopo aver compilato il kernel dobbiamo installarlo nella posizione corretta, configurare il bootloader allo scopo di permettergli di riconoscere il nuovo kernel all’avvio del sistema e, in ultima istanza, di riavviare correttamente il nostro kernel e verificare il lavoro svolto. Prima di procedere è buona norma fare una copia di backup del vecchio kernel, in modo da poterlo ripristinare in caso di problemi. Non solo, è anche necessario tenere una copia di un kernel di lavoro su un disco di avvio. A questo punto, una volta compilato il nostro kernel, copiamo il file bzImage nella directory /boot, e rinominiamolo come ci conviene, magari in modo che comprenda il numero di versione del kernel.

[root@example]# cp /usr/src/linux-
3.10/arch/i386/boot/bzImage /
boot/vmlinuz-3.10

A questo punto non ci rimane altro che configurare il bootloader, allo scopo di riconoscere il nuovo kernel. Se siamo in presenza di LiLo, o Linux Loader, dobbiamo editare il file lilo.conf che potrebbe presentarsi in questo modo:

# lilo.conf configuration file
prompt
sitimeout=
50
default=linux
boot=/dev/hda
map=/boot/map
install=/boot/boot.b
message=/boot/message
lba32
image=/boot/vmlinuz-3.10.12-4.EL
label=linux
initrd=/boot/initrd-3.10.12-4.EL.img
read-only
append=”root=LABEL=/”

In questo caso, l’immagine del boot di default è specificata come default=linux, la corrispondente immagine del kernel è specificata come vmlinuz-3.10.12-4.EL con la label=linux. Al fine di permettere il riconoscimento del nuovo kernel è necessario includere il nome dell’immagine binaria in lilo.conf e per fare il booting: in questo caso è indispensabile specificare in default la nuova versione del kernel, così:

# lilo.conf configuration file
prompt
timeout=50
default=linux-2.6
boot=/dev/hda
map=/boot/map
install=/boot/boot.b
message=/boot/message
lba32
image=/boot/vmlinuz-3.11.5-1.667
label=linux-3.11
initrd=/boot/initrd-3.11.5-1.667.img
read-only
root=/dev/VolGroup00/LogVol00
append=”rhgb quiet”
image=/boot/vmlinuz-3.10.12-4.EL
label=linux
initrd=/boot/initrd-3.10.12-4.EL.img
read-only
append=”root=LABEL=/”

Una volta apportate le modifiche, occorre eseguire LILO per permettere l’aggiornamento della configurazione: in caso di problemi in questa fase, LILO non permetterà di eseguire il nuovo kernel, ma si preoccuperà di eseguire il kernel precedente.

[root@example]# lilo

Al termine, possiamo fare il re-boot del computer e aspettare l’esecuzione del nuovo kernel appena generato. È anche possibile utilizzare LILO per selezionare il kernel che si intende avviare.

[root@example]# shutdown -r now

Una valida alternativa a LILO è GRUB.

RICOMPILIAMO LINUX NON SU *NIX

Può capitare anche di non poter disporre di un sistema operativo *nix; in questo caso, è sempre possibile ricompilare Linux utilizzando, in ambiente Windows, Cygwin. Cygwin è un applicazione che permette di trasformare il vostro Microsoft Windows in un *nix perché consente di emulare un sistema di questo tipo. Una volta installato Cygwin, dobbiamo disporre di una cross toolchain. Possiamo ottenerla direttamente su Internet perché ormai esistono differenti versioni e alternative possibili o, in sua assenza, possiamo pensare di generarne una. Personalmente ho utilizzato “cygwin-gcc-linux. tar.bz2”, una distribuzione di quasi 70 Mb con un md5sum composto dalla sequenza “340e91a346f5bb17e660db10e43005b8”. Questo pacchetto contiene gcc-3.3.4 e gcc-2.95.3 per i386 (glibc 2.1.3) e gcc- 3.3.3 per amd64 (glibc 2.3.2). Alcuni, poi, suggeriscono di utilizzare una versione più recente con glibc 2.3.2, ovvero “cygwin- gcc-3.3.6-glibc-2.3.2-linux.tar.bz2 (i386, x86_64)”. Per utilizzare correttamente questa toolchain è necessario copiare ‘cygwin-gcc-linux. tar.bz2’ in ‘c:\cygwin’ o, in alternativa, è pensabile di installarla con il suo setup. exe. Successivamente, occorre attivare la shell di cygwin e andare su root ‘cd /’ e decomprimere con ‘tar -jxvf cygwin-gcc-linux. tar.bz2’. I file della suite di compilazione sono così posizionati sotto ‘/opt/crosstool’: una volta copiati i file, può essere tranquillamente utilizzata attraverso i comandi gcc-linux, g++-linux, gcc-linux-2.95, g++-linux-2.95, gcc-linux-x86_64 e g++-linux-x86_64.

Riquadro 1: make clean

 

Riquadro 2: make bzImage

 

Riquadro 3: make modules

 

Riquadro 4: make modules_install

Articolo della rivista cartacea Firmware Anno 2015 - Numero 111

Scarica subito una copia gratis

Scrivi un commento

Seguici anche sul tuo Social Network preferito!

Send this to a friend