4 pontos por GN⁺ 2025-10-27 | 1 comentários | Compartilhar no WhatsApp
  • Explica passo a passo como criar uma “microdistribuição Linux” compilando o kernel Linux manualmente e montando um espaço de usuário mínimo
  • Aborda desde o básico o papel do kernel do sistema operacional, os componentes de uma distribuição Linux e a relação entre kernel e espaço de usuário
  • Usa como exemplo a arquitetura RISC-V (máquina riscv64 virt do QEMU), mas os mesmos princípios podem ser aplicados a outras arquiteturas, como x86
  • Constrói um ambiente Linux mínimo e executável diretamente, incluindo o processo init, initramfs e um shell simples escrito em Go
  • Por fim, apresenta como usar o projeto u-root para criar uma microdistribuição realmente útil e conclui como um guia introdutório para entender a estrutura geral de sistemas Linux

O que é o kernel de um sistema operacional

  • O kernel é o componente central do sistema operacional responsável por gerenciar recursos de hardware e controlar a execução de programas
    • Mesmo em um ambiente de núcleo único, ele oferece funções de gerenciamento de multitarefa que fazem vários programas parecerem executar ao mesmo tempo
  • O kernel abstrai o controle dos dispositivos de entrada e saída, para que os aplicativos não precisem lidar diretamente com endereços de hardware ou valores de registradores
    • Por exemplo, um programa simplesmente pede para “escrever uma mensagem na saída padrão”, e o kernel cuida da interação com o hardware real
  • Ele fornece uma forma de acesso a dados em alto nível por meio da interface de sistema de arquivos
    • Um arquivo não é apenas dado em disco, mas funciona como uma interface lógica para comunicação com o kernel
  • O kernel fornece isolamento entre processos e um modelo de comunicação, permitindo que cada aplicação rode de forma independente ou cooperativa
  • O kernel Linux é open source, pode rodar em várias arquiteturas e é um dos kernels mais usados no mundo

O que é uma distribuição Linux

  • Só com o kernel Linux o usuário não consegue executar um navegador web ou aplicativos com GUI; é necessária uma infraestrutura de software em várias camadas sobre o kernel
  • Configuração de rede, atribuição de IP, gerenciamento de VPN etc. são responsabilidade de programas de espaço de usuário em camadas superiores, não do kernel
  • Portanto, uma distribuição Linux é definida como a combinação de kernel + infraestrutura de espaço de usuário
  • A distribuição inclui, sobre as funções básicas oferecidas pelo kernel, pacotes, ferramentas, configurações e processo de inicialização (init)
  • A complexidade varia bastante, indo de configurações mínimas como o Arch Linux até opções mais amigáveis ao usuário como o Ubuntu

Infraestrutura fora do kernel: espaço de usuário e processo init

  • Quando o kernel termina o boot, ele executa primeiro o processo init, de PID 1
    • O init é o ancestral de todos os processos do espaço de usuário e executa em sequência os serviços e ferramentas do sistema
  • O conjunto de processos e ferramentas executados pelo init constitui a parte prática de uma distribuição Linux
  • À medida que a distribuição fica mais complexa, ela pode acumular recursos desnecessários e receber críticas por ser “inchada”
  • Em contrapartida, ao criar uma microdistribuição customizada, é possível montar um sistema leve com apenas o mínimo necessário

Compilando o kernel Linux para RISC-V

  • Em um ambiente x86, compila-se o kernel para RISC-V usando uma toolchain de cross-compilation
    • Baixa-se o código-fonte linux-6.5.2.tar.xz em kernel.org e executa-se make ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- defconfig
  • É possível editar visualmente as configurações do kernel com menuconfig
  • Depois da compilação paralela com make -j16, é gerado arch/riscv/boot/Image
  • No QEMU, o boot é feito com qemu-system-riscv64 -machine virt -kernel arch/riscv/boot/Image
    • Nos logs de boot, é possível verificar mensagens como detecção da camada SBI, inicialização da UART e ativação do printk

Primeiro obstáculo: sem sistema de arquivos raiz

  • Durante o boot do kernel, ocorre kernel panic com o erro VFS: Unable to mount root fs
    • Causa: não foi fornecido um sistema de arquivos raiz (initramfs)
  • Um sistema de arquivos pode ser montado não só em disco, mas também em RAM (initramfs)
  • O initramfs é empacotado no formato cpio e, no QEMU, pode ser carregado com a opção -initrd

Montando o initramfs e executando “Hello world”

  • O requisito mínimo é a presença do binário /init
    • Escreve-se init.c e compila-se com linkagem estática (-static)
    • O empacotamento é feito com cpio -o -H newc < file_list.txt > initramfs.cpio
  • Ao rodar no QEMU, a mensagem “Hello world” é exibida, mas ao encerrar o init ocorre novamente um kernel panic
    • Solução: adicionar um loop infinito para que o init não termine

Adicionando um shell simples escrito em Go

  • O init executa /little_shell usando fork e execl
  • little_shell.go é um shell simples que recebe entrada do usuário e repete os comandos digitados
    • A compilação para RISC-V é feita com GOOS=linux GOARCH=riscv64 go build little_shell.go
  • Tanto init quanto little_shell compartilham a saída pela UART
    • A entrada e saída padrão são gerenciadas como descritores de arquivo e herdadas durante o fork
  • Como resultado, forma-se um ambiente Linux básico, em que “Hello from init” e a entrada do shell aparecem de forma intercalada

Resumo do papel do kernel

  • Abstração de hardware: programas de usuário conseguem imprimir saída sem conhecer detalhes da UART ou dos dispositivos
  • Fornecimento de interfaces de alto nível: acesso a outros binários (little_shell) por meio do sistema de arquivos
  • Isolamento de processos: init e o shell executam em espaços de memória independentes
  • O kernel fornece uma base de execução estável e portável sobre hardware complexo

Definição de sistema operacional

  • Há quem considere apenas o kernel como sistema operacional, e há quem considere a distribuição inteira como o sistema operacional
  • O importante é entender os limites de papel e a estrutura de interação entre kernel e espaço de usuário

Criando uma microdistribuição realmente útil com u-root

  • O projeto u-root fornece um conjunto de ferramentas de espaço de usuário baseado em Go
    • O u-root inclui um bootloader de espaço de usuário e um ambiente de shell executados sobre o kernel Linux
  • Após a instalação, o comando GOOS=linux GOARCH=riscv64 u-root gera automaticamente um initramfs
    • O arquivo /tmp/initramfs.linux_riscv64.cpio pode ser executado no QEMU
  • Durante o boot, é exibido o banner “Welcome to u-root!” junto com um prompt básico de shell
    • Há suporte a comandos básicos como ls, pwd e echo, além de autocompletar com tab

Prática de conexão de rede

  • Adicionam-se ao QEMU os dispositivos virtio-net-device e virtio-rng-pci
    • Usa-se a opção -device virtio-net-device,netdev=usernet -netdev user,id=usernet
  • Com o dhclient do u-root, o IP é atribuído automaticamente via DHCP
    • Exemplo: atribuição de 10.0.2.15/24 à interface eth0
  • Com wget http://google.com, confirma-se acesso à rede externa e o download de index.html

A importância do gerenciador de pacotes e do init

  • Distribuições comuns usam um gerenciador de pacotes para instalar e atualizar software dinamicamente
    • Neste exercício, a abordagem é mais próxima de sistemas embarcados, em que é preciso recompilar a imagem inteira
  • O init não é apenas um executor simples de processos, mas um componente central da inicialização de dispositivos, gerenciamento de serviços e controle do boot do sistema
    • Pelo código-fonte do init do u-root, é possível observar vários processos de configuração de dispositivos como /dev

Repositório no GitHub

  • Todo o código e os exemplos deste guia estão disponíveis em popovicu/linux-micro-distro
    • É possível compilar a imagem initramfs e reproduzir a prática

1 comentários

 
GN⁺ 2025-10-27
Comentários do Hacker News
  • Há alguns meses venho criando minha própria microdistribuição Linux
    O modo de usuário é composto por um único binário estático, com apenas alguns arquivos para dar suporte a contêineres microVM confidenciais
    A estrutura do initramfs é especialmente interessante. O processo em que o kernel descompacta o arquivo cpio, entra no tmpfs e executa o /init parece mágica
    Também é possível concatenar vários arquivos cpio, cada um com compressão própria, e eles são sobrepostos em sequência
    Graças a esse design simples e elegante, aprendi muito escrevendo meu próprio código de desempacotamento

  • Recentemente, o qemu passou a oferecer suporte a uftrace nas principais arquiteturas
    Quando especialistas perguntam “como depurar isso?”, essa é exatamente a resposta
    Mais detalhes podem ser vistos nesta thread

  • Eu também estou tocando um projeto parecido — azathos
    Ele inclui um toy init, um shell e alguns utilitários
    Coloquei o GNU coreutils para depuração e agora estou focado em desenhar janelas no framebuffer

  • Esse projeto é muito legal. Me lembra da época em que eu fazia uma “distribuição” baseada em disquete em 98 para criar imagens de PCs com Windows via broadcast UDP
    “make bzimage”, erros em scripts de init, reboot infinito… muitas lembranças
    É interessante como o jeito de fazer hoje não é tão diferente. Portar isso para o Raspberry Pi parece algo divertido e educativo. Talvez eu mesmo tente

    • Eu também me lembro de ter tentado instalar o Mandrake Linux em 98 com NetBIOS e ISDN, reiniciando dezenas de vezes por causa de erros de checksum
      No fim, um amigo gravou o conteúdo do sftp em um CD e isso resolveu, mas naquela época só dava para gravar em 2x
  • Fico curioso sobre o quão difícil seria executar isso como uma imagem de nuvem (por exemplo, Vultr, DigitalOcean) ou subir uma GUI para rodar o Firefox

    • Rodar como imagem de nuvem é relativamente fácil. Basta ter os drivers padrão do kernel e instalar a imagem
      Também dá para inicializar com outra distribuição e depois executar seu próprio kernel com kexec para instalar tudo em memória
      Para um exemplo real de implementação, dá para consultar o nixos-anywhere
    • Basta criar uma imagem com drivers virtio para rede e armazenamento, converter para qcow2 e registrar no DigitalOcean e afins
      É um trabalho mais simples do que parece
  • Se existisse uma versão desse projeto voltada para Raspberry Pi, seria realmente muito interessante

  • Eu estava me perguntando por que alguém faria isso manualmente, em vez de simplesmente explorar Linux com Gentoo

    • O Gentoo faz “build a partir do código-fonte”, mas o gerenciador de pacotes cuida da maior parte do trabalho
      Dá para customizar o espaço do usuário, mas não é ideal para aprender Linux em si
      Só o stage3 tarball já é praticamente uma “mini distribuição”
  • Para aprendizado, isso é realmente ótimo, e se a ideia for terminar rápido, buildroot é uma boa escolha

  • Aprendi muito com este post. Obrigado por ser um post tão rico em informação