- Explicação técnica, passo a passo, do processo desde o momento em que se aperta o botão de energia do computador até a execução do kernel Linux
- Aborda em detalhe como a CPU sai do real mode e entra no protected mode e no long mode
- Descreve com detalhes o papel e o funcionamento de cada etapa, como firmware BIOS/UEFI, bootloader (GRUB) e descompressão e relocação de endereços do kernel
- Explica, com exemplos concisos, conceitos centrais necessários para a inicialização do kernel, como mapeamento de memória, interrupções, tabelas de páginas e kASLR
- Ao compreender os mecanismos internos do boot do Linux, oferece insights sobre arquitetura de sistemas, segurança e otimização de desempenho
Part 1 — Do botão de energia até a primeira execução do kernel
-
Ao apertar o botão de energia, a CPU é resetada em real mode e executa as instruções iniciais
- O real mode é um esquema simples de endereçamento que existe desde a era do 8086 e calcula o endereço físico combinando segmento (segment) e offset
- Exemplo:
physical_address = (segment << 4) + offset - Após o reset, a CPU salta para o endereço
0xFFFFFFF0(vetor de reset) e entrega o controle ao firmware
-
Registradores (registers) são slots de armazenamento ultrarrápidos dentro da CPU, como CS (code segment) e IP (instruction pointer)
- CS indica a localização do código atual, e IP aponta para a próxima instrução a ser executada
BIOS e UEFI
- BIOS é o firmware mais antigo: após o POST (autoteste ao ligar), verifica a ordem de boot e procura um disco inicializável
- Um disco inicializável é marcado por
0x55AAno fim dos primeiros 512 bytes do setor inicial - A BIOS copia esse setor para o endereço
0x7C00e então salta para executá-lo
- Um disco inicializável é marcado por
- UEFI é a alternativa moderna, capaz de entender diretamente o sistema de arquivos e carregar programas de boot maiores
- Diferentemente da BIOS, não há a limitação do “primeiro setor”, e ela entrega informações de sistema mais ricas ao sistema operacional
Bootloader
- O bootloader é o programa que carrega o kernel na memória e prepara sua execução
- O mais comum é o GRUB, que lê o arquivo de configuração e carrega o kernel e o initrd (initial ramdisk) na memória
- O arquivo do kernel é composto por um pequeno programa de setup para real mode e pelo corpo principal compactado do kernel
- O GRUB grava informações como a localização do kernel, a linha de comando e a posição do initrd na estrutura setup header e então salta para o código de configuração do kernel
Programa de setup (setup code)
- Antes da execução do kernel, ele cria um espaço de trabalho previsível
- Alinha os registradores de segmento (CS, DS, SS) e limpa a direction flag para que a cópia de memória funcione de forma consistente
- Cria a stack para armazenar dados temporários durante chamadas de função
- Inicializa com zero a área BSS (espaço de variáveis globais que devem começar com valor 0)
- Se a opção
earlyprintkestiver presente, pode configurar a porta serial para emitir mensagens iniciais de depuração - Solicita ao firmware o mapa de RAM (e820) para identificar áreas de memória disponíveis e reservadas
- Quando tudo está pronto, chama
main, a primeira função em C, e em seguida entra na etapa de troca de modo
Interrupções
- Interrupções são o mecanismo pelo qual a CPU pausa temporariamente a tarefa atual para tratar algo urgente
- Eventos de hardware como teclas pressionadas e timers são exemplos típicos
- Interrupções mascaráveis podem ser bloqueadas temporariamente, enquanto a NMI (Non-Maskable Interrupt) é sempre tratada
- Durante a troca de modo, elas são bloqueadas temporariamente para evitar interrupções inesperadas
Part 2 — Do real mode para 32 bits, e depois para 64 bits
- O Linux moderno roda no long mode da arquitetura x86_64
- É necessário fazer uma transição em etapas: real mode → protected mode → long mode
Protected mode
- Trata-se do modo de 32 bits introduzido para superar limitações dos anos 1980, com duas estruturas centrais
- GDT (Global Descriptor Table): define endereço inicial, tamanho e permissões dos segmentos
- O Linux usa o flat model, simplificando todo o espaço de 32 bits como uma única região contínua
- IDT (Interrupt Descriptor Table): armazena os endereços dos handlers a serem chamados quando ocorre uma interrupção
- Durante o boot, apenas uma IDT mínima é carregada; depois da inicialização do kernel, instala-se a IDT completa
- GDT (Global Descriptor Table): define endereço inicial, tamanho e permissões dos segmentos
Processo de troca de modo
- O código de setup primeiro realiza desativação de interrupções, parada do chip PIC, ativação da linha A20 e inicialização do coprocessador matemático
- A linha A20 é um mecanismo histórico para resolver o problema de wrap de endereços em 1 MB
- Depois de carregar uma GDT e uma IDT mínimas, ele define o bit PE do registrador CR0 e executa um far jump
- Com isso, entra no protected mode e reconfigura os segmentos e o ponteiro de stack de acordo com o novo esquema de endereçamento
Registradores de controle
- CR0: ativa o protected mode
- CR3: armazena o endereço de topo das tabelas de páginas
- CR4: ativa recursos estendidos como PAE
Preparação para entrar no long mode
- Para mudar para o modo de 64 bits, duas condições são necessárias
- Ativar a paginação (paging): faz o mapeamento entre endereços virtuais e físicos
- Definir o bit LME (Long Mode Enable) no registrador EFER
- As tabelas de páginas mapeiam páginas de 4 KB e, no boot inicial, são montadas de forma simples com um identity map em blocos de 2 MB
Procedimento para ativar a paginação
- Ativa o recurso PAE em CR4 e cria o conjunto mínimo de tabelas de páginas cobrindo a região de endereços baixos em blocos de 2 MB
- Grava o endereço da tabela de topo em CR3 e ativa a paginação
- Define o bit LME em EFER e salta para código de 64 bits, entrando no long mode
- Com endereços e registradores expandidos para 64 bits, a execução do kernel fica pronta para começar
Part 3 — Descompressão do kernel, ajuste de endereços e auto-relocação
- Agora a CPU já está em modo de 64 bits e existe na memória uma imagem compactada do kernel
- Um pequeno stub de 64 bits fica responsável por descompactar o kernel e ajustar seus endereços
Limpeza inicial e configuração de mecanismos de segurança
- O stub calcula sua posição real de execução e, se houver sobreposição com o kernel, move-se para uma posição segura por self-relocation
- Inicializa sua própria área BSS e carrega uma IDT simples (incluindo handlers de page fault e NMI)
- Se ocorrer um page fault, ele adiciona imediatamente o mapeamento ausente para se recuperar
- Cria mapeamentos identity para as áreas necessárias, como kernel, parâmetros de boot e buffer da linha de comando
Descompressão do kernel
- A função
extract_kernelé executada para descompactar o kernel- Suporta vários algoritmos de compressão, como gzip, xz, zstd e lzo
- Após a descompressão, lê o cabeçalho ELF e copia as seções de código/dados para os endereços corretos
- Se o endereço em que o kernel foi compilado diferir do endereço real em que foi carregado, é feita a relocação (relocation)
- Instruções e ponteiros que contêm endereços são ajustados para corresponder à posição real na memória
- Quando tudo está pronto, ele salta para a função
start_kernel, iniciando a fase principal de inicialização do kernel
Auto-relocação do kernel (kASLR)
- kASLR (Kernel Address Space Layout Randomization) randomiza os endereços físicos e virtuais do kernel para dificultar ataques
- Durante o boot, escolhe aleatoriamente duas bases
- Base física: o endereço de RAM onde o kernel realmente ficará
- Base virtual: o endereço virtual inicial que o kernel usará
- Durante o boot, escolhe aleatoriamente duas bases
- Processo de escolha
- Cria uma lista de áreas que precisam ser protegidas, como bootloader, initrd e buffer da linha de comando
- Examina o mapa de memória do firmware em busca de uma área livre suficientemente grande
- Escolhe um slot aleatório com base em entropia obtida, por exemplo, de instruções de geração de números aleatórios do hardware
- Se não houver uma área adequada, volta ao endereço padrão; com a opção
nokaslr, a randomização é desativada
Resumo dos termos
- Hexadecimal (base 16): indicado pelo prefixo
0x, facilita a representação de estruturas de bits e alinhamento em hardware - Register: armazenamento temporário dentro da CPU (CS, DS, SS, IP, SP etc.)
- Segment/Offset: forma de cálculo de endereços no real mode
(segment * 16 + offset) - BIOS/UEFI: firmware responsável pela inicialização do sistema e pelo carregamento do programa de boot
- Bootloader (GRUB): carrega o kernel e repassa informações do sistema
- Stack/BSS: área temporária para funções e área de variáveis globais inicializadas com zero
- Interrupt/NMI: mecanismo de tratamento de eventos de hardware e software
- GDT/IDT: tabelas que definem segmentos e interrupções
- A20 Line: chave para evitar o wrap de endereços em 1 MB
- Protected Mode/Long Mode: modos de execução de 32 e 64 bits
- Paging/Page Tables: mapeamento entre endereços virtuais e físicos
Ainda não há comentários.