Uma introdução aos processos de boot e inicialização do Linux

O entendimento dos processos de boot e inicialização do Linux é importante para ser capaz de configurar o Linux e resolver problemas de inicialização. Este artigo apresenta uma visão geral da sequência de arranque utilizando o gestor de arranque GRUB2 e a sequência de arranque executada pelo sistema de inicialização systemd.

Na realidade, existem duas sequências de eventos que são necessários para arrancar um computador Linux e torná-lo utilizável: arranque e arranque. A sequência de arranque começa quando o computador é ligado, e termina quando o kernel é inicializado e o systemd é iniciado. O processo de inicialização então assume e termina a tarefa de colocar o computador Linux em um estado operacional.

Overall, o processo de inicialização e inicialização do Linux é bastante simples de entender. Ele é composto dos seguintes passos que serão descritos em mais detalhes nas seções seguintes.

  • BIOS POST
  • Boot loader (GRUB2)
  • Kernel initialization
  • Start systemd, o pai de todos os processos.

Note que este artigo cobre GRUB2 e systemd porque eles são o carregador de inicialização atual e software de inicialização para a maioria das principais distribuições. Outras opções de software têm sido usadas historicamente e ainda são encontradas em algumas distribuições.

O processo de inicialização

O processo de inicialização pode ser iniciado de uma de duas maneiras. Primeiro, se a energia for desligada, ligando a energia começará o processo de boot. Se o computador já estiver executando um usuário local, incluindo root ou um usuário sem privilégios, o usuário pode programar a seqüência de inicialização usando a GUI ou linha de comando para iniciar uma reinicialização. Uma reinicialização irá primeiro fazer um shutdown e depois reiniciar o computador.

BIOS POST

O primeiro passo do processo de arranque do Linux realmente não tem nada a ver com o Linux. Esta é a parte de hardware do processo de boot e é a mesma para qualquer sistema operacional. Quando a energia é aplicada pela primeira vez ao computador, ele executa o POST (Power On Self Test) que faz parte da BIOS (Basic I/O System).

Quando a IBM projetou o primeiro PC em 1981, a BIOS foi projetada para inicializar os componentes de hardware. POST é a parte da BIOS cuja tarefa é assegurar que o hardware do computador funciona correctamente. Se o POST falhar, o computador pode não ser utilizável e assim o processo de inicialização não continua.

BIOS POST verifica a operabilidade básica do hardware e então ele emite uma interrupção da BIOS, INT 13H, que localiza os setores de inicialização em qualquer dispositivo de inicialização anexado. O primeiro setor de boot que ele encontra que contém um registro de boot válido é carregado na RAM e o controle é então transferido para o código que foi carregado do setor de boot.

O setor de boot é realmente o primeiro estágio do gerenciador de boot. Existem três carregadores de inicialização usados pela maioria das distribuições Linux, GRUB, GRUB2, e LILO. GRUB2 é o mais novo e é usado muito mais frequentemente hoje em dia do que as outras opções antigas.

GRUB2

GRUB2 significa “GRand Unified Bootloader, versão 2” e agora é o carregador de inicialização principal para a maioria das distribuições Linux atuais. GRUB2 é o programa que torna o computador inteligente o suficiente para encontrar o kernel do sistema operacional e carregá-lo na memória. Como é mais fácil escrever e dizer GRUB do que GRUB2, eu posso usar o termo GRUB neste documento, mas estarei me referindo ao GRUB2 a menos que especificado de outra forma.

GRUB foi projetado para ser compatível com a especificação multiboot que permite ao GRUB inicializar muitas versões do Linux e outros sistemas operacionais livres; ele também pode carregar em cadeia o registro de inicialização de sistemas operacionais proprietários.

GRUB também pode permitir ao usuário escolher inicializar entre vários kernels diferentes para qualquer distribuição Linux. Isto dá a capacidade de arrancar para uma versão anterior do kernel se uma versão actualizada falhar de alguma forma ou for incompatível com uma peça de software importante. O GRUB pode ser configurado usando o arquivo /boot/grub/grub.conf.

GRUB1 é agora considerado como legado e foi substituído na maioria das distribuições modernas pelo GRUB2, que é uma reescrita do GRUB1. As distribuições baseadas na Red Hat foram atualizadas para GRUB2 em torno do Fedora 15 e CentOS/RHEL 7. GRUB2 fornece a mesma funcionalidade de inicialização do GRUB1, mas o GRUB2 também é um ambiente pré-OS baseado em comando mainframe e permite maior flexibilidade durante a fase de pré-boot. GRUB2 é configurado com /boot/grub2/grub.cfg.

A função primária de qualquer um dos dois GRUB é carregar o kernel Linux na memória e executá-lo. Ambas as versões do GRUB funcionam essencialmente da mesma maneira e têm os mesmos três estágios, mas eu vou usar o GRUB2 para esta discussão de como o GRUB faz seu trabalho. A configuração do GRUB ou GRUB2 e o uso dos comandos GRUB2 está fora do escopo deste artigo.

Embora o GRUB2 não utilize oficialmente a notação de estágios para os três estágios do GRUB2, é conveniente referir-se a eles dessa forma, então eu irei neste artigo.

Estágio 1

Como mencionado na seção POST da BIOS, no final do POST, a BIOS procura nos discos anexos por um registro de inicialização, geralmente localizado no Master Boot Record (MBR), carrega o primeiro que encontra na memória e então inicia a execução do registro de inicialização. O código bootstrap, ou seja, GRUB2 estágio 1, é muito pequeno porque deve caber no primeiro setor de 512 bytes no disco rígido junto com a tabela de partições. A quantidade total de espaço alocada para o código bootstrap real em um MBR genérico clássico é de 446 bytes. O arquivo 446 Byte para o estágio 1 é chamado boot.img e não contém a tabela de partições que é adicionada ao registro de inicialização separadamente.

Porque o registro de inicialização deve ser tão pequeno, ele também não é muito inteligente e não entende estruturas de sistemas de arquivos. Portanto, o único propósito do estágio 1 é localizar e carregar o estágio 1.5. Para conseguir isto, o estágio 1.5 do GRUB deve estar localizado no espaço entre o registro de inicialização em si e a primeira partição no drive. Após carregar o estágio 1.5 do GRUB em RAM, o estágio 1 passa para o estágio 1.5.

Etapa 1.5

Como mencionado acima, o estágio 1.5 do GRUB deve estar localizado no espaço entre o próprio boot record e a primeira partição no drive de disco. Este espaço foi deixado historicamente sem uso por razões técnicas. A primeira partição no disco rígido começa no setor 63 e com o MBR no setor 0, que deixa 62 setores de 512 bytes-31.744 bytes-in para armazenar o arquivo core.img que é o estágio 1.5 do GRUB. O arquivo core.img é 25.389 bytes, portanto há muito espaço disponível entre o MBR e a primeira partição do disco para armazená-lo.

Por causa da maior quantidade de código que pode ser acomodado para o estágio 1.5, ele pode ter código suficiente para conter alguns drivers de sistema de arquivos comuns, como o EXT padrão e outros sistemas de arquivos Linux, FAT, e NTFS. O GRUB2 core.img é muito mais complexo e capaz do que o antigo GRUB1 estágio 1.5. Isto significa que o estágio 2 do GRUB2 pode ser localizado em um sistema de arquivos padrão EXT, mas não pode ser localizado em um volume lógico. Então a localização padrão para os arquivos estágio 2 está no sistema de arquivos /boot, especificamente /boot/grub2.

Nota que o diretório /boot deve estar localizado em um sistema de arquivos que é suportado pelo GRUB. Nem todos os sistemas de arquivos estão. A função do estágio 1.5 é iniciar a execução com os drivers do sistema de arquivos necessários para localizar os arquivos do estágio 2 no sistema de arquivos /boot e carregar os drivers necessários.

Etapa 2

Todos os arquivos para o GRUB estágio 2 estão localizados no diretório /boot/grub2 e em vários subdiretórios. O GRUB2 não tem um arquivo de imagem como os estágios 1 e 2. Ao invés disso, ele consiste principalmente de módulos do kernel em tempo de execução que são carregados conforme necessário do diretório /boot/grub2/i386-pc.

A função do GRUB2 estágio 2 é localizar e carregar um kernel Linux em RAM e passar o controle do computador para o kernel. O kernel e os seus ficheiros associados estão localizados no directório /boot. Os arquivos do kernel são identificáveis pois todos eles são nomeados começando com vmlinuz. Você pode listar o conteúdo do directório /boot para ver os kernels actualmente instalados no seu sistema.

GRUB2, como o GRUB1, suporta o arranque a partir de um de uma selecção de kernels Linux. O gerenciador de pacotes da Red Hat, DNF, suporta manter múltiplas versões do kernel para que, se ocorrer um problema com o mais novo, uma versão antiga do kernel possa ser inicializada. Por padrão, o GRUB fornece um menu pré-boot dos kernels instalados, incluindo uma opção de recuperação e, se configurado, uma opção de recuperação.

Etapa 2 do GRUB2 carrega o kernel selecionado na memória e transfere o controle do computador para o kernel.

Kernel

Todos os kernels estão em um formato auto-extraível e comprimido para economizar espaço. Os kernels estão localizados no diretório /boot, juntamente com uma imagem inicial do disco RAM e mapas de dispositivos dos discos rígidos.

Após o kernel selecionado ser carregado na memória e começar a execução, ele deve primeiro extrair-se da versão compactada do arquivo antes de poder realizar qualquer trabalho útil. Uma vez que o kernel se extraiu, ele carrega systemd, que é a substituição do antigo programa de inicialização do SysV, e passa o controle para ele.

Este é o fim do processo de inicialização. Neste ponto, o kernel e o systemd do Linux estão rodando mas não conseguem executar nenhuma tarefa produtiva para o usuário final porque nada mais está rodando.

O processo de inicialização

O processo de inicialização segue o processo de inicialização e traz o computador Linux para um estado operacional no qual ele é utilizável para o trabalho produtivo.

systemd

systemd é a mãe de todos os processos e é responsável por trazer o host Linux para um estado no qual o trabalho produtivo pode ser feito. Algumas de suas funções, que são muito mais extensas que o antigo programa init, são gerenciar muitos aspectos de um host Linux em execução, incluindo a montagem de sistemas de arquivos e o início e gerenciamento dos serviços de sistema necessários para ter um host Linux produtivo. Qualquer tarefa do systemd que não esteja relacionada com a sequência de arranque está fora do âmbito deste artigo.

First, systemd monta os sistemas de ficheiros como definido pelo /etc/fstab, incluindo quaisquer ficheiros swap ou partições. Neste ponto, ele pode acessar os arquivos de configuração localizados em /etc, incluindo os seus próprios arquivos. Ele usa seu arquivo de configuração, /etc/systemd/system/default.target, para determinar qual estado ou alvo, em qual ele deve inicializar o host. O arquivo default.target é apenas um link simbólico para o verdadeiro arquivo alvo. Para uma estação de trabalho desktop, este será tipicamente o graphical.target, que é equivalente ao runlevel 5 no antigo init SystemV. Para um servidor, o padrão é mais provável que seja o multi-user.target, que é como o runlevel 3 no SystemV. O emergency.target é similar ao single user mode.

Note that targets and services are systemd units.

Table 1, abaixo, é uma comparação dos targets systemd com os antigos runlevels de inicialização do SystemV. Os aliases de destino do systemd são fornecidos pelo systemd para compatibilidade com versões anteriores. Os aliases de destino permitem que os scripts – e muitos outros codinomes como myself – usem comandos SystemV como o init 3 para alterar os níveis de execução. 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. O arquivo default.target nunca deve ser aliado a halt.target, poweroff.target ou reboot.target.

Tabela 1: Comparação dos níveis de execução SystemV com os targets systemd e alguns aliases de target.

Cada target tem um conjunto de dependências descritas em seu arquivo de configuração. systemd inicia as dependências requeridas. Estas dependências são os serviços necessários para executar o host Linux em um nível específico de funcionalidade. Quando todas as dependências listadas nos arquivos de configuração alvo são carregadas e executadas, o sistema está rodando nesse nível alvo.

systemd também olha os diretórios init SystemV antigos para ver se algum arquivo de inicialização existe lá. Se assim for, o systemd usou-os como arquivos de configuração para iniciar os serviços descritos pelos arquivos. O serviço de rede depreciado é um bom exemplo de um daqueles que ainda usam arquivos de inicialização SystemV no Fedora.

Figure 1, abaixo, é copiado diretamente da página de manual do bootup. Ele mostra a sequência geral de eventos durante a inicialização do systemd e os requisitos básicos de ordenação para garantir uma inicialização bem sucedida.

Os alvos sysinit.target e basic.target podem ser considerados como pontos de verificação no processo de inicialização. Embora o systemd tenha como um de seus objetivos de projeto iniciar serviços do sistema em paralelo, ainda há certos serviços e alvos funcionais que devem ser iniciados antes que outros serviços e alvos possam ser iniciados. Estes pontos de verificação não podem ser passados até que todos os serviços e alvos requeridos por aquele ponto de verificação sejam cumpridos.

Então o sysinit.target é alcançado quando todas as unidades das quais ele depende são completadas. Todas essas unidades, montar sistemas de arquivos, configurar arquivos swap, iniciar o udev, configurar a semente do gerador aleatório, iniciar serviços de baixo nível e configurar serviços criptográficos se um ou mais sistemas de arquivos estiverem criptografados, devem ser completados, mas dentro do sysinit.target essas tarefas podem ser executadas em paralelo.

O sysinit.target inicia todos os serviços e unidades de baixo nível necessários para que o sistema seja marginalmente funcional e que são necessários para permitir a mudança para o 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

Figure 1: O systemd startup map.

Após o sysinit.target ser preenchido, o systemd em seguida inicia o basic.target, iniciando todas as unidades necessárias para cumpri-lo. O alvo básico fornece algumas funcionalidades adicionais ao iniciar unidades que são necessárias para o próximo alvo. Estas incluem a configuração de caminhos para vários diretórios executáveis, soquetes de comunicação e timers.

Finalmente, os alvos em nível de usuário, multi-user.target ou graphical.target podem ser inicializados. Note que o multi-user.target deve ser alcançado antes que as dependências do alvo gráfico possam ser alcançadas.

Os alvos sublinhados na Figura 1, são os alvos usuais de inicialização. Quando um destes alvos é atingido, então a inicialização é completada. Se o multi-user.target é o padrão, então você deve ver um login em modo texto no console. Se o graphical.target é o padrão, então você deve ver um login gráfico; a tela específica de login GUI que você vê dependerá do gerenciador de exibição padrão que você usa.

Issues

Tive recentemente a necessidade de alterar o kernel de inicialização padrão em um computador Linux que usava o GRUB2. Eu descobri que alguns dos comandos não pareciam funcionar corretamente para mim, ou que eu não os estava usando corretamente. Eu ainda não tenho certeza qual foi o caso, e preciso fazer mais alguma pesquisa.

O comando grub2-set-default não definiu corretamente o índice padrão do kernel para mim no arquivo /etc/default/grub para que o kernel alternativo desejado não inicialize. Então eu alterei manualmente o /etc/default/grub GRUB_DEFAULT=saved para GRUB_DEFAULT=2 onde 2 é o índice do kernel instalado que eu queria inicializar. Então executei o comando grub2-mkconfig > /boot/grub2/grub.cfg para criar o novo arquivo de configuração do grub. Esta circunvenção funcionou como esperado e inicializou para o kernel alternativo.

Conclusions

GRUB2 e o sistema de inicialização do systemd são os componentes chave nas fases de inicialização e inicialização da maioria das distribuições Linux modernas. Apesar do fato de que tem havido controvérsia em torno do systemd especialmente, esses dois componentes trabalham juntos sem problemas para primeiro carregar o kernel e depois iniciar todos os serviços de sistema necessários para produzir um sistema Linux funcional.

P>Embora eu ache o GRUB2 e o systemd mais complexos que seus predecessores, eles também são igualmente fáceis de aprender e gerenciar. As páginas man têm muita informação sobre systemd, e freedesktop.org tem o conjunto completo de páginas man do systemd online. Consulte os recursos, abaixo, para mais links.