LKN: Personalizzare un Kernel: differenze tra le versioni

Da Guide@Debianizzati.Org.
Vai alla navigazione Vai alla ricerca
Nessun oggetto della modifica
Riga 1: Riga 1:
''Torna all'indice: [[Linux Kernel in a Nutshell]]''
''Torna all'indice: [[Linux Kernel in a Nutshell]]''


__TOC__
Uno dei punti più delicati e difficili nella creazione della propria versione del kernel Linux è quello di determinare esattamente quali driver e quali opzioni di configurazione sono richiesti per il corretto funzionamento dalla macchina su cui viene installato.
Questo capitolo guiderà il lettore attraverso questo processo di selezione e scelta dei driver corretti.


Ora che avete scaricato i sorgenti della versione del kernel che avete scelto e che li avete installati in una cartella locale, � giunto il momento di compilare il codice. Il primo passo � di configurare il kernel con le opzioni appropriate; in seguito il kernel potr� essere compilato. Entrambe le operazioni sono portate a termine attraverso lo strumento standard ''make''.
==Usare un kernel di una distribuzione==


== '''Creare una configurazione''' ==
Uno dei metodi più semplici, per determinare quali moduli siano necessari, è quello di partire dalla configurazione che viene installata dal pacchetto del kernel della distribuzione che si sta usando. È infatti molto più semplice determinare di quali driver si ha bisogno basandosi su quelli installati in un sistema in funzione, in cui i driver corretti sono già associati all'hardware in utilizzo.


La configurazione del kernel risiede in un file chiamato ''.config'' nella cartella principale dell'albero dei sorgenti del kernel. Se avete appena estratto il codice sorgente del kernel, non vi sar� alcun file ''.config'', quindi dovr� essere creato. Il file pu� essere creato da zero, creato partendo dalla "configurazione predefinita", preso da una versione funzionante del kernel, o preso da quello rilasciato da una distribuzione. Copriremo i primi due metodi adesso, gli ultimi due metodi nel [[LKN:_Personalizzare_un_Kernel|Capitolo 7]].
Se invece si sta personalizzando un kernel per una macchina sulla quale non è installata una distribuzione Linux, allora conviene partire dalla versione LiveCD di una distribuzione. Questo consente all'utente di far partire Linux sulla macchina in oggetto e di determinare in maniera semplice le opzioni di configurazione del kernel e che consentono il funzionamento ottimale della macchina stessa.


==='''Configurare dall'inizio'''===
===Dove si trova la configurazione del kernel?===
Il modo pi� spartano per configurare un kernel � usare il metodo ''make config'':
<pre>$ cd linux-2.6.17.10
  $ make config
make config
scripts/kconfig/conf arch/i386/Kconfig
*
* Linux Kernel Configuration
*
*
* Code maturity level option
*
Prompt for development and/or incomplete code/drivers (EXPERIMENTAL) [Y/n/?]
Y


*
Quasi tutte le distribuzioni forniscono il file di configurazione nello stesso pacchetto del kernel. Si consiglia di leggere la documentazione relativa alla distribuzione stessa per sapere dove viene installato il file di configurazione. Solitamente si trova da qualche parte in una sotto-directory di <tt>/usr/src/linux/</tt>.
* General setup
*
Local version - append to kernel release (LOCALVERSION) []
Automatically append version information to the version string
(LOCALVERSION_AUTO) [Y/n/?] Y
...</pre>
Il programma di configurazione del kernel proceder� attraverso ogni opzione di configurazione e chieder� se la si vuole abilitare o meno. Tipicamente, le possibilit� per ogni opzione sono presentate nella forma <tt>[Y/m/n/?]</tt>. La lettera maiuscola � la scelta predefinita, e pu� essere selezionata semplicemente premendo il tasto Invio. Le quattro scelte sono:
* <tt>Y</tt>  Compilare direttamente nel kernel.
* <tt>n</tt>  Lasciare completamente al di fuori del kernel.
* <tt>m</tt>  Compilare come modulo, da caricare se necessario.
* <tt>?</tt>   Stampa un breve messaggio descrittivo e ripropone il quesito.
Il kernel contiene quasi duemila opzioni di configurazioni differenti, quindi rispondere ad una domanda su ognuna di esse richiede un notevole dispendio di tempo. Fortunatamente, vi � un modo pi� facile di configurare un kernel: basare la configurazione su di un'altra precostituita.


==='''Opzioni della configurazione predefinita'''===
{{Box|Nota per Debian (NdT)|In debian il file di configurazione di ogni kernel installato si trova in <tt>/boot/</tt> ed ha come nome <tt>config-''versione''</tt>.}}
Ogni versione del kernel ha una configurazione "predefinita". Questa configurazione � in parte basata sulle scelte che il responsabile di quella architettura crede siano le opzioni migliori da essere usate. In alcuni casi, � la configurazione usata dal responsabile stesso sulle proprie macchine. Questo � vero per l'architettura i386, dove la configurazione predefinita corrisponde strettamente a quella che Linus Torvalds usa per la sua macchina di sviluppo principale.


Per creare questa configurazione predefinita, eseguite:
Se avete difficoltà a trovare la configurazione del kernel, allora guardate nel kernel stesso. I kernel di molte distribuzioni sono compilati in modo da includere il file di configurazione dentro il filesystem <tt>/proc</tt>. Per verificare se questo è il vostro caso, digitate:
<pre>$ cd linux-2.6.17.10
$ make defconfig</pre>
Un'enorme quantit� di opzioni di configurazione scorrer� velocemente sullo schermo, e un file ''.config'' sar� creato e piazzato nella cartella del kernel. Il kernel � ora correttamente configurato, ma dovrebbe essere adattato alla vostra macchina per assicurarsi che funzioni correttamente.


==='''Modificare la configurazione'''===
<pre>
Ora che abbiamo un file di configurazione di base, dovrebbe essere modificato per supportare l'hardware presente nel vostro sistema. Per ulteriori dettagli su come individuare quali opzioni siano necessarie per ottenere ci�, potete leggere il [[LKN:_Personalizzare_un_Kernel|Capitolo 7]]. Qui mostreremo come selezionare le opzioni che potreste voler cambiare.
$ ls /proc/config.gz
/proc/config.gz
</pre>


Ci sono tre differenti strumenti interattivi per la configurazione del kernel: uno basato su terminale chiamato ''menuconfig'', uno grafico basato sulle GTK+ chiamato ''gconfig'', e un altro grafico basato sulle QT chiamato ''xconfig''.
Se il file ''/proc/config.gz'' è presente, allora copiatelo nella directory del sorgente kernel ed estraetelo:


==='''Configurazione tramite terminale'''===
<pre>
Il metodo chiamato '''menuconfig''' per configurare un kernel � un programma per terminale che d� modo di muoversi nella configurazione del kernel usando i tasti freccia della tastiera. Per avviare questa modalit� di configurazione, digitate:
$ cp /proc/config.gz -/linux/
<pre>$ make menuconfig</pre>
$ cd -/linux
Vi apparir� una schermata molto simile a quella di figura 4-1.
$ gzip -dv config.gz
config.gz:      74.9% - - replaced with config
</pre>
 
Copiate questo file di configurazione nella vostra directory del kernel e rinominatelo in ''.config''.
Ora potrete utilizzare questo file come base di partenza nella personalizzazione della configurazione del kernel così come descritto nel [[LKN:_Configurare_e_Compilare|Capitolo 4]].
 
Usando questo file di configurazione si dovrebbe ottenere sempre un file immagine del kernel (un ''kernel ricompilato'', NdT) funzionante sulla propria macchina.
Lo svantaggio di questa immagine è che verranno compilati quasi tutti i moduli e driver presenti nei sorgenti del kernel. Ciò non è quasi mai necessario per una singola macchina, quindi sarebbe meglio disabilitare tutti i driver e le opzioni non necessarie. Si raccomanda di disabilitare solo quelle opzioni che si è sicuri non serviranno, poiché ci sono parti del sistema che richiedono l'abilitazione di certe opzioni.
 
===Determinare quali moduli siano necessari===
Usando il file di configurazione fornito dalla vostra distribuzione il tempo richiesto per la compilazione del kernel è molto lungo poiché tutti i possibili driver vengono abilitati. Si dovrebbe cercare di abilitare solo i driver per l'hardware presente nel sistema, così da ridurre i tempi di compilazione del kernel. Inoltre, compilando ''staticamente'' (invece che come moduli) alcuni o tutti i driver necessari, si riduce la memoria utilizzata ed in alcune architetture si velocizza il funzionamento del sistema. Per escludere i driver dal kernel è necessario però determinare quali moduli sono indispensabili per il funzionamento dell'hardware installato. Attraverso l'utilizzo di due esempi, cercheremo di spiegare come determinare quali driver siano indispensabili al controllo dell'hardware.
 
Le informazioni che mettono in relazione i dispositivi ai driver presenti nel kernel sono conservate in varie parti del sistema. Uno dei posti più importanti dove sono salvate queste informazioni è il filesystem virtuale ''sysfs''. All'avvio di Linux, ''sysfs'', dovrebbe essere montato dagli script di inizializzazione della vostra distribuzione nella directory ''/sys''. ''sysfs'' consente di dare un'occhiata a come le varie parti del kernel sono legate l'una a l'altra, questo lo si deduce grazie ai vari collegamenti simbolici (''symlink'' NdT) che puntano all'interno dell'intero filesystem.
 
In tutti gli esempi di seguito, saranno riportati i veri percorsi (''path'' NdT) di ''sysfs'' corrispondenti ad hardware specifico. La vostra macchina sarà certamente diversa, ma la posizione  relativa delle informazioni sarà la stessa. Non ci si deve allarmare se i nomi di file nel ''sysfs'' non sono i medesimi, ciò è normale e prevedibile.
 
Inoltre, la struttura interna del file di sistema ''sysfs'' subisce modifiche, a causa sia della riorganizzazione dei driver sia del fatto che gli sviluppatori del kernel trovano nuovi modi per meglio presentare in ''user space'' le strutture interne del kernel. A causa di questo, col tempo, alcuni dei ''symlink'', precedentemente menzionati in questo capitolo, possono non essere presenti. Tuttavia, le informazioni sono ancora tutte presenti, al massimo sono state un po' spostate.
 
====Esempio: Come determinare il driver di rete====
 
Uno degli elementi più comuni ed importanti in un sistema è la scheda di rete. È essenziale capire quale driver la controlla ed attivarlo nella configurazione in maniera da consentire un corretto funzionamento delle connessioni di rete.
 
Primo: partendo dalle connessioni di rete si risale al device PCI
<pre>$ ls /sys/class/net/
eth0  eth1  eth2  lo</pre>
 
La directory ''lo'' rappresenta il dispositivo di rete loopback, ed non è dipendente da nessun dispositivo di rete realmente installato. Invece si dovrebbe riservare particolare attenzione alle directory ''eth0'', ''eth1'' e ''eth2'', dato che si riferiscono a dispositivi realmente esistenti
 
Per determinare di quali dispositivi ci si deve occupare, si utilizza il comando ''ifconfig'':
 
<pre>$ /sbin/ifconfig -a
eth0 Link  encap:Ethernet  HWaddr 00:12:3F:65:7D:C2
inet  addr:192.168.0.13  Bcast:192.168.0.255  Mask:255.255.255.0
UP BROADCAST NOTRAILERS RUNNING MULTICAST  MTU:1500  Metric:1
RX packets:2720792 errors:0 dropped:0 overruns:0 frame:0
TX packets:1815488 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:100
RX bytes:3103826486 (2960.0 Mb) TX bytes:371424066 (354.2 Mb)
Base address:0xdcc0 Memory:dfee0000-dff00000
eth1 Link  encap:UNSPEC  HWaddr 80-65-00-12-7D-C2-3F-00-00-00-00-00-00-00-00
BROADCAST MULTICAST  MTU:1500  Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 b) TX bytes:0 (0.0 b)
eth2 Link  encap:UNSPEC  HWaddr 00-02-3C-04-11-09-D2-BA-00-00-00-00-00-00-00
BROADCAST MULTICAST  MTU:1500  Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 b) TX bytes:0 (0.0 b)
lo Link  encap:Local Lookback
        inet addr:127.0.0.1 Mask:255.0.0.0
UP  LOOPBACK  RUNNING  MTU:16436  Metric:1
RX packets:60 errors:0 dropped:0 overruns:0 frame:0
TX packets:60 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:13409 (13.0 Kb) TX bytes:13409 (13.0 Kb)</pre>
 
Da questo listato si può riconoscere nel dispositivo di rete <tt>eth0</tt>, quello attivo e funzionante, infatti nelle righe;


[[Immagine:Menuconfig_1.png|center|500px|thumb|''Figura 4-1. Schermata iniziale di menuconfig'']]
<pre>eth0 Link  encap:Ethernet  HWaddr 00:12:3F:65:7D:C2
inet  addr:192.168.0.13  Bcast:192.168.0.255  Mask:255.255.255.0</pre>


Le istruzioni per navigare attraverso il programma, e i significati dei diversi caratteri, sono mostrati in cima allo schermo. Il resto dello schermo contiene le diverse opzioni di configurazione.
Questo risultato dimostra che il dispositivo Ethernet si vede assegnato un indirizzo IP valido (<tt>inet</tt>).


La configurazione del kernel � divisa in sezioni. Ogni sezione contiene opzioni che corrispondo ad argomenti specifici. Al loro interno possono esserci sottosezioni per vari argomenti specifici. Per esempio tutti i driver per le periferiche possono essere trovati sotto l'opzione del menu principale <tt>Device Drivers ---></tt>.
Ora, dopo che abbiamo individuato il dispositivo <tt>eth0</tt> e ci siamo accertati di volerlo abilitare nel nostro nuovo kernel, dobbiamo individuare quale driver lo controlla. Ciò si realizza con una semplice procedura, che è quella si seguire i link nel filesystem sysfs, basta digitare un comando di una sola riga:


[[Immagine:Menuconfig_2.png|center|500px|thumb|''Figura 4-2. Selezione dell'opzione Device Drivers'']]
<pre>$ basename `readlink /sys/class/net/eth0/device/driver/module`
e1000</pre>


Per aprire questo menu, premete la freccia in basso nove volte, finch� la riga <tt>Device Drivers ---></tt> non � sottolineata, come mostrato in figura 4-2.
Il risultato mostra che il modulo <tt>e1000</tt> controlla il dispositivo di rete <tt>eth0</tt>. Il comando ''basename'' racchiude in un'unica linea di comando i seguenti passaggi:


Premete poi il tasto Invio. Vi porter� nel sotto-menu <tt>Device Drivers</tt> e lo mostrer� come mostrato nella figura 4-3.
: 1. Individua il symlink ''/sys/class/net/eth0/device'' contenuto all'interno della directory ''/sys/device/'', la quale contiene le informazioni relative al dispositivo che controlla ''eth0''. Fate attenzione al fatto che nelle nuove versioni del kernel la directory ''/sys/class/net/eth0'' potrebbe essere un symlink.  


[[Immagine:Menuconfig_3.png|center|500px|thumb|''Figura 4-3. Sottomenu Device Drivers'']]
: 2. All'interno della directory che descrive il dispositivo in sysfs, c'è un symlink che punta al driver relativo a questo dispositivo. Questo symlink è nominato ''driver'', pertanto si segue questo collegamento.


Potete continuare a muovervi nella gerarchia dei menu allo stesso modo. Per visualizzare il sotto-menu <tt>Generic Driver Options</tt> premete Invio di nuovo, e vedrete se tre opzioni mostrate in figura 4-4.
: 3. All'interno della directory che descrive il driver in sysfs, c'è un symlink che punta al modulo che si trova all'interno del driver in oggetto. Questo symlink è chiamato <tt>module</tt>. Noi cerchiamo l'oggetto a cui punta questo symlink, per ottenerlo ci serviamo del comando ''readlink'', il quale produce un risultato simile a questo:
:<pre>$ readlink /sys/class/net/eth0/device/driver/module </pre>
:<pre> ../../../../module/e1000</pre>


[[Immagine:Menuconfig_4.png|center|500px|thumb|''Figura 4-4. Sottomenu Generic Driver Options'']]
: 4. Dato che a noi interessa solo il nome del modulo e ci disinteressiamo del resto del risultato ottenuto con il comando ''readlink'', tenendo solo la parte più a destra del risultato. Questo è appunto ciò che il comando ''basename'' realizza. Applicandolo direttamente all'intero percorso, questo comando ci ritorna quanto segue:
: <pre>$ basename ../../../../module/e1000</pre>
: <pre>e1000</pre>


Le prime due opzioni hanno un simbolo <tt>[*]</tt> vicino a esse. Questo significa che quest'opzione � selezionata (perch� il simbolo <tt>*</tt> sta al centro dei due caratteri <tt>[]</tt>), e che questa � un'opzione del tipo s�-o-no. La terza opzione ha un segno <tt>< ></tt>, che mostra che questa opzione pu� essere inserita nel kernel (<tt>Y</tt>), compilata come modulo (<tt>M</tt>), o esclusa del tutto (<tt>N</tt>).
Così abbiamo inserito il lungo risultato del symlink, ottenuto da ''readlink'', quale parametro nel programma ''basemane'', permettendo così l'intero processo di essere realizzato in una sola riga.


Se l'opzione � selezionata con <tt>Y</tt>, le parentesi ad angolo conterranno un <tt>*</tt>. Se � selezionata come modulo con una <tt>M</tt>, conterranno una lettera <tt>M</tt>. Se � disabilitata con <tt>N</tt>, mostreranno solo uno spazio bianco.
Ora che abbiamo identificato il nome del modulo, si dovrebbe trovare l'opzione della configurazione del kernel che lo controlla. Si può cercare nei vari menu di configurazione dei dispositivi di rete oppure cercare nel codice sorgente del kernel stesso per essere sicuri di avere l'opzione giusta.


Cos�, se desiderate cambiare queste tre opzioni per selezionare solo driver che non necessitano di firmware esterno in tempo di compilazione, disabilitate l'opzione per impedire che il firmware sia compilato, e compilate il caricatore del firmware in spazio utente come modulo, digitando <tt>Y</tt> per la prima opzione, <tt>N</tt> per la seconda e <tt>M</tt> per la terza, rendendo la schermata come quella in figura 4-5.
<pre>
$ cd ~/linux/linux-2.6.17.8
$ find -type f -name Makefile | xargs grep e1000
./drivers/net/Makefile:obj-$(CONFIG_E1000) += e1000/
./drivers/net/e1000/Makefile:obj-$(CONFIG_E1000) += e1000.o
./drivers/net/e1000/Makefile:e1000-objs := e1000_main.o e1000_hw.o e1000_ethtool.o e1000_param.o
</pre>


[[Immagine:Menuconfig_5.png|center|500px|thumb|''Figura 4-5. Sottomenu Generic Driver Options cambiato'']]
Si precisa che "e1000'', usato in questo esempio, deve essere sostituito con il nome del modulo che state analizzando.


Quando avete completato le vostre modifiche in questa schermata, premete il tasto Esc o la freccia destra seguita dal tasto Invio per lasciare questo sottomenu. Tutte le opzioni del kernel possono essere esplorate in questa maniera.
La cosa che ci interessa nel risultato del precedente comando ''find'' sono le righe dove compaia il termine <tt>'''CONFIG_'''</tt>. Questa è l'opzione di configurazione che il kernel deve aver attivato per poter compilare il modulo. Nell'esempio precedente l'opzione di configurazione che c'interessa è pertanto <tt>CONFIG_E1000</tt>.


Quando avete finito di fare tutte le modifiche che desideriate apportare alla configurazione del kernel, uscite dal programma premendo il tasto Esc quando siete nel menu principale.
Adesso si dispone dell'informazione necessaria per poter configurare il kernel. Si esegue lo strumento menu di configurazione:


[[Immagine:Menuconfig_6.png|center|500px|thumb|''Figura 4-6. Salvare le opzioni del kernel'']]
<pre>$ make menuconfig</pre>


Vi sar� mostrata la schermata in figura 4-6, che vi chiede se desiderate salvare la vostra modificata configurazione.
Dopodiché si prema il tasto / (slash) (che ha il compito di far partire una ricerca), e si digita l'opzione di configurazione, senza la parte di testo <tt>CONFIG_</tt>. Questo processo è mostrato nella [[:Immagine:Config_search.png|figura 7-1]].


Premete Invio per salvare la configurazione, o, se volete eliminare ogni modifica fatta, digitate la freccia destra per selezionare la voce <tt>< No ></tt> e premete Invio.
[[Immagine:Config_search.png|center|frame|''Figura 7-1. Ricerca in menuconfig.'']]


Il sistema di configurazione del kernel vi dirà ora esattamente dove selezionare l'opzione per abilitare questo modulo. Vedi [[:Immagine:Config_search_found.png|figura 7-2]].


==='''Metodi grafici di configurazione'''===
[[Immagine:Config_search_found.png|center|frame|''Figura 7-2. Risultato della ricerca in menuconfig.'']]
I metodi di configurazione del kernel ''gconfig'' e ''xconfig'' usano un programma grafico per permettervi di modificare la configurazione. I due metodi sono pressoch� identici, l'unica differenza risiede nei diversi strumenti grafici attraverso i quali sono scritti. ''gconfig'' � scritto usando il toolkit GTK+ e ha uno schermo diviso in due regioni, come mostrato in figura 4-7.


[[Immagine:Gconfig_1.png|center|500px|thumb|''Figura 4-7. Schermata di make gconfig'']]
Il primo elemento nella schermata mostra l'opzione che stavate cercando. Le informazioni mostrate dalla schermata vi dicono che, per attivare il modulo <tt>E1000</tt> nel kernel,  la seguente opzione di configurazione deve essere abilitata:


Il metodo ''xconfig'' � scritto usando il toolkit QT e ha uno schermo diviso in tre regioni, come in figura 4-8.
  Device Drivers
      Network device support
      [*] Network device support
          Ethernet (1000 Mbit)
      [*] Intel(R) PRO/1000 Gigabit Ethernet support


[[Immagine:Xconfig_1.png|center|500px|thumb|''Figura 4-8. Schermata di make xconfig'']]
Questo modo di procedere funziona per ogni tipo di dispositivo attivo nel kernel.


Usate il mouse per navigare nei sottomenu e selezionare le opzioni. Per esempio, nella figura 4-8 potreste usarlo per selezionare il sottomenu <tt>Generic Driver Options</tt> del menu <tt>Device Drivers</tt>. Questo cambier� la schermata di ''xconfig'' e la far� diventare quella dell'immagine 4-9.
====Esempio: Un dispositivo USB====


[[Immagine:Xconfig_2.png|center|500px|thumb|''Figura 4-9. Generic Driver Options in make xconfig'']]
Come secondo esempio, esaminiamo ora un convertitore USB-seriale che è presente nel nostro sistema preso ad esempio. Attualmente il convertitore è collegato alla porta ''/dev/ttyUSB0'', pertanto si deve prendere in esame la sezione tty del ''sysfs''.
<pre>$ ls /sys/class/tty/ | grep USB
ttyUSB0</pre>
Potete ora eseguire una ricerca di questo dispositivo nel ''sysfs'' allo scopo di trovare il modulo che lo gestisce, utilizzando la stessa procedura mostrata nella sezione precedente:


La corrispondente immagine di ''gconfig'' � in figura 4-10.
<pre>$ basename `readlink /sys/class/tty/ttyUSB0/device/driver/module`
pl2303</pre>
Dopodiché, per poter individuare l'opzione di configurazione che si deve abilitare, si cerca nell'albero del codice sorgente del kernel:
<pre>$ cd ~/linux/linux-2.6.17.8
$ find -type f -name Makefile | xargs grep pl2303
./drivers/usb/serial/Makefile:obj-$(CONFIG_USB_SERIAL_PL2303) += pl2303.o</pre>


[[Immagine:Gconfig_2.png|center|500px|thumb|''Figura 4-10. Generic Driver Options in make gconfig'']]
Si utilizzi lo strumento di configurazione del kernel, come indicato in [[:Immagine:Config_search_pl2303.png|figura 7-3]], per trovare l'opzione adeguata da abilitare relativa al settaggio dell'opzione CONFIG_USB_SERIAL_PL2303.


Modificare questo sottomenu per disabilitare la seconda opzione e rendere la terza opzione compilata come modulo genera le schermate apparire come nelle figure 4-11 e 4-12.
[[Immagine:Config_search_pl2303.png|center|frame|''Figura 7-3. Ricerca di USB_SERIAL_PL2303''.]]


[[Immagine:Xconfig_3.png|center|500px|thumb|''Figura 4-11. Generic Driver Options in make xconfig, modificato'']]
Nel nostro caso il risultato è mostrato nella [[:Immagine:Config_search_pl2303_found.png|figura 7-4]].
[[Immagine:gconfig_3.png|center|500px|thumb|''Figura 4-12. Generic Driver Options in make gconfig, modificato'']]


Notate che nel metodo ''gconfig'' un riquadro con il segno di visto significa che l'opzione sar� compilata nel kernel, laddove una linea nel riquadro significa che l'opzione sar� compilata come modulo. Nel metodo ''xconfig'' un'opzione compilata come modulo sar� mostrata con un punto nel riquadro.
[[Immagine:Config_search_pl2303_found.png|center|frame|''Figura 7-4. Risultato della ricerca di USB_SERIAL_PL2303'']]


Entrambi questi metodi vi chiedono di salvare la configurazione quando uscite dal programma, e offrono la possibilit� di scrivere quella configurazione in un altro file. Potete cos� creare molteplici, distinte configurazioni.
Ciò mostra esattamente dove trovare l'opzione <tt>USB Profilic 2303 Single Port Serial Driver</tt> che è necessaria alla corretta gestione di questo dispositivo.


====Riassunto: Alla scoperta del dispositivo====


=='''Compilazione del kernel'''==
Riassumendo, ecco i vari passaggi che servono per identificare il driver funzionante di un dispositivo ad esso collegato:
Ora che avete creato la configurazione che intendete usare, dovete compilare il kernel. Questo � semplice come digitare un comando di un parola:
: 1. Trovate la corretta classe di dispositivi in ''sysfs'' relativa al dispositivo che ci interessa. I dispositivi di rete sono elencati in ''/sys/class/net'', mentre i dispositivi tty sono elencati in ''/sys/class/tty''. Gli altri vari dispositivi si trovano in altre sotto-directory di ''/sys/class'', a seconda del tipo.
<pre>$ make
: 2. Ricercate nell'albero di ''sysfs''  il nome del modulo che controlla il dispositivo in oggetto. Lo si trova in ''/sys/class/class_name/device_name/device/driver/module'', la ricerca è agevolata se si utilizzano i comandi ''readlink'' e ''basename''.
CHK include/linux/version.h
:<pre>$ basename `readlink /sys/class/class_name/device_name/device/driver/module`</pre>
UPD include/linux/version.h
: 3. Ricercate nei file Makefile con ''find'' e ''grep'' le opzioni <tt>CONFIG_</tt> che abilitano il modulo
SYMLINK include/asm -> include/asm-i386
:<pre>$ find -type f -name Makefile | xargs grep ''module_name''</pre>
SPLIT include/linux/autoconf.h -> include/config/*
: 4. Ricercate l'opzione trovata nel sistema di configurazione del kernel, dopodiché andate dove indicato dal menu per attivare il driver in oggetto.
CC arch/i386/kernel/asm-offsets.s
GEN include/asm-i386/asm-offsets.h
CC scripts/mod/empty.o
HOSTCC scripts/mod/mk_elfconfig
MKELF scripts/mod/elfconfig.h
HOSTCC scripts/mod/file2alias.o
HOSTCC scripts/mod/modpost.o
HOSTCC scripts/mod/sumversion.o
HOSTLD scripts/mod/modpost.o
HOSTCC scripts/kallsyms
HOSTCC scripts/conmakehash
HOSTCC scripts/bin2c
CC init/main.o
CHK include/linux/compile.h
UPD include/linux/compile.h
CC init/version.o
CC init/do_mounts.o
...</pre>


Eseguire ''make'' fa s� che il sistema di compilazione del kernel usi il file di configurazione che avete selezionato per compilare un kernel e tutti i moduli necessari per supportare tale configurazione. Mentre il kernel � in compilazione, ''make'' mostra cosa sta correntemente succedendo ai singoli file, insieme a tutti gli avvertimenti ("warnings", N.d.T.) e gli errori di compilazioni.
====Lasciamo che il kernel ci dica ciò di cui abbiamo bisogno====
Dopo esserci infilati nel ''sysfs'' e aver seguito i sui symlinks per ricercare passo passo i nomi dei moduli, presentiamo un semplice script che farà per noi tutto il lavoro in un modo leggermente diverso:


Se la compilazione del kernel termina senza errori, avete creato con successo l'immagine di un kernel. Comunque deve essere propriamente installata prima che proviate ad avviarla. Leggete il [[LKN:_Installare_ed_Avviare_con_un_Kernel|Capitolo 5]] per sapere come fare.
<pre>
#!/bin/bash
#
# find_all_modules.sh
#
for i in `find /sys/ -name modalias -exec cat {} \;`; do
    /sbin/modprobe --config /dev/null --show-depends $1 ;
done | rev | cut -f i -d '/' | rev | sort -u
</pre>


� molto raro avere errori di compilazione quando state compilando una versione del kernel rilasciata. Se vi capita, riportateli agli sviluppatori del kernel Linux cosicch� possano essere corretti.
Si può scaricare un file d'esempio, contenente questo script, dal sito web del libro, riportato nella sezione ''Come contattarci'' che si trova nella prefazione.


nota: Versioni del kernel pi� vecchie, precedenti al rilascio 2.6 richiedevano l'ulteriore passo ''make modules'' per compilare tutti i moduli necessari. Questo non � pi� necessario.
Questo script cerca nel ''sysfs'' tutti file chiamati ''modalias''. Il file ''modalias'' contiene gli alias dei moduli e comunica al comando ''modprobe'' quali moduli debbano essere caricati per ogni dispositivo. L'alias del modulo è composto da una combinazione di: produttore del dispositivo, ID, tipo di classe ed altri identificativi univoci per il tipo di dispositivo in questione. Tutti i moduli del driver del kernel hanno una lista interna dei dispositivi che supportano, che è generata automaticamente dalla lista dei dispositivi che il driver comunica al kernel di poter supportare. Il comando ''modprobe'' ricerca tutti i dispositivi nella lista di tutti i driver e cerca di trovare una corrispondenza confrontando l'alias. Se trova una corrispondenza, allora provvede al caricamento del modulo (questa procedura è la stessa seguita dal caricamento automatico dei driver in Linux).


=='''Opzioni di compilazione avanzate'''==
Lo script prevede l'arresto del programma ''modprobe'' prima di caricare il modulo, e visualizza a schermo solo le azioni che eseguirebbe. Questo ci d&agrave; una lista di tutti i moduli che sono necessari al controllo di tutti i dispositivi del sistema. Eseguendo una piccola pulizia della lista, ordinandola e selezionando i campi adeguati,  
Il sistema di compilazione del kernel consente di fare molte altre cose, oltre a compilare l'intero kernel e i relativi moduli. Il Capitolo 10 contiene l'intero elenco delle opzioni che il sistema di compilazione fornisce. In questa sezione discuteremo alcune di queste opzioni avanzate. Per avere una descrizione completa di come usare altre opzioni avanzate, fate riferimento alla documentazione dentro il kernel stesso, che pu� essere trovata nella cartella ''Documentation/kbuild'' nei sorgenti.
otteniamo il seguente risultato:


==='''Velocizzare la compilazione in macchine multiprocessore'''===
<pre>
Il sistema di compilazione del kernel lavora molto bene come operazione che pu� essere divisa in pezzi pi� piccoli e assegnati a diversi processori. Facendo questo, potete usare la piena potenza di una macchina multiprocessore e ridurre considerevolmente il tempo di compilazione del kernel.
$ find_all_modules.sh
8139cp.ko
8139too.koo
ehci-hcd.ko
fimware_vlass.ko
i2c-i801.ko
ieee80211.ko
ieee80211_crypt.ko
ipw2200.ko
mii.ko
mmc_core.ko
pcmcia_core.ko
rsrc_nonstatic.ko
sdhci.ko
snd-hda-codec.ko
snd-hda-intel.ko
snd-page-alloc.ko
snd-pmc.ko
snd-timer.ko
snd.ko
soundcore.ko
uhci-hcd.ko
usbcore.ko
yenta_socket.ko
</pre>


Per compilare un kernel in modo parallelo, usate l'opzione ''-j'' del comando ''make''. � meglio dare un numero all'opzione ''-j'' che corrisponda al doppio del numero di processori nel sistema. Quindi, per macchine con due processori, usate:
Questa è la lista di tutti i moduli che sono necessari alla gestione dell'hardware della macchina.
<pre>$ make -j4</pre>
e per macchine con quattro processori, usate:
<pre>$ make -j8</pre>
Se non passate un numero all'opzione ''-j'':
<pre>$ make -j</pre>
il sistema di compilazione creer� un nuovo filo ("thread", N.d.T.) per ogni sottocartella nell'albero delle cartelle del kernel, che pu� facilmente rendere la vostra macchina non in grado di rispondere ai comandi, e impiegare molto pi� tempo per completare la compilazione. Per questo si raccomanda di passare sempre un valore numerico all'opzione ''-j''.


==='''Compilare solo una parte del kernel'''===
Lo script mostrerà probabilmente alcuni messaggi di errore che possono essere del tipo:
Quando ci si dedica allo sviluppo del kernel, a volte si desidera compilare solo una specifica sottocartella, o un singolo file dell'intero albero del kernel. Il sistema di compilazione lo consente agevolmente. Per compilare selettivamente una sottocartella, specificatela nel comando di compilazione. Per esempio, per compilare i file nella cartella '''drivers/usb/serial''', inserite: <pre>$ make drivers/usb/serial</pre>
Usando questa sintassi, comunque, non si compiler� l'immagine finale del modulo in quella cartella. Per fare questo, potete usare l'opzione <tt>M=</tt>argomento:<pre>$ make M=drivers/usb/serial</pre>che compiler� tutti i file necessari in quella cartella e collegher� le immagini finali dei moduli.


Quando si compila una singola cartella in uno dei modi mostrati, l'immagine finale del kernel non viene ricollegata. Comunque ogni cambiamento che era stato effettuato alle sottocartelle non influenzer� l'immagine finale del kernel, che probabilmente non � quello che desiderate. Eseguite alla fine un:<pre>$ make</pre> perch� il sistema di compilazione controlli tutti i file oggetto cambiati e colleghi in modo proprio l'immagine finale del kernel.
<pre>FATAL: Module pci:v00008086d00002592sv000010CFsd000012E0bc03sc00i00 not found.
FATAL: Module serio:ty01pr00id00ex00 not found.</pre>


Per compilare un solo specifico file nell'albero del kernel, semplicemente passatelo come parametro a ''make''. Per esempio, se desiderate compilare il modulo ''drivers/usb/serial/visor.ko'', inserite:<pre>$ make drivers/usb/serial/visor.ko</pre>
Questo ci dice che non si trova un modulo che gestisce quel dispositivo. Questo non deve comunque interessare più di tanto, poiché alcuni dispositivi non hanno driver nel kernel che lavorino per loro.
Il sistema di compilazione compiler� tutti i file necessari per il modulo visor.ko, e far� il collegamento finale per creare il modulo.


==='''Sorgente in un posto, destinazione in un altro'''===
==Determinare il modulo corretto partendo da zero==
Alle volte � pi� semplice avere i sorgenti del kernel in un posto accessibile in sola lettura (come un CD-ROM, o in un sistema di controllo del codice sorgente), e collocare il risultato della compilazione altrove, cos� da non alterare l'albero originale del sorgente. Il sistema di compilazione lo realizza facilmente, richiedendo il solo argomento <tt>O=</tt> per specificare dove collocare l'output della compilazione. Per esempio se i sorgenti del kernel sono in un CD-ROM montato in ''/mnt/cdrom/'' e desiderate mettere i file compilati nella vostra cartella locale, inserite:<pre>$ cd /mnt/cdrom/linux-2.6.17.11
Talvolta non c'è la possibilità di avere un kernel funzionante su una macchina in modo da determinare quali moduli del kernel siano necessari per gestire l'hardware. Oppure si è aggiunto del nuovo hardware al sistema e bisogna trovare le opzioni della configurazione necessarie a farlo funzionare correttamente. Questa sezione illustrerà come determinare le opzioni di configurazione necessarie ad far funzionare l'hardware.
$ make O=~/linux/linux-2.6.17.11</pre>
Tutti i file compilati saranno creati nella cartella ''~/linux/linux-2.6.17.11''. Notate che questa opzione <tt>O=</tt> dovrebbe essere passata anche alle opzioni di configurazione della compilazione cosicch� la configurazione sia correttamente collocata nella cartella di destinazione e non in quella contenente il codice sorgente.


==='''Architetture differenti'''===
Il modo più semplice per capire quale driver controlla un nuovo dispositivo è quello di compilare come moduli tutti i driver di quel tipo disponibili nei sorgenti del kernel, e lasciare che il processo di avvio tramite ''udev'' associ il driver al dispositivo. Una volta fatto ciò, si dovrebbe essere in grado di risalire al driver necessario seguendo i passi descritti precedentemente, ed infine ricompilare il kernel abilitando il solo driver necessario.
Una caratteristica molto utile � la costruzione di un kernel in una compilazione incrociata, per permettere a una macchina pi� potente di compilare un kernel per una sistema integrato pi� piccolo, o anche solo per controllare una compilazione per un'architettura diversa per assicurare che a un cambiamento nel codice sorgente non danneggi qualcosa di inaspettato. Il sistema di compilazione del kernel consente di specificare un'architettura diversa da quella della macchina corrente con il parametro <tt>ARCH=</tt>argomento. Il sistema di compilazione consente, inoltre, di specificare il compilatore che si desidera usare con il parametro <tt>CC=</tt>argomento o uno strumento per concatenare ("toolchain", N.d.T.) la compilazione incrociata con <tt>CROSS_COMPILE</tt> argomento.


Per esempio, per avere la configurazione predefinita dell'architettura x86_64, si pu� inserire:
===Dispositivi PCI===


<pre>$ make ARCH=x86_64 defconfig</pre>


Per compilare l'intero kernel con uno strumento per concatenare la compilazione situato in ''/usr/local/bin'', si pu� inserire:
===Dispositivi USB===
<pre>$ make ARCH=arm CROSS_COMPILE=/usr/local/bin/arm-linux-</pre>


� utile anche per i kernel non ottenuti con compilazione incrociata cambiare ci� che il sistema di costruzione del kernel usa per il compilatore. Esempi di questo sono l'utilizzo dei programmi ''distcc'' o ''ccache'', i quali riducono notevolmente il tempo di compilazione di un kernel. Per usare il programma ''ccache'' come parte del sistema di costruzione del kernel, digitate:
===Root Filesystem===


<pre>$ make CC="ccache gcc"</pre>


Per usare contemporaneamente ''distcc'' e ''ccache'', inserite:
====Controller di Disco====


<pre>$ make CC="ccache distcc"</pre>
===Un aiuto dallo script===





Versione delle 14:02, 14 ago 2007

Torna all'indice: Linux Kernel in a Nutshell

Uno dei punti più delicati e difficili nella creazione della propria versione del kernel Linux è quello di determinare esattamente quali driver e quali opzioni di configurazione sono richiesti per il corretto funzionamento dalla macchina su cui viene installato. Questo capitolo guiderà il lettore attraverso questo processo di selezione e scelta dei driver corretti.

Usare un kernel di una distribuzione

Uno dei metodi più semplici, per determinare quali moduli siano necessari, è quello di partire dalla configurazione che viene installata dal pacchetto del kernel della distribuzione che si sta usando. È infatti molto più semplice determinare di quali driver si ha bisogno basandosi su quelli installati in un sistema in funzione, in cui i driver corretti sono già associati all'hardware in utilizzo.

Se invece si sta personalizzando un kernel per una macchina sulla quale non è installata una distribuzione Linux, allora conviene partire dalla versione LiveCD di una distribuzione. Questo consente all'utente di far partire Linux sulla macchina in oggetto e di determinare in maniera semplice le opzioni di configurazione del kernel e che consentono il funzionamento ottimale della macchina stessa.

Dove si trova la configurazione del kernel?

Quasi tutte le distribuzioni forniscono il file di configurazione nello stesso pacchetto del kernel. Si consiglia di leggere la documentazione relativa alla distribuzione stessa per sapere dove viene installato il file di configurazione. Solitamente si trova da qualche parte in una sotto-directory di /usr/src/linux/.

Info.png Nota per Debian (NdT)
In debian il file di configurazione di ogni kernel installato si trova in /boot/ ed ha come nome config-versione.


Se avete difficoltà a trovare la configurazione del kernel, allora guardate nel kernel stesso. I kernel di molte distribuzioni sono compilati in modo da includere il file di configurazione dentro il filesystem /proc. Per verificare se questo è il vostro caso, digitate:

$ ls /proc/config.gz
/proc/config.gz

Se il file /proc/config.gz è presente, allora copiatelo nella directory del sorgente kernel ed estraetelo:

$ cp /proc/config.gz -/linux/
$ cd -/linux
$ gzip -dv config.gz
config.gz:      74.9% - - replaced with config

Copiate questo file di configurazione nella vostra directory del kernel e rinominatelo in .config. Ora potrete utilizzare questo file come base di partenza nella personalizzazione della configurazione del kernel così come descritto nel Capitolo 4.

Usando questo file di configurazione si dovrebbe ottenere sempre un file immagine del kernel (un kernel ricompilato, NdT) funzionante sulla propria macchina. Lo svantaggio di questa immagine è che verranno compilati quasi tutti i moduli e driver presenti nei sorgenti del kernel. Ciò non è quasi mai necessario per una singola macchina, quindi sarebbe meglio disabilitare tutti i driver e le opzioni non necessarie. Si raccomanda di disabilitare solo quelle opzioni che si è sicuri non serviranno, poiché ci sono parti del sistema che richiedono l'abilitazione di certe opzioni.

Determinare quali moduli siano necessari

Usando il file di configurazione fornito dalla vostra distribuzione il tempo richiesto per la compilazione del kernel è molto lungo poiché tutti i possibili driver vengono abilitati. Si dovrebbe cercare di abilitare solo i driver per l'hardware presente nel sistema, così da ridurre i tempi di compilazione del kernel. Inoltre, compilando staticamente (invece che come moduli) alcuni o tutti i driver necessari, si riduce la memoria utilizzata ed in alcune architetture si velocizza il funzionamento del sistema. Per escludere i driver dal kernel è necessario però determinare quali moduli sono indispensabili per il funzionamento dell'hardware installato. Attraverso l'utilizzo di due esempi, cercheremo di spiegare come determinare quali driver siano indispensabili al controllo dell'hardware.

Le informazioni che mettono in relazione i dispositivi ai driver presenti nel kernel sono conservate in varie parti del sistema. Uno dei posti più importanti dove sono salvate queste informazioni è il filesystem virtuale sysfs. All'avvio di Linux, sysfs, dovrebbe essere montato dagli script di inizializzazione della vostra distribuzione nella directory /sys. sysfs consente di dare un'occhiata a come le varie parti del kernel sono legate l'una a l'altra, questo lo si deduce grazie ai vari collegamenti simbolici (symlink NdT) che puntano all'interno dell'intero filesystem.

In tutti gli esempi di seguito, saranno riportati i veri percorsi (path NdT) di sysfs corrispondenti ad hardware specifico. La vostra macchina sarà certamente diversa, ma la posizione relativa delle informazioni sarà la stessa. Non ci si deve allarmare se i nomi di file nel sysfs non sono i medesimi, ciò è normale e prevedibile.

Inoltre, la struttura interna del file di sistema sysfs subisce modifiche, a causa sia della riorganizzazione dei driver sia del fatto che gli sviluppatori del kernel trovano nuovi modi per meglio presentare in user space le strutture interne del kernel. A causa di questo, col tempo, alcuni dei symlink, precedentemente menzionati in questo capitolo, possono non essere presenti. Tuttavia, le informazioni sono ancora tutte presenti, al massimo sono state un po' spostate.

Esempio: Come determinare il driver di rete

Uno degli elementi più comuni ed importanti in un sistema è la scheda di rete. È essenziale capire quale driver la controlla ed attivarlo nella configurazione in maniera da consentire un corretto funzionamento delle connessioni di rete.

Primo: partendo dalle connessioni di rete si risale al device PCI

$ ls /sys/class/net/
eth0  eth1  eth2  lo

La directory lo rappresenta il dispositivo di rete loopback, ed non è dipendente da nessun dispositivo di rete realmente installato. Invece si dovrebbe riservare particolare attenzione alle directory eth0, eth1 e eth2, dato che si riferiscono a dispositivi realmente esistenti

Per determinare di quali dispositivi ci si deve occupare, si utilizza il comando ifconfig:

$ /sbin/ifconfig -a
eth0	Link  encap:Ethernet  HWaddr 00:12:3F:65:7D:C2
	inet  addr:192.168.0.13  Bcast:192.168.0.255  Mask:255.255.255.0
	UP BROADCAST NOTRAILERS RUNNING MULTICAST  MTU:1500  Metric:1
	RX packets:2720792 errors:0 dropped:0 overruns:0 frame:0
	TX packets:1815488 errors:0 dropped:0 overruns:0 carrier:0
	collisions:0 txqueuelen:100
	RX bytes:3103826486 (2960.0 Mb)	TX bytes:371424066 (354.2 Mb)
	Base address:0xdcc0 Memory:dfee0000-dff00000
eth1	Link  encap:UNSPEC  HWaddr 80-65-00-12-7D-C2-3F-00-00-00-00-00-00-00-00
	BROADCAST MULTICAST  MTU:1500  Metric:1
	RX packets:0 errors:0 dropped:0 overruns:0 frame:0
	TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
	collisions:0 txqueuelen:1000
	RX bytes:0 (0.0 b)	TX bytes:0 (0.0 b)
eth2	Link  encap:UNSPEC  HWaddr 00-02-3C-04-11-09-D2-BA-00-00-00-00-00-00-00
	BROADCAST MULTICAST  MTU:1500  Metric:1
	RX packets:0 errors:0 dropped:0 overruns:0 frame:0
	TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
	collisions:0 txqueuelen:1000
	RX bytes:0 (0.0 b)	TX bytes:0 (0.0 b)
lo	Link  encap:Local Lookback
        inet addr:127.0.0.1  Mask:255.0.0.0
	UP  LOOPBACK  RUNNING  MTU:16436  Metric:1
	RX packets:60 errors:0 dropped:0 overruns:0 frame:0
	TX packets:60 errors:0 dropped:0 overruns:0 carrier:0
	collisions:0 txqueuelen:1000
	RX bytes:13409 (13.0 Kb)	TX bytes:13409 (13.0 Kb)

Da questo listato si può riconoscere nel dispositivo di rete eth0, quello attivo e funzionante, infatti nelle righe;

eth0	Link  encap:Ethernet  HWaddr 00:12:3F:65:7D:C2
	inet  addr:192.168.0.13  Bcast:192.168.0.255  Mask:255.255.255.0

Questo risultato dimostra che il dispositivo Ethernet si vede assegnato un indirizzo IP valido (inet).

Ora, dopo che abbiamo individuato il dispositivo eth0 e ci siamo accertati di volerlo abilitare nel nostro nuovo kernel, dobbiamo individuare quale driver lo controlla. Ciò si realizza con una semplice procedura, che è quella si seguire i link nel filesystem sysfs, basta digitare un comando di una sola riga:

$ basename `readlink /sys/class/net/eth0/device/driver/module`
e1000

Il risultato mostra che il modulo e1000 controlla il dispositivo di rete eth0. Il comando basename racchiude in un'unica linea di comando i seguenti passaggi:

1. Individua il symlink /sys/class/net/eth0/device contenuto all'interno della directory /sys/device/, la quale contiene le informazioni relative al dispositivo che controlla eth0. Fate attenzione al fatto che nelle nuove versioni del kernel la directory /sys/class/net/eth0 potrebbe essere un symlink.
2. All'interno della directory che descrive il dispositivo in sysfs, c'è un symlink che punta al driver relativo a questo dispositivo. Questo symlink è nominato driver, pertanto si segue questo collegamento.
3. All'interno della directory che descrive il driver in sysfs, c'è un symlink che punta al modulo che si trova all'interno del driver in oggetto. Questo symlink è chiamato module. Noi cerchiamo l'oggetto a cui punta questo symlink, per ottenerlo ci serviamo del comando readlink, il quale produce un risultato simile a questo:
$ readlink /sys/class/net/eth0/device/driver/module 
 ../../../../module/e1000
4. Dato che a noi interessa solo il nome del modulo e ci disinteressiamo del resto del risultato ottenuto con il comando readlink, tenendo solo la parte più a destra del risultato. Questo è appunto ciò che il comando basename realizza. Applicandolo direttamente all'intero percorso, questo comando ci ritorna quanto segue:
$ basename ../../../../module/e1000
e1000

Così abbiamo inserito il lungo risultato del symlink, ottenuto da readlink, quale parametro nel programma basemane, permettendo così l'intero processo di essere realizzato in una sola riga.

Ora che abbiamo identificato il nome del modulo, si dovrebbe trovare l'opzione della configurazione del kernel che lo controlla. Si può cercare nei vari menu di configurazione dei dispositivi di rete oppure cercare nel codice sorgente del kernel stesso per essere sicuri di avere l'opzione giusta.

$ cd ~/linux/linux-2.6.17.8
$ find -type f -name Makefile | xargs grep e1000
./drivers/net/Makefile:obj-$(CONFIG_E1000) += e1000/
./drivers/net/e1000/Makefile:obj-$(CONFIG_E1000) += e1000.o
./drivers/net/e1000/Makefile:e1000-objs := e1000_main.o e1000_hw.o e1000_ethtool.o e1000_param.o

Si precisa che "e1000, usato in questo esempio, deve essere sostituito con il nome del modulo che state analizzando.

La cosa che ci interessa nel risultato del precedente comando find sono le righe dove compaia il termine CONFIG_. Questa è l'opzione di configurazione che il kernel deve aver attivato per poter compilare il modulo. Nell'esempio precedente l'opzione di configurazione che c'interessa è pertanto CONFIG_E1000.

Adesso si dispone dell'informazione necessaria per poter configurare il kernel. Si esegue lo strumento menu di configurazione:

$ make menuconfig

Dopodiché si prema il tasto / (slash) (che ha il compito di far partire una ricerca), e si digita l'opzione di configurazione, senza la parte di testo CONFIG_. Questo processo è mostrato nella figura 7-1.

Figura 7-1. Ricerca in menuconfig.

Il sistema di configurazione del kernel vi dirà ora esattamente dove selezionare l'opzione per abilitare questo modulo. Vedi figura 7-2.

Figura 7-2. Risultato della ricerca in menuconfig.

Il primo elemento nella schermata mostra l'opzione che stavate cercando. Le informazioni mostrate dalla schermata vi dicono che, per attivare il modulo E1000 nel kernel, la seguente opzione di configurazione deve essere abilitata:

 Device Drivers
     Network device support
     [*] Network device support
         Ethernet (1000 Mbit)
     [*] Intel(R) PRO/1000 Gigabit Ethernet support

Questo modo di procedere funziona per ogni tipo di dispositivo attivo nel kernel.

Esempio: Un dispositivo USB

Come secondo esempio, esaminiamo ora un convertitore USB-seriale che è presente nel nostro sistema preso ad esempio. Attualmente il convertitore è collegato alla porta /dev/ttyUSB0, pertanto si deve prendere in esame la sezione tty del sysfs.

$ ls /sys/class/tty/ | grep USB
ttyUSB0

Potete ora eseguire una ricerca di questo dispositivo nel sysfs allo scopo di trovare il modulo che lo gestisce, utilizzando la stessa procedura mostrata nella sezione precedente:

$ basename `readlink /sys/class/tty/ttyUSB0/device/driver/module`
pl2303

Dopodiché, per poter individuare l'opzione di configurazione che si deve abilitare, si cerca nell'albero del codice sorgente del kernel:

$ cd ~/linux/linux-2.6.17.8
$ find -type f -name Makefile | xargs grep pl2303
./drivers/usb/serial/Makefile:obj-$(CONFIG_USB_SERIAL_PL2303) += pl2303.o

Si utilizzi lo strumento di configurazione del kernel, come indicato in figura 7-3, per trovare l'opzione adeguata da abilitare relativa al settaggio dell'opzione CONFIG_USB_SERIAL_PL2303.

Figura 7-3. Ricerca di USB_SERIAL_PL2303.

Nel nostro caso il risultato è mostrato nella figura 7-4.

Figura 7-4. Risultato della ricerca di USB_SERIAL_PL2303

Ciò mostra esattamente dove trovare l'opzione USB Profilic 2303 Single Port Serial Driver che è necessaria alla corretta gestione di questo dispositivo.

Riassunto: Alla scoperta del dispositivo

Riassumendo, ecco i vari passaggi che servono per identificare il driver funzionante di un dispositivo ad esso collegato:

1. Trovate la corretta classe di dispositivi in sysfs relativa al dispositivo che ci interessa. I dispositivi di rete sono elencati in /sys/class/net, mentre i dispositivi tty sono elencati in /sys/class/tty. Gli altri vari dispositivi si trovano in altre sotto-directory di /sys/class, a seconda del tipo.
2. Ricercate nell'albero di sysfs il nome del modulo che controlla il dispositivo in oggetto. Lo si trova in /sys/class/class_name/device_name/device/driver/module, la ricerca è agevolata se si utilizzano i comandi readlink e basename.
$ basename `readlink /sys/class/class_name/device_name/device/driver/module`
3. Ricercate nei file Makefile con find e grep le opzioni CONFIG_ che abilitano il modulo
$ find -type f -name Makefile | xargs grep ''module_name''
4. Ricercate l'opzione trovata nel sistema di configurazione del kernel, dopodiché andate dove indicato dal menu per attivare il driver in oggetto.

Lasciamo che il kernel ci dica ciò di cui abbiamo bisogno

Dopo esserci infilati nel sysfs e aver seguito i sui symlinks per ricercare passo passo i nomi dei moduli, presentiamo un semplice script che farà per noi tutto il lavoro in un modo leggermente diverso:

#!/bin/bash
#
# find_all_modules.sh
#
for i in `find /sys/ -name modalias -exec cat {} \;`; do
    /sbin/modprobe --config /dev/null --show-depends $1 ;
done | rev | cut -f i -d '/' | rev | sort -u

Si può scaricare un file d'esempio, contenente questo script, dal sito web del libro, riportato nella sezione Come contattarci che si trova nella prefazione.

Questo script cerca nel sysfs tutti file chiamati modalias. Il file modalias contiene gli alias dei moduli e comunica al comando modprobe quali moduli debbano essere caricati per ogni dispositivo. L'alias del modulo è composto da una combinazione di: produttore del dispositivo, ID, tipo di classe ed altri identificativi univoci per il tipo di dispositivo in questione. Tutti i moduli del driver del kernel hanno una lista interna dei dispositivi che supportano, che è generata automaticamente dalla lista dei dispositivi che il driver comunica al kernel di poter supportare. Il comando modprobe ricerca tutti i dispositivi nella lista di tutti i driver e cerca di trovare una corrispondenza confrontando l'alias. Se trova una corrispondenza, allora provvede al caricamento del modulo (questa procedura è la stessa seguita dal caricamento automatico dei driver in Linux).

Lo script prevede l'arresto del programma modprobe prima di caricare il modulo, e visualizza a schermo solo le azioni che eseguirebbe. Questo ci dà una lista di tutti i moduli che sono necessari al controllo di tutti i dispositivi del sistema. Eseguendo una piccola pulizia della lista, ordinandola e selezionando i campi adeguati, otteniamo il seguente risultato:

$ find_all_modules.sh
8139cp.ko
8139too.koo
ehci-hcd.ko
fimware_vlass.ko
i2c-i801.ko
ieee80211.ko
ieee80211_crypt.ko
ipw2200.ko
mii.ko
mmc_core.ko
pcmcia_core.ko
rsrc_nonstatic.ko
sdhci.ko
snd-hda-codec.ko
snd-hda-intel.ko
snd-page-alloc.ko
snd-pmc.ko
snd-timer.ko
snd.ko
soundcore.ko
uhci-hcd.ko
usbcore.ko
yenta_socket.ko

Questa è la lista di tutti i moduli che sono necessari alla gestione dell'hardware della macchina.

Lo script mostrerà probabilmente alcuni messaggi di errore che possono essere del tipo:

FATAL: Module pci:v00008086d00002592sv000010CFsd000012E0bc03sc00i00 not found.
FATAL: Module serio:ty01pr00id00ex00 not found.

Questo ci dice che non si trova un modulo che gestisce quel dispositivo. Questo non deve comunque interessare più di tanto, poiché alcuni dispositivi non hanno driver nel kernel che lavorino per loro.

Determinare il modulo corretto partendo da zero

Talvolta non c'è la possibilità di avere un kernel funzionante su una macchina in modo da determinare quali moduli del kernel siano necessari per gestire l'hardware. Oppure si è aggiunto del nuovo hardware al sistema e bisogna trovare le opzioni della configurazione necessarie a farlo funzionare correttamente. Questa sezione illustrerà come determinare le opzioni di configurazione necessarie ad far funzionare l'hardware.

Il modo più semplice per capire quale driver controlla un nuovo dispositivo è quello di compilare come moduli tutti i driver di quel tipo disponibili nei sorgenti del kernel, e lasciare che il processo di avvio tramite udev associ il driver al dispositivo. Una volta fatto ciò, si dovrebbe essere in grado di risalire al driver necessario seguendo i passi descritti precedentemente, ed infine ricompilare il kernel abilitando il solo driver necessario.

Dispositivi PCI

Dispositivi USB

Root Filesystem

Controller di Disco

Un aiuto dallo script


This is an indipendent translation of the book Linux Kernel in a Nutshell by Greg Kroah-Hartman. This translation (like the original work) is available under the terms of Creative Commons Attribution-ShareAlike 2.5.