Un’introduzione ai processi di avvio di Linux

Comprendere i processi di avvio di Linux è importante per essere in grado sia di configurare Linux che di risolvere i problemi di avvio. Questo articolo presenta una panoramica della sequenza di avvio utilizzando il bootloader GRUB2 e la sequenza di avvio eseguita dal sistema di inizializzazione systemd.

In realtà, ci sono due sequenze di eventi che sono necessari per avviare un computer Linux e renderlo utilizzabile: avvio e avvio. La sequenza di avvio inizia quando il computer viene acceso, ed è completata quando il kernel viene inizializzato e systemd viene lanciato. Il processo di avvio poi prende il sopravvento e termina il compito di portare il computer Linux in uno stato operativo.

In generale, il processo di avvio e avvio di Linux è abbastanza semplice da capire. È composto dai seguenti passi che saranno descritti più in dettaglio nelle sezioni seguenti.

  • BIOS POST
  • Boot loader (GRUB2)
  • Inizializzazione del kernel
  • Avvio di systemd, il genitore di tutti i processi.

Nota che questo articolo copre GRUB2 e systemd perché sono gli attuali boot loader e software di inizializzazione per la maggior parte delle distribuzioni principali. Altre opzioni software sono state usate storicamente e si trovano ancora in alcune distribuzioni.

Il processo di avvio

Il processo di avvio può essere iniziato in uno dei due modi. In primo luogo, se l’alimentazione è spenta, l’accensione inizierà il processo di avvio. Se il computer sta già eseguendo un utente locale, incluso root o un utente non privilegiato, l’utente può avviare programmaticamente la sequenza di avvio usando la GUI o la linea di comando per avviare un riavvio. Un riavvio farà prima uno spegnimento e poi riavvierà il computer.

POST DEL BIOS

Il primo passo del processo di avvio di Linux non ha davvero nulla a che fare con Linux. Questa è la parte hardware del processo di avvio ed è la stessa per qualsiasi sistema operativo. Quando il computer viene alimentato per la prima volta, viene eseguito il POST (Power On Self Test) che fa parte del BIOS (Basic I/O System).

Quando IBM progettò il primo PC nel 1981, il BIOS fu progettato per inizializzare i componenti hardware. Il POST è la parte del BIOS il cui compito è di assicurare che l’hardware del computer funzioni correttamente. Se il POST fallisce, il computer potrebbe non essere utilizzabile e quindi il processo di avvio non continua.

Il POST del BIOS controlla l’operatività di base dell’hardware e poi emette un interrupt del BIOS, INT 13H, che individua i settori di avvio su qualsiasi dispositivo di avvio collegato. Il primo settore di avvio che trova e che contiene un record di avvio valido viene caricato nella RAM e il controllo viene poi trasferito al codice che è stato caricato dal settore di avvio.

Il settore di avvio è in realtà il primo stadio del boot loader. Ci sono tre boot loader usati dalla maggior parte delle distribuzioni Linux: GRUB, GRUB2 e LILO. GRUB2 è il più recente ed è usato molto più frequentemente in questi giorni rispetto alle altre opzioni più vecchie.

GRUB2

GRUB2 sta per “GRand Unified Bootloader, versione 2” ed è ora il bootloader principale per la maggior parte delle attuali distribuzioni Linux. GRUB2 è il programma che rende il computer abbastanza intelligente da trovare il kernel del sistema operativo e caricarlo in memoria. Poiché è più facile scrivere e dire GRUB che GRUB2, posso usare il termine GRUB in questo documento ma mi riferirò a GRUB2 a meno che non sia specificato diversamente.

GRUB è stato progettato per essere compatibile con la specifica multiboot che permette a GRUB di avviare molte versioni di Linux e altri sistemi operativi liberi; può anche caricare a catena il boot record di sistemi operativi proprietari.

GRUB può anche consentire all’utente di scegliere di avviare da diversi kernel per qualsiasi distribuzione Linux. Questo permette la possibilità di avviare una versione precedente del kernel se una aggiornata fallisce in qualche modo o è incompatibile con un pezzo importante di software. GRUB può essere configurato utilizzando il file /boot/grub/grub.conf.

GRUB1 è ora considerato legacy ed è stato sostituito nella maggior parte delle distribuzioni moderne con GRUB2, che è una riscrittura di GRUB1. Le distribuzioni basate su Red Hat hanno aggiornato a GRUB2 intorno a Fedora 15 e CentOS/RHEL 7. GRUB2 fornisce la stessa funzionalità di avvio di GRUB1, ma GRUB2 è anche un ambiente pre-OS basato su comandi simile a quello di un mainframe e permette una maggiore flessibilità durante la fase di pre-avvio. GRUB2 è configurato con /boot/grub2/grub.cfg.

La funzione primaria di entrambi i GRUB è quella di ottenere il kernel Linux caricato in memoria e in esecuzione. Entrambe le versioni di GRUB funzionano essenzialmente allo stesso modo e hanno le stesse tre fasi, ma userò GRUB2 per questa discussione su come GRUB fa il suo lavoro. La configurazione di GRUB o GRUB2 e l’uso dei comandi di GRUB2 è al di fuori dello scopo di questo articolo.

Anche se GRUB2 non usa ufficialmente la notazione di stadio per i tre stadi di GRUB2, è conveniente riferirsi ad essi in quel modo, così lo farò in questo articolo.

Fase 1

Come menzionato nella sezione BIOS POST, alla fine del POST, il BIOS cerca sui dischi collegati un record di avvio, di solito situato nel Master Boot Record (MBR), carica il primo che trova in memoria e poi inizia l’esecuzione del record di avvio. Il codice di bootstrap, cioè GRUB2 stage 1, è molto piccolo perché deve entrare nel primo settore da 512 byte del disco rigido insieme alla tabella delle partizioni. La quantità totale di spazio allocato per il codice di bootstrap effettivo in un classico MBR generico è di 446 byte. Il file da 446 byte per la fase 1 si chiama boot.img e non contiene la tabella delle partizioni che viene aggiunta al record di avvio separatamente.

Perché il record di avvio deve essere così piccolo, non è nemmeno molto intelligente e non capisce le strutture del filesystem. Quindi l’unico scopo dello stage 1 è quello di localizzare e caricare lo stage 1.5. Per fare questo, lo stage 1.5 di GRUB deve essere posizionato nello spazio tra il boot record stesso e la prima partizione del disco. Dopo aver caricato lo stage 1.5 di GRUB nella RAM, lo stage 1 gira il controllo allo stage 1.5.

Stage 1.5

Come detto sopra, lo stage 1.5 di GRUB deve essere situato nello spazio tra il boot record stesso e la prima partizione sul disco. Questo spazio è stato lasciato storicamente inutilizzato per ragioni tecniche. La prima partizione sul disco rigido inizia al settore 63 e con l’MBR nel settore 0, rimangono 62 settori da 512 byte-31.744 byte in cui memorizzare il file core.img che è lo stage 1.5 di GRUB. Il file core.img è di 25.389 byte, quindi c’è molto spazio disponibile tra l’MBR e la prima partizione del disco in cui memorizzarlo.

A causa della maggiore quantità di codice che può essere ospitato per lo stage 1.5, può avere abbastanza codice per contenere alcuni driver di filesystem comuni, come lo standard EXT e altri filesystem Linux, FAT, e NTFS. Il core.img di GRUB2 è molto più complesso e capace del vecchio GRUB1 stage 1.5. Questo significa che lo stage 2 di GRUB2 può essere localizzato su un filesystem EXT standard, ma non può essere localizzato su un volume logico. Quindi la posizione standard per i file della fase 2 è nel filesystem /boot, in particolare /boot/grub2.

Nota che la directory /boot deve essere situata su un filesystem supportato da GRUB. Non tutti i filesystem lo sono. La funzione dello stage 1.5 è quella di iniziare l’esecuzione con i driver del filesystem necessari per localizzare i file dello stage 2 nel filesystem /boot e caricare i driver necessari.

Stage 2

Tutti i file per GRUB stage 2 si trovano nella directory /boot/grub2 e in diverse sottodirectory. GRUB2 non ha un file immagine come le fasi 1 e 2. Invece, consiste principalmente di moduli runtime del kernel che sono caricati come necessario dalla directory /boot/grub2/i386-pc.

La funzione dello stadio 2 di GRUB2 è di localizzare e caricare un kernel Linux nella RAM e girare il controllo del computer al kernel. Il kernel e i suoi file associati si trovano nella directory /boot. I file del kernel sono identificabili in quanto sono tutti nominati a partire da vmlinuz. Puoi elencare il contenuto della directory /boot per vedere i kernel attualmente installati sul tuo sistema.

GRUB2, come GRUB1, supporta l’avvio da una selezione di kernel Linux. Il gestore di pacchetti di Red Hat, DNF, supporta il mantenimento di più versioni del kernel in modo che se si verifica un problema con la più recente, una vecchia versione del kernel può essere avviata. Per impostazione predefinita, GRUB fornisce un menu di pre-avvio dei kernel installati, inclusa un’opzione di salvataggio e, se configurata, un’opzione di ripristino.

La fase 2 di GRUB2 carica il kernel selezionato in memoria e gira il controllo del computer al kernel.

Kernel

Tutti i kernel sono in un formato compresso e autoestraente per risparmiare spazio. I kernel si trovano nella directory /boot, insieme a un’immagine iniziale del disco RAM e alle mappe dei dispositivi dei dischi rigidi.

Dopo che il kernel selezionato viene caricato in memoria e inizia l’esecuzione, deve prima estrarre se stesso dalla versione compressa del file prima di poter eseguire qualsiasi lavoro utile. Una volta che il kernel si è estratto, carica systemd, che è il sostituto del vecchio programma di init SysV, e gli gira il controllo.

Questa è la fine del processo di avvio. A questo punto, il kernel Linux e systemd sono in esecuzione, ma incapaci di eseguire qualsiasi compito produttivo per l’utente finale perché nient’altro è in esecuzione.

Il processo di avvio

Il processo di avvio segue il processo di avvio e porta il computer Linux in uno stato operativo in cui è utilizzabile per il lavoro produttivo.

systemd

systemd è la madre di tutti i processi ed è responsabile di portare l’host Linux in uno stato in cui può essere fatto un lavoro produttivo. Alcune delle sue funzioni, che sono molto più estese del vecchio programma init, sono quelle di gestire molti aspetti di un host Linux in esecuzione, compreso il montaggio dei filesystem e l’avvio e la gestione dei servizi di sistema necessari per avere un host Linux produttivo. Tutti i compiti di systemd che non sono legati alla sequenza di avvio sono al di fuori dello scopo di questo articolo.

Prima di tutto, systemd monta i filesystem come definito da /etc/fstab, compresi eventuali file di swap o partizioni. A questo punto, può accedere ai file di configurazione situati in /etc, incluso il suo. Usa il suo file di configurazione, /etc/systemd/system/default.target, per determinare quale stato o target, in cui dovrebbe avviare l’host. Il file default.target è solo un collegamento simbolico al vero file target. Per una workstation desktop, questo è tipicamente il graphical.target, che è equivalente al runlevel 5 nel vecchio SystemV init. Per un server, è più probabile che il default sia il multiutente.target che è come il runlevel 3 in SystemV. L’emergency.target è simile alla modalità utente singolo.

Nota che i target e i servizi sono unità di systemd.

La tabella 1, qui sotto, è un confronto dei target di systemd con i vecchi runlevel di avvio di SystemV. Gli alias dei target di systemd sono forniti da systemd per la compatibilità all’indietro. Gli alias di destinazione permettono agli script e a molti amministratori di sistema come me di usare i comandi di SystemV come init 3 per cambiare i runlevel. Of course, the SystemV commands are forwarded to systemd for interpretation and execution.

SystemV Runlevel systemd target systemd target aliases Description
halt.target Halts the system without powering it down.
0 poweroff.target runlevel0.target Halts the system and turns the power off.
S emergency.target Single user mode. No services are running; filesystems are not mounted. This is the most basic level of operation with only an emergency shell running on the main console for the user to interact with the system.
1 rescue.target runlevel1.target A base system including mounting the filesystems with only the most basic services running and a rescue shell on the main console.
2 runlevel2.target Multiuser, without NFS but all other non-GUI services running.
3 multi-user.target runlevel3.target All services running but command line interface (CLI) only.
4 runlevel4.target Unused.
5 graphical.target runlevel5.target multi-user with a GUI.
6 reboot.target runlevel6.target Reboot
default.target This target is always aliased with a symbolic link to either multi-user.target or graphical.target. systemd always uses the default.target to start the system. Il default.target non dovrebbe mai avere come alias halt.target, poweroff.target, o reboot.target.

Tabella 1: Confronto dei runlevel di SystemV con i target di systemd e alcuni alias di target.

Ogni target ha un insieme di dipendenze descritto nel suo file di configurazione. systemd avvia le dipendenze richieste. Queste dipendenze sono i servizi richiesti per far funzionare l’host Linux ad uno specifico livello di funzionalità. Quando tutte le dipendenze elencate nei file di configurazione dell’obiettivo sono caricate e funzionanti, il sistema è in esecuzione a quel livello di obiettivo.

systemd guarda anche le directory init legacy di SystemV per vedere se esiste qualche file di avvio. Se è così, systemd li usa come file di configurazione per avviare i servizi descritti dai file. Il deprecato servizio di rete è un buon esempio di uno di quelli che usano ancora i file di avvio di SystemV in Fedora.

La figura 1, sotto, è copiata direttamente dalla pagina man di bootup. Mostra la sequenza generale di eventi durante l’avvio di systemd e i requisiti di ordine di base per assicurare un avvio di successo.

I target sysinit.target e basic.target possono essere considerati come punti di controllo nel processo di avvio. Anche se systemd ha come uno dei suoi obiettivi di progettazione quello di avviare i servizi di sistema in parallelo, ci sono ancora alcuni servizi e obiettivi funzionali che devono essere avviati prima che altri servizi e obiettivi possano essere avviati. Questi punti di controllo non possono essere superati fino a quando tutti i servizi e i target richiesti da quel punto di controllo sono soddisfatti.

Così il target sysinit.target è raggiunto quando tutte le unità da cui dipende sono completate. Tutte queste unità, montare i filesystem, impostare i file di swap, avviare udev, impostare il seme del generatore casuale, avviare i servizi di basso livello e impostare i servizi crittografici se uno o più filesystem sono criptati, devono essere completati, ma all’interno del sysinit.target questi compiti possono essere eseguiti in parallelo.

Il sysinit.avvia tutti i servizi di basso livello e le unità necessarie affinché il sistema sia marginalmente funzionale e che sono necessarie per permettere il passaggio all’obiettivo basic.

local-fs-pre.target
|
v
(various mounts and (various swap (various cryptsetup
fsck services...) devices...) devices...) (various low-level (various low-level
| | | services: udevd, API VFS mounts:
v v v tmpfiles, random mqueue, configfs,
local-fs.target swap.target cryptsetup.target seed, sysctl, ...) debugfs, ...)
| | | | |
\__________________|_________________ | ___________________|____________________/
\|/
v
sysinit.target
|
____________________________________/|\________________________________________
/ | | | \
| | | | |
v v | v v
(various (various | (various rescue.service
timers...) paths...) | sockets...) |
| | | | v
v v | v rescue.target
timers.target paths.target | sockets.target
| | | |
v \_________________ | ___________________/
\|/
v
basic.target
|
____________________________________/| emergency.service
/ | | |
| | | v
v v v emergency.target
display- (various system (various system
manager.service services services)
| required for |
| graphical UIs) v
| | multi-user.target
| | |
\_________________ | _________________/
\|/
v
graphical.target

Figura 1: La mappa di avvio di systemd.

Dopo che l’obiettivo sysinit.target è soddisfatto, systemd avvia l’obiettivo basic.target, avviando tutte le unità richieste per soddisfarlo. L’obiettivo di base fornisce alcune funzionalità aggiuntive avviando le unità che sono richieste per l’obiettivo successivo. Queste includono l’impostazione di cose come i percorsi delle varie directory eseguibili, i socket di comunicazione e i timer.

Infine, gli obiettivi a livello utente, multi-user.target o graphical.target possono essere inizializzati. Notate che il target multiutente.target deve essere raggiunto prima che le dipendenze del target grafico possano essere soddisfatte.

I target sottolineati nella Figura 1, sono i soliti target di avvio. Quando uno di questi obiettivi viene raggiunto, allora l’avvio è completato. Se l’obiettivo multiutente.target è quello predefinito, allora dovresti vedere un login in modalità testo sulla console. Se graphical.target è quello predefinito, allora dovresti vedere un login grafico; la specifica schermata di login GUI che vedrai dipenderà dal display manager predefinito che usi.

Problemi

Recentemente ho avuto la necessità di cambiare il kernel di avvio predefinito su un computer Linux che utilizzava GRUB2. Ho scoperto che alcuni comandi non sembravano funzionare correttamente per me, o che non li stavo usando correttamente. Non sono ancora sicuro di quale fosse il caso, e ho bisogno di fare qualche altra ricerca.

Il comando grub2-set-default non ha impostato correttamente l’indice del kernel di default per me nel file /etc/default/grub, così che il kernel alternativo desiderato non si è avviato. Così ho cambiato manualmente /etc/default/grub GRUB_DEFAULT=saved in GRUB_DEFAULT=2 dove 2 è l’indice del kernel installato che volevo avviare. Poi ho eseguito il comando grub2-mkconfig > /boot/grub2/grub.cfg per creare il nuovo file di configurazione di grub. Questo aggiramento ha funzionato come previsto e si è avviato al kernel alternativo.

Conclusioni

GRUB2 e il sistema systemd init sono i componenti chiave nelle fasi di avvio e avvio della maggior parte delle moderne distribuzioni Linux. Nonostante il fatto che ci sia stata una controversia intorno a systemd in particolare, questi due componenti lavorano insieme senza problemi per caricare prima il kernel e poi per avviare tutti i servizi di sistema richiesti per produrre un sistema Linux funzionale.

Anche se trovo sia GRUB2 che systemd più complessi dei loro predecessori, sono anche altrettanto facili da imparare e gestire. Le pagine man hanno una grande quantità di informazioni su systemd, e freedesktop.org ha il set completo di pagine man di systemd online. Fate riferimento alle risorse, qui sotto, per altri link.