LKN: Personalizzare un Kernel: differenze tra le versioni

Da Guide@Debianizzati.Org.
Vai alla navigazione Vai alla ricerca
Nessun oggetto della modifica
mNessun oggetto della modifica
 
(55 versioni intermedie di 9 utenti non mostrate)
Riga 1: Riga 1:
{{Debianized}}
{{LKN}}


==Introduzione==
Uno dei punti più delicati e difficili nella compilazione della propria versione del kernel Linux è quello di determinare esattamente quali driver e quali opzioni di configurazione sono richiesti per il corretto funzionamento della macchina su cui sarà eseguito.
In Debian, il kernel Linux pu� essere ricompilato con il metodo standard (valido con tutte le distribuzioni, e quindi anche con Debian) oppure nel cosiddetto ''Debian-way'' (traduzione: ''metodo Debian'' o ''alla Debian'').
Questo capitolo guiderà il lettore attraverso questo processo di ricerca e selezione dei driver corretti.


Questa guida illustrer� il metodo Debian di compilare il kernel Linux. Questo metodo consiste nel creare un pacchetto Debian del kernel compilato per una sua facile installazione/disinstallazione.
==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.


==Installazione Pacchetti==
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 le opzioni di configurazione del kernel necessarie al suo corretto funzionamento su quell'hardware.


Avremo innanzitutto bisogno di alcuni pacchetti di base per compilare e pacchettizzare un kernel:
===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 <code>/usr/src/linux/</code>.


{{Box|Nota per Debian (NdT)|In debian il file di configurazione di ogni kernel installato si trova in <code>/boot/</code> ed ha come nome <code>config-''versione''</code>.}}
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 <code>/proc</code>. Per verificare se questo è il vostro caso, digitate:
<pre>
<pre>
# apt-get install debhelper modutils kernel-package libncurses5-dev fakeroot
$ ls /proc/config.gz
/proc/config.gz
</pre>
</pre>
 
Se il file ''/proc/config.gz'' è presente, allora copiatelo nella directory del sorgente kernel ed estraetelo:
Adesso installiamo i sorgenti veri e propri del kernel. Useremo i sorgenti debian che hanno tutte le patch specifiche di debian. Nel seguito prenderemo come esempio la versione 2.6.8 del kernel, sostituitela con qualsiasi altra versione vogliate usare.
 
<pre>
<pre>
# apt-get install kernel-source-2.6.8
$ cp /proc/config.gz -/linux/
$ cd -/linux
$ gzip -dv config.gz
config.gz:      74.9% - - replaced with config
</pre>
</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]].


{{Box|Nota|Dalla versione 2.6.12 in poi del kernel di linux, i pacchetti sorgenti e binari si chiamano rispettivamente <tt>linux-source-x.x.x</tt> e <tt>linux-image-x.x.x</tt> (invece di <tt>kernel-source-x.x.x</tt> e
Usando questo file di configurazione si dovrebbe ottenere sempre un file immagine del kernel (un ''kernel ricompilato'', NdT) funzionante sulla propria macchina.
<tt>kernel-image.x.x.x</tt>). Questo perch� in Debian sono presenti anche altri kernel diversi da linux, come hurd o freebsd. }}
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 potrebbero essere parti del sistema che richiedono l'abilitazione di certe opzioni.


Per ricompilare il kernel non � necessario essere root, anzi � sconsigliato. In debian, per policy, tutti i sorgenti contenuti in <tt>/usr/src</tt> (almeno quelli installati dai pacchetti debian) hanno come proprietario <tt>root</tt> e come gruppo proprietario <tt>src</tt>. Gli utenti del gruppo <tt>src</tt> hanno inoltre diritto di scrittura in <tt>/usr/src/*</tt>. Baster� dunque aggiungere al gruppo <tt>'''src'''</tt> l'utente che si vuole usare per la compilazione, con i seguenti comandi:
===Determinare quali moduli sono 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 e permettere la compilazione di tutti o parte dei driver nel kernel stesso (compilando ''staticamente'' invece che come moduli NdT), riducendo un po' la memoria utilizzata e, in alcune architetture, creando un kernel che sarà eseguito più velocemente. Per escludere i driver dal kernel è necessario 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.


<pre>
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.
# adduser nome_vostro_utente src
</pre>


{{Box|Nota|Ricordate di non usare l'utente root per ricompilare il kernel (e neanche per scompattarlo) altrimenti tutti i file che verranno creati apparterranno a <tt>root:root</tt>. Se a questo punto si cercher� di compilare dall'utente normale si avranno problemi di permessi e per risolverli dovrete dare un:
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.
# chown -R root:src /usr/src/
Se, inoltre, il gruppo <tt>src</tt> non ha pi� i diritti di scrittura dovranno anch'essi essere ripristinati con:
# chmod -R g+w /usr/src/*
}}


== Configurazione del kernel ==
Inoltre, la struttura interna del file di sistema ''sysfs'' subisce modifiche, a causa sia della riorganizzazione dei driver sia dei ripensamenti degli sviluppatori del kernel su come presentare al meglio 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. Comunque le informazioni saranno ancora tutte lì, solo spostate un po'.


=== Passi preliminari ===
====Esempio: Come determinare il driver di rete====
Entriamo ora nella directory dei sorgenti del kernel:
Uno dei dispositivi (''device'' NdT) 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.


In primo luogo, partendo dal nome dell'interfaccia di rete si deve risalire al device PCI che la sta controllando. I nomi delle interfacce di rete si ottengono come segue:
<pre>
<pre>
$ cd /usr/src
$ ls /sys/class/net/
eth0  eth1  eth2  lo
</pre>
</pre>
La directory ''lo'' rappresenta solo il dispositivo di rete loopback, che non è connesso e nessun reale dispositivo di rete. Invece si deve prestare attenzione alle directory ''eth0'', ''eth1'' e ''eth2'', dato che si riferiscono a dispositivi realmente esistenti.


Troveremo in questa directory (avendoli installati precedentemente) i sorgenti del kernel in un archivio tar.bz2:
Per ottenere maggiori informazioni su questi dispositivi, si utilizza il comando ''ifconfig'':
 
<pre>
<pre>
$ ls
$ /sbin/ifconfig -a
...
eth0 Link  encap:Ethernet  HWaddr 00:12:3F:65:7D:C2
kernel-source-2.6.8.tar.bz2
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>
</pre>
 
Da questo listato si può riconoscere nel dispositivo di rete <code>eth0</code> quello attivo e funzionante, come si può vedere dalle righe:
Decomprimiamo il kernel:
 
<pre>
<pre>
$ tar xvjf kernel-source-2.6.8.tar.bz2
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>
</pre>
Questo risultato mostra che tale dispositivo è di tipo Ethernet e gli è stato assegnato un indirizzo IP valido (<code>inet</code>).


A fine decompressione avremo una directory kernel-source-2.6.8, creiamo un link simbolico linux che punta ai sorgenti del kernel:
Ora, dopo che abbiamo individuato il dispositivo <code>eth0</code> 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 di seguire i diversi link nel filesystem sysfs, eseguibile con un comando di una sola riga:
 
<pre>
<pre>
$ ln -s /usr/src/kernel-source-2.6.8 linux
$ basename `readlink /sys/class/net/eth0/device/driver/module`
e1000
</pre>
</pre>


Non � necessario creare questo link, ma � una usuale convenzione farlo anche perch� risulta comodo per entrare nella directory dei sorgenti del kernel.
Il risultato mostra che il modulo chiamato <code>e1000</code> controlla il dispositivo di rete <code>eth0</code>. Il comando ''basename'' appena mostrato racchiude in un'unica riga i seguenti passaggi:
 
# Segue il percorso a cui punta il symlink ''/sys/class/net/eth0/device'', contenuto all'interno della directory ''/sys/device/'', che contiene le informazioni relative al dispositivo che controlla ''eth0''. Notare che nelle versioni più recenti del kernel la directory ''/sys/class/net/eth0'' potrebbe essere anch'essa un symlink.  
Ora spostiamoci della directory e puliamo i sorgenti del kernel:
# 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.
# 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 <code>module</code>. Noi cerchiamo il file 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>
# Dato che a noi interessa solo il nome del modulo, vogliamo scartare il 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, ritorna quanto segue:<pre>$ basename ../../../../module/e1000</pre><pre>e1000</pre>
Così abbiamo inserito il lungo percorso ottenuto seguendo il symlink, ottenuto grazie a ''readlink'', quale parametro del programma ''basename'', permettendo così l'intero processo di essere realizzato in una sola riga.


Ora che abbiamo il nome del modulo, si deve trovare l'opzione di 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:
<pre>
<pre>
$ cd linux
$ cd ~/linux/linux-2.6.17.8
$ make-kpkg clean
$ 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>
</pre>


Questo passaggio � inutile se � la prima volta che compilate il kernel, ma dalla seconda volta in poi diviene necessario per eliminare i file generati dalle precedenti compilazioni che potrebbero creare conflitti.
Si ricordi di sostituire il nome '''e1000''', usato in questo esempio, con quello del modulo che avete intenzione di trovare.


Ora, se avete installato un kernel precompilato che abbia la stessa versione del kernel che volete ricompilare potreste usare il suo file di configurazione come base di partenza per configurare il vostro kernel. A tal scopo basta copiare il file di configurazione che st� in <tt>/boot</tt> (i file di configurazione dei kernel installati hanno come nome <code>config</code> seguito dalla versione del kernel) nella directory dei sorgenti:
La cosa importante da cercare nel risultato del precedente comando ''find'' sono le righe dove compare il termine <code>'''CONFIG_'''</code>. Questa è l'opzione di configurazione che il kernel deve aver attivato per poter compilare il modulo. Nell'esempio precedente l'opzione di configurazione che ci interessa è pertanto <code>CONFIG_E1000</code>.


<pre>
Adesso si dispone dell'informazione necessaria per poter configurare il kernel. Si esegue lo strumento di configurazione a menù:
$ cp /boot/config-2.6.8 .config
<pre>$ make menuconfig</pre>
</pre>
 
Dopodiché si prema il tasto '''<code>/</code>''' (slash) (che ha il compito di far partire una ricerca), e si digiti l'opzione di configurazione, senza la parte di testo <code>CONFIG_</code>. Questo processo è mostrato nella [[:Immagine:Config_search.png|figura 7-1]].


C'� chi arriva anche a installare un kernel precompilato per usare semplicemente il suo file di configurazione. Se avete banda da sprecare � possibile farlo. Tuttavia si pu� benissimo partire da zero senza copiare nessun file di configurazione.
[[Immagine:Config_search.png|center|frame|''Figura 7-1. Ricerca in menuconfig.'']]


=== Configurazione: <code>make menuconfig</code> ===
Il sistema di configurazione del kernel dirà ora esattamente dove selezionare l'opzione per abilitare questo modulo. Si veda la [[:Immagine:Config_search_found.png|figura 7-2]].


A questo punto, per configurare il nostro kernel, non ci resta che lanciare il comando:
[[Immagine:Config_search_found.png|center|frame|''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 <code>E1000</code> nel kernel, la seguente opzione di configurazione deve essere abilitata:
<pre>
<pre>
$ make menuconfig
Device Drivers
    Network device support
    [*] Network device support
        Ethernet (1000 Mbit)
    [*] Intel(R) PRO/1000 Gigabit Ethernet support
</pre>
</pre>
Questo modo di procedere funziona per ogni tipo di dispositivo attivo nel kernel.


Vi apparir� un'interfaccia testuale dalla quale sar� possibile configurare le opzioni del kernel. ''Questo � il passaggio pi� delicato, nonch� il pi� lungo e difficile''.  
====Esempio: Un dispositivo USB====
Come secondo esempio, esaminiamo ora un convertitore USB-seriale che è presente nel sistema. 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>
Si può 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:
<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>
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 <code>CONFIG_USB_SERIAL_PL2303</code>.


Se dovete configurare un kernel per la prima volta prendetevi almeno un'ora di tempo ed iniziate con calma, leggendo tutte le pagine dell'help in linea. Uno dei vantaggi di un kernel ricompilato � la possibilit� di ottenere un kernel estremamente piccolo e leggero proprio perch� viene compilato il supporto per le sole periferiche e i soli filesystem effettivamente usati. In questo modo si ha un kernel piccolo e pochi moduli. Un kernel di questo tipo impiega anche molto meno tempo ad essere compilato. Per fare un esempio potrebbe impiegare sui 10 min. su in athlon 1000, quando un kernel debian ufficiale impiegherebbe sicuramente pi� di un'ora sulla stessa macchina. In definitiva, compilando un kernel snello, sar� possibile anche fare pi� prove ed ottimizzarlo quindi al meglio.  
[[Immagine:Config_search_pl2303.png|center|frame|''Figura 7-3. Ricerca di USB_SERIAL_PL2303''.]]


Per trovare quali moduli sono richiesti dal vostro hardware potete usare il comando '''lspci''' o meglio '''lspci -v'''. Inoltre risulta utilissimo consultare il database dei driver di Linux a [http://kmuto.jp/debian/hcl/ questo indirizzo]: inserendo semplicemente l'output di <code>lspci -n</code>, otterrete l'elenco dei moduli da compilare
Nel nostro caso il risultato è mostrato nella [[:Immagine:Config_search_pl2303_found.png|figura 7-4]].


Per approfondire la configurazione del kernel:
[[Immagine:Config_search_pl2303_found.png|center|frame|''Figura 7-4. Risultato della ricerca di USB_SERIAL_PL2303'']]


* [[Esempio configurazione kernel]] nel nostro wiki, per un semplice esempio.
Ciò mostra esattamente dove trovare l'opzione <code>USB Profilic 2303 Single Port Serial Driver</code>, che è necessaria alla corretta gestione di questo dispositivo.
* [http://a2.pluto.it/a266.htm#almltitle484 Elementi della configurazione] per una descrizione pi� dettagliata delle varie voci. Questo � un capitolo della monumentale opera [http://a2.pluto.it/appunti_di_informatica_libera.htm Appunti di Informatica Libera], per la quale tutti noi siamo grati all'autore '''Daniele Giacomini'''.
* [http://kernel.xc.net/ Linux Kernel Configuration Archive]: potrete cercare le varie opzioni di configurazione di ogni versione del kernel.


In bocca al lupo con la configurazione ;-).
====Sommario della scoperta del dispositivo====
Riassumendo, ecco i vari passaggi che servono per identificare il driver funzionante di un dispositivo ad esso collegato:
# Trovare 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.
# Seguire i link simboilci nell'albero di ''sysfs'' per trovare il nome del modulo che controlla il dispositivo in oggetto. Lo si trova seguendo il symlink ''/sys/class/class_name/device_name/device/driver/module'', e può essere visualizzato combinando i comandi ''readlink'' e ''basename'':<pre>$ basename `readlink /sys/class/class_name/device_name/device/driver/module`</pre>
# Ricercare nei file Makefile con ''find'' e ''grep'' le opzioni <code>CONFIG_</code> usate per compilare il modulo: <pre>$ find -type f -name Makefile | xargs grep module_name</pre>
# Ricercare l'opzione trovata nel sistema di configurazione del kernel, dopodiché andare nella posizione del menù che specifica di attivare quel driver per compilarlo.


Una volta finita la configurazione, uscite e salvate i cambiamenti. A questo punto il file <tt>/usr/src/linux/.config</tt> conterr� la nostra configurazione del kernel.
====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:
<pre>
#!/bin/bash
#
# find_all_modules.sh
#
for i in `find /sys/ -name modalias -exec cat {} \;`; do
    /sbin/modprobe --config /dev/null --show-depends $i ;
done | rev | cut -f1 -d '/' | rev | sort -u
</pre>


{{Box|Nota|Se avete gi� ricompilato il vostro kernel e volete passare ad una versione pi� aggiornata, ma non troppo diversa (ad esempio: 2.6.8 --> 2.6.10), non conviene rifare tutta la configurazione da capo. D'altro canto non � neanche possibile usare il vecchio file di configurazione dato che nel nuovo kernel ci saranno voci in pi� e o in meno e sarebbe improponibile cercarle ad una ad una.
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 (ossia [http://www.oreilly.com/catalog/9780596100797/ qui] NdT).


Basta allora copiare il vecchio file di configurazione nella directory dei sorgenti del nuovo kernel e lanciare il comando:
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).


$ make oldconfig
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,
otteniamo il seguente risultato:
<pre>
$ 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>


in questo modo verranno fatte delle domande su come configurare ''le sole nuove voci'' presenti nel kernel. Se i due kernel sono troppo diversi questo metodo non conviene pi� dato che bisogna rispondere ad uno ad uno a tutte le domande sulle voci diverse. Sicuramente non conviene usarlo per il passaggio 2.4 --> 2.6.<br>
Questa è la lista di tutti i moduli che sono necessari alla gestione dell'hardware della macchina.
Un file config del vostro attuale kernel pu� essere trovato in <tt>/boot</tt> sotto il nome di <tt>config-2.x.x</tt>.}}


=== Alternative a <code>make menuconfig</code> ===
Lo script mostrerà probabilmente alcuni messaggi di errore che possono essere del tipo:
<pre>
FATAL: Module pci:v00008086d00002592sv000010CFsd000012E0bc03sc00i00 not found.
FATAL: Module serio:ty01pr00id00ex00 not found.
</pre>


Per completezza segnalo le altre interfacce grafiche che � possibile usare per configurare il kernel al posto di <code>make menuconfig</code>.
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.


;<code>make xconfig</code>: per usare una interfaccia grafica '''qt''' per la configurazione.
==Determinare il modulo corretto partendo da zero==
;<code>make gconfig</code>: per usare una interfaccia grafica '''gtk''' per la configurazione.
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 a far funzionare l'hardware.


Questi frontend non aggiungono niente di nuovo e sono pertanto funzionalmente equivalenti tra di loro. Per usarli sono per� necessarie le librerie di sviluppo, rispettivamente, di ''qt'' e ''gtk''.
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, e infine ricompilare il kernel abilitando il solo driver necessario.


== Compilazione del kernel ==
Se invece non si vogliono compilare tutti i driver, o questo meccanismo non funziona per qualche motivo, sarà necessario un pò più di lavoro per individuare il driver necessario. I passi successivi sono complessi e richiedono talvolta di dover cercare nei sorgenti del kernel. Non abbiate timore di ciò, sarà solo di aiuto a comprendere meglio l'hardware ed i sorgenti del kernel.
Ora � venuto il momento di cominciare la compilazione, a tal scopo useremo make-kpkg. Vediamo come utilizzare velocemente questo tool per compilare il nostro kernel personalizzato:


<pre>
I passi necessari per trovare il driver corrispondente di un dispositivo cambiano a seconda del tipo di dispositivo in questione. In questo capitolo discuteremo le due tipologie di dispositivi più comuni: PCI e USB; ma i metodi qui descritti saranno validi anche per altri tipi di dispositivi.
$ fakeroot make-kpkg --append-to-version -nomepersonalizzato --revision=1 kernel_image
</pre>


Questo comando compiler� il nostro kernel e lo inserir� in un pacchetto debian in <tt>/usr/src</tt>. Il comando '''<tt>fakeroot</tt>''' viene usato semplicemente per simulare un ambiente di root per l'utente normale.
&Egrave; inoltre molto importante per il kernel di essere in grado di trovare tutti i filesystem presenti nel sistema, di cui il più importante è quello radice (''root'' NdT). Approfondiremop questo aspetto successivamente in [[LKN: Personalizzare un Kernel#Root filesystem|"Root filesystem"]].


Diamo uno sguardo alle opzioni usate:
===Dispositivi PCI===
I dispositivi PCI si distinguono per ''vendor ID'' e ''device ID''; ogni combinazione di  ''vendor ID'' e di ''device ID'' può richiedere un driver unico. Questa è la base per la ricerca mostrata in questa sezione.


; <tt>--append-to-version</tt> : serve ad aggiungere un nome personalizzato al pacchetto che verr� aggiunto dopo il numero di versione, che in questo caso diventer� ''2.6.8-nomepersonalizzato''.
Per questo esempio useremo un scheda di rete PCI che supporremo non funzionante con l'attuare versione del kernele in esecuzione. Questo esempio sarà diverso dalla vostra situazione, con differenti device PCI e valori ID del bus, ma i passi salienti dovrebbero essere rilevanti per ogni tipo di dispositivo PCI per il quale vogliate trovare un driver funzionante.


; <tt>--revision</tt> : permette di impostare il numero di revisione del pacchetto, normalmente viene indicato con un numero intero.  
In primo luogo troviamo nel sistema il dispositivo PCI che non sta funzionando. Per ottenere una lista di tutti i dispositivi PCI usiamo il programma <code>lspci</code>. Poiché a noi interessano solo dispositivi PCI ethernet restringeremo la nostra ricerca filtrado tra i risultati solo quelli che conterranno la parola ''ethernet'' (ignorando se i caratteri sono minuscoli o maiuscoli):
<pre>
$ /usr/sbin/lspci | grep -i ethernet
06:04.0 Ethernet controller: Realtek Semiconductor Co., Ltd. RTL-8139/
8139C/8139C+ (rev 10)
</pre>


; <tt>kernel_image</tt> : dice a make-kpkg di compilare l'immagine del kernel creare il pacchetto debian.
Questo è il dispositivo che vorremmo fare funzionare.<sup>*</sup>


Se ad esempio compileremo per la seconda volta lo stesso kernel, per fare solo delle modifiche minori, pu� essere utile usare lo stesso nome per --append-to-version ed usare un numero di revisione maggiore. In questo modo quando installerete il pacchetto del kernel ricompilato questo sostituir� il pacchetto precedente. Al contrario se ricompilate un secondo kernel cambiando la stringa da appendere alla versione, il pacchetto del nuovo kernel conviver� tranquillamente col precedente.
<small>Nota ('''<sup>*</sup>'''): potreste anche provare a cercare in tutta la configurazione del kernel un dispositivo che corrisponde alla stringa mostrata sopra (un dispositivo della Realtek Semiconductors con nome prodotto RTL-8139/8139C/8139C+), ma questo non funziona sempre. Per questo motivo useremo la via lunga in questo capitolo.</small>


In realt� il comando '''make-kpkg''' accetta molti ulteriori parametri (elencher� solo i pi� importanti per gli altri leggete l'amichevole pagina di manuale aka read the friendly manual):
::[[Immagine:Warning_65x68.jpg|left]] Quasi tutte le distribuzioni mettono il programma <code>lspci</code> in <code>/usr/sbin/</code>, ma alcune lo mettono in altri percorsi. Per trovare in quale posizione è stato messo digitare:


; <tt>--initrd</tt> : da usare se state compilando un kernel che utilizza le immagini initrd.img (''vedi [[Debian_Kernel_Howto#Bisogna_usare_l.27initrd_oppure_no.3F|FAQ: Bisogna usare l'initrd_oppure no?]]'').
::<code>$ '''which lspci'''</code>
; <tt>--added-modules foo</tt> : compila dei sorgenti esterni (presenti in <tt>/usr/src/modules</tt>) insieme al kernel, potete mettere pi� nomi separati da virgole.
::<code>/usr/sbin/lspci</code>
; <tt>--added-patches foo</tt> : aggiunge delle patch al kernel, le patch possono essere molteplici separate da virgole.
; <tt>--config</tt> : sceglie quale frontend usare per configurare il kernel (config, menuconfig, xconfig, gconfig).
; <tt>--zimage</tt> : crea una zImage per il kernel.
; <tt>--bzImage</tt> : crea una bzImage per il kernel.
; <tt>--mkimage</tt> : qui potete passare dei parametri a <code>mkinitrd</code>, ad esempio se volete creare una immagine rom: <code>genromfs -d %s -f %s</code>.
; <tt>--rootcmd foo</tt> : per passare un comando a make-kpkg ad esempio fakeroot o sudo
; <tt>CONCURRENCY_LEVEL</tt> : questa variabile e' l'omonimo di -j per make, per usarla vi basta mettere il numero intero che desiderate usare (''$ CONCURRENCY_LEVEL=4 make-kpkg --blabla ecc.ecc...'' )


Come ultimo parametro dovremo mettere un'azione da compiere, vediamo le principali:
Se state usando una distribuzione che mette ''lspci'' in un'altra posizione, usate il percorso corretto per la vostra installazione ogni volta che verrà usato ''lspci''.


; <tt>clean</tt> : pulisce i sorgenti.
I primi pochi spezzoni dell'output di ''lspci'' mostrano l'ID del bus PCI per questo dispositivo, <code>06:04.0</code>. Questo è il valore che useremo quando cercheremo in ''sysfs'' per trovare più informazioni riguardo questo dispositivo.
; <tt>kernel_headers</tt> : questo genera un pacchetto con gli headers del kernel.
; <tt>binary</tt> : questo genera un nuovo pacchetto deb con i sorgenti, uno con gli header, uno con la documentazione e uno con l' immagine del kernel.
; <tt>buildpackage</tt> : pulisce i sorgenti e avvia "binary" (vedere sopra).
; <tt>build</tt> : compila solo l'immagine del kernel.
; <tt>modules</tt> :compila tutti moduli esterni sotto <tt>/usr/src/modules</tt> e genera un file .diff e un pacchetto sorgente.
; <tt>modules_config</tt> : permette di configurare i moduli esterni residenti in <tt>/usr/src/modules</tt> prima di compilarli.
; <tt>modules_image</tt> : crea i pacchetti deb dei moduli esterni residenti in <tt>/usr/src/modules</tt> senza il file .diff e senza creare un'altro pacchetto sorgente.
; <tt>modules_clean</tt> : pulisce i sorgenti dei moduli esterni presenti in <tt>/usr/src/modules</tt>.
; <tt>debian</tt> : questo crea la directory <tt>./debian</tt> utile per compilare i kernel vanilla e patcharli alla maniera debian.
 
==Installazione nuovo kernel==
Una volta finito torneremo alla riga di comando e ci sposteremo nella directory precedente (/usr/src/) dove troveremo il pacchetto .deb del kernel appena compilato:


Andiamo in ''sysfs'' dove tutti i dispositivi PCI sono elencati, e guardiamo i loro nomi:
<pre>
<pre>
$ cd ..
$ cd /sys/bus/pci/devices/
$ ls
$ ls
...
0000:00:00.0 0000:00:1d.0  0000:00:1e.0 0000:00:1f.3 0000:06:03.3
kernel-image-2.6.8-nomepersonalizzato-386_1.Custom_i386.deb
0000:00:02.0 0000:00:1d.1  0000:00:1f.0 0000:06:03.0 0000:06:03.4
...
0000:00:02.1 0000:00:1d.2 0000:00:1f.1 0000:06:03.1 0000:06:04.0
0000:00:1b.0 0000:00:1d.7  0000:00:1f.2 0000:06:03.2 0000:06:05.0
</pre>
</pre>


Adesso possiamo installare il pacchetto con il nostro nuovo kernel ricompilato. Diventiamo quindi root con '''su''', e digitiamo:
Il kernel numera i dispositivi PCI con un <code>0000:</code> iniziale che non viene mostrato nell'output di ''lspci''.<sup>+</sup> Dunque, aggiungiamo un <code>0000:</code> al numero datoci da ''lspci'' e entriamo in quella directory:
<pre>
<pre>
# dpkg -i kernel-image-2.6.8-nomepersonalizzato-386_1.Custom_i386.deb
$ cd 0000:06:04.0
</pre>
</pre>


Se abbiamo lilo dovremo configurare lilo.conf aggiungendo le righe relative al kernel. Ricordatevi che, con lilo, per rendere effettive le modifiche bisogna aggiornare il [[MBR]] (Master Boot Record) con il comando:
<small>Nota ('''<sup>+</sup>'''): alcuni processori 64-bit mostreranno il "leading bus number" per i dispositivi PCI nell'output di lspci, ma per la maggiorparte delle comuni macchine Linux, non verrà mostrato di default.</small>


In questa directory vogliamo conoscere il valori dei file ''vendor'' e ''device''.
<pre>
<pre>
# lilo -v
$ cat vendor
0x10ec
 
$ cat device
0x8139
</pre>
</pre>


Se abbiamo grub, invece, non ci resta altro che riavviare :D. Tuttavia per approfondire le personalizzazioni che � possibile fare su grub, potete leggere l'apposita sezione della [[Guida a Grub]]:
Questi sono il ''vendor ID'' ed il ''device ID'' per questo dispositivo PCI. Il kernel usa questi valori per associare correttamente un driver ad un dispositivo. I driver PCI dicono al kernel quale vendor e device ID supporteranno così che il kernel sappia come collegare il driver al dispositivo corretto. Scriveteli da qualche parte, dato che ci riferiremo a loro più tardi.


* [[Guida_a_Grub#Usare_update-grub|Guida a Grub: Usare update-grub]]
Ora che sappiamo il ''vendor ID'' e il ''device ID'' per questo dipositivo PCI, abbiamo bisogno di trovare i driver del kernel corretto che riporta di supportare questo dispositivo. Tornate indietro alla directory di source del kernel:
<pre>
$ cd ~/linux/linux-2.6.17.8/
</pre>
Il posto più comune per gli ID di tipo PCI nell'albero sorgente del kernel è ''include/linux/pci_ids.h''. Cercate in quel file il vostro ''vendor id'':
<pre>
$ grep -i 0x10ec include/linux/pci_ids.h
#define PCI_VENDOR_ID_REALTEK                  0x10ec
</pre>
Il valore qui definito, <code>PCI_VENDOR_ID_REALTEK</code>, è ciò che probabilmente sarà usato in qualsiasi kernel driver che riporta di supportare i dispositivi di quel produttore.


==Installare e gestire i moduli==
Per essere sicuri, si cerchi il ''device ID'' anche in questo file , dato che è a volte descritto là:
<pre>
$ grep -i 0x8139 include/linux/pci_ids.h
#define PCI_DEVICE_ID_REALTEK_8139        0x8139
</pre>
Questa definizione sarà utile più avanti.


Per compilare e creare automaticamente pacchetti .deb per moduli non presenti nei sorgenti del kernel, Debian fornisce un comodo strumento: [[Pagina di manuale di module-assistant|module-assistant]]. Per un uso interattivo baster� lanciarlo da root per installare i pacchetti, scaricare i sorgenti del modulo che interessa, compilarlo e creare un pacchetto debian.
Ora si cerchi nei file sorgenti dei driver relativi a questo produttore:
<pre>
$ grep -Rl PCI_VENDOR_ID_REALTEK *
include/linux/pci_ids.h
drivers/net/r8169.c
drivers/net/8139too.c
drivers/net/8139cp.c
</pre>


Per scegliere invece quali moduli fare partire all'avvio ci sono diverse strade.
Non serve guardare nel primo file riportato qui, ''pci_ids.h'', dato che è dove è stata trovata la definizione originale. Ma i file ''r8139.c'', ''8139too.c'', e ''8169cp.c'' nella sottodirectory ''drivers/net/'' dovrebbero essere esaminati più da vicino.


# Se si usa l'hotplug, questi dovrebbe caricare automaticamente al boot tutti i moduli necessari. Per evitare il caricamento di certi moduli che possono creare conflitti basta inserili in '''/etc/hotplug/blacklist'''.
Si apra uno di questi file in un editor, cercando <code>PCI_VENDOR_ID_REALTEK</code>. Nel file ''drivers/net/r8169.c'', si vede nella seguente sezione di codice:
# Se non si usa l'hotplug bisogna specificare manualmente quali moduli caricare all'avvio. Per far ci� baster� inserire i nomi dei moduli da caricare in '''/etc/modules''', uno per riga. Se non vi va di editare un file di testo (o non ricordate esattamente i nomi dei moduli) potrete usare '''modconf''' che permette di scegliere interattivamente quali moduli caricare all'avvio.
<pre>
static struct pci_device_id rtl8169_pci_tbl[] = {
      { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8169), },
      { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8129), },
      { PCI_DEVICE(PCI_VENDOR_ID_DLINK,      0x4300), },
      { PCI_DEVICE(0x16ec,                  0x0116), },
      { PCI_VENDOR_ID_LINKSYS,              0x1032, PCI_ANY_ID, 0x0024, },
      {0,},
};
</pre>


==FAQ==
Tutti i driver PCI contengono una lista di dispositivi differenti che supportano. Questa lista è contenuta in una struttura di valori <code>struct pci_device_id</code>, come questa. Questo è ciò che dobbiamo guardare per determinare se il nostro dispositivo è supportato da questo driver. Il valore del vendor corrisponde qui, ma il secondo valore dopo il vendor è il valore del dispositivo. Il nostro dispositivo ha il valore 0x8139, mentre questo driver supporta i valori di dispositivi per 0x8169 e 0x8129 con il ''vendor ID'' di <code>PCI_VENDOR_ID_REALTEK</code>. Per cui questo driver non supporterà il nostro dispositivo.
===Per aggiungere un modulo devo ricompilare tutto il kernel?===
Dipende.


Se il modulo fa parte del kernel debian (cio� il suo sorgente � contenuto nel pacchetto <tt>kernel-source</tt> del kernel) allora bisogna ricompilare il kernel. Tenete presente, tuttavia, che i kernel binari debian includono gi� la maggior parte dei moduli presenti nei sorgenti del kernel. Per caricarli basta usare:
Spostandoci al prossimo file, ''drivers/net/8139too.c'', si può trovare la stringa <code>PCI_VENDOR_ID_REALTEK</code> nel seguente pezzo di codice:
<pre>
if (pdev->vendor == PCI_VENDOR_ID_REALTEK &&
pdev->device == PCI_DEVICE_ID_REALTEK_8139 && pci_rev >= 0x20) {
  dev_info(&pdev->dev,"This (id %04x:%04x rev %02x) is an enhanced 8139C+ chip\n",
      pdev->vendor, pdev->device, pci_rev);
  dev_info(&pdev->dev, "Use the \"8139cp\" driver for improved performance and stability.\n");
}
</pre>


  # modprobe ''nomemodulo''
L'utilizzo del valore di <code>PCI_VENDOR_ID_REALTEK</code> qui corrisponde anche con il codice che controlla se il dispositivo PCI ID corrisponde al valore <code>PCI_DEVICE_ID_REALTEK_8139</code>. Se corrisponde, il driver stamperà un messaggio che dice: "Use the 8139cp for improved performance and stability." Forse dovremmo guardare a quel driver di seguito. Anche se non avessimo tale visibile consiglio, il driver ''8139too.c'' non ha la coppia vendor e device ID che stiamo cercando in una variabile del tipo <code>struct pci_device_id</code>, ciò ci dice che non supporta il nostro dispositivo.


Se il sorgente del modulo � invece pacchettizzato singolarmente (il nome di questi pacchetti comincia per <tt>module-source</tt>) '''non � necessario''' ricompilare il kernel.
Infine, guardate nel file ''drivers/net/8139cp.c''. Usa la definizione <code>PCI_VENDOR_ID_REALTEK</code> nel seguente sezione di codice:
Debian ci fornisce la comoda utility '''module-assistant''' che permette di scaricare, compilare e pacchettizzare un modulo del kernel. Basta lanciare il comando
<pre>
static struct pci_device_id cp_pci_tbl[] = {
      { PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8139,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
      { PCI_VENDOR_ID_TTTECH, PCI_DEVICE_ID_TTTECH_MC322,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
      { },
};
MODULE_DEVICE_TABLE(pci, cp_pci_tbl);
</pre>


  # m-a
Ecco l'uso di entrambi i valori del nostro ''vendor ID'' e ''device ID'' in una variabile <code>struct pci_device_id</code>. Questo driver dovrebbe supportare il nostro dispositivo.


e una interfaccia ''dialog'' ci guider� passo passo.
Ora che abbiamo il nome del driver, possiamo lavorare a ritroso, come mostrato nella prima sezione del capitolo, per trovare l'appropriato valore di configurazione del kernel che dovrebbe essere abilitato per compilare questo driver.


Si pu� usare il comando <tt>module-assistant list-avaible</tt> (o il diminutivo <tt>m-a la</tt>) per ottenere la lista completa dei moduli installabili con module-assistant. Per le altre innumerevoli opzioni potete leggere la pagina di manuale tradotta in italiano:
Riassumendo, ecco i passaggi necessari per trovare quale driver PCI può controllare uno specifico dispositivo PCI:
# Trovare l'ID del bus PCI del dispositivo per il quale volete trovare il driver, usando ''lspci''.
# Andare nella directory ''/sys/bus/pci/devices/0000:bus_id'', dove ''bus_id'' è l'ID del bus PCI trovato nel passaggio precedente.
# Leggere i valori dai file ''vendor'' e ''device'' nella directory dei dispositivi PCI.
# Tornare all'albero sorgente del kernel e cercare in ''include/linux/pci_ids.h'' per il ''vendor PCI'' e ''device ID'' trovato nel passaggio precedente.
# Cercare nell'albero sorgente del kernel per le referenze a quei valori nei driver. Sia il ''vendor'' che il ''device ID'' devono essere in una definizione di tipo <code>struct pci_device_id</code>.
# Cercare nei Makefile del kernel la regola <code>CONFIG_</code> che compila questo driver, usando ''find'' e ''grep'': <pre>$ find -type f -name Makefile | xargs grep DRIVER_NAME</pre>
# Cercare nel sistema di configurazione del kernel quel valore di configurazione e andate nella posizione del menù che specifica di abilitare quel driver per essere compilato.


* [[Pagina di manuale di module-assistant]]
===Dispositivi USB===
Trovare il driver specifico per un dispositivo USB è come trovare un driver per un dispositivo PCI come descritto nella precedente sezione, con solo differenze minori nel trovare i valori ID del bus.


===Bisogna usare l'initrd oppure no?===
In questo esempio, troviamo il driver che è necessario per un dispositivo USB wireless. Come per l'esempio del dispositivo PCI, i dettagli in questo esempio saranno differenti dalla vostra situazione, ma i passi necessari dovrebbero essere rilevanti per ogni tipo di dispositivo USB per cui desideriate trovare un driver funzionante.
La risposta breve �: no non usatelo.


Di seguito la risposta lunga:
Come per il dispositivo PCI, l'ID del bus deve essere trovato per il dispositivo USB per cui volete trovare il driver. Per fare ciò, potete usare il programma ''lsusb'' che si trova nel pacchetto ''usbutils''.


L'immagine initrd (ramdisk iniziale) serve per caricare dei moduli nel kernel prima che questo abbia l'accesso alla partizione di root. Quindi basta compilare questi moduli staticamente e non avremo mai bisogno di un ramdisk. Ma quali sono questi moduli che servono nelle prime fasi di avvio? Semplicemente i moduli che permettono di leggere la partizione di root, ovvero:
Il programma ''lsusb'' mostra tutti i dispositivi USB attaccati al sistema. Dato che voi non conoscete come il dispositivo specifico che state cercando è chiamato, cominciate guardando tutti i dispositivi:
<pre>
$ /usr/sbin/lsusb
Bus 002 Device 003:  ID 045e:0023 Microsoft Corp. Trackball Optical
Bus 002 Device 001:  ID 0000:0000
Bus 005 Device 003:  ID 0409:0058 NEC Corp. HighSpeed Hub
Bus 005 Device 001:  ID 0000:0000
Bus 004 Device 003:  ID 157e:300d
Bus 004 Device 002:  ID 045e:001c Microsoft Corp.
Bus 004 Device 001:  ID 0000:0000
Bus 003 Device 001:  ID 0000:0000
Bus 001 Device 001:  ID 0000:0000
</pre>


* il modulo del controller del proprio harddisk
I dispositivi con un ID di 0000:0000 possono venir ignorati, dal momento che sono ''USB host controller'' che guidano il bus stesso. Filtrandoli, restiamo con quattro dispositivi:
* il modulo del filesystem della partizione di root
<pre>
$ /usr/sbin/lsusb |  grep -v 0000:0000
Bus 002 Device 003:  ID 045e:0023 Microsoft Corp. Trackball Optical
Bus 005 Device 003:  ID 0409:0058 NEC Corp. HighSpeed Hub
Bus 004 Device 003:  ID 157e:300d
Bus 004 Device 002:  ID 045e:001c Microsoft Corp.
</pre>


Per un kernel ricompilato, l'initrd � generalmente inutile e rende l'avvio leggermente pi� lento. &Egrave; anche facile sbagliare se non attivate le giuste opzioni nel kernel (vedi [[#Ma se io devo usare l'initrd assolutamente?|FAQ successiva]]), in tal caso otterreste un kernel panic all'avvio. L'initrd serve soprattutto per i kernel ufficiali delle distribuzioni che devono supportare tutti i controller esistenti e una gran variet� di filesystem. Sarebbe assurdo compilare tutti questi supporti staticamente e quindi vengono inseriti come moduli nel ram disk. L'initrd � necessario anche se si vuole usare un bootsplash, ma questa � un'altra storia:
Dato che i dispositivi USB sono facili da rimuovere, scollegate il dispositivo di cui volete trovare il driver ed eseguite ''lsusb'' nuovamente:
<pre>
$ /usr/sbin/lsusb | grep -v 0000:0000
Bus 002 Device 003:  ID 045e:0023 Microsoft Corp. Trackball Optical
Bus 005 Device 003:  ID 0409:0058 NEC Corp. HighSpeed Hub
Bus 004 Device 002:  ID 045e:001c Microsoft Corp.
</pre>


* [[Compilazione Kernel 2.6.11 con Bootsplash]]
Il terzo dispositivo ora manca, che significa il dispositivo mostrato come:
* [[Kernel2.6.10 - Framebuffer - Gensplash Patch]]
<pre>
Bus 004 Device 003: ID 157e:300d
</pre>
è il dispositivo per cui volete trovare il driver.


La risposta lunga � quindi no, non usate il'initrd quando questo non sia strettamente necessario.
Se voi riattaccate il dispositivo e guardate all'output di ''lsusb'' ancora una volta, il numero del dispositivo sarà cambiato:
 
<pre>
===Ma se io devo usare l'initrd assolutamente?===
/usr/sbin/lsusb | grep 157e
Per usare l'intrd '''si deve''' compilare staticamente il supporto per l'initrd impostando le seguenti voci:
Bus 004 Device 004: ID 157e:300d
</pre>
Questo è dovuto al fatto che i numeri dei dispositivi USB non sono unici, ma cambiano ogni volta che un dispositivo viene inserito. Ciò che resta costante sono il ''vendor ID'' e ''product ID'', mostrati qui da ''lsusb'' come due valori a quattro cifre con un '''<code>:</code>''' tra di loro. Per questo dispositivo, il ''vendor ID'' è '''157e''' e il ''product ID'' è '''300d'''. Scrivetevi i valori che trovate, dato che li userete nei passi successivi.


Come per i dispositivi PCI, cercheremo nel codice sorgente del kernel il vendor USB e i product ID per trovare il driver adeguato per controllare questo dispositivo. Sfortunatamente, nessun singolo file contiene tutti gli ID dei vendor USB, come invece per quelli PCI. Perciò è necessaria una ricerca nel codice sorgente dell'intero kernel:
<pre>
<pre>
Device Drivers  --->
$ grep -i -R -l 157e drivers/*
  Block devices  --->
drivers/atm/pca200e.data
    <*> RAM disk support
drivers/atm/pca200e_ecd.data
    (16)  Default number of RAM disks
drivers/atm/sba200e_ecd.data
    (8192) Default RAM disk size (kbytes)
drivers/net/wireless/zd1211rw/zd_usb.c
    [*]  Initial RAM disk (initrd) support
drivers/scsi/ql1040_fw.h
drivers/scsi/ql1280_fw.h
drivers/scsi/qlogicpti_asm.c
</pre>
</pre>


Inoltre bisogna anche aggiungere il supporto per il filesystem usato nell'immagine del ram disk. In debian si usa di default il '''cramfs''', attivabile alla voce:
Sappiamo che questo è un dispositivo USB wireless, e non un dispositivo ATM o SCSI, per cui possiamo tranquillamente ignorare i file trovati nelle directory ''atm'' e ''scsi''. Quindi resta da cercare solo il file ''drivers/
net/wireless/zd1211rw/zd_usb.c''.


''zd_usb.c'' mostra la stringa 157e nel seguente pezzo di codice:
<pre>
<pre>
File systems --->
static struct usb_device_id usb_ids[]    ={
    Miscellaneous filesystems --->
      /* ZD1211 */
        <*> Compressed ROM file system support
      { USB_DEVICE(0x0ace, 0x1211),  .driver_info =  DEVICE_ZD1211  },
      { USB_DEVICE(0x07b8, 0x6001),  .driver_info =  DEVICE_ZD1211  },
      { USB_DEVICE(0x126f, 0xa006),  .driver_info = DEVICE_ZD1211  },
      { USB_DEVICE(0x6891, 0xa727),  .driver_info = DEVICE_ZD1211  },
      { USB_DEVICE(0x0df6, 0x9071),  .driver_info =  DEVICE_ZD1211  },
      { USB_DEVICE(0x157e, 0x300b),  .driver_info =  DEVICE_ZD1211  },
      /* ZD1211B */
      { USB_DEVICE(0x0ace, 0x1215),  .driver_info = DEVICE_ZD1211B },
      { USB_DEVICE(0x157e, 0x300d),  .driver_info = DEVICE_ZD1211B },
      {}
};
</pre>
</pre>


Se si vuole usare un'altro filesystem basta impostarlo in '''/etc/mkinitrd/mkinitrd.conf'''.
Come per i driver PCI, i driver USB dicono al kernel quali dispositivi supportano affinché il kernel possa associare il driver al dispositivo. Ciò viene fatto usando una variabile di tipo <code>struct usb_device_id</code>, come mostrato qui. Questa è una lista dei differenti vendor e product ID che sono supportati da questo driver. La linea:
<pre>
{ USB_DEVICE(0x157e, 0x300b), .driver_info = DEVICE_ZD1211 },
</pre>
mostra che il nostro vendor e product ID sono supportati da questo driver.


Con tali configurazioni � possibile compilare il kernel con initrd aggiungendo semplicemente l'opzione <code>--initrd</code> al comando <code>make-kpkg</code>. Il pacchetto risultante conterr� degli script che creeranno l'immagine initrd in fase di installazione del pacchetto.
Una volta che avete il nome del driver che è necessario per controllare il dispositivo, lavorate a ritroso tramite i Makefile del kernel, come descritto precedentemente nel capitolo su come abilitare il driver per compilarlo appropriatamente.


Attualmente ci sono tre tool in debian che permettono di creare l'immagine initrd:  
Riassumendo, i passaggi necessari per trovare quale driver USB controllerà uno specifico dispositivo USB sono:
# Trovare il vendor USB e il product ID del dispositivo per il quale si vuole trovare il driver, usando ''lsusb'' dopo aver aggiunto e rimosso il dispositivo per vedere cosa è cambiato nella lista.
# Cercare l'albero del codice sorgente del kernel per il vendor e il product ID del dispositivo USB. Sia il vendor e il product ID dovrebbero essere in una definizione <code>struct usb_device_id</code>.
# Cercare nei Makefile del kernel la regola <code>CONFIG_</code> che compila questi driver, ricorrendo a ''find'' e ''grep'': <pre>$ find -type f -name Makefile | xargs grep DRIVER_NAME</pre>
# Cercare nella configurazione di sistema del kernel il valore di quella configurazione e andate alla posizione nel menù che specifica di abilitare il driver per essere compilato.


* '''<code>mkinitrd</code> ''' (fornito dal pacchetto <code>initrd-tools</code>): questo � il vecchio metodo usato fino al kernel 2.6.12.
===Root filesystem===
* '''<code>update-initramfs</code> ''' (fornito dal pacchetto <code>initramfs-tools</code>): utilizzabile con kernel 2.6.13 o pi� recenti. Aggiunge tutti i controller del disco e i supporti che potrebbero servire per il boot che sono stati complati come moduli.
Il filesystem radice (''root'' NdT) è il filesystem da cui la porzione principale del sistema in esecuzione si avvia. Contiene tutti i programmi iniziali che fanno partire la distribuzione e solitamente contiene anche l'intera configurazione di sistema della macchina. In breve, è molto importante, e deve essere in grado di esser trovato dal kernel a tempo di avvio (''boot time'' NdT) affinché le cose funzionino propriamente.
* '''<code>mkinitrd.yaird</code> ''' (fornito dal pacchetto <code>yaird</code>): utilizzabile con kernel 2.6.13 o pi� recenti. Analizza il sistema e aggiunge all'immagine initrd '''solo''' i moduli necessari al boot della macchina su cui si installa il kernel. Permette di ottenere una immagine molto pi� piccola del caso precedente.


Per ulteriori informazioni sui kernel debian e le immagini initrd:
Se il vostro nuovo kernel configurato muore a boot time con un errore del tipo:
<pre>
VFS: Cannot open root device hda2 (03:02)
    Please append a correct "root=" boot option
    Kernal panic: VFS: Unable to mount root fs on 03:02
</pre>
significa che il root filesystem non è stato trovato. Se non state usando un'immagine ramdisk a ''boot time'', è solitamente raccomandabile che compiliate nel kernel sia il filesystem che usate come partizione di root che il controller per quel disco nel kernel, invece di averlo come modulo. Se invece usate un ramdisk a boot time, dovreste essere coperti anche compilando queste porzioni come moduli.
::[[Immagine:Warning_65x68.jpg|left]]Come potete determinare se state usando un ramdisk a boot time? Nel [[LKN:_Installare_ed_Avviare_con_un_Kernel|Capitolo 5]] abbiamo menzionato l'uso dello script di installazione della vostra distribuzione per installare il kernel rispetto all'effettuare l'installazione per proprio conto. Se state usando lo script di installazione della distribuzione, state probabilmente già usando un ramdisk. Se invece lo state installando per vostro conto, probabilmente non lo state usando.


* [http://kernel-handbook.alioth.debian.org/ch-initramfs.html Debian Linux Kernel Handbook: Managing the initial ramfs (initramfs) archive]
Le sottosezioni seguenti mostrano come lasciare che il kernel trovi il root filesystem durante il boot.


=== Ma il kernel non fa il boot senza initrd! ===
====Tipo del filesystem====
Vedi FAQ precedente. L'initrd non � necessario per fare il boot. Se il sistema non parte ci� dipende da una incorretta configurazione del kernel.
Per prima cosa, bisogna determinare il tipo di filesystem che la partizione di root sta utilizzando. Per fare ciò, si guardi al risultato del comando ''mount'':
<pre>
$ mount | grep " / "
/dev/sda2 on / type ext3 (rw,noatime)
</pre>
Siamo interessati al tipo di filesystem, che viene mostrato dopo la parola <code>type</code>. In questo esempio è ext3. Questo è il tipo di filesystem che la partizione di root sta usando. Andate nel sistema di configurazione del kernel e siate sicuri che questo tipo di filesystem sia abilitato, come descritto nel [[LKN:_Ricette_per_Configurare_il_Kernel|Capitolo 8]].


'''lordnisse''' ha riportato sul forum che per avviare il suo sistema � stato necessario compilare anche il supporto per partizioni MS-DOS:
====Controller del disco====
Nell'output del comando ''mount'' appena mostrato, la prima porzione della linea mostra su quale dispositivo a blocchi il root filesystem è montato. In questo esempio è ''/dev/sda2''. Ora che il filesystem è correttamente configurato nel vostro kernel, dovete essere sicuri che questo dispositivo a blocchi funzionerà correttamente. Per trovare quali driver sono necessari, ancora una volta bisognerà guardare in ''sysfs''.


Tutti i dispositivi a blocchi sono mostrati in ''sysfs'' in ''/sys/block'' oppure in ''/sys/class/block'', a seconda della versione del kernel che state usando. In entrambi i luoghi, i dispositivi a blocchi costituiscono un albero, con le diverse partizioni figlie del dispositivo principale:
<pre>
<pre>
File systems  --->
$ tree -d /sys/block/ | egrep "hd|sd"
    Partition Types --->
|-- hdc
        [*] Advanced partition selection
|-- hdd
        [*]  PC BIOS (MSDOS partition tables) support (NEW)
`-- sda
  |-- sda1
|-- sda2
|-- sda3
</pre>
</pre>
Data l'informazione nel comando di ''mount'', dovete essere sicuri che il dispositivo sda2 è configurato correttamente. Poiché questa è una partizione (le partizioni di un disco sono numerate, mentre i dispositivi a blocchi principali non lo sono), l'intero dispositivo sda deve essere configurato. (Senza il dispositivo a blocchi principale, non c'è possibilità di accedere alle partizioni individuali su quel dispositivo).


=== Posso usare make-kpkg con un kernel vanilla ===
Il dispositivo a blocchi sda è rappresentato semplicemente come il dispositivo di rete che abbiamo visto precedentemente in questo capitolo. Esiste un symlink nella directory del dispositivo chiamato ''device'' che punta al dispositivo logico che controlla il dispositivo a blocchi:
Certamente, <tt>make-kpkg</tt> pu� essere usato indifferentemente sia con i sorgenti Debian del kernel di linux che con i sorgenti del [[kernel vanilla]].  
<pre>
$ ls -l /sys/block/sda
...
device -> ../../devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0
...
</pre>
Ora avete bisogno di iniziare a percorrere la catena dei dispositivi nel ''sysfs'' per trovare quale driver sta controllando questo dispositivo:
<pre>
$ ls -l /sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0
...
driver -> ../../../../../../bus/scsi/drivers/sd
...
</pre>
Qui vediamo che il driver del controller del disco SCSI è responsabile per il funzionamento di questo dispositivo. Così sappiamo che dobbiamo configurare il supporto ai dischi SCSI nella nostra configurazione del kernel.


I sorgenti Debian sono contenuti nei pacchetti <tt>kernel-source-*</tt> (o <tt>linux-source-*</tt> per i kernel dal 2.6.12 in poi) e sono installabili come usuali pacchetti con [[APT]].
Continuando a salire la catena delle directory in ''sysfs'', provate a trovare dov'è il driver che controlla l'hardware:
<pre>
$ ls -l /sys/devices/pci0000:00/0000:00:1f.2/host0
...
</pre>
Ancora, nessun driver qui. Continuando di un livello in su:
<pre>
$ ls -l /sys/devices/pci0000:00/0000:00:1f.2
...
driver -> ../../../bus/pci/drivers/ata_piix
</pre>
Eccolo! Questo è il controller del disco che abbiamo bisogno di assicurarci sia nella nostra configurazione del kernel.


I sorgenti vanilla devono essere scaricati manualmente da [http://www.kernel.org www.kernel.org]. Devono essere scompattati in <code>/usr/src</code>, e per il resto la procedura di compilazione � assolutamente identica al caso di sorgenti Debian.
Così per questo root filesystem, abbiamo bisogno di abilitare i driver ext3, sd, e ata_piix nella nostra configurazione del kernel, così che saremo capaci di fare il boot con successo del nostro kernel su questo hardware.


Nel caso di sorgenti vanilla, pu� essere interessante vedere l'opzione <tt>debian</tt> nella sezione [[Debian_Kernel_Howto#Compilazione_del_kernel|Compilazione del kernel]], tuttavia l'uso di tale parametro � del tutto opzionale.
===Script d'aiuto===
Come menzionato all'inizio del capitolo, file e directory in ''sysfs'' cambiano da una versione del kernel a un'altra. Qui c'è uno script che è a portata di mano per determinare i necessari driver del kernel e il nome del modulo per ogni dispositivo nel sistema. È stato sviluppato con gli sviluppatori del kernel responsabili per ''sysfs'' e dovrebbe funzionare con successo con tutte le versioni future del kernel 2.6 .


===Errore con l'opzione <tt>--revision</tt> ===
Per esempio, liquida il precedente esempio, quando dovevate prendere tutti i driver appropriati per i dispositivi a blocco sda:
Pu�' capitare che, ricompilando il kernel variando il valore dell'opzione <tt>--revision</tt> venga rilevato un errore simile al seguente:
<pre>
<pre>
I note that you are using the --revision flag with the value
$ get-driver.sh sda
  2.
looking at sysfs device: /sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0
However, the ./debian/changelog file exists, and has a different value
found driver: sd
  1.
found driver: ata_piix
I am confused by this discrepancy, and am halting.</pre>
</pre>
 
Posso anche trovare tutto sui driver appropriati necessari per cose complicate come i dispositivi USB-to-serial:
Questo problema e' semplicemente dovuto al fatto che non si � pulito il tree dei sorgenti dopo la prima compilazione. Per ovviare basta dunque:
<pre>
$ get-driver.sh ttyUSB0
looking at sysfs device: /sys/devices/pci0000:00/0000:00:1d.3/usb4/4-2/4-2.3/4-2.3:1.0/ttyUSB0
found driver: pl2303 from module: pl2303
found driver: pl2303 from module: pl2303
found driver: usb from module: usbcore
found driver: usb from module: usbcore
found driver: usb from module: usbcore
found driver: uhci_hcd from module: uhci_hcd
</pre>


<pre>$ make-kpkg clean</pre>
Potete scaricare un file di esempio contenente questo script dal web site del libro, fornito nella sezione "How to Contact Us" nella prefazione (ossia [http://www.oreilly.com/catalog/9780596100797/ qui] NdT).


e rilanciare la compilazione.
Di seguito lo script:
 
===You are attempting to install a kernel image (version ''version-revision'') However, the directory /lib/modules/''version-revision'' still exists.===
Se si aggiorna il kernel ad una [[revisione]] successiva, durante l'installazione del pacchetto verr� fatta la seguente domanda:
<pre>
<pre>
You are attempting to install a kernel image (version 2.6.15.4-swsusp) However, the directory /lib/modules/2.6.15.4-swsusp still existsIf this directory
#!/bin/sh
belongs to a previous linux-image-2.6.15.4-swsusp package, and if you have deselected some modules, or installed standalone modules packages, this could be
#
bad. However, if this directory exists because you are also installing some stand alone modules right now, and they got unpacked before I did, then this is
# Find all modules and drivers for a given class device.
pretty benign. Unfortunately, I can not tell the difference.
#
 
if [ $# != "1" ] ; then
If /lib/modules/2.6.15.4-swsusp belongs to a old install of linux-image-2.6.15.4-swsusp, then this is your last chance to abort the installation of this
  echo
kernel image (nothing has been changed yet).
echo "Script to display the drivers and modules for a specified sysfs class device"
 
echo "usage: $0 <CLASS_NAME>"
If this directory is because of stand alone modules being installed right now, or if it does belong to an older linux-image-2.6.15.4-swsusp package but you
echo
know what you are doing, and if you feel that this image should be installed despite this anomaly, Please answer n to the question.
echo "example usage:"
 
echo " $0 sda"
Otherwise, I suggest you move /lib/modules/2.6.15.4-swsusp out of the way, perhaps to /lib/modules/2.6.15.4-swsusp.old or something, and then try
echo "Will show all drivers and modules for the sda block device."
re-installing this image. 
echo
 
exit 1
Stop install since the kernel-image is already installed?    
fi
DEV=$1
if test -e "$1"; then
  DEVPATH=$1
else
# find sysfs device directory for device
DEVPATH=$(find /sys/class -name "$1" | head -1)
test -z "$DEVPATH" && DEVPATH=$(find /sys/block -name "$1" | head -1)
test -z "$DEVPATH" && DEVPATH=$(find /sys/bus -name "$1" | head -1)
if ! test -e "$DEVPATH"; then
  echo "no device found"
  exit 1
fi
fi
echo "looking at sysfs device: $DEVPATH"
if test -L "$DEVPATH"; then
# resolve class device link to device directory
DEVPATH=$(readlink -f $DEVPATH)
echo "resolve link to: $DEVPATH"
fi
if test -d "$DEVPATH"; then
# resolve old-style "device" link to the parent device
PARENT="$DEVPATH";
while test "$PARENT" != "/"; do
  if test -L "$PARENT/device"; then
  DEVPATH=$(readlink -f $PARENT/device)
  echo "follow 'device' link to parent: $DEVPATH"
  break
  fi
  PARENT=$(dirname $PARENT)
done
fi
while test "$DEVPATH" != "/"; do
DRIVERPATH=
DRIVER=
MODULEPATH=
MODULE=
if test -e $DEVPATH/driver; then
  DRIVERPATH=$(readlink -f $DEVPATH/driver)
  DRIVER=$(basename $DRIVERPATH)
  echo -n "found driver: $DRIVER"
  if test -e $DRIVERPATH/module; then
  MODULEPATH=$(readlink -f $DRIVERPATH/module)
  MODULE=$(basename $MODULEPATH)
  echo -n " from module: $MODULE"
   fi
  echo
fi
DEVPATH=$(dirname $DEVPATH)
done
</pre>
</pre>


La risposta da dare � '''<tt>No</tt>'''! L'avvertimento ci ricorda che i moduli del vecchio kernel (quello con la stessa versione ma numero di revisione diverso) verranno cancellati e sostituiti dai moduli del nuovo kernel.
----
 
This is an indipendent translation of the book [http://www.kroah.com/lkn/ Linux Kernel in a Nutshell] by [http://www.kroah.com/log/ Greg Kroah-Hartman]. This translation (like the original work) is available under the terms of [http://creativecommons.org/licenses/by-sa/2.5/ Creative Commons Attribution-ShareAlike 2.5].
Questo � il comportamento normale, infatti, nel caso non si voglia sostituire un vecchio kernel ma semplicemente installarne parallelamente uno nuovo (con la stessa identica versione) si sarebbe dovuta modificare la stringa dopo <code>--append-to-version</code> invece che quella dopo <code>--revision</code> (vedi sez. [[Debian_Kernel_Howto#Compilazione_del_kernel|Compilazione kernel]]).
----
 
Se il kernel che si sta sostituendo � quello in esecuzione ''� necessario riavviare la macchina il prima possibile!''
 
== Link ==
 
* [http://www.debian.org/doc/manuals/reference/ch-kernel.it.html Manuale di Riferimento Debian: Capitolo 7 - Il kernel Linux su Debian]
* [http://kernel-handbook.alioth.debian.org/index.html Debian Linux Kernel Handbook ]: ottimo documento sulla gestione dei kernel debian delle relative patch (''in inglese'').
* [http://a2.pluto.it/kernel_linux_1.htm Appunti di informatica Libera: Kernel Linux]: Il capitolo dedicato al kernel della monumentale opera di ''Daniele Giacomini'' contiene sia istruzioni generiche che istruzioni per Debian. Inoltre c'� una descrizione dettagliata della configurazione delle varie voci del kernel!
* [http://kernel.xc.net/ Linux Kernel Configuration Archive]: database che permette di ricercare tra le voci di configurazione (e le loro descrizioni) per varie versioni di kernel.


Buon divertimento con Debian GNU/Linux!
----


Autore iniziale: Abortigeno
[http://files.kroah.com/lkn/lkn_pdf/ch07.pdf ''Capitolo originale'']


Rivisto ed esteso: [[Utente:TheNoise|~ The Noise]]


[[Categoria:Kernel]]
[[Categoria:Documentazione tecnica]]
[[Categoria:Linux Kernel in a Nutshell]]

Versione attuale delle 16:59, 14 mag 2016

Linux Kernel in a Nutshell

Sommario

Parte I
Compilare il kernel
  1. Introduzione
  2. Requisiti
  3. Procurarsi i sorgenti
  4. Configurazione e compilazione
  5. Installazione e avvio
  6. Aggiornare il kernel
Parte II
Personalizzazioni principali
  1. Personalizzare un kernel
  2. Ricette per configurare un kernel
Parte III
Guide di riferimento per il kernel
  1. Guida di riferimento dei parametri di boot del kernel - parte1
  2. Guida di riferimento dei parametri di boot del kernel - parte2
  3. Guida di riferimento dei parametri di compilazione del kernel
  4. Guida di riferimento delle opzioni di configurazione del kernel - parte1
  5. Guida di riferimento delle opzioni di configurazione del kernel - parte2
Parte IV
Informazioni aggiuntive
  1. Programmi utili
  2. Bibliografia


Uno dei punti più delicati e difficili nella compilazione della propria versione del kernel Linux è quello di determinare esattamente quali driver e quali opzioni di configurazione sono richiesti per il corretto funzionamento della macchina su cui sarà eseguito. Questo capitolo guiderà il lettore attraverso questo processo di ricerca e selezione 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 le opzioni di configurazione del kernel necessarie al suo corretto funzionamento su quell'hardware.

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 potrebbero essere parti del sistema che richiedono l'abilitazione di certe opzioni.

Determinare quali moduli sono 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 e permettere la compilazione di tutti o parte dei driver nel kernel stesso (compilando staticamente invece che come moduli NdT), riducendo un po' la memoria utilizzata e, in alcune architetture, creando un kernel che sarà eseguito più velocemente. Per escludere i driver dal kernel è necessario 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 dei ripensamenti degli sviluppatori del kernel su come presentare al meglio 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. Comunque le informazioni saranno ancora tutte lì, solo spostate un po'.

Esempio: Come determinare il driver di rete

Uno dei dispositivi (device NdT) 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.

In primo luogo, partendo dal nome dell'interfaccia di rete si deve risalire al device PCI che la sta controllando. I nomi delle interfacce di rete si ottengono come segue:

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

La directory lo rappresenta solo il dispositivo di rete loopback, che non è connesso e nessun reale dispositivo di rete. Invece si deve prestare attenzione alle directory eth0, eth1 e eth2, dato che si riferiscono a dispositivi realmente esistenti.

Per ottenere maggiori informazioni su questi dispositivi, 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, come si può vedere dalle 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 mostra che tale dispositivo è di tipo Ethernet e gli è stato 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 di seguire i diversi link nel filesystem sysfs, eseguibile con un comando di una sola riga:

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

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

  1. Segue il percorso a cui punta il symlink /sys/class/net/eth0/device, contenuto all'interno della directory /sys/device/, che contiene le informazioni relative al dispositivo che controlla eth0. Notare che nelle versioni più recenti del kernel la directory /sys/class/net/eth0 potrebbe essere anch'essa 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 il file 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, vogliamo scartare il 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, ritorna quanto segue:
    $ basename ../../../../module/e1000
    e1000

Così abbiamo inserito il lungo percorso ottenuto seguendo il symlink, ottenuto grazie a readlink, quale parametro del programma basename, permettendo così l'intero processo di essere realizzato in una sola riga.

Ora che abbiamo il nome del modulo, si deve trovare l'opzione di 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 ricordi di sostituire il nome e1000, usato in questo esempio, con quello del modulo che avete intenzione di trovare.

La cosa importante da cercare nel risultato del precedente comando find sono le righe dove compare 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 ci interessa è pertanto CONFIG_E1000.

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

$ make menuconfig

Dopodiché si prema il tasto / (slash) (che ha il compito di far partire una ricerca), e si digiti 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 dirà ora esattamente dove selezionare l'opzione per abilitare questo modulo. Si veda la 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 sistema. 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

Si può 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.

Sommario della scoperta del dispositivo

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

  1. Trovare 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. Seguire i link simboilci nell'albero di sysfs per trovare il nome del modulo che controlla il dispositivo in oggetto. Lo si trova seguendo il symlink /sys/class/class_name/device_name/device/driver/module, e può essere visualizzato combinando i comandi readlink e basename:
    $ basename `readlink /sys/class/class_name/device_name/device/driver/module`
  3. Ricercare nei file Makefile con find e grep le opzioni CONFIG_ usate per compilare il modulo:
    $ find -type f -name Makefile | xargs grep module_name
  4. Ricercare l'opzione trovata nel sistema di configurazione del kernel, dopodiché andare nella posizione del menù che specifica di attivare quel driver per compilarlo.

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 $i ;
done | rev | cut -f1 -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 (ossia qui NdT).

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 a 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, e infine ricompilare il kernel abilitando il solo driver necessario.

Se invece non si vogliono compilare tutti i driver, o questo meccanismo non funziona per qualche motivo, sarà necessario un pò più di lavoro per individuare il driver necessario. I passi successivi sono complessi e richiedono talvolta di dover cercare nei sorgenti del kernel. Non abbiate timore di ciò, sarà solo di aiuto a comprendere meglio l'hardware ed i sorgenti del kernel.

I passi necessari per trovare il driver corrispondente di un dispositivo cambiano a seconda del tipo di dispositivo in questione. In questo capitolo discuteremo le due tipologie di dispositivi più comuni: PCI e USB; ma i metodi qui descritti saranno validi anche per altri tipi di dispositivi.

È inoltre molto importante per il kernel di essere in grado di trovare tutti i filesystem presenti nel sistema, di cui il più importante è quello radice (root NdT). Approfondiremop questo aspetto successivamente in "Root filesystem".

Dispositivi PCI

I dispositivi PCI si distinguono per vendor ID e device ID; ogni combinazione di vendor ID e di device ID può richiedere un driver unico. Questa è la base per la ricerca mostrata in questa sezione.

Per questo esempio useremo un scheda di rete PCI che supporremo non funzionante con l'attuare versione del kernele in esecuzione. Questo esempio sarà diverso dalla vostra situazione, con differenti device PCI e valori ID del bus, ma i passi salienti dovrebbero essere rilevanti per ogni tipo di dispositivo PCI per il quale vogliate trovare un driver funzionante.

In primo luogo troviamo nel sistema il dispositivo PCI che non sta funzionando. Per ottenere una lista di tutti i dispositivi PCI usiamo il programma lspci. Poiché a noi interessano solo dispositivi PCI ethernet restringeremo la nostra ricerca filtrado tra i risultati solo quelli che conterranno la parola ethernet (ignorando se i caratteri sono minuscoli o maiuscoli):

$ /usr/sbin/lspci | grep -i ethernet
06:04.0 Ethernet controller: Realtek Semiconductor Co., Ltd. RTL-8139/
8139C/8139C+ (rev 10)

Questo è il dispositivo che vorremmo fare funzionare.*

Nota (*): potreste anche provare a cercare in tutta la configurazione del kernel un dispositivo che corrisponde alla stringa mostrata sopra (un dispositivo della Realtek Semiconductors con nome prodotto RTL-8139/8139C/8139C+), ma questo non funziona sempre. Per questo motivo useremo la via lunga in questo capitolo.

Warning 65x68.jpg
Quasi tutte le distribuzioni mettono il programma lspci in /usr/sbin/, ma alcune lo mettono in altri percorsi. Per trovare in quale posizione è stato messo digitare:
$ which lspci
/usr/sbin/lspci

Se state usando una distribuzione che mette lspci in un'altra posizione, usate il percorso corretto per la vostra installazione ogni volta che verrà usato lspci.

I primi pochi spezzoni dell'output di lspci mostrano l'ID del bus PCI per questo dispositivo, 06:04.0. Questo è il valore che useremo quando cercheremo in sysfs per trovare più informazioni riguardo questo dispositivo.

Andiamo in sysfs dove tutti i dispositivi PCI sono elencati, e guardiamo i loro nomi:

$ cd /sys/bus/pci/devices/
$ ls
0000:00:00.0 0000:00:1d.0  0000:00:1e.0 0000:00:1f.3 0000:06:03.3
0000:00:02.0 0000:00:1d.1  0000:00:1f.0 0000:06:03.0 0000:06:03.4
0000:00:02.1 0000:00:1d.2  0000:00:1f.1 0000:06:03.1 0000:06:04.0
0000:00:1b.0 0000:00:1d.7  0000:00:1f.2 0000:06:03.2 0000:06:05.0

Il kernel numera i dispositivi PCI con un 0000: iniziale che non viene mostrato nell'output di lspci.+ Dunque, aggiungiamo un 0000: al numero datoci da lspci e entriamo in quella directory:

$ cd 0000:06:04.0

Nota (+): alcuni processori 64-bit mostreranno il "leading bus number" per i dispositivi PCI nell'output di lspci, ma per la maggiorparte delle comuni macchine Linux, non verrà mostrato di default.

In questa directory vogliamo conoscere il valori dei file vendor e device.

$ cat vendor
0x10ec

$ cat device
0x8139

Questi sono il vendor ID ed il device ID per questo dispositivo PCI. Il kernel usa questi valori per associare correttamente un driver ad un dispositivo. I driver PCI dicono al kernel quale vendor e device ID supporteranno così che il kernel sappia come collegare il driver al dispositivo corretto. Scriveteli da qualche parte, dato che ci riferiremo a loro più tardi.

Ora che sappiamo il vendor ID e il device ID per questo dipositivo PCI, abbiamo bisogno di trovare i driver del kernel corretto che riporta di supportare questo dispositivo. Tornate indietro alla directory di source del kernel:

$ cd ~/linux/linux-2.6.17.8/

Il posto più comune per gli ID di tipo PCI nell'albero sorgente del kernel è include/linux/pci_ids.h. Cercate in quel file il vostro vendor id:

$ grep -i 0x10ec include/linux/pci_ids.h
#define PCI_VENDOR_ID_REALTEK                  0x10ec

Il valore qui definito, PCI_VENDOR_ID_REALTEK, è ciò che probabilmente sarà usato in qualsiasi kernel driver che riporta di supportare i dispositivi di quel produttore.

Per essere sicuri, si cerchi il device ID anche in questo file , dato che è a volte descritto là:

$ grep -i 0x8139 include/linux/pci_ids.h
#define PCI_DEVICE_ID_REALTEK_8139         0x8139

Questa definizione sarà utile più avanti.

Ora si cerchi nei file sorgenti dei driver relativi a questo produttore:

$ grep -Rl PCI_VENDOR_ID_REALTEK *
include/linux/pci_ids.h
drivers/net/r8169.c
drivers/net/8139too.c
drivers/net/8139cp.c

Non serve guardare nel primo file riportato qui, pci_ids.h, dato che è dove è stata trovata la definizione originale. Ma i file r8139.c, 8139too.c, e 8169cp.c nella sottodirectory drivers/net/ dovrebbero essere esaminati più da vicino.

Si apra uno di questi file in un editor, cercando PCI_VENDOR_ID_REALTEK. Nel file drivers/net/r8169.c, si vede nella seguente sezione di codice:

static struct pci_device_id rtl8169_pci_tbl[] = {
      { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8169), },
      { PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8129), },
      { PCI_DEVICE(PCI_VENDOR_ID_DLINK,      0x4300), },
      { PCI_DEVICE(0x16ec,                   0x0116), },
      { PCI_VENDOR_ID_LINKSYS,               0x1032, PCI_ANY_ID, 0x0024, },
      {0,},
};

Tutti i driver PCI contengono una lista di dispositivi differenti che supportano. Questa lista è contenuta in una struttura di valori struct pci_device_id, come questa. Questo è ciò che dobbiamo guardare per determinare se il nostro dispositivo è supportato da questo driver. Il valore del vendor corrisponde qui, ma il secondo valore dopo il vendor è il valore del dispositivo. Il nostro dispositivo ha il valore 0x8139, mentre questo driver supporta i valori di dispositivi per 0x8169 e 0x8129 con il vendor ID di PCI_VENDOR_ID_REALTEK. Per cui questo driver non supporterà il nostro dispositivo.

Spostandoci al prossimo file, drivers/net/8139too.c, si può trovare la stringa PCI_VENDOR_ID_REALTEK nel seguente pezzo di codice:

if (pdev->vendor == PCI_VENDOR_ID_REALTEK &&
 pdev->device == PCI_DEVICE_ID_REALTEK_8139 && pci_rev >= 0x20) {
  dev_info(&pdev->dev,"This (id %04x:%04x rev %02x) is an enhanced 8139C+ chip\n",
       pdev->vendor, pdev->device, pci_rev);
  dev_info(&pdev->dev, "Use the \"8139cp\" driver for improved performance and stability.\n");
}

L'utilizzo del valore di PCI_VENDOR_ID_REALTEK qui corrisponde anche con il codice che controlla se il dispositivo PCI ID corrisponde al valore PCI_DEVICE_ID_REALTEK_8139. Se corrisponde, il driver stamperà un messaggio che dice: "Use the 8139cp for improved performance and stability." Forse dovremmo guardare a quel driver di seguito. Anche se non avessimo tale visibile consiglio, il driver 8139too.c non ha la coppia vendor e device ID che stiamo cercando in una variabile del tipo struct pci_device_id, ciò ci dice che non supporta il nostro dispositivo.

Infine, guardate nel file drivers/net/8139cp.c. Usa la definizione PCI_VENDOR_ID_REALTEK nel seguente sezione di codice:

static struct pci_device_id cp_pci_tbl[] = {
      { PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8139,
	PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
      { PCI_VENDOR_ID_TTTECH, PCI_DEVICE_ID_TTTECH_MC322,
	PCI_ANY_ID, PCI_ANY_ID, 0, 0, },
      { },
};
MODULE_DEVICE_TABLE(pci, cp_pci_tbl);

Ecco l'uso di entrambi i valori del nostro vendor ID e device ID in una variabile struct pci_device_id. Questo driver dovrebbe supportare il nostro dispositivo.

Ora che abbiamo il nome del driver, possiamo lavorare a ritroso, come mostrato nella prima sezione del capitolo, per trovare l'appropriato valore di configurazione del kernel che dovrebbe essere abilitato per compilare questo driver.

Riassumendo, ecco i passaggi necessari per trovare quale driver PCI può controllare uno specifico dispositivo PCI:

  1. Trovare l'ID del bus PCI del dispositivo per il quale volete trovare il driver, usando lspci.
  2. Andare nella directory /sys/bus/pci/devices/0000:bus_id, dove bus_id è l'ID del bus PCI trovato nel passaggio precedente.
  3. Leggere i valori dai file vendor e device nella directory dei dispositivi PCI.
  4. Tornare all'albero sorgente del kernel e cercare in include/linux/pci_ids.h per il vendor PCI e device ID trovato nel passaggio precedente.
  5. Cercare nell'albero sorgente del kernel per le referenze a quei valori nei driver. Sia il vendor che il device ID devono essere in una definizione di tipo struct pci_device_id.
  6. Cercare nei Makefile del kernel la regola CONFIG_ che compila questo driver, usando find e grep:
    $ find -type f -name Makefile | xargs grep DRIVER_NAME
  7. Cercare nel sistema di configurazione del kernel quel valore di configurazione e andate nella posizione del menù che specifica di abilitare quel driver per essere compilato.

Dispositivi USB

Trovare il driver specifico per un dispositivo USB è come trovare un driver per un dispositivo PCI come descritto nella precedente sezione, con solo differenze minori nel trovare i valori ID del bus.

In questo esempio, troviamo il driver che è necessario per un dispositivo USB wireless. Come per l'esempio del dispositivo PCI, i dettagli in questo esempio saranno differenti dalla vostra situazione, ma i passi necessari dovrebbero essere rilevanti per ogni tipo di dispositivo USB per cui desideriate trovare un driver funzionante.

Come per il dispositivo PCI, l'ID del bus deve essere trovato per il dispositivo USB per cui volete trovare il driver. Per fare ciò, potete usare il programma lsusb che si trova nel pacchetto usbutils.

Il programma lsusb mostra tutti i dispositivi USB attaccati al sistema. Dato che voi non conoscete come il dispositivo specifico che state cercando è chiamato, cominciate guardando tutti i dispositivi:

$ /usr/sbin/lsusb
Bus 002 Device 003:  ID 045e:0023 Microsoft Corp. Trackball Optical
Bus 002 Device 001:  ID 0000:0000
Bus 005 Device 003:  ID 0409:0058 NEC Corp. HighSpeed Hub
Bus 005 Device 001:  ID 0000:0000
Bus 004 Device 003:  ID 157e:300d
Bus 004 Device 002:  ID 045e:001c Microsoft Corp.
Bus 004 Device 001:  ID 0000:0000
Bus 003 Device 001:  ID 0000:0000
Bus 001 Device 001:  ID 0000:0000

I dispositivi con un ID di 0000:0000 possono venir ignorati, dal momento che sono USB host controller che guidano il bus stesso. Filtrandoli, restiamo con quattro dispositivi:

$ /usr/sbin/lsusb |  grep -v 0000:0000
Bus 002 Device 003:  ID 045e:0023 Microsoft Corp. Trackball Optical
Bus 005 Device 003:  ID 0409:0058 NEC Corp. HighSpeed Hub
Bus 004 Device 003:  ID 157e:300d
Bus 004 Device 002:  ID 045e:001c Microsoft Corp.

Dato che i dispositivi USB sono facili da rimuovere, scollegate il dispositivo di cui volete trovare il driver ed eseguite lsusb nuovamente:

$ /usr/sbin/lsusb |  grep -v 0000:0000
Bus 002 Device 003:  ID 045e:0023 Microsoft Corp. Trackball Optical
Bus 005 Device 003:  ID 0409:0058 NEC Corp. HighSpeed Hub
Bus 004 Device 002:  ID 045e:001c Microsoft Corp.

Il terzo dispositivo ora manca, che significa il dispositivo mostrato come:

Bus 004 Device 003: ID 157e:300d

è il dispositivo per cui volete trovare il driver.

Se voi riattaccate il dispositivo e guardate all'output di lsusb ancora una volta, il numero del dispositivo sarà cambiato:

/usr/sbin/lsusb | grep 157e
Bus 004 Device 004: ID 157e:300d

Questo è dovuto al fatto che i numeri dei dispositivi USB non sono unici, ma cambiano ogni volta che un dispositivo viene inserito. Ciò che resta costante sono il vendor ID e product ID, mostrati qui da lsusb come due valori a quattro cifre con un : tra di loro. Per questo dispositivo, il vendor ID è 157e e il product ID è 300d. Scrivetevi i valori che trovate, dato che li userete nei passi successivi.

Come per i dispositivi PCI, cercheremo nel codice sorgente del kernel il vendor USB e i product ID per trovare il driver adeguato per controllare questo dispositivo. Sfortunatamente, nessun singolo file contiene tutti gli ID dei vendor USB, come invece per quelli PCI. Perciò è necessaria una ricerca nel codice sorgente dell'intero kernel:

$ grep -i -R -l 157e drivers/*
drivers/atm/pca200e.data
drivers/atm/pca200e_ecd.data
drivers/atm/sba200e_ecd.data
drivers/net/wireless/zd1211rw/zd_usb.c
drivers/scsi/ql1040_fw.h
drivers/scsi/ql1280_fw.h
drivers/scsi/qlogicpti_asm.c

Sappiamo che questo è un dispositivo USB wireless, e non un dispositivo ATM o SCSI, per cui possiamo tranquillamente ignorare i file trovati nelle directory atm e scsi. Quindi resta da cercare solo il file drivers/ net/wireless/zd1211rw/zd_usb.c.

zd_usb.c mostra la stringa 157e nel seguente pezzo di codice:

static struct usb_device_id usb_ids[]    ={
      /* ZD1211 */
      { USB_DEVICE(0x0ace, 0x1211),   .driver_info =  DEVICE_ZD1211  },
      { USB_DEVICE(0x07b8, 0x6001),   .driver_info =  DEVICE_ZD1211  },
      { USB_DEVICE(0x126f, 0xa006),   .driver_info =  DEVICE_ZD1211  },
      { USB_DEVICE(0x6891, 0xa727),   .driver_info =  DEVICE_ZD1211  },
      { USB_DEVICE(0x0df6, 0x9071),   .driver_info =  DEVICE_ZD1211  },
      { USB_DEVICE(0x157e, 0x300b),   .driver_info =  DEVICE_ZD1211  },
      /* ZD1211B */
      { USB_DEVICE(0x0ace, 0x1215),   .driver_info = DEVICE_ZD1211B },
      { USB_DEVICE(0x157e, 0x300d),   .driver_info = DEVICE_ZD1211B },
      {}
};

Come per i driver PCI, i driver USB dicono al kernel quali dispositivi supportano affinché il kernel possa associare il driver al dispositivo. Ciò viene fatto usando una variabile di tipo struct usb_device_id, come mostrato qui. Questa è una lista dei differenti vendor e product ID che sono supportati da questo driver. La linea:

{ USB_DEVICE(0x157e, 0x300b), .driver_info = DEVICE_ZD1211 },

mostra che il nostro vendor e product ID sono supportati da questo driver.

Una volta che avete il nome del driver che è necessario per controllare il dispositivo, lavorate a ritroso tramite i Makefile del kernel, come descritto precedentemente nel capitolo su come abilitare il driver per compilarlo appropriatamente.

Riassumendo, i passaggi necessari per trovare quale driver USB controllerà uno specifico dispositivo USB sono:

  1. Trovare il vendor USB e il product ID del dispositivo per il quale si vuole trovare il driver, usando lsusb dopo aver aggiunto e rimosso il dispositivo per vedere cosa è cambiato nella lista.
  2. Cercare l'albero del codice sorgente del kernel per il vendor e il product ID del dispositivo USB. Sia il vendor e il product ID dovrebbero essere in una definizione struct usb_device_id.
  3. Cercare nei Makefile del kernel la regola CONFIG_ che compila questi driver, ricorrendo a find e grep:
    $ find -type f -name Makefile | xargs grep DRIVER_NAME
  4. Cercare nella configurazione di sistema del kernel il valore di quella configurazione e andate alla posizione nel menù che specifica di abilitare il driver per essere compilato.

Root filesystem

Il filesystem radice (root NdT) è il filesystem da cui la porzione principale del sistema in esecuzione si avvia. Contiene tutti i programmi iniziali che fanno partire la distribuzione e solitamente contiene anche l'intera configurazione di sistema della macchina. In breve, è molto importante, e deve essere in grado di esser trovato dal kernel a tempo di avvio (boot time NdT) affinché le cose funzionino propriamente.

Se il vostro nuovo kernel configurato muore a boot time con un errore del tipo:

VFS: Cannot open root device hda2 (03:02)
     Please append a correct "root=" boot option
     Kernal panic: VFS: Unable to mount root fs on 03:02

significa che il root filesystem non è stato trovato. Se non state usando un'immagine ramdisk a boot time, è solitamente raccomandabile che compiliate nel kernel sia il filesystem che usate come partizione di root che il controller per quel disco nel kernel, invece di averlo come modulo. Se invece usate un ramdisk a boot time, dovreste essere coperti anche compilando queste porzioni come moduli.

Warning 65x68.jpg
Come potete determinare se state usando un ramdisk a boot time? Nel Capitolo 5 abbiamo menzionato l'uso dello script di installazione della vostra distribuzione per installare il kernel rispetto all'effettuare l'installazione per proprio conto. Se state usando lo script di installazione della distribuzione, state probabilmente già usando un ramdisk. Se invece lo state installando per vostro conto, probabilmente non lo state usando.

Le sottosezioni seguenti mostrano come lasciare che il kernel trovi il root filesystem durante il boot.

Tipo del filesystem

Per prima cosa, bisogna determinare il tipo di filesystem che la partizione di root sta utilizzando. Per fare ciò, si guardi al risultato del comando mount:

$ mount | grep " / "
/dev/sda2 on / type ext3 (rw,noatime)

Siamo interessati al tipo di filesystem, che viene mostrato dopo la parola type. In questo esempio è ext3. Questo è il tipo di filesystem che la partizione di root sta usando. Andate nel sistema di configurazione del kernel e siate sicuri che questo tipo di filesystem sia abilitato, come descritto nel Capitolo 8.

Controller del disco

Nell'output del comando mount appena mostrato, la prima porzione della linea mostra su quale dispositivo a blocchi il root filesystem è montato. In questo esempio è /dev/sda2. Ora che il filesystem è correttamente configurato nel vostro kernel, dovete essere sicuri che questo dispositivo a blocchi funzionerà correttamente. Per trovare quali driver sono necessari, ancora una volta bisognerà guardare in sysfs.

Tutti i dispositivi a blocchi sono mostrati in sysfs in /sys/block oppure in /sys/class/block, a seconda della versione del kernel che state usando. In entrambi i luoghi, i dispositivi a blocchi costituiscono un albero, con le diverse partizioni figlie del dispositivo principale:

$ tree -d /sys/block/ | egrep "hd|sd"
|-- hdc
|-- hdd
`-- sda
 |-- sda1
 |-- sda2
 |-- sda3

Data l'informazione nel comando di mount, dovete essere sicuri che il dispositivo sda2 è configurato correttamente. Poiché questa è una partizione (le partizioni di un disco sono numerate, mentre i dispositivi a blocchi principali non lo sono), l'intero dispositivo sda deve essere configurato. (Senza il dispositivo a blocchi principale, non c'è possibilità di accedere alle partizioni individuali su quel dispositivo).

Il dispositivo a blocchi sda è rappresentato semplicemente come il dispositivo di rete che abbiamo visto precedentemente in questo capitolo. Esiste un symlink nella directory del dispositivo chiamato device che punta al dispositivo logico che controlla il dispositivo a blocchi:

$ ls -l /sys/block/sda
...
device -> ../../devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0
...

Ora avete bisogno di iniziare a percorrere la catena dei dispositivi nel sysfs per trovare quale driver sta controllando questo dispositivo:

$ ls -l /sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0
...
driver -> ../../../../../../bus/scsi/drivers/sd
...

Qui vediamo che il driver del controller del disco SCSI è responsabile per il funzionamento di questo dispositivo. Così sappiamo che dobbiamo configurare il supporto ai dischi SCSI nella nostra configurazione del kernel.

Continuando a salire la catena delle directory in sysfs, provate a trovare dov'è il driver che controlla l'hardware:

$ ls -l /sys/devices/pci0000:00/0000:00:1f.2/host0
...

Ancora, nessun driver qui. Continuando di un livello in su:

$ ls -l /sys/devices/pci0000:00/0000:00:1f.2
...
driver -> ../../../bus/pci/drivers/ata_piix

Eccolo! Questo è il controller del disco che abbiamo bisogno di assicurarci sia nella nostra configurazione del kernel.

Così per questo root filesystem, abbiamo bisogno di abilitare i driver ext3, sd, e ata_piix nella nostra configurazione del kernel, così che saremo capaci di fare il boot con successo del nostro kernel su questo hardware.

Script d'aiuto

Come menzionato all'inizio del capitolo, file e directory in sysfs cambiano da una versione del kernel a un'altra. Qui c'è uno script che è a portata di mano per determinare i necessari driver del kernel e il nome del modulo per ogni dispositivo nel sistema. È stato sviluppato con gli sviluppatori del kernel responsabili per sysfs e dovrebbe funzionare con successo con tutte le versioni future del kernel 2.6 .

Per esempio, liquida il precedente esempio, quando dovevate prendere tutti i driver appropriati per i dispositivi a blocco sda:

$ get-driver.sh sda
looking at sysfs device: /sys/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0
found driver: sd
found driver: ata_piix

Posso anche trovare tutto sui driver appropriati necessari per cose complicate come i dispositivi USB-to-serial:

$ get-driver.sh ttyUSB0
looking at sysfs device: /sys/devices/pci0000:00/0000:00:1d.3/usb4/4-2/4-2.3/4-2.3:1.0/ttyUSB0
found driver: pl2303 from module: pl2303
found driver: pl2303 from module: pl2303
found driver: usb from module: usbcore
found driver: usb from module: usbcore
found driver: usb from module: usbcore
found driver: uhci_hcd from module: uhci_hcd

Potete scaricare un file di esempio contenente questo script dal web site del libro, fornito nella sezione "How to Contact Us" nella prefazione (ossia qui NdT).

Di seguito lo script:

#!/bin/sh
#
# Find all modules and drivers for a given class device.
#
if [ $# != "1" ] ; then
 echo
 echo "Script to display the drivers and modules for a specified sysfs class device"
 echo "usage: $0 <CLASS_NAME>"
 echo
 echo "example usage:"
 echo " $0 sda"
 echo "Will show all drivers and modules for the sda block device."
 echo
 exit 1
fi
DEV=$1
if test -e "$1"; then
 DEVPATH=$1
else
 # find sysfs device directory for device
 DEVPATH=$(find /sys/class -name "$1" | head -1)
 test -z "$DEVPATH" && DEVPATH=$(find /sys/block -name "$1" | head -1)
 test -z "$DEVPATH" && DEVPATH=$(find /sys/bus -name "$1" | head -1)
 if ! test -e "$DEVPATH"; then
  echo "no device found"
  exit 1
 fi
fi
echo "looking at sysfs device: $DEVPATH"
if test -L "$DEVPATH"; then
 # resolve class device link to device directory
 DEVPATH=$(readlink -f $DEVPATH)
 echo "resolve link to: $DEVPATH"
fi
if test -d "$DEVPATH"; then
 # resolve old-style "device" link to the parent device
 PARENT="$DEVPATH";
 while test "$PARENT" != "/"; do
  if test -L "$PARENT/device"; then
   DEVPATH=$(readlink -f $PARENT/device)
   echo "follow 'device' link to parent: $DEVPATH"
   break
  fi
  PARENT=$(dirname $PARENT)
 done
fi
while test "$DEVPATH" != "/"; do
 DRIVERPATH=
 DRIVER=
 MODULEPATH=
 MODULE=
 if test -e $DEVPATH/driver; then
  DRIVERPATH=$(readlink -f $DEVPATH/driver)
  DRIVER=$(basename $DRIVERPATH)
  echo -n "found driver: $DRIVER"
  if test -e $DRIVERPATH/module; then
   MODULEPATH=$(readlink -f $DRIVERPATH/module)
   MODULE=$(basename $MODULEPATH)
   echo -n " from module: $MODULE"
  fi
  echo
 fi
 DEVPATH=$(dirname $DEVPATH)
done

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.



Capitolo originale