Configurare, compilare e installare un kernel 2.6 per (open)SUSE Linux
Autore e copyright: Dr. Thomas
Hertweck
Versione: 0.8; aggiornamento al: 6 Agosto 2006
Correzioni, proposte, miglioramenti, modifiche per la parte italiana
a:
Luigi di Lazzaro
Sommario
- Come utilizzare questo documento
- Prefazione
- Il codice sorgente del kernel
- Scompattare il codice sorgente
- Patching del codice sorgente
- Clonare una configurazione esistente
- Adattare la release del kernel
- Configurare il kernel
- Compilare il kernel
- Installare il kernel
- Riconfigurazione del bootloader
- Problemi in fase di boot con il nuovo kernel
- Varie
- Installazione di più di un kernel con RPM
- Installazione di moduli kernel esterni
- Il processo di boot
- Il kernel Linux: l'inizio di tutto
- Links
- Ringraziamenti
- Disclaimer
Come utilizzare questo documento
La versione più recente di questo documento si trova sempre al
seguente indirizzo: https://www.thomashertweck.de/kernel26i.html.
In questo howto si farà riferimento sempre a SUSE e non a Novell o
al progetto openSuse per non complicare inutilmente la materia. Questo
documento non è collegato nè direttamente nè
indirettamente con Novell/SUSE, per cui, qualora dovessero insorgere dei
problemi con esso, non si potrà fare uso del modulo di feedback.
Tutti i marchi protetti qui citati appartengono al rispettivo
proprietario.
Configurare, compilare e installare un kernel è un'operazione complessa. Parte delle operazioni deve essere eseguita da root ed errori o sviste possono avere conseguenze fatali per il sistema, per cui si raccomanda la massima cura e attenzione. Per cortesia, si leggano le varie sezioni sempre completamente prima di passare all'azione. Questo documento si riferisce principalmente all'installazione di un kernel della serie 2.6 su architettura x86. Ovviamente non si possono prevedere tutte le eventualità o situazioni in cui è dato incorrere, da qui la necessità di comprendere perfettamente i singoli comandi prima di eseguirli o di adattarli alle proprie esigenze. Il testo è organizzato secondo la sequenza logica delle singole operazioni e può quindi servire da traccia. Informazioni aggiuntive, spiegazioni più dettagliate o altre cose importanti di cui occorre tenere conto, sono presentate su sfondo colorato ed evidenziate da icone specifiche :
![]() |
Annotazioni |
![]() |
Spiegazioni |
![]() |
Importante |
Nomifile o simili (in particolare quando riportano codici di versione) hanno funzione d'esempio e vanno sostituiti con i nomifile, patches, ecc... effettivamente presenti. Ovviamente le istruzioni non possono essere adattate ogni volta che viene rilasciata una nuova versione del kernel. Il manoscritto non ha pretese di infallibilità o completezza e ovviamente non si danno garanzie nè si assumono responsabilità per eventuali danni diretti o indiretti. Vedasi l'avviso (Disclaimer al termine del documento).
Prefazione
L'installazione del codice sorgente del kernel, la configurazione e la compilazione di un kernel personalizzato può servire a tante cose. Forse si vuole iniziare a programmare sul kernel oppure si vuole avere accesso alla documentazione, che viene installata assieme al codice sorgente. O forse si vuole semplicemente imparare qualcosa di nuovo divertendosi. Si fa notare che l'installazione di un kernel autocostruito non è un'operazione priva di rischi, per cui sarà bene premunirsi eseguendo un backup prima di inziare e procurandosi anche un CD di salvataggio. Per questo scopo si può ricorrere al CD/DVD di SUSE, ma anche il CD/DVD di Knoppix https://www.knopper.net/knoppix/ si presta allo scopo.
Questo testo si riferisce principalmete alla distribuzione (open)SUSE Linux ; tuttavia le istruzioni fornite dovrebbero essere facilmente adattabili anche ad altre distribuzioni.
Questo howto si propone di facilitare il compito ai principianti. Esperti non scopriranno nulla di nuovo. Esistono molti testi in lingua inglese riguardo al kernel di Linux, poca documentazione aggiornata in lingua tedesca e probabilmente altrettanto poca in lingua italiana. Sollecitato da diverse parti, l'autore ha deciso di raccogliere in un documento in lingua tedesca le informazioni fondamentali riguardanti l'argomento kernel; la successiva traduzione in lingua italiana rende le informazioni disponibili ad un fetta più ampia di appassionati.
Il documento non va scambiato con una ricetta e meno che mai va interpretato come un invito a manipolare un software fondamentale per la macchina senza farsi troppi pensieri. Taluni kernel possono richiedere l'update di altri pacchetti (per es. mkinitrd, udev, o simili) per funzionare correttamente. Il kernel 2.6 viene rielaborato con continuità e al momento non esiste una linea di sviluppo separata. Ciò significa che nuove versioni non devono necessariamente essere compatibili con le versioni precedenti. L'abitudine abbastanza diffusa di voler sempre avere la versione più nuova del software ("versionitis") è, almeno nel caso del kernel, sicuramente controproducente! Su sistemi SUSE i security-updates possono essere installati con YOU (YaST Online Update) e questo vale anche per il kernel. Neanche i KOTD devono venire installati partendo dal codice sorgente in quanto è sufficiente aggiungere con YAST agli archivi la relativa directory del server ftp (o di un mirror). Chi decide di mettere in pratica le istruzioni contenute in questo documento deve rendersi conto di quello che sta facendo e deve aver compreso perfettamente concetti e istruzioni esposte. Chi decide di affrontare spensieratamente la materia non troverà alcuna compassione.
Due parole sul kernel 2.6: nel Dicembre 2003 veniva dichiarato stabile e rilasciato ufficialmente il kernel 2.6.0. La serie 2.6, mantenuta e curata da Andrew Morton, sostituisce la vecchia versione stabile 2.4. Con il kernel 2.6 fanno il loro ingresso nel mondo linux diversi tra ampliamenti e miglioramenti, che avrebbero anche giustificato una serie 3.0. Questa possibilità era anche stata oggetto di discussione per diverso tempo. A differenza dei problemi insorti con la serie 2.4 (tra l'altro di stabilità, per la sostituzione del Virtual-Memory-Management all'interno di una serie dichiarata stabile, per problemi con il filesystem ReiserFS e NFS - in ultima istanza la release 2.4.11 era stata ufficialmente dichiarata "don't use"), si è fatta attenzione al funzionamento stabile e affidabile delle features più importanti. Di seguito alcune delle modifiche principali:
- Supporto per svariate nuove piattaforme.
- Sistema di assemblaggio del kernel rinnovato e migliorato, con diverse nuove funzionalità.
- Codice ACPI nuovo, sensibilmente più robusto, USB 2.0, driver IPMI, supporto espansioni BIOS (per esempio EDD, SBF) e molte altre cose.
- Reimplementazione del layer IDE (in parte ripreso dalla serie 2.4) e Tagged Command Queueing per devices IDE; eliminazione dell'emulazione ide-scsi e accesso diretto ai masterizzatori CD/DVD attraverso l'interfaccia ATAPI compreso il DMA. Inoltre sono state apportate modifiche significative all'input-layer, block-layer e al memory-management-layer.
- Introduzione di un nuovo modello di drivers LDM (Linux Device Model).
- Introduzione di un nuovo filesystem sysfs in funzione di interfaccia tra il modello drivers LDM e lo user-space. Per il futuro è previsto il passaggio di tutti i dati delle periferiche dal filesystem /proc al filesystem sysfs.
- Il kernel 2.6 supporta oltre a modprobe anche un hotplug-executable.
- Integrazione di LM-sensors, miglioramenti del suspend-to-disk e del decremento dinamico del clock CPU (Speedstep, PowerNow).
- Miglioramenti fondamentali per scalabilità e reazione (nuovo 0(1)-scheduler, con un algoritmo indipendente dal numero dei processi, nuovo block-device-layer compreso I/O-scheduler e I/O asincrono; supporto NUMA; riduzione degli spin-locks globali).
- Estensione del sottosistema VM (per esempio: reverse mapping).
- Rivisitazione del codice AGP e supporto per AGP 3.0.
- Rielaborazione del framebuffer-layer.
- Creazione di funzionalità real-time basate su preemption (in parte presenti già nel kernel 2.4).
- Inserimento della Native POSIX Thread Library (NPTL) e quindi thread-model rinnovato.
- Impianto del filesystem XFS e implementazione di un nuovo quota-code nel layer VFS; POSIX-ACLs; driver NTFS rinnovato e velocizzato.
- Integrazione della Advanced Linux Sound Architecture (ALSA).
- Supporto completo per IPv6 e IPSec oltre al supporto per lo Stream Control Transport Protocol (STCP).
Queste sono solo alcune delle modifiche rispetto al kernel della serie 2.4. Il progresso maggiore viene sicuramente dai miglioramenti riguardanti le caratteristiche di latenza e scalabilità, che riducono sensibilmente le distanze rispetto ai sistemi unix commerciali.
Viene chiesto molto di frequente quanto spazio sia
necessario avere sul disco e il tempo occorrente per compilare un kernel.
Di seguito alcune indicazioni approssimative: la directory con i codici
sorgente decompressi del kernel 2.6.16 richiede circa 275MB (kernel
SuSE). Durante il processo di compilazione vengono creati diversi,
ulteriori files (object-files, header- files, ecc.), per cui per un
kernel attuale si dovranno mettere in preventivo circa 400MB di spazio su
disco (con quasi tutte le funzioni del kernel attivate). Kernel
più recenti abbisognano per solito di uno spazio maggiore. Il
tempo impiegato per la compilazione dipende in larga misura da CPU e RAM,
ma anche dalla configurazione impostata. Si va da pochi minuti (PC
moderni con abbondante RAM) fino ad alcune ore per macchine vecchie o
molto vecchie. Per fortuna è possibile compilare un kernel per una
macchina anche molto datata su di un sistema nuovo, più
veloce.
Il codice sorgente del kernel
Prima di poter iniziare con la configurazione bisogna ovviamente procurarsi il codice sorgente del kernel desiderato. Vi sono diverse possibilità al riguardo:
- (open)SUSE-DVD oppure un archivio online: qui è possibile reperire il codice sorgente del kernel di prima installazione. Chi ha spazio sul disco sufficiente potrà installare il codice sorgente durante la prima installazione.
- https://www.kernel.org/ o un mirror: qui si possono trovare i codici sorgente attuali (ma anche quelli meno recenti) sotto forma di archivio compresso bzip o gzip oltre a patches per versioni più nuove o per kernel particolari. Kernel di provenienza kernel.org vengono chiamati di solito Vanilla. I kernel Vanilla non sono disponibili in formato RPM.
Per orientarsi rapidamente tra le varie versioni attuali
del kernel si può ricorrere al programma "finger"
contenuto nell'omonimo rpm. Un "finger @finger.kernel.org"
riporta le informazioni richieste in un terminal. Tuttavia questa
funzionalità non va assolutamente utilizzata per eseguire un
monitoraggio automatico. L'informazione cercata può essere
ottenuta anche direttamente da https://www.kernel.org/kdist/finger_banner
- ftp://ftp.suse.com/pub/projects/kernel/kotd/ o un mirror del server ftp di SUSE: qui si trova il codice sorgente (oltre a kernel precompilati in formato RPM) del kernel SuSE 2.6 più recente. SUSE non supporta ufficialmente questi kernel, ma li mette a disposizione della comunità per prove o esperimenti. Questi kernel vengono anche chiamati Kernel-Of-The-Day (KOTD). È possibile quindi che qualcosa non funzioni come previsto; eventualmente si rendono necessari updates di altri pacchetti. In linea di massima però questi kernel sono relativamente stabili. I kernel di prova KOTD possono essere installati con YAST se nell'elenco degli archivi di YAST è stato inserito il repository corretto.
I kernel SUSE sono diversi dai kernel Vanilla. Il kernel
SUSE deriva dal kernel Vanilla, ma vengono applicati dei patches
specifici di SUSE. Se alcuni di questi patches risultano collegati con
features rilevanti del sistema SUSE, può capitare che un kernel
vanilla non funzioni correttamente su di un sistema SUSE.
Per il download del codice sorgente si raccomanda di utilizzare sempre un mirror locale, per non sovraccaricare i server FTP originali di kernel.org ovvero suse.com/opensuse.org. Un elenco di mirror è riportato sul sito web di openSUSE https://de.opensuse.org/Mirror_della_versione_stabile oppure https://www.novell.com/de-de/products/linuxprofessional/downloads/ftp/index.html. Un elenco di mirrors di kernel.org si trova presso https://www.kernel.org/mirrors/. Inoltre anche parecchi server dell'elenco SUSE fanno da mirror parziali per kernel.org.
Kernel diversi come per esempio il kernel SUSE-default o
il kernel SUSE-SMP vengono creati sempre partendo dal medesimo
codice sorgente, questo significa che esiste un unico RPM con il codice
sorgente del kernel SUSE. I kernel sono diversi solo per la
configurazione.
I pacchetti kernel-source-2.6.xx-y.rpm e
kernel-source-2.6.xx-y.src.rpm sono diversi e servono
per scopi diversi. Se si vuole installare il codice sorgente del kernel
si dovrà ricorrere al primo citato. Il secondo è un
cosiddetto source-RPM che può venire compilato con il comando
"rpmbuild --rebuild" (rpm v4, a partire da SUSE Linux 9.0). Se
si installa questo source-RPM si cercherà inutilmente il codice
sorgente nella directory /usr/src! Infatti, in questo caso il
codice sorgente (raccolto in un archivio tar con eventuali patches)
è stato scompattato assieme ad un cosiddetto spec-file in
/usr/src/packages nei sottoindirizzari SOURCES ovvero
SPECS. È così possibile in teoria adattare il file
spec, applicare un patch al codice sorgente del kernel o assemblare un
nuovo source-RPM. questo procedimenteo non verrà approfondito in
questa sede. Dettagli si trovano nel manuale "Maximum
RPM" (in inglese) o "Das RPM
Buch" (in tedesco).
Esistono alcune persone che mettono a disposizioni o
mantengono patches ufficiali per i kernel Vanilla. Al momento il patchset
più importante viene curato da Andrew Morton, il manutentore dello
stable tree per il kernel della serie 2.6. È marcato con un "-mm"
e riporta bugfixes, estensioni o integrazioni per il kernel 2.6. Patches
denominati "-rc" sono cosiddetti "release candidates", cioè
precursori della prossima versione.
A partire dal kernel 2.6.11 la versione può
essere indicata con quattro cifre. Si è ricorsi a questa
possibilità con il kernel 2.6.8 per poter rilasciare un bug-fix
urgente. Le versioni a quattro cifre correggono solamente errori reali e
confermati e non contengono innovazioni! La quarta cifra integra
l'indicazione classica costituida da Major-Version ("2"), Minor-Version
("6") e Patch-Level (z.B. "11").
Scompattare il codice sorgente
Il codice sorgente del kernel della distribuzione SUSE può essere facilmente installato con YAST2 (o con un altro software di management dei pacchetti). Ad installazione completata si dovrà trovare un sottoindirizzario nella directory /usr/src con il codice sorgente. Probabilmente anche il link /usr/src/linux punterà verso questo nuovo indirizzario. Qualora il codice sorgente venga installato successivamente e al kernel effettivo sia già stato applicato un patch con YOU, si dovrà riavviare YOU per aggiornare il codice sorgente alla versione attuale.
Se il codice sorgente scaricato dal server ftp di (open)SUSE è presente in formato RPM e lo si vuole installare in parallelo con il codice sorgente del kernel della distribuzione non si potrà ricorrere al comando "rpm -Uhv kernel-source.nuovo.rpm", perchè così si sovrascriverebbe il codice sorgente già installato. A seconda di come è stato assemblato il pacchetto RPM si potrà installarlo semplicemente con il comando
$> su $> rpm -ihv /percorso/verso/kernel-source.nuovo.rpm
Se RPM dovesse segnalare conflitti si potrà eventualmente ricorrere alle opzioni RPM "--nodeps --force". Un
$> su $> rpm -ihv --force --nodeps /percorso/al/kernel-source.nuovo.rpm
dovrebbe anch'esso installare correttamente il codice sorgente nella directory /usr/src in una propria sottodirectory. questa è probabilemnte una delle poche occasioni in cui è consentito ricorrere alle opzioni RPM citate. In linea generale i conflitti segnalati da RPM non vanno ignorati! Con "rpm -qpl /percorso/al/kernel-source.nuovo.rpm" si può verificare prima il punto in cui verrà installato il codice sorgente e,qualora fosse già presente una directory con lo stesso nome, si potrà spostarla o rinominarla. Inoltre è possibile verificare se il pacchetto RPM installerà files in directory diverse da /usr/src. Probabilmente, come osservato in precedenza, il link /usr/src/linux punterà punterà verso la nuova directory.
Se il codice sorgente è presente sotto forma di archivio tar (p.e. il codice sorgente del kernel Vanilla), lo si dovrà prima scompattare con il progarmma tar. Per evitare conflitti si dovranno verificare prima i nomi delle directory kernel presenti in /usr/src (la directory in cui per solito si installa il codice sorgente del kernel) modificandoli (temporaneamente).
$> su $> cd /usr/src/ $> tar xvjf /percorso/verso/linux-2.6.17.tar.bz2
ovvero
$> tar xvzf /percorso/verso/linux-2.6.17.tar.gz
Esiste la possibilità di assegnare la directory così creata e i file in essa contenuti ad un semplice user (e al gruppo relativo) per eseguire la compilazione (per eseguire la compilazione basta uno user; solo per l'installazione bisogna ricorrere a root). Eseguire dunque un:
$> chown -R myuser. linux-2.6.17 $> exit
(ci troviamo sempre ancora nella directory /usr/src). L'indicazione "myuser" va ovviamente adattata. Lo stesso dicasi per il nome della directory con il codice sorgente. Chi fa ricorso alla nuova funzionalità build-directory del kernel 2.6 può fare a meno di modificare il proprietario della directory.
Il kernel 2.6 offre la possibilità di indicare
una build-directory. Per solito si salvano i files di configurazione e i
files generati dal compilatore nella stessa directory in cui si trova il
codice sorgente. Se si ricorre ad una build-directory i files vengono
inseriti in una directory diversa da quella contenente il codice
sorgente. In questo modo diventa possibile separare completamente la
directory di assemblaggio dalla directory contenente il codice sorgente,
con un incremento notevole in termini di flessibilità. Questa
funzionalità non era presente nei kernel della serie 2.4.
L'impiego della build-directory viene reso possibile dall'indicazione
"O=/percorso/verso-la/build/directory" al make - la variabile
KBUILD_OUTPUT del makefile viene impostata e tutti i files prodotti
vengono deviati. La directory da passare a make deve naturalmente
esistere altrimenti viene segnalato un errore!
Si osservi che nel caso in cui si ricorra ad una
build-directory l'indicazione
"O=/percorso/verso-la/build/directory" deve essere fornita per
ognuno dei comandi make (di seguito descritti più da
vicino) oppure (ed è il metodo più comodo), dopo
aver clonato o creato una configurazione, ci si sposta nella directory di
build e si immettono i comandi di make da lì!
A questo punto si raccomanda un'ispezione in veste di semplice user della directory ./Documentation, che si trova subito sotto la directory con il codice sorgente e la lettura del file "Changes". Di particolare interesse in questo file è il capitoletto "Current Minimal Requirements": in esso sono descritti i requisiti minimi per l'impiego del nuovo kernel. Eventualmente si dovranno rinnovare alcuni pacchetti di software prima di poter impiegare il kernel nuovo. Nel caso in cui si installasse il codice sorgente del kernel fornito assieme alla distribuzione non occorrerà ovviamente verificare nulla, poichè i requisiti minimi devono essere soddisfatti in ogni caso. Naturalmente andranno rinnovati solo i pacchetti che vengono effettivamente utilizzati: se, per esempio, non si impiega il filesystem XFS non sarà necessario rinnovare i pacchetti relativi, anche se i "Current Minimal Requirements" non dovessero risultare soddisfatti.
Il link /usr/src/linux è una fonte
continua di equivoci. In linea di principio questo link non serve
più (Linus Torvalds va anche oltre e ne propone l'abolizione). Per
configurare, compilare e installare un nuovo kernel esso non è
più necessario. Se però il link esiste, sarebbe opportuno
se puntasse sempre verso il codice sorgente del kernel attivo. Il link
viene utilizzato spesso (purtroppo) per compilare moduli esterni al
kernel; il makefile corrispondente non esamina sempre il link
/lib/modules/`uname -r`/build (come sarebbe corretto), ma
confida in una corretta impostazione del link /usr/src/linux. Il
modulo però verrà caricato e funzionerà solamente se
per la sua compilazione sono stati adoperati gli header-files corretti.
Quindi, se esiste un link /usr/src/linux che punta verso una
directory contenente il codice sorgente di un kernel (meno recente)
attualmente in funzione, durante l'installazione del nuovo codice
sorgente esso può rimanere inalterato. Solo dopo che si è
compilato, installato e avviato con successo il kernel nuovo conviene
adattare il link /usr/src/linux alla nuova situazione. Se il
codice sorgente viene installato con un pacchetto RPM può capitare
che il link venga aggiornato automaticamente. Verificare e intervenire
manualmente (o cancellare completeamente il link).
Ogni distribuzione arriva con due sets di
kernel-headers: i "System Kernel Headers" e i "Kernel Source Headers". I
"System Kernel Headers" sono gli header-files che vengono effettivamente
utilizzati dal sistema. Ogni programma presente nel cosiddetto user-space
(cioè ogni applicazione) viene compilato con l'aiuto di questi
header-files. Di solito questi header-files si trovano in
/usr/include/asm e /usr/include/linux. Questi files non
dovrebbero mai essere sostituiti salvo il caso di un update
della C library (un'operazione che si sconsiglia, perchè difficile
anche per chi è già molto esperto!). Questi header-files
possono essere utilizzati con molti kernel diversi (esiste un codice di
compatibilità) e fanno parte del pacchetto glibc. Per solito
vengono installati con il pacchetto glibc-devel. Ogni utente intenzionato
a compilare programmi propri dovrebbe avere installato questo pacchetto
di development! I "Kernel Source Headers" fanno parte del codice sorgente
del kernel. Questi header-files non dovrebbero mai venire
inclusi direttamente nel codice sorgente degli applicativi (salvo poche
eccezioni). Nelle distribuzioni più vecchie
/usr/include/linux e /usr/include/asm erano links
simbolici verso le sottodirectory del codice sorgente in
/usr/src/linux e non contenevano quindi un proprio set di
header-files, ragion per cui il link /usr/src/linux era
assolutamente necessario. Difficile imbattersi attualmente ancora in una
simile costellazione. I "Kernel Source Headers" vengono utilizzati per
compilare il kernel stesso o i suoi moduli. Il makefile per la
compilazione di moduli esterni al kernel non dovrebbe dunque fare
affidamento sull'esistenza di un link /usr/src/linux nè
sulla sua corretta impostazione (per permettere l'individuazione degli
header-files nella sottodirectory ./include del codice sorgente
del kernel), ma invece dovrebbe esaminare il link /lib/modules/`uname
-r`/build.
La directory con il codice sorgente non deve
necessariamente trovarsi sotto /usr/src, anche se si tratta di
un'abitudine consolidata. In linea di principio è possibile
spostarla dove si vuole. In quest'ultimo caso vanno verificati i links
/usr/src/linux e /lib/modules/`uname -r`/build se
presenti, qualora si voglia spostare il codice sorgente dopo
l'installazione dei moduli. In caso di dubbio si consiglia di eliminare
completamente il link /usr/src/linux!
Patching del codice sorgente
Può essere necessario eseguire un patch sul codice sorgente, ad esempio per utilizzare una preversione di un nuovo kernel o per aggiornare il codice sorgente presente.
Fare attenzione con il patching: il patch deve corrispondere esattamente con il codice sorgente installato, in caso contrario il patch non funzionerà oppure sarà richiesto un intervento manuale. Per fare ancora un esempio, volendo passare dal codice sorgente del Vanilla 2.6.17 alla versione 2.6.18-rc3, andrà applicato il patch patch-2.6.18-rc3.bz2 (eventualmente anche compresso con gzip, nel qual caso esso presenterà il suffisso .gz) al codice sorgente della versione 2.6.17. Patches nella forma patch-2.6.x-yy.bz2 vengono applicati esclusivamente alla versione stabile del codice del kernel. Questo significa che per eseguire il patch patch-2.6.x-rc3.bz2 non è necessario eseguire prima i patches -rc1 e -rc2, ma il patch va applicato direttamente al codice sorgente del kernel 2.6.(x-1). Vanno tenuti distinti i patches incrementali, che hanno la denominazione patch-2.6.x-yy-zz.bz2; e, come suggerito dalla denominazione, andrebbero eseguiti sul codice sorgente del kernel 2.6.x-yy (si tratta di un kernel sul quale è già stato eseguito un patch), che verrebbe trasformato in un kernel 2.6.x-zz. Sembra un po' complicato, ma una volta comprese le convenzioni diventa abbastanza semplice.
Per eseguire il patch vero e proprio si ricorre al programma "patch" presente sotto forma di RPM sui CD o sul DVD della distribuzione. Di regola i patches sono compressi, per cui occorrerà procedere come segue:
$> cd /usr/src/linux-2.6.x $> gunzip -c /percorso/verso/patch.gz | patch -p1 --dry-run
ovvero
$> bunzip2 -c /percorso/verso/patch.bz2 | patch -p1 --dry-run
a seconda che il patch sia stato compresso con gzip o con bzip. L'opzione "--dry-run" non modifica i files e verifica solo l'applicazione del patch. Nel caso di un patch correttamente eseguito non verranno rivolte domande all'operatore e dovranno apparire sul terminale solamente i nomi dei files ai quali il patch è stato applicato con successo. Se il sistema segnala un errore già con il primo file, probabilmente è sbagliata l'opzione -p1 del comando patch. Questa opzione indica il numero di / da togliere nei nomi file elencati nel patch. Ciò dipende dal modo in cui è stato creato il patch e, in caso di problemi, si potrà adattare l'opzione -p (eventualmente -p0 oppure anche -p2). Se il test ha successo si potrà eseguire il patch cancellando l'opzione "--dry-run":
$> gunzip -c /percorso/verso/patch.gz | patch -p1
ovvero
$> bunzip2 -c /percorso/verso/patch.bz2 | patch -p1
Se il patch non corrisponde esattamente con il codice sorgente del kernel può capitare che alcuni files non vengano lavorati. In questo caso vengono generati files con il suffisso .rej. Chi è abbastanza progredito può tentare di eseguire a mano il patch rifiutato, ma si tratta di un'operazione che si raccomanda solo a chi ha esperienza. Per un'analisi precisa si consiglia di protocollare l'output del comando patch; vedasi al riguardo il capitolo "Varie". Eseguito con successo il patch, andrebbero modificati i nomi delle directory con il codice sorgente. Per esempio, se si è eseguito un patch patch-2.6.18-rc3 sul codice sorgenti del kernel 2.6.17, si dovrebbe rinominare la directory:
$> su $> cd /usr/src/ $> mv linux-2.6.17 linux-2.6.18-rc3 $> exit
Anche se non assolutamente necessario, serve per mantenere l'orientamento. Come sempre si tratta di un esempio e le denominazioni da utilizzare vanno adattate alla propria realtà.
Per il patch si può anche utilizzare lo script ./scripts/patch-kernel presente nella directory del codice sorgente. Un breve messaggio di aiuto si ottiene con un:
$> ./scripts/patch-kernel -h
nella directory principale del codice sorgente. Per ulteriori informazioni sul patching vedasi anche
$> man patch
come intuibile :-). Recentemente è stato presentato un programma sulla Linux Kernel Mailinglist (LKML) in grado di eseguire un patch anche su codici sorgente anche un po' diversi. Il programma di Neil Brown si chiama "Wiggle" e può essere scaricato da https://cgi.cse.unsw.edu.au/~neilb/source/wiggle/. Ovviamente il programma ha i suoi limiti, ma in certi casi può risultare molto utile.
Un patch eseguito con successo può essere
annullato con l'identico comando e con l'opzione "-R"! Purtroppo
la pagina del manuale non è molto chiara al riguardo, per cui si
riporta esplicitamente questa possibilità.
Per prudenza e per avere un kernel-tree sicuramente
pulito si potrà utilizzare il seguente comando. Esso
cancellerà tutti i files generati, una eventuale configurazione
presente ed anche tutti i files di backup eventualemente presenti
riportando il codice sorgente allo stato primitivo:
$> cd /usr/src/linux-2.6.x
$> make mrproper
Vedasi al riguardo il capitolo "Varie".
Clonare una configurazione esistente
Può capitare di dover trasferire una configurazione esistente su codici sorgente nuovi. Poter partire con una configurazione funzionante da adattare poi alle proprie esigenze può essere particolarmente utile per chi inizia. Vi sono diversi metodi per clonare una configurazione esistente. Dipende tra l'altro dalla presenza o meno della build-directory. Come accennato in precedenza, la build-directory serve a tenere separati i files generati durante configurazione e compilazione del kernel dai files del codice sorgente.
- Build-directory e /proc/config.gz presenti:
In questo caso la clonazione della configurazione è estremamente semplice, poichè la configurazione del kernel attivo può essere copiata direttamente dal proc-filesystem:$> cd /usr/src/linux-2.6.x $> zcat /proc/config.gz > /percorso/alla/build/directory/.config $> make O=/percorso/alla/build/directory oldconfig $> make O=/percorso/alla/build/directory modules_prepare
- Build-directory presente e /proc/config.gz assente:
In questo caso la copia diventa un pochino più complicata. Si dovrà copiare manualmente il vecchio file di configurazione (sperando che esista) .config, forse salvato con un nome diverso, nella build-directory:$> cd /usr/src/linux-2.6.x $> cp /percorso/al/vecchio/.config /percorso/alla/build/directory/.config $> make O=/percorso/alla/build/directory oldconfig $> make O=/percorso/alla/build/directory modules_prepare
- Build-directory assente e /proc/config.gz presente:
In questo caso la clonazione è semplificata, poichè la configurazione può essere letta direttamente dal proc-filesystem:$> cd /usr/src/linux-2.6.x $> zcat /proc/config.gz > .config $> make oldconfig $> make modules_prepare
- Build-directory e /proc/config.gz assenti:
In questo caso la copia diventa nuovamente un po' più complicata. Si dovrà copiare manualmente il vecchio file di configurazione (sperando che esista) .config, forse salvato con un nome diverso, nella directory del codice sorgente:$> cd /usr/src/linux-2.6.x $> cp /percorso/al/vecchio/.config .config $> make oldconfig $> make modules_prepare
Se il codice sorgente da configurare appartiene al kernel attivo non vengono rivolte domande all'operatore. Se il codice sorgente è più recente del kernel attivo verranno probabilmente poste alcune domande riguardanti l'attivazione di funzioni nuove o diverse. Alle domande si risponderà di conseguenza.
Utilizzando il codice sorgente (open)SUSE con il kernel
SUSE attivo ovvero con l'opzione "Kernel .config support" (cioè lo
pseudo-file /proc/config.gz viene generato), si può
clonare una configurazione con i comandi:
$> cd /usr/src/linux-2.6.x
$> make cloneconfig && make modules_prepare
Questo procedimento non funziona con i kernel Vanilla provenienti da
kernel.org. Se si impiega una build-directory:
$> cd /usr/src/linux-2.6.x
$> make O=/percorso/alla/build/directory cloneconfig &&
\
make O=/percorso/alla/build/directory modules_prepare
Adattare la release del kernel
Prima di compilare un nuovo kernel si dovranno porre in essere accorgimenti per evitare conflitti. Questo significa che al nuovo kernel dovrà essere data una denominazione univoca diversa per evitare conflitti con kernel e moduli già installati sul sistema.Questo passo non solo non si rende necessario, ma si rivela addirittura controproducente se si è clonata una configurazione per, ad esempio, compilare moduli esterni per il kernel attivo. I problemi qui esposti si presentano solamente se sivuole compilare es installre un kernel accatno ad un kernel già presente nel sistema.
Perchè è importante? Per esempio: si
supponga che sul sistema sia installato solamente il kernel
2.6.16-default (file vmlinuz nella directory /boot) e i
relativi moduli si trovino in /lib/modules/2.6.16-default/. A
questo punto si decide di creare un nuovo kernel, modificando alcune
opzioni nel file di configurazione e di installare il nuovo kernel
accanto a quello presente sul sistema. Clonata la configurazione,
modificate le opzioni secondo le proprie necessità, compilato e
installato il nuovo kernel con i suoi moduli si pone un problema: per
questo nuovo kernel i moduli verranno installati probabilmente nella
stessa directory /lib/modules. Però, siccome la
configurazione è stata modificata (si sono forse introdotte nel
nuovo kernel opzioni, che prima erano realizzate sotto forma di modulo o
viceversa), ne risulta un conflitto! Può anche capitare che un
kernel meno recente richieda impostazioni diverse nel file
/etc/modprobe.conf. Esistono poi altre possibili
incompatibilità. In questo paragrafo si propongono soluzioni al
problema.
Il procedimento da seguire per impostare una release univoca è diverso a seconda che si tratti di un kernel Vanilla o di un kernel SUSE. Procedimento per il kernel Vanilla:
Per l'installazione di kernel diversi evitando conflitti si utilizzerà la variabile EXTRAVERSION nel Makefile. Editare il Makefile presente nella directory principale del codice sorgente. Esso inizia come segue:
VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 17 EXTRAVERSION = .7
L'aggiunta di una EXTRAVERSION identifica in modo univoco la kernel release, evitando collisioni con altri kernel. Il Makefile può essere modificato e salvato come segue:
VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 17 EXTRAVERSION = .7-th1
Il kernel compilato, installato e attivato sulla macchina risponderebbe al comando "uname -r" con un 2.6.17.7-th1 e i moduli corrispondenti verrebbero installati nella directory /lib/modules/2.6.17.7-th1, senza scontrarsi quindi con i moduli di un altro kernel 2.6.17.7 già presente.
Adattatato quindi il makefile alle proprie esigenze, si potrà passare alla configurazione o alla compilazione del codice sorgente.
Nel caso di un kernel SUSE si può inserire una denominazione univoca durante la fase di configurazione (vedasi al riguardo la prossima sezione). Il punto "General Setup" offre l'opzione "Local version - append to kernel release". Questa opzione potrà eventualmente essere già impostata a "-default", come è consuetudine per i kernel SUSE (senza SMP). Questa impostazione può essere integrata come per il kernel Vanilla in modo da ottenere una denominazione di release univoca. La lunghezza dell'opzione non deve superare i 64 caratteri.
Il Makefile del kernel è in grado di mostrare la denominazione di release configurata:
$> cd /percorso/alla/build/directory $> make kernelrelease
Consentendo cosí un facile controllo.
Configurare il kernel
Il sistema offre diverse possibilità per eseguire la configurazione del kernel. Come detto in precedenza, si raccomanda di eseguire la configurazione come semplice user. Per una configurazione (quasi) automatica esistono le seguenti possibilità (i comandi vengono immessi dalla directory pricipale del codice sorgente):
- "make oldconfig" ovvero "make
O=/percorso/alla/build/directory oldconfig"
Questa possibilità di configurazione è già stata descritta: la clonazione (e l'integrazione) di una vecchia configurazione già esistente, vedasi il capitolo "Clonazione di una configurazione esistente". - "make defconfig" ovvero "make
O=/percorso/alla/build/directory defconfig"
In questo modo si crea automaticamente un nuovo file di configurazione. Le opzioni vengono impostate con dei valori standard. - "make allmodconfig" ovvero "make
O=/percorso/alla/build/directory allmodconfig"
Così si crea automaticamente una configurazione in cui, per quanto possibile, ogni opzione viene realizzata sotto forma di modulo. - "make allyesconfig" ovvero "make
O=/percorso/alla/build/directory allyesconfig"
Si crea automaticamente un file di configurazione in cui viene sempre risposto "si" a tutte le opzioni. - "make allnoconfig" ovvero "make
O=/percorso/alla/build/directory allnoconfig"
Si genera automaticamente una configurazione nuova, minima, in cui per quanto possibile viene risposto "no" a tutte le opzioni del kernel. - "make randconfig" ovvero "make
O=/percorso/alla/build/directory randconfig"
Questo comando produce una configurazione più o meno casuale.
Resta da osservare che la configurazione ottenute
mediante "defconfig", "allmodconfig", "allyesconfig", "allnoconfig" o
randconfig raramente porta a risultati accettabili. Però questa
opzione può servire da base di partenza o per tests. La
configurazione definitiva andrà adattata sempre alle reali
necessità con uno dei seguenti metodi.
- "make menuconfig" ovvero "make
O=/percorso/alla/build/directory menuconfig"
Il comando avvia una maschera d'immissione basata su ncurses. Per poter utilizzare questo metodo devono essere installati i pacchetti ncurses e ncurses-devel. - "make xconfig" ovvero "make
O=/percorso/alla/build/directory xconfig"
Questo metodo funziona solo in ambiente X11 (cioè in modalità grafica) e propone una maschera d'immissione basata sulla QT. Per utilizzare questo metodo di configurazione deve essere presente una QT funzionante (compreso il pacchetto qt-devel). - "make gconfig" ovvero "make
O=/percorso/alla/build/directory gconfig"
Anche questo metodo funziona solo in ambiente X11 (cioè in modalità grafica) e presenta una maschera d'immissione basata sulla GTK. Per servirsi di questo metodo deve essere presente una GKT+ funzionante (compreso il pacchetto pkgconfig).
Il programma di configurazione offre dei testi d'aiuto per ogni opzione da configurare. Se ne raccomanda un'attenta lettura fino a comprendere il significato dell'opzione corrispondente. Di solito viene anche consigliato cosa impostare in caso di dubbio. Non è possibile discutere tutte le opzioni di configurazione, perchè a) si uscirebbe dai limiti imposti da questo testo e b) funzioni e opzioni vengono aggiunte o modificate in continuazione, per cui questo testo non sarebbe mai aggiornato e c) ogni sistema è diverso a causa delle diverse composizioni a livello di hardware. Si elencano solo alcuni punti di particolare rilievo:
- Scelta del processore: in ogni caso scegliere il processore corretto per consentire un'ottimizzazione del kernel, con conseguenti vantaggi nelle prestazioni. Una scelta sbagliata può impedire la compilazione del kernel o, in seguito, causare il mancato avvio della macchina.
- Disattivare le funzioni di cui sicuramente non si ha bisogno (per esempio il supporto per Video4Linux, se nel sistema non è installata la relativa scheda oppure l'interfaccia Firewire (IEEE 1394) se non è presente). Così, oltre a eliminare potenziali conflitti, si riduce il tempo impiegato per la compilazione.
- Se si intende impiegare una Initial Ramdisk occorre atttivare la corrispondente opzione al punto "Block devices".
- Per un funzionamento corretto delle unità disco IDE va scelto il dispositivo adatto al punto "IDE/ATA/MFM/RLL support" ovvero il corrispondente driver SCSI alla voce "SCSI device support".
- Impostare correttamente le opzioni AGP al punto "Character devices". Se si impiegano driver NVIDIA o ATI si dovrà realizzare l'agpgart-support sotto forma di modulo, poichè questi driver cotengono un proprio modulo.
- Al punto "file systems" attivare il supporto per tutti i filesystem presenti sul sistema (almeno come modulo).
- Attivare l'opzione "Magic SysRq key" al punto "Kernel hacking". L'opzione consente eventualmente uno shutdown ordinato in caso di problemi. Dettagli al riguardo e una descrizione delle combinazioni di tasti disponibili sono descritti nel file ./Documentation/sysrq.txt nella directory del codice sorgente.
Per la configurazione di kernels SuSE impostare le
"Build options" con valori validi e inequivoci. Come accennato, queste
indicazioni sostituiscono l'editazione manuale del makefile e
l'adattamento delle variabile EXTRAVERSION.
Prima di abbandonare la maschera di configurazione si devono salvare le impostazioni, altrimenti le modifiche vanno perdute. Inoltre si può salvare la propria configurazione in un secondo file, con un nome qualunque. Si raccomanda questa operazione, perchè basta poco per sovrascrivere il file .config. Per questo secondo file (in linea di principio si tratta solo di una copia di .config), conviene scegliere un nome pregnante. Ovviamente si può eseguire anche una semplice copia dalla console. Tenere presente che se si impiega una buil-directory il file .config non viene inserito nella directory del codice sorgente, ma nella build-directory.
Dopo la configurazione e qualora si impieghi una build-directory conviene spostarsi all'interno di quest'ultima. Tutti i comandi make si immetteranno senza l'indicazione "O=/percorso/alla/build/directory". In analogia, di seguito si riportano i comandi di make senza l'indicazione della build-directory.
Compilare il kernel
Configurato il nuovo kernel, si passerà alla sua compilazione. Per solito si esegue questa operazione con i soli diritti di user (non come root), in analogia con quanto praticato per la configurazione. Per il kernel esiste la possibilità di creare un pacchetto RPM (rudimentale). Questa possibilità verrà esaminata più avanti. Il comando
$> make
ovvero
$> make all
compila kernel e moduli. Se si vuole compilare solamente il file del kernel (senza moduli), si potrà ricorrere al comando "make bzImage" (su sistemi i386). I moduli stessi vengono compilati successivamente immettendo un "make modules" ovvero "make O=/percorso/alla/build/directory modules". Supponendo una corretta compilazione, l'assenza di bugs nel codice del kernel o del compiler impiegato, il processo di compilazione e linking dovrà terminare senza messaggi d'errore.
Se il sistema, su cui si compila il kernel, è
dotato di più processori questi potranno essere utilizzati per
ridurre i tempi di compilazione. Allo scopo si potrà utilizzare
l'opzione "-j jobs" del comando make, con la quale si indica il
numero di job (comandi) eseguibili in parallelo. Quindi si potrebbe
compilare un kernel con:
$> make -j4 all
L'utilizzo di questa opzione fa senso solo su sistemi
multiprocessore.
Quale effetto ha il comando "make bzImage" (in
linea di principio dipende dall'architettura; qui si considera quindi
solo la famiglia x86)? Il primo passo consiste nel compilare i sorgenti
in C e in Assembler nel formato ELF (Executable and Linking Format)
Object-Files (.o); durante questo procedimento alcuni files vengono
raggruppati secondo uno schema logico e raccolti in archivi (.a). Con il
linker ld si collegano staticamente verso vmlinux gli
archivi e gli object-files. Con "nm vmlinux" viene generata la
System.map. Nella directory ./arch/i386/boot/ il codice
assembler del settore di boot bootsect.S viene preprocessato in
bbootsect.s, poi viene elaborato e convertito nel raw binary
bbootsect. Poi viene preprocessato il codice di setup
setup.S in bsetup.s, che viene a sua volta convertito
nel raw binary bsetup. Dopo il passaggio alla directory
./arch/i386/boot/compressed/, viene convertito
<source-directory/vmlinux nel formato raw binary, le sezioni
ELF .note e .comment vengono rimosse e salvate in un
file temporaneo. Subito dopo il file viene compresso con un "gzip
-9", convertito nel formato ELF "ld -r" e salvato in
piggy.o. Vengono compilate le routines di compressione
head.S e misc.c in head.o e misc.o,
per poi venire "linkate" assieme a piggy.o con
bvmlinux. bvmlinux viene portato nel formato raw binary
(dopo che sono state rimosse le sezioni ELF .note e
.comment) e salvato nel file bvmlinux.out. Per ultimo
in ./arch/i386/boot/ vengono riuniti i files bbootsect,
bsetup e compressed/bvmlinux.out con l'aiuto di
./arch/i386/boot/tools/build per formare il file
bzImage.
l'image del kernel è compressa. Si fa notare che
il nome "bzImage" non ha nulla a che vedere con il programma di
compressione bzip2. Il kernel viene compresso con gzip. Il nome "bzImage"
sta per "big zImage". In passato, quando l'image del kernel era
più piccola, il kernel veniva creato con il comando "make
zImage". La differenza tra "zImage" e "bzImage" consiste in un
layout e in un algoritmo di caricamento per il kernel diversi, per cui un
kernel creato con un "make bzImage" può avere dimensioni
maggiori, perchè in questo caso il kernel Linux viene caricato in
memoria oltre il limite di 1MB del real-mode.
Se la compilazione si interrompe con un "Signal 11" o
con un "Segmentation fault", la causa più probabile è un
difetto nell'hardware! Per solito si tratta di un banco RAM difettoso.
Raramente programmi di test delle memorie sollecitano le RAM in misura
maggiore del gcc, il programma di compilazione del kernel. Si può
dire che quando si compila un kernel si esegue anche un test
dell'hardware. Se, dopo un'interruzione di questo tipo, si riavvia il
compilatore con "make" e il processo di compilazione si
interrompe nuovamente con un "Signal 11", ma un po' più avanti
rispetto al primo tentativo, al 99,9% si tratta di un difetto
nell'hardware. Per questo genere di problemi si raccomanda una visita
all'indirizzo https://www.bitwizard.nl/sig11/.
La produzione di un pacchetto RPM per il kernel 2.6 con un proprio file di configurazione risulta molto facile; volendo, si crea automaticamente anche un source-RPM. Il pacchetto RPM può essere installato successivamente nel sistema molto semplicemente: occorre solamente creare un'eventuale ramdisk e adattare la configurazione del bootloader. Il pacchetto RPM si crea immettendo
$> make rpm-pkg
ovvero
$> make binrpm-pkg
(a seconda dei casi, cioè se si vuole avere anche un source-RPM). In luogo di "make rpm-pkg" si può anche immettere "make rpm". Dipende dalla configurazione del sistema se per questa operazione è necessario ricorrere a root. In /usr/src/packages/RPMS/i386/ verrà depositato il kernel compilato con i suoi moduli mentre il source-RPM si troverà in /usr/src/packages/SRPMS/ Se si ricorre ad un RPM non occorrerà compilare esplicitamente kernel e moduli (make bzw. make bzImage und make modules) nè ovviamente installare kernel e moduli manualmente (make modules_install). Al posto di queste operazioni verrà installato il pacchetto RPM (non scordarsi della Initial Ramdisk, se necessaria).
Il binary-RPM completato viene sempre inserito in
/usr/src/packages/RPMS/i386/, a prescindere dalle opzioni RPM
eventualmente selezionate. Questo dipende dal fatto che l'architettura
del sistema viene indicata nel kernel com i386, cioè il Makefile
del kernel sostituisce tutti i i?86 con i386. Ciò non significa
però che il kernel venga tradotto con l'opzione
"-march=i386". Questo dipende da arch/i386/Makefile, la
porzione del Makefile dipendente dall'architettura, che ricava i flags
ottimali di compilazione dall'opzione di configurazione relativa al
processore. Se nella configurazione del kernel si è impostata
l'opzione Pentium-M CPU, il compilatore utilizzerà
"-march=i686". Giustamente, il Makefile del kernel ricava flags
di compilazione ottimali sulla base del sistema di destinazione. Opzioni
RPM come "--target=i686" vengono ignorate, poichè
potrebbero scontrarsi con l'opzione impostata nella configurazione (il
nuovo kernel potrebbe eventualmente non funzionare sul sistema di
destinazione).
Installare il kernel
Compilati il kernel e i moduli per esso necessari, si dovrà procedere alla sua installazione. Si parte dal presupposto che le indicazioni circa la kernel-release siano state considerate. Diversamente potranno insorgere dei porblemi, specialmente se il nuovo kernel si scontra con il kernel standard di SUSE, pretendendo l'installazione dei moduli nella stessa directory. Si presuppone che non sia stato generato un RPM.
Per prima cosa si dovranno installare i moduli. Questa operazione (e le seguenti riguardanti l'installazione del kernel e la riconfigurazione del bootloader) deve essere eseguita da root. Ci troviamo sempre ancora nella directory principale ovvero nella build-directory:
$> su $> make modules_install
Il comando installa i moduli compilati in precedenza in /lib/modules/ e precisamente in una directory il cui nome corrisponde con il contenuto della variabile UTS_RELEASE del file ./include/linux/version.h. La variabile corrisponde con l'output prodotto dal comando "make kernelrelease" oppure da un "uname -r" una volta avviato il nuovo kernel. Il comando dovrebbe eseguire anche automaticamente un "depmod -ae" per attualizzare le dipendenze dei moduli.
A questo punto si copieranno il nuovo kernel e il file System.map (come root) nell'indirizzario /boot. Fare attenzione ad usare suffissi uguali per i files copiati nella directory /boot. I suffissi usati dovranno corrispondere con il nome dato alla directory in cui si sono installati i moduli (=kernel-release). Supponendo si sia creato un nuovo kernel 2.6.18-th1, i moduli corrispondenti sono stati installati in /lib/modules/2.6.18-th1, quindi si procederà con un:
$> cp ./arch/i386/boot/bzImage /boot/vmlinuz-2.6.18-th1 $> cp ./System.map /boot/System.map-2.6.18-th1
Si ossservi il trattino posto tra il nome del file e l'indicazione di versione.
Se si è inserito il nuovo kernel in un pacchetto RPM non si potranno installare manualmente kernel, moduli e il file System.map (come indicato sopra). Invece si dovrà installare da root il pacchetto binary-RPM. Il file spec utilizzato per la costruzione del kernel è molto semplice, per cui una initial ramdisk non viene generata automaticamente da uno script di postinstallazione. Quindi la initial ramdisk deve essere fatta a mano, come indicato più avanti. In alternativa si poterbbe creare un kernel-RPM con un file spec di SUSE adattato. In tal caso le operazioni manuali verrebbero eliminate quasi completamente. Tuttavia si consiglia questo metodo solo agli user progrediti, esperti nell'assemblaggio di pacchetti RPM.
Il file System.map, generato dal programma
"nm", contiene i nomi e gli indirizzi simbolici del kernel
Linux. Il file non è di vitale importanza, ma se si verifica un
cosiddetto kernel oops (che per solito viene registrato in
/var/log/messages) il programma "ksymoops" decodifica
il messaggio con l'aiuto del file System.map convertendolo in un
qualcosa di utile per gli sviluppatori del kernel. Il file
System.map viene dunque adoperato essenzialmente per il debug
del kernel. Ma anche il tool "ps" richiamato con l'opzione
"-l" ricorre alla System.map per il contenuto del campo
WCHAN nell'output. Da ps viene utilizzato il primo file
System.map utile secondo quest'ordine:
/boot/System.map-`uname -r`
/boot/System.map
/lib/modules/`uname -r`/System.map
/usr/src/linux/System.map
Come si vede, è molto utile dotare tutti i files presenti in
/boot di un suffisso, che corrisponde con l'output di "uname
-r". Informazioni più dettagliate sugli oops si trovano in
./Documentation/oops-tracing.txt nella directory del codice
sorgente.
Cos'è esattamente un oops? Chi sviluppa software
riconoscerà immediatamente l'errore: Signal 11 o "Segmentation
Fault". Un errore simile può verificarsi anche con il kernel. Se
il kernel di linux legge un pointer non valido, questo può avere
conseguente molto serie. Un oops dunque indica un bug nel kernel, che
andrebbe sempre corretto. In altre parole: un oops è il modo con
cui il kernel comunica all'operatore un evento particolarmente sgradevole
(solo un'attenta analisi dell'oops è in grado di fornire
informazioni più precise). Il kernel di Linux è comunque
particolarmente robusto per cui, contrariamente con quanto accade per il
segmentation fault di un programma, esso non dovrà necessariamente
diventare instabile o addirittura bloccarsi. Un oops non ha nulla in
comune con un kernel-panic. In quest'ultimo caso il kernel Linux si trova
in una situazione di stallo, il sistema deve essere riavviato.
Naturalmente anche un oops può causare un kernel-panic, se
l'errore coinvolge parti vitali del codice. Se l'errore si manifesta solo
in un driver probabilmente non ne nascerà un kernel-panic. Il
kernel probabilmente si ritirerà più o meno elegantemente
dal contesto e proverà a riportare la situazione sotto controllo.
L'oops verrà registrato attraverso i canali tradizionali in
/var/log/messages.
Eventualmente va creata una initial ramdisk per il nuovo kernel (da root):
$> cd /boot $> mkinitrd -k vmlinuz-2.6.18-th1 -i initrd-2.6.18-th1
Come si vede, anche la initial ramdisk andrebbe "versionata". Le opzioni "-k" e "-i" sono necessarie, perchè in loro assenza la initial ramdisk verrebbe compilata per il kernel attivo e non per il kernel nuovo. I moduli da inserire nella initial ramdisk vengono letti dal file /etc/sysconfig/kernel (variabile: INITRD_MODULES). Se si vogliono inserire altri moduli nella initial ramdisk se ne indicheranno i nomi dopo il parametro -m del comando mk_initrd. Vedasi anche "mk_initrd -h" per ulteriori dettagli. Uno splash-screen dovrebbe generarsi automaticamente. Allo scopo viene esaminato il file /etc/sysconfig/bootsplash. Per dettagli al riguardo (anche per l'impiego di themes propri) si veda https://www.bootsplash.org/.
Per l'installazione del kernel si può ricorrere
anche al comando "make install". Ma attenzione: il comando
modifica link simbolici nella directory /boot, che possono
riguardare le impostazioni standard del bootloader. Può capitare
quindi che, riavviata la macchina, sia presente ancora l'opzione del
vecchio kernel funzionante, ma alle spalle di essa si trovi il kernel
nuovo, per cui il boot con il vecchio kernel non è più
possibile. Eseguito un make install o si verificano subito le
impostazioni standard per il kernel default di SUSE o si installa il
kernel a mano, come indicato in precedenza. Questo ultimo metodo pare
più sicuro, poichè i singoli passi possono essere
ricontrollati e corretti.
Ora si andrà a riconfigurare il bootloader per avviare il nuovo kernel. Di seguito si descriverà questa operazione.
Riconfigurazione del bootloader
Chi impiega LILO dovrà adattare il file /etc/lilo.conf (da root). Il file va integrato con un ulteriore sezione per il nuovo kernel. Ci si potrà orientare osservando le sezioni esistenti. Una simile sezione potrebbe avere questo aspetto:
[...] image = /boot/vmlinuz-2.6.18-th1 label = linux2618 append = "selinux=0 splash=0 resume=/dev/hda7 showopts" initrd = /boot/initrd-2.6.18-th1 optional root = /dev/hda6 [...]
Una descrizione dettagliata delle opzioni si trova con un "man lilo.conf". Inoltre si raccomanda la lettura dei files presenti in /usr/share/doc/packages/lilo/.
Se nel file /etc/lilo.conf viene trovata
l'opzione default il sistema avvierà il kernel specificato in quel
punto, diversamente sarà il kernel specificato con "image" oppure
"other" (questo potrebbe essere anche un sistema operativo diverso da
linux). Si raccomanda di non assegnare immediatamente al kernel nuovo
l'opzione default, ma di sceglierlo dal menù o dal boot-prompt di
LILO. Una volta verificato il funzionamento del nuovo kernel, si
adatterà il file /etc/lilo.conf, assegnando a questo
kernel il default.
Dopo aver modificato il file /etc/lilo.conf si dovrà reinstallare il bootloader (da root!) come d'uso:
$> /sbin/lilo
Vengono elencati i labels di /etc/lilo.conf, il label che viene avviato per default viene contrassegnato con un asterisco *.
Per chi usa grub: la differenza maggiore tra LILO e grub sta nel fatto che grub è in grado di leggere la propria configurazione direttamente dalla directory di /boot. In caso di modifiche alla configurazione non sarà più necessario reinstallare il bootloader. Il file di configurazione si trova in /boot/grub e si chiama menu.lst. Un file menu.lst potrebbe contenere queste indicazioni:
default 0 title linux root (hd0,5) kernel /boot/vmlinuz root=/dev/hda6 vga=0x342 resume=/dev/hda7 showopts initrd /boot/initrd title linux2618 root (hd0,5) kernel /boot/vmlinuz-2.6.18-th1 root=/dev/hda6 vga=0x342 resume=/dev/hda7 showopts initrd /boot/initrd-2.6.18-th1
Con il seguente significato
- default: numero (partendo da 0) della sezione da avviare per default.
- title: opzione visibile del menù (corrisponde con il "label" di LILO).
- kernel: qui si indica il device e il percorso completo per l'image del kernel.
- root: il device per root.
- initrd: device e percorso completo per la Initial Ramdisk.
Nella notazione di grub un device viene indicato con (hdX,Y). X sta indicare il disco, si comincia a contare da 0 per il numero dei dischi presenti sul sistema. La sequenza viene definita dal BIOS di sistema. Y è il numero della partizione sul disco individuato precedentemente con X e anche qui si inizia a contare partendo da zero. Nell'esempio (hd0,5) corrisponde alla sesta partizione presente sul primo disco. Se /boot è una partizione separata e non fa parte della partizione root(/), potranno trovarsi per kernel e initrd impostazioni tipo "(hd0,0)/vmlinuz-2.6.18-th1" o "(hd0,0)/initrd-2.6.18-th1", con le partizioni indicate così come spiegato sopra.
Informazioni dettagliate riguardo la configurazione si possono trovare come sempre con "man grub" oppure "info grub" e naturalmente in /usr/share/doc/packages/grub/. Anche qui vale la regola di non assegnare ad un kernel nuovo l'opzione default senza averne prima verificato il corretto funzionamento.
Moduli, che non fanno parte dei sorgenti del kernel,
(come per esempio i moduli per i chips grafici) devono venire ricompilati
e installati dopo che il nuovo kernel è stato avviato! Per il caso
dei driver delle schede grafiche, avviare il kernel nuovo nel runlevel 3
immettendo un "3" al bootprompt (invece di partire con il runlevel
standard 5). Compilare e installare dalla console in nuovo driver. Si
veda al riguardo la documentazione presente nel pacchetto del driver per
la grafica.
Installato il kernel (e dopo aver eventualmente adattato il file /etc/modprobe.conf si dovrà riavviare la macchina. Se non si sono fatti errori, la macchina dovrebbe avviarsi senza problemi.
Problemi in fase di boot con il nuovo kernel
Durante l'avviamento del nuovo kernel potrà
apparire sulla console o in /var/log/boot.msg il seguente
messaggio:
Inspecting /boot/System.map-2.6.13-15.11-default
Loaded 24247 symbols from
/boot/System.map-2.6.13-15.11-default.
Symbols match kernel version 2.6.13.
No module symbols loaded - kernel modules not enabled.
Il messaggio non è originato direttamente dal kernel, ma da klogd,
il demone del kernel e proviene dal file ksym_mod.c del codice
sorgente di sysklogd. Qui si utilizza un metodo superato
(get_kernel_syms) per ottenere informazioni sui moduli. Un'indicazione al
riguardo si trova in "man get_kernel_syms": Because of these
limitations, this system call is deprecated in favor of query_module. Il
problema produce in ultima analisi un messaggio d'errore con il kernel
2.6 (impostazione CONFIG_MODULES=y nel file di configurazione
.config), nonostante i moduli vengano comunque utilizzati. Il
module-handling funzionerà correttamente, a dispetto del
messaggio, quindi non lasciarsi confondere! Se si vuole eliminare il
messaggio è necessario fare ricorso ad una versione (patch) nuova
di sysklogd.
Durante il boot del nuovo kernel possono presentarsi problemi. Essi stanno ad indicare che alcuni punti durante la configurazione o durante l'installazione non sono stati rispettati. Per esempio:
-
Il sistema si blocca al LILO o durante l'avviamento del nuovo kernel:Probabilmente LILO non è stato installato correttamente. Vedasi il messaggio di LILO. Forse è stato dimenticato il comando /sbin/lilo, dopo le modifiche al file di configurazione /etc/lilo.conf. Resettare la macchina, avviare il vecchio kernel e da root eseguire /sbin/lilo.
-
Il sistema si blocca con il messaggio: "Not a compressed kernel image file".Probabilmente è stata copiata un'image sbagliata verso /boot. Si deve utilizzare l'image ./arch/i386/boot/bzImage e non ./vmlinux (visto dalla directory principale del codice sorgente). Avviare la macchina con il vecchio kernel e correggere l'errore senza scordarsi di eseguire il comando /sbin/lilo.
-
Il nuovo kernel non parte e appare il messaggio: "No init found".Questo messaggio appare per solito se si è indicato il root-device sbagliato nella configurazione del boot-loader. Controllare questo particolare. Lo stesso errore capita se (a prescindere dalle cause) non è possibile avviare un programma di init (/sbin/init, /etc/init o /bin/init, in questo ordine). Dopo aver riavviato la macchina si potrà indicare al boot-prompt il root-device corretto con l'opzione "root=/dev/<device>", inserendo ovviamente il proprio root-device. Se il nuovo kernel parte regolarmente si dovrà modificare il file di configurazione del bootloader (se si utilizza LILO non dimenticarsi di eseguire anche uno /sbin/lilo).
-
Il nuovo kernel non si avvia e appare il messaggio "kernel panic: VFS: unable to mount root fs on <device>".Il messaggio indica che non è stato possibile montare il root-filesystem. Cause possono essere a) un mancato inserimento del supporto per il filesystem (ext2, ext3, ReiserFS, xfs, ecc.) nel kernel o b) il relativo modulo non è stato inserito nella initial ramdisk. È possibile anche che non sia stata creata una nuova initrd, siano stati fatti errori durante la sua creazione o nella configurazione del boot-loader sia stata indicata una initrd sbagliata. Per risolvere il problema si avvierà nuovamente il vecchio kernel e si correggerà la initrd e/o la configurazione del boot-loader.
-
Il nuovo kernel non parte e appare il messaggio "Unable to open an initial console":Possono esserci più ragioni. È possibile che il boot-loader non sia stato installato correttamente o sia stata indicata una root-partition sbagliata. Questi casi sono stati già trattati. Può essere che il nuovo kernel sia stato compilato senza il supporto per i terminals virtuali (e le console ad essi associate). Si tratta di un errore di configurazione per cui si dovrà riconfigurare, ricompilare e reinstallare il nuovo kernel. In ultimo può essere che sia stato cancellato il /dev/tty1, anche se per questo caso particolare sembrerebbe poco probabile.
-
Avviando il nuovo kernel appare il messaggio "System.map does not match actual kernel":Non è stato ricopiato il file System.map del nuovo kernel (con il suffisso di versione) verso la directory /boot. La soluzione è semplice: ricopiare il file System.map (con il suffisso di versione) verso la directory /boot. Vedasi anche il capitolo "Installazione del kernel".
-
All'avviamento dl nuovo kernel il video scompare:Una causa potrebbero essere problemi con il supporto per il framebuffer. In questo caso si può tentare di avviare la macchina immettendo al boot-prompt il parametro "vga=normal".
-
I driver NVIDIA/ATI (e quindi la grafica) non funzionano più con il nuovo kernel:Il modulo del driver NVIDIA/ATI per il nuovo kernel deve essere ricompilato e reinstallato.
-
Durante il boot appare il messaggio "Waiting for device /dev/<...> to appear" e il sistema rimane bloccato:Il programma udev crea per solito automaticamente i device-nodes, cosa che in questo caso non si verifica. Le cause possono essere a) una initial ramdisk sbagliata o afflitta da errori b) una versione di udev non corrispondente con il kernel c) una versione superata dello script mkinitrd. Esaminare queste possibilità ed eseguire le correzioni ncecesarie.
Il seguente articolo (in lingua tedesca) può
essere d'aiuto se si presentano problemi di boot: Oliver Diedrich (odi),
"Wenn der Pinguin nicht abhebt: Erste Hilfe bei Linux-Startproblemen",
Praxis PC-Selbsthilfe: Linux, lilo, grub, ext2, ext3, reiserfs, fsck, c't
26/01, Seite 130.
Varie
- Può essere necessario riportare le directory del codice
sorgente alla situazione di partenza (il discorso non vale per patches
già applicati). Anche il kernel dispone di un suo Mr. Proper per
le pulizie:
$> cd /usr/src/linux-2.6.x $> make mrproper
Il comando può essere utilizzato anche nella build-directory.
Il comando cancella il file .config
eventualmente presente! Se si vuole mantenere il file questo dovrà
essere salvato separatamente prima di eseguire il comando.
- Durante la compilazione di un kernel 2.6 si noterà l'assenza dei numerosi messaggi che accompagnavano la compilazione del kernel 2.4. L'output appare molto più ordinato. Se, come per il kernel 2.4, si volessero comunque vedere tutti i messaggi (di notevole aiuto in caso di problemi), si dovrà passare al make una variabile V=1. Il comando per la compilazione dei moduli diventerebbe dunque "make V=1 modules". Se si vogliono compilare tutti i files di una determinata sottodirectory del codice sorgente basterà immettere "make dir/", sostituendo /dir con il nome della directory effettiva (incluse eventualmente altre sottodirectory). Un unico file può essere compilato con un "make dir/file.o", dove "dir" sta per il nome della sottodirectory e "file.o" per il nome del file object. Un unico modulo può essere compilato con il comando "make dir/module.ko", dove "dir/ rappresenta la relativa sottodirectory e "module.ko" il modula da generare
Immettendo un "make help" nella directory del
codice sorgente si ottiene un breve messaggio d'aiuto (in inglese),
riguardo possibili targets del makefile. Viene riassunta la maggior parte
dei comandi citati in questo testo.
- Durante la compilazione del kernel o dei moduli (o, più in
generale, durante l'esecuzione dei targets del Makefile), ma anche
durante il patching appaiono sul terminale numerosi messaggi. Questi
messaggi si possono salvare in un file (di particolare utilità
se sono messaggi d'errore) per analizzare successivamente e con calma
gli errori o per chiedere consiglio a qualcuno. Uno strumento semplice
ed efficace viene offerto con il programma "tee". Il programma
legge dallo standard-input, scrive in copia sullo standard-output e in
aggiunta anche in un file. Il comando make può quindi essere
eseguito come segue (l'esempio si riferisce al target "bzImage"):
$> make bzImage 2>&1 | tee make_bzImage.log
I messaggi appaiono come al solito sulla console, ma in più lo standard-ouput e lo standard-error vengono deviati verso il file make_bzImage.log. Riguardo il trasferimento degli output standard ed error si veda "Una breve introduzione sull'output della shell" (non tradotto). - A volte lo spazio su disco a disposizione comincia a essere scarso, specie se si sono create alcune directory con i codici sorgente per kernel diversi. Una volta constatato il corretto funzionamento di un nuovo kernel si potrà eseguire nella directory del codice sorgente ovvero nella build-directory "make clean". Il comando cancella gli object-files generati dal compiler e libera un po' di spazio sul disco. Come detto, i codici sorgente del kernel non devono trovarsi obbligatoriamente nella directory /usr/src. Se vi sono presenti partizioni con più spazio si possono trasferire i codici sorgenti anche verso un altro posto. Inoltre la funzionalità build-directory del kernel 2.6 aggiunge ulteriore flessibilità.
Installazione di più di un kernel con RPM
Capita di frequente che, accanto al kernel di prima installazione, si voglia installare un altro kernel SuSE (per esempio un nuovo kernel sperimentale dall'archivio ftp di SUSE). Sarebbe comodo se si potesse fare con il comando RPM, senza dover compilare i codici sorgente stessi. SuSE mette a disposizione esplicitamente binary-rpms ( o si è assemblato un RPM, vedasi più sopra). Con il comando
$> rpm -ihv nuovo-kernel.rpm
si può tentare l'installazione. In caso di successo si potrà verificare ed adattare la configurazione del bootloader (non dimenticarsi della initial ramdisk). Come accennato in precedenza, si può aggiungere la directory KOTD di SUSE con YAST in funzione di archivio d'installazione. In questo modo si potranno installare kernel KOTD per mezzo del Software Management-System di SUSE (in questo caso però non si tratta d'installazioni di kernel in parallelo).
Il comando "rpm -Uhv nuovo-kernel.rpm"
sostituirà il kernel attualmente installato con il nuovo
kernel! Con questo metodo non è possibile installare kernel in
parallelo.
Per scoprire quale kernel-Rpm risulta installato
momentaneamente sul sistema si può utilizzare il comando "rpm
-qa | grep '^kernel'".
A secondo del procediemnto seguito nella creazione del file RPM, può capitare che vengano segnalati conflitti se si tenta l'installazione. Per risolvere il problema esistono diverse possibilità. Con il comando
$> rpm -qpl nuovo-kernel.rpm
si possono vedere i files che verrebbero installati sul sistema. Se non emergono gravi conflitti con kernel già installati sul sistema si può tentare l'installazione del nuovo kernel con l'opzione RPM "--force --nodeps". Si fa però presente che questo procedimento porta ad una banca dati RPM inconsistente. In alternativa si può fare in modo che dalla banca dati RPM venga cancellato il record del vecchio kernel (viene cancellata solo l'inserimento, non viene modificato il filesystem cioè non vengono cancellati files):
$> rpm -e --justdb vecchio-kernel
Ora è possibile installare il nuovo kernel:
$> rpm -ihv nuovo-kernel.rpm
Il comando crea la directory /lib/modules (che contiene i moduli del nuovo kernel) e ricopia l'image del kernel nella directory /boot. Una eventuale Initial Ramdisk dovrebbe venire creata correttamente durante l'installazione; diversamente (nel caso di kernel Vanilla) si dovrà intervenire manualmente come spiegato nel capitolo riguardante l'installazione del kernel. Attenzione: la cancellazione del kernel standard di SUSE dalla banca dati RPM comporta che in futuro non verranno più offerti kernel-updates attraverso YOU. Se si utilizza un proprio kernel si dovrà provvedere personalmente per gli aggiornamenti.
Per poter avviare tanto il vecchio quanto il nuovo kernel si dovrà eventualmente ancora riconfigurare il bootloader. Il procedimento è descritto nell'apposito capitoletto. Attenzione: controllare attentamente nomi e sezioni del file di configurazione del bootloader, pena il mancato avviamento del sistema.
Per il nuovo kernel vanno creati/installati i moduli
esterni.
Installazione di moduli kernel esterni
Capita talvolta che si debbano installare o aggiornare moduli esterni, che cioè non fanno parte del codice sorgente del kernel, poichè un modulo kernel binario di solito funziona solamente con una versione del kernel ben precisa. Moduli kernel possono eventualmente essere utilizzati con versioni del kernel non proprio identiche se è stato attivato il meccanismo chiamato "modversions" (impostabile tramite il file di configurazione del kernel). In questo caso viene aggiunto ad ogni simbolo (variabile, funzione) un codice di controllo. In questo modo dovrebbero essere disponibili informazioni sufficienti a scoprire un eventuale incompatibilità tra il modulo ed il kernel. In ogni caso è preferibile compilare sempre un modulo su misura per il kernel che si intende usare.
Per compilare un modulo esterno devono essere presenti determinati header-files del kernel. In altre parole, il kernel-source deve essere configurato correttamente. Se si è configurato, compilato ed installato un kernel e non si sono più apportate modifiche alla configurazione, il codice sorgente del kernel risulterà correttamente configurato. In tutti gli altri casi procedere come descritto nel capitoletto sulla clonazione di una configurazione. Particolarmente importante è il comando "make modules_prepare", poichè esso genera tra l'altro gli header-files collegati con il modulo esterno ( come per esempio: linux/version.h).
Il procedimento da seguire per compilare un modulo esterno dipende dal Makefile del modulo stesso. Di regola si parte dal presupposto che il kernel, per il quale si vuole compilare il modulo, sia quello attivo al momento sul sistema.
Per compilare il modulo esterno vero e proprio ci si sposterà nella sua source-directory. Con il comando
$> make -C /percorso/alla/build/directory M=$(pwd) modules
(si spera) verrà compilato il modulo esterno che potrà essere installato da root con un
$> make -C /percorso/alla/build/directory M=$(pwd) modules_install
Se inizialmente non si è fatto uso della build-directory si dovrà indicare all'opzione "-C" la directory del codice sorgente (al posto della build-directory). La lettura della documentazione del modulo può fornire ulteriori informazioni circa le modalità di compilazione. In caso di dubbio non rimane che analizzare il Makefile del modulo.
Il processo di boot
Il BIOS del PC avvia il processo di boot. Terminato il Power-on-self-test (POST), il BIOS cercherà di caricare il primo settore del primo dischetto, il cosiddetto bootsector. Se questo tentativo fallisce, il BIOS cercherà di leggere il primo settore del primo disco rigido. BIOS abbastanza recenti sono in grado di modificare la sequenza di lettura delle periferiche (floppy, disco rigido, CD-ROM, scheda di rete, ecc.) secondo i desideri dell'utente. Il boot del sistema operativo si svolge poi in più passi. Siccome lo spazio disponibile nel boot-sector è molto limitato, viene caricato per solito un secondo loader, ecc., fino a caricare il sistema operativo vero e proprio. In linea di principio la struttura del boot-sector è abbastanza semplice e la sua grandezza è sempre uguale a 512 bytes. Il codice inizia con l'offset 0 e il boot-sector termina sempre con il Magic Number 0xAA55.
Il boot da dischetto è molto semplice, poichè ogni dischetto dispone di un unico boot-sector. Dischi rigidi possono essere suddivisi in partizioni per il cui il boot si complica. Il BIOS nulla sa di questa ulteriore ripartizione, per cui si limita a leggere il primo settore del disco, chiamato anche Master Boot Record (MBR). La struttura del MBR è identica con quella di un qualsiasi altro boot-sector, cioè il codice inizia all'offset 0 e all'offset 0x1FE si trova il magic number 0xAA55. La parte terminale del MBR accoglie la partition table, che è costituita sempre da 4 registrazioni. Ogni registrazione nella partition table è lunga 16 bytes (boot-flag: 1 byte; numero di head d'inizio della partizione: 1 byte; numero settore e cilindro del boot-sector: 2 bytes; systemcode: 1 byte; numero di head alla fine della partizione: 1 byte; numero settore e cilindro dell'ultimo settore della partizione: 2 bytes; numero relativo del settore di inizio: 4 bytes; numero di settori nella partizione: 4 bytes). Dunque, un disco può essere suddiviso in 4 partizioni, le cosiddette partizioni primarie. Se questo non dovesse essere sufficiente si potrà ricorrere ad una partizione estesa. Quest'ultima accoglie come minimo almeno un device logico. La struttura del primo settore di una partizione estesa corrisponde con un MBR. La prima registrazione della partizione estesa contiene il primo device logico della partizione. La seconda viene utilizzata come pointer nel caso esistano ulteriori devices logici. Il pointer è impostato in modo da puntare dietro al device logico, dove, a sua volta, si trova una partition table con la registrazione del prossimo device logico. I devices logici sono dunque organizzati in una lista concatenata. Il primo settore di ogni partizione primaria o estesa contiene un boot-sector strutturato come descritto. Siccome è possibile avviare la macchina solo da una partizione, il boot-flag indica la partizione attiva. Il codice nel MBR deve dunque a) indicare la partizione attiva, b) caricare il boot-sector della partizione attiva con l'ausilio del BIOS e c) eseguire un salto logico verso l'offset 0 del boot-sector. Un bootloader come LILO o grub è in grado di sostituire il MBR con codice proprio o occupare il boot-sector di una partizione.
Se il bootloader (LILO o grub) viene installato nel MBR esso sostituisce il codice lì presente, cioè il MBR originale viene sovrascritto. Se il MBR originale non viene salvato automaticamente, si può provvedere con
$> dd if=/dev/hda of=MBR.backup bs=512 count=1
al salvataggio. Con
$> dd if=MBR.backup of=/dev/hda bs=446 count=1
si potrà ripristinare. Attenzione: questa è un'operazione estremamente delicata. Prestare la massima attenzione, pena la perdita di tutti i dati del disco. Se si vuole ripristinare la vecchia partition table si può ricorrere al parametro bs=512. Si raccomanda prudenza: è molto facile distruggere la propria partition table. Il boot-sector, che avvia il kernel Linux, può essere il boot-sector di Linux (corrisponde con arch/i386/boot/bootsect.S) o anche il boot-sector di un bootloader.
Il boot continua come segue: il BIOS sceglie il device di boot. Poi viene letto il boot-sector di questo device, nel nostro caso si tratta del boot-sector del bootloader sul disco rigido. Questo carica setup, routines di espansione e image del kernel in memoria. Un kernel originato da un "make bzImage" può essere trasferito con il BIOS-service "int 0x15" direttamente dalla zona bassa della memoria alla zona alta. (il boot-loader utilizza le stesse tecniche contenute nel boot-sector del kernel). Una volta caricato (un bootloader come LILO termina qui) viene elaborato arch/i386/boot/setup.S e si raggiunge il punto di ingresso start: viene inizializzata una parte dell'hardware e il processore viene posto nel "Protected Mode". In ultimo si passa all'inizio del kernel compresso che corrisponde con arch/i386/boot/compressed/{head.S,misc.c}. Il kernel viene espanso e vengono eseguite le inizializzazioni contenute in arch/i386/boot/compressed/head.S (per esempio inizializzazione della page-table, del coprocessore, dello stack, ecc.). Poi viene avviato start_kernel(). Qui avvengono le inizializzazioni "high level", tra l'altro: setup specifico per l'architettura, output del Linux-banner (versione kernel, compiler, ecc.); inizializzazione di IRQs, ACPI, scheduler, timer, ecc.; esame della riga di comando al boot (boot-parameter); inizializzazione della console e caricamento dinamico dei moduli; vengono permessi interrupts; accertamento dei BogoMIPS; inizializzazione del management della memoria e output del valori (riga di memory); inizializzazione del proc-filesystem, di diversi caches e del thread-handler; analisi di bugs specifici per l'architettura e attivazione di workarounds (per esempio il classico CPU "f00f Bug") Finalmente viene creato il kernel-thread init(), che inizializza i driver per l'hardware per poi avviare il programma init= immesso al boot come parametro o tentare uno /sbin/init, /etc/init o /bin/init (in questo ordine). Se nessuno dei programmi viene trovato viene tentato l'avviamento di una console di rescue con la shell /bin/sh. Se anche questo tentativo fallisce il l'elaborazione termina con un kernel-panic. Altrimenti il boot continua come descritto in "man init". Di solito vengono avviati i processi attivi in background e si provvede ad avviare il programma getty su ogni terminale connesso. Uno user può accedere al sistema.
Il boot non è descritto in modo completo ed esauriente, anche per i limiti imposti al documento. In pratica esso è molto più complicato, dato che si dovrebbe considerare l'impiego di una Initial Ramdisk o di un sistema multiprocessore. La descrizione in forma molto semplificata serve comunque a dare un'idea della complessità e dei processi che avvengono dietro le quinte.
Il kernel Linux: l'inizio di tutto
Linus Torvalds, uno studente finlandese a Helsinki, diede il via nel 1991 ad un piccolo, nuovo sistema operativo:
From: torvalds@klaava.Helsinki.FI (Linus Benedict Torvalds)
Newsgroups: comp.os.minix
Subject: What would you like to see most in minix?
Date: 25 Aug 91 20:57:08 GMT
Hello everybody out there using minix -
I'm doing a (free) operating system (just a hobby, won't be big and professional like gnu) for 386(486) AT clones. This has been brewing since april, and is starting to get ready. I'd like any feedback on things people like/dislike in minix, as my OS resembles it somewhat (same physical layout of the file-system (due to practical reasons) among other things).
I've currently ported bash(1.08) and gcc(1.40), and things seem to work. This implies that I'll get something practical within a few months, and I'd like to know what features most people would want. Any suggestions are welcome, but I won't promise I'll implement them :-)
Linus (torvalds@kruuna.helsinki.fi)
PS. Yes - it's free of any minix code, and it has a multi-threaded fs. It is NOT protable (uses 386 task switching etc), and it probably never will support anything other than AT-harddisks, as that's all I have :-(.
Il suo piccolo progetto ebbe una grande eco e un gruppo di attivisti formatosi rapidamente iniziò a sviluppare il nuovo sistema operativo. Oggi vi sono numerosi utenti che provano nuove versioni e contribuiscono a ripulire il software da errori. Linux viene sviluppato spesso a condizioni aperte e distribuite. Con "aperte" si intende dire che chiunque sia in grado di farlo può partecipare allo sviluppo. Per questo scopo è necessario un mezzo di comunicazione rapido, efficiente e su scala planetaria: internet. Non meraviglia quindi che buona parte dello sviluppo provenga da studenti, che hanno accesso a internet attraverso le università. Nella fase iniziale questi studenti avevano a disposizione equipaggiamenti modesti, per cui Linux è sempre ancora il sistema operativo a 32 bit, che necessita di meno risorse senza rinunciare a funzionalità. Nel frattempo Linux è presente su quasi tutto ciò che elabora bits e bytes. L'hardware supportato va da sistemi embedded ai mainframes IBM. Questa indipendenza dall'hardware non viene raggiunta da nessun altro sistema operativo.
Il rapido sviluppo di Linux è dimostrato dalle dimensioni del codice sorgente:
- Linux 0.01 (Sett. 1991) 10239 righe di codice, 0.2 MB
- Linux 0.10 (Dic. 1991) 17750 righe di codice, 0.4 MB
- Linux 0.99 (Dic. 1992) 81091 righe di codice, 2.2 MB
- Linux 1.0.0 (Marzo 1994) 176250 righe di codice, 4.7 MB
- Linux 1.2.0 (Marzo 1995) 310950 righe di codice, 8.4 MB
- Linux 2.0.0 (Giugno 1996) 777956 righe di codice, 22 MB
- Linux 2.2.0 (Genn. 1999) 1800847 righe di codice, 52 MB
- Linux 2.4.0 (Genn. 2001) 3377902 righe di codice, 100 MB
- Linux 2.6.0 (Dic. 2003) 5929913 righe di codice, 208 MB
Con una crescita esponenziale e si può immaginare cosa significa per i futuri kernel :-). L'obbiettivo di far funzionare la maggior parte del software GNU su Linux era già stato raggiunto con la versione 0.99.
Links
Alcuni links, che riguardano il kernel o altri aiuti. L'elenco non è completo, ma dovrebbe essere sufficiente per trovare ulteriori informazioni. Si osservi: la maggior parte della documentazione, che riguarda il kernel Linux, è redatta in inglese.
- https://www.kernel.org: l'indirizzo principale per il download del codice sorgente di Linux
- https://www.linux.org.uk/~davej/docs/post-halloween-2.6.txt: The post-halloween document. (aka, 2.6 - what to expect)
- https://www.kubieziel.de/computer/halloween-german.html: Post-Halloween Documents in tedesco.
- https://www.kniggit.net/wwol26.html: The Wonderful World of Linux 2.6
- https://thomer.com/linux/migrate-to-2.6.html: Migrating to Linux Kernel 2.6
- https://kernelbook.sourceforge.net/: The Linux Kernel: Blueprints for World Domination
- https://kernelbook.sourceforge.net/kernel-hacking.html/: Unreliable Guide To Hacking The Linux Kernel
- https://www.kernelnewbies.org/: Interesting information for Newbies to the Linux kernel
- https://lkml.org/: the Linux Kernel Mailing List (LKML)
- https://www.kerneltraffic.org/: Kernel Traffic - weekly newsletter about the Linux Kernel Mailing List
- https://www.tldp.org/HOWTO/Kernel-HOWTO/: the Linux Kernel HowTo
- https://www.tldp.org/HOWTO/KernelAnalysis-HOWTO.html: the Linux Kernel Analysis HowTo
- https://www.tldp.org/LDP/lkmpg/index.html: The Linux Kernel Module Programming Guide
- https://www.tldp.org/LDP/lki/index.html: Linux Kernel 2.4 Internals
- https://www.linuxhq.com/: the Linux information headquarters
- https://jungla.dit.upm.es/~jmseyas/linux/kernel/hackers-docs.html: Index of Documentation for People Interested in Writing and/or Understanding the Linux Kernel; un elenco lunghissimo di links di documentazione anche per dettagli particolari
Ringraziamenti
Un grazie a tutti quelli che hanno fornito idee e aiuto sulla mailinglist suse-linux@suse.com, che mi hanno incoraggiato e sostenuto durante la stesura di questa piccola traccia. Un grazie ad Andreas Winkelmann per il testo su grub e a Philipp Thomas, che mi ha esposto alcuni dettagli del kernel SuSE, a David Haller per il suo multi-kernel-howto. Inolter a Sebastian Huber, Klaus Ondrich, David Hundenborn, Hans-Robert Wagner, Horst Graffy und Guido Nottebrok (olte purtroppo ad alcuni anonimi), che con il loro feedback hanno contribuito a migliore il documento.
A personal note by the author: special thanks go to Luigi di Lazzaro for the translation into Italian! He did a magnificent job!
Disclaimer
Questo testo non avanza pretese di correttezza e completezza e naturalmente non si possono dare garanzie riguardo contenuti e conseguenze derivanti. Per completezza:
There is no warranty for this text. The author provides it 'as is', without warranty of any kind, either expressed or implied, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose. The entire risk as to the quality of this text is with you. In no event will any author named in this text be liable to you for damages, including any general, special, incidental or consequential damages arising out of any use of this text (including, but not limited to, loss of data, data being rendered inaccurate, or losses sustained by anyone as a result of using this text).
Può darsi che altri vedano le cose in modo diverso, ma mi auguro che il principio ispiratore venga condiviso e che il testo non contenga troppi bugs. Il manuale SuSE recita: Questo testo è frutto di molte ore di lavoro. Inevitabilmente vi saranno passaggi buoni e meno buoni. Anche se sono riuscito ad eliminare parecchi errori, non vorrei dare l'impressione di aver creato un prodotto finito. Gli errori grossi sono solo nascosti meglio ;-) e forse mi offerta data la possibilità di fare meglio la prossima volta. Pertanto correzioni, miglioramenti, consigli, critiche e lodi sono sempre benvenuti.
Dr. Thomas Hertweck