O introducere în procesele de boot și de pornire Linux

Înțelegerea proceselor de boot și de pornire Linux este importantă atât pentru a putea configura Linux, cât și pentru a rezolva problemele de pornire. Acest articol prezintă o prezentare generală a secvenței de pornire folosind încărcătorul de boot GRUB2 și a secvenței de pornire așa cum este realizată de sistemul de inițializare systemd.

În realitate, există două secvențe de evenimente care sunt necesare pentru a porni un calculator Linux și a-l face utilizabil: boot și startup. Secvența de pornire începe atunci când computerul este pornit și se finalizează atunci când kernelul este inițializat și systemd este lansat. Procesul de pornire preia apoi controlul și finalizează sarcina de a aduce computerul Linux într-o stare operațională.

În general, procesul de pornire și de pornire Linux este destul de simplu de înțeles. Acesta este alcătuit din următorii pași care vor fi descriși mai detaliat în secțiunile următoare.

  • BIOS POST
  • Încărcător de boot (GRUB2)
  • Inițializare kernel
  • Începe systemd, părintele tuturor proceselor.

Rețineți că acest articol acoperă GRUB2 și systemd deoarece acestea sunt încărcătorul de boot și software-ul de inițializare curent pentru majoritatea distribuțiilor majore. Alte opțiuni software au fost folosite istoric și încă se găsesc în unele distribuții.

Procesul de pornire

Procesul de pornire poate fi inițiat în două moduri. În primul rând, dacă alimentarea este oprită, pornirea va începe procesul de pornire. Dacă pe calculator rulează deja un utilizator local, inclusiv root sau un utilizator neprivilegiat, utilizatorul poate iniția secvența de pornire în mod programatic, folosind interfața grafică sau linia de comandă pentru a iniția o repornire. O repornire va efectua mai întâi o închidere și apoi va reporni computerul.

BIOS POST

Primul pas al procesului de pornire Linux nu are de fapt nicio legătură cu Linux. Aceasta este partea hardware a procesului de pornire și este aceeași pentru orice sistem de operare. Când calculatorul este alimentat pentru prima dată, acesta rulează POST (Power On Self Test) care face parte din BIOS (Basic I/O System).

Când IBM a proiectat primul PC în 1981, BIOS a fost conceput pentru a inițializa componentele hardware. POST este partea din BIOS a cărei sarcină este de a se asigura că hardware-ul calculatorului a funcționat corect. Dacă POST nu reușește, este posibil ca computerul să nu fie utilizabil și astfel procesul de pornire nu continuă.

BIOS POST verifică operabilitatea de bază a hardware-ului și apoi emite o întrerupere BIOS, INT 13H, care localizează sectoarele de pornire pe orice dispozitive de pornire atașate. Primul sector de boot pe care îl găsește și care conține o înregistrare de boot validă este încărcat în RAM și controlul este apoi transferat la codul care a fost încărcat din sectorul de boot.

Sectorul de boot este de fapt prima etapă a încărcătorului de boot. Există trei încărcătoare de boot utilizate de majoritatea distribuțiilor Linux, GRUB, GRUB2 și LILO. GRUB2 este cel mai nou și este folosit mult mai frecvent în zilele noastre decât celelalte opțiuni mai vechi.

GRUB2

GRUB2 înseamnă „GRand Unified Bootloader, versiunea 2” și este acum încărcătorul de boot principal pentru majoritatea distribuțiilor Linux actuale. GRUB2 este programul care face calculatorul suficient de inteligent pentru a găsi nucleul sistemului de operare și a-l încărca în memorie. Deoarece este mai ușor să scrii și să spui GRUB decât GRUB2, este posibil să folosesc termenul GRUB în acest document, dar mă voi referi la GRUB2 dacă nu se specifică altfel.

GRUB a fost proiectat pentru a fi compatibil cu specificația multiboot care permite GRUB să booteze mai multe versiuni de Linux și alte sisteme de operare libere; de asemenea, poate încărca în lanț înregistrarea de bootare a sistemelor de operare proprietare.

GRUB poate, de asemenea, să permită utilizatorului să aleagă să booteze din mai multe nuclee diferite pentru orice distribuție Linux dată. Acest lucru oferă posibilitatea de a porni de la o versiune anterioară de kernel dacă una actualizată eșuează cumva sau este incompatibilă cu o piesă importantă de software. GRUB poate fi configurat cu ajutorul fișierului /boot/grub/grub.conf.

GRUB1 este considerat acum ca fiind vechi și a fost înlocuit în majoritatea distribuțiilor moderne cu GRUB2, care este o rescriere a GRUB1. Distribuțiile bazate pe Red Hat au fost actualizate la GRUB2 în jurul Fedora 15 și CentOS/RHEL 7. GRUB2 oferă aceeași funcționalitate de pornire ca GRUB1, dar GRUB2 este, de asemenea, un mediu pre-OS bazat pe comenzi de tip mainframe și permite o mai mare flexibilitate în timpul fazei de pre-pornire. GRUB2 este configurat cu /boot/grub2/grub.cfg.

Funcția principală a oricăruia dintre cele două GRUB-uri este de a face ca nucleul Linux să fie încărcat în memorie și să funcționeze. Ambele versiuni de GRUB funcționează în esență în același mod și au aceleași trei etape, dar voi folosi GRUB2 pentru această discuție despre modul în care GRUB își face treaba. Configurarea GRUB sau GRUB2 și utilizarea comenzilor GRUB2 nu intră în sfera de aplicare a acestui articol.

Deși GRUB2 nu folosește în mod oficial notația etapelor pentru cele trei etape ale GRUB2, este convenabil să ne referim la ele în acest mod, așa că o voi face în acest articol.

Etapa 1

După cum s-a menționat în secțiunea BIOS POST, la sfârșitul POST, BIOS caută pe discurile atașate o înregistrare de boot, de obicei localizată în Master Boot Record (MBR), o încarcă pe prima pe care o găsește în memorie și apoi începe execuția înregistrării de boot. Codul de bootstrap, adică GRUB2 stage 1, este foarte mic, deoarece trebuie să încapă în primul sector de 512 octeți de pe hard disk, împreună cu tabela de partiții. Spațiul total alocat pentru codul de bootstrap propriu-zis într-un MBR generic clasic este de 446 de octeți. Fișierul de 446 de octeți pentru etapa 1 se numește boot.img și nu conține tabelul de partiții, care este adăugat separat la înregistrarea de boot.

Pentru că înregistrarea de boot trebuie să fie atât de mică, nu este, de asemenea, foarte inteligentă și nu înțelege structurile sistemului de fișiere. Prin urmare, singurul scop al etapei 1 este de a localiza și încărca etapa 1.5. Pentru a realiza acest lucru, etapa 1.5 a GRUB trebuie să fie localizată în spațiul dintre înregistrarea de pornire propriu-zisă și prima partiție de pe unitate. După ce a încărcat stadiul 1.5 al GRUB în RAM, stadiul 1 predă controlul către stadiul 1.5.

Stadiul 1.5

După ce s-a menționat mai sus, stadiul 1.5 al GRUB trebuie să fie localizat în spațiul dintre înregistrarea de boot propriu-zisă și prima partiție de pe unitatea de disc. Acest spațiu a fost lăsat nefolosit din punct de vedere istoric din motive tehnice. Prima partiție de pe hard disk începe la sectorul 63 și, cu MBR-ul în sectorul 0, rămân 62 de sectoare de 512 octeți-31.744 de octeți-în care se poate stoca fișierul core.img, care reprezintă etapa 1.5 a GRUB. Fișierul core.img are 25.389 de octeți, astfel încât există suficient spațiu disponibil între MBR și prima partiție a discului în care să fie stocat.

Din cauza cantității mai mari de cod care poate fi găzduită pentru stadiul 1.5, acesta poate avea suficient cod pentru a conține câteva drivere de sisteme de fișiere obișnuite, cum ar fi EXT standard și alte sisteme de fișiere Linux, FAT și NTFS. GRUB2 core.img este mult mai complex și mai capabil decât vechiul GRUB1 stage 1.5. Acest lucru înseamnă că etapa 2 a GRUB2 poate fi localizată pe un sistem de fișiere EXT standard, dar nu poate fi localizată pe un volum logic. Așadar, locația standard pentru fișierele din etapa 2 este în sistemul de fișiere /boot, mai exact /boot/grub2.

Rețineți că directorul /boot trebuie să fie localizat pe un sistem de fișiere care este acceptat de GRUB. Nu toate sistemele de fișiere sunt. Funcția etapei 1.5 este de a începe execuția cu driverele de sistem de fișiere necesare pentru a localiza fișierele etapei 2 în sistemul de fișiere /boot și pentru a încărca driverele necesare.

Etapa 2

Toate fișierele pentru etapa 2 a GRUB sunt localizate în directorul /boot/grub2 și în mai multe subdirectoare. GRUB2 nu are un fișier imagine ca în cazul etapelor 1 și 2. În schimb, acesta constă în mare parte din module kernel de execuție care sunt încărcate în funcție de necesități din directorul /boot/grub2/i386-pc.

Funcția etapei 2 a GRUB2 este de a localiza și încărca un kernel Linux în memoria RAM și de a preda controlul computerului către kernel. Kernelul și fișierele asociate acestuia sunt localizate în directorul /boot. Fișierele kernelului sunt identificabile, deoarece toate sunt denumite începând cu vmlinuz. Puteți lista conținutul directorului /boot pentru a vedea kernel-urile instalate în prezent pe sistemul dumneavoastră.

GRUB2, ca și GRUB1, suportă pornirea de la unul dintr-o selecție de kernel-uri Linux. Managerul de pachete Red Hat, DNF, suportă păstrarea mai multor versiuni ale kernelului, astfel încât, dacă apare o problemă cu cea mai nouă, poate fi pornită o versiune mai veche a kernelului. În mod implicit, GRUB oferă un meniu de pre-aruncare a nucleelor instalate, inclusiv o opțiune de salvare și, dacă este configurată, o opțiune de recuperare.

Etapa 2 a GRUB2 încarcă nucleul selectat în memorie și transferă controlul calculatorului către nucleu.

Nucleu

Toate nucleele sunt într-un format comprimat, cu autoextragere, pentru a economisi spațiu. Kernel-urile sunt localizate în directorul /boot, împreună cu o imagine inițială a discului RAM și hărți ale dispozitivelor de pe hard disk-uri.

După ce kernel-ul selectat este încărcat în memorie și începe să se execute, acesta trebuie mai întâi să se extragă din versiunea comprimată a fișierului înainte de a putea efectua orice activitate utilă. Odată ce kernelul s-a extras singur, acesta încarcă systemd, care este înlocuitorul vechiului program de init SysV, și îi predă controlul.

Acesta este sfârșitul procesului de pornire. În acest moment, nucleul Linux și systemd rulează, dar nu pot efectua nicio sarcină productivă pentru utilizatorul final, deoarece nimic altceva nu rulează.

Procesul de pornire

Procesul de pornire urmează procesului de boot și aduce calculatorul Linux într-o stare operațională în care este utilizabil pentru muncă productivă.

systemd

systemd este mama tuturor proceselor și este responsabil pentru aducerea gazdei Linux într-o stare în care se poate face muncă productivă. Unele dintre funcțiile sale, care sunt mult mai extinse decât vechiul program init, constau în gestionarea multor aspecte ale unei gazde Linux care rulează, inclusiv montarea sistemelor de fișiere, precum și pornirea și gestionarea serviciilor de sistem necesare pentru a avea o gazdă Linux productivă. Oricare dintre sarcinile lui systemd care nu sunt legate de secvența de pornire sunt în afara scopului acestui articol.

În primul rând, systemd montează sistemele de fișiere așa cum sunt definite de /etc/fstab, inclusiv orice fișiere swap sau partiții. În acest moment, poate accesa fișierele de configurare aflate în /etc, inclusiv pe cele proprii. Acesta utilizează fișierul său de configurare, /etc/systemd/system/default.target, pentru a determina starea sau ținta în care ar trebui să pornească gazda. Fișierul default.target este doar o legătură simbolică către adevăratul fișier țintă. Pentru o stație de lucru de tip desktop, acesta va fi, de obicei, graphical.target, care este echivalent cu runlevel 5 în vechiul SystemV init. Pentru un server, este mai probabil ca fișierul implicit să fie multi-user.target, care este echivalent cu runlevel 3 din SystemV. Ținta.emergency.target este similară modului utilizator unic.

Rețineți că țintele și serviciile sunt unități systemd.

Tabelul 1, de mai jos, este o comparație între țintele systemd și vechile niveluri de execuție de pornire din SystemV. Aliasurile țintelor systemd sunt furnizate de systemd pentru compatibilitate retroactivă. Aliasurile de țintă permit scripturilor – și multor administratori de sistem ca mine – să folosească comenzi SystemV precum init 3 pentru a schimba nivelurile de execuție. 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. Ținta.default.target nu trebuie să fie niciodată aliasată cu halt.target, poweroff.target sau reboot.target.

Tabelul 1: Compararea nivelurilor de execuție SystemV cu țintele systemd și unele alias-uri ale țintelor.

Care țintă are un set de dependențe descrise în fișierul său de configurare. systemd pornește dependențele necesare. Aceste dependențe sunt serviciile necesare pentru a rula gazda Linux la un anumit nivel de funcționalitate. Atunci când toate dependențele listate în fișierele de configurare ale țintei sunt încărcate și funcționează, sistemul funcționează la nivelul acelei ținte.

systemd se uită, de asemenea, în directoarele de init SystemV moștenite pentru a vedea dacă există fișiere de pornire acolo. Dacă da, systemd le folosește pe acelea ca fișiere de configurare pentru a porni serviciile descrise de aceste fișiere. Serviciul de rețea depreciat este un bun exemplu al unuia dintre cele care încă utilizează fișiere de pornire SystemV în Fedora.

Figura 1, de mai jos, este copiată direct din pagina de manual bootup. Ea arată secvența generală a evenimentelor din timpul pornirii systemd și cerințele de ordine de bază pentru a asigura o pornire reușită.

Obiectivele sysinit.target și basic.target pot fi considerate ca puncte de control în procesul de pornire. Deși systemd are ca unul dintre obiectivele sale de proiectare să pornească serviciile de sistem în paralel, există totuși anumite servicii și ținte funcționale care trebuie să fie pornite înainte ca alte servicii și ținte să poată fi pornite. Aceste puncte de control nu pot fi depășite până când toate serviciile și țintele cerute de acel punct de control nu sunt îndeplinite.

Așa că ținta sysinit.target este atinsă atunci când toate unitățile de care depinde sunt finalizate. Toate aceste unități, montarea sistemelor de fișiere, configurarea fișierelor swap, pornirea udev, setarea sămânței generatorului aleatoriu, inițierea serviciilor de nivel scăzut și configurarea serviciilor criptografice dacă unul sau mai multe sisteme de fișiere sunt criptate, trebuie să fie finalizate, dar în cadrul sysinit.target aceste sarcini pot fi efectuate în paralel.

Sysinit.target pornește toate serviciile și unitățile de nivel scăzut necesare pentru ca sistemul să fie marginal funcțional și care sunt necesare pentru a permite trecerea la basic.target.

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: Harta de pornire systemd.

După ce sysinit.target este îndeplinit, systemd pornește apoi basic.target, pornind toate unitățile necesare pentru a-l îndeplini. Ținta de bază oferă unele funcționalități suplimentare prin pornirea unităților care sunt necesare pentru următoarea țintă. Acestea includ configurarea unor lucruri cum ar fi căile de acces la diverse directoare executabile, socluri de comunicare și cronometre.

În cele din urmă, pot fi inițializate țintele la nivel de utilizator, multi-user.target sau graphical.target. Observați că ținta multi-user.target trebuie să fie atinsă înainte ca dependențele țintei grafice să poată fi îndeplinite.

Țintele subliniate în figura 1, sunt țintele obișnuite de pornire. Atunci când una dintre aceste ținte este atinsă, atunci pornirea s-a încheiat. Dacă ținta multi-user.target este cea implicită, atunci ar trebui să vedeți o autentificare în modul text pe consolă. Dacă ținta.graphical.target este cea implicită, atunci ar trebui să vedeți o logare grafică; ecranul specific de logare GUI pe care îl vedeți va depinde de managerul de afișare implicit pe care îl utilizați.

Probleme

De curând am avut nevoie să schimb kernelul de pornire implicit pe un calculator Linux care folosea GRUB2. Am constatat că unele dintre comenzi nu păreau să funcționeze corespunzător pentru mine sau că nu le foloseam corect. Nu sunt încă sigur care a fost cazul și trebuie să fac mai multe cercetări.

Comanda grub2-set-default nu a setat corect indicele kernelului implicit pentru mine în fișierul /etc/default/grub, astfel încât kernelul alternativ dorit nu a pornit. Așa că am schimbat manual /etc/default/grub GRUB_DEFAULT=saved în GRUB_DEFAULT=2, unde 2 este indicele nucleului instalat pe care doream să îl pornesc. Apoi am rulat comanda grub2-mkconfig > /boot/grub2/grub.cfg pentru a crea noul fișier de configurare grub. Această eludare a funcționat așa cum era de așteptat și a pornit pe kernelul alternativ.

Concluzii

GRUB2 și sistemul systemd init sunt componentele cheie în fazele de pornire și demarare ale majorității distribuțiilor Linux moderne. În ciuda faptului că au existat controverse în special în jurul systemd, aceste două componente lucrează împreună fără probleme pentru a încărca mai întâi nucleul și apoi pentru a porni toate serviciile de sistem necesare pentru a produce un sistem Linux funcțional.

Deși consider că atât GRUB2 cât și systemd sunt mai complexe decât predecesorii lor, ele sunt, de asemenea, la fel de ușor de învățat și de gestionat. Paginile de manual au foarte multe informații despre systemd, iar freedesktop.org are online setul complet de pagini de manual systemd. Consultați resursele, de mai jos, pentru mai multe linkuri.

.