Linux embedded – Introdução a sistemas embarcados – Parte 3

Fazendo um boot mínimo
Seguindo o cronograma, vamos primeiramente visualizar como acontece um boot com o mínimo de recursos possíveis. O processo é muito simples, mas servirá como base para o que vem por ai.
Primeiramente baixe o Phantom daqui.

Processo de boot do Phantom
Basicamente o Phantom é um kernel, um initrd e um bootloader – no caso, o syslinux. O processo para gerar uma iso ‘bootável’ não é o mesmo para efetuar boot por um HD por exemplo. Já quando se faz o boot pelo pendrive, o processo é bastante parecido. O processo de boot de um sistema operacional está brevemente descrito no primeiro post da série, mas agora vamos direcioná-lo ao Phantom.
Quando o boot é efetuado por um CD, o dispositivo deve estar referenciado na sequência de boot do hardware como dispositivo de boot primário. Para tal, é necessário entrar no menu da BIOS. Diversas motherboards permitem que se acesse o menu de boot através da tecla F8 enquanto a máquina está em processo de POST (Power On Self Test). Selecionado esse dispositivo, então é iniciado o menu de boot, que foi configurado de forma a ser exibido e com um timeout de 10 segundos.

O kernel
Ao selecionar uma das entradas do menu, o kernel e o initrd são carregados para a memória. O Kernel se auto-descomprime seguidamente fazendo o mesmo processo com o initrd. Após a descompressão do initrd em uma área reservada de memória, o kernel chama o programa init e finaliza sua parte na tarefa de boot inicial.

O initrd
Como explicado no primeiro post, o initrd é uma estrutura raiz mínima necessária para preparação de um boot inicial. Ele é utilizado para preparar o ambiente para o sistema raiz instalado em disco. O initrd possui as rotinas de preparação do hardware, modulos que devem ser pré-carregados, criação dos dispositivos e então monta a raiz do disco.

O programa init
Inicialmente parece obscuro o processo de boot inicial porque não se vê realmente a origem desse processo. Sabendo que o processo é iniciado pelo programa init, tem-se agora alguma pista; mas vamos além da pista.
Quando o programa init é chamado pelo kernel, ele lê em /etc/init/ os scripts lá contidos. O primeiro é o boot.conf, com o seguinte conteúdo:

Ou seja, a primeira tarefa do startup é chamar o /etc/init.d/boot. Esse script de boot poderia ter outro nome e outro conteúdo dependendo do propósito, então para não entrar em detalhes nesse momento (que não é o propósito), resumidamente esse script de boot faz todo o processo de inicialização do Phantom e chama a interface.

Então, para o boot mínimo vamos utilizar apenas o kernel e o initrd.

Boot com Qemu
Durante o desenvolvimento pode ser uma tarefa desagradável efetuar os testes se não tiver disponível uma ferramenta pra agilizar o processo de testes. O Qemu é uma ferramenta essencial para tais testes, mas o bom mesmo é compilá-lo, porque quando instalado via ferramentas do sistema é muito comum que o pacote principal contenha apenas o boot para a plataforma x86. Compilando-o você garantirá suporte a outras arquiteturas como ARM por exemplo.
Baixe-o daqui e compile-o. Em seu site também se encontra toda a documentação para sanar suas dúvidas, sendo que aqui veremos apenas alguns comandos, requeridos para o teste.

Como citado lá em cima, nesse momento da leitura seu download do Phantom já deve ter terminado. Todo o ambiente é (obviamente) Linux, assim como todos os comandos de sistema disponíveis aqui.

– Monte a iso
ALgumas pessoas não sabem, mas para montar o arquivo iso deve-se utilizar o dispositivo loop. O comando é simples e normalmente só é possível executá-lo como root. Execute-o e faça a copia do kernel e initrd para /tmp:

Agora façamos o boot com o Qemu que você já deve ter a compilação concluída:

Esse comando faz com que a máquina virtual use seu gerenciador de boot com os parâmetros passados por linha. Essa é uma boa forma de efetuar um boot para quem está desenvolvendo e certamente você o preferirá quando for testar a sua compilação de sistema. Para testar um boot diretamente da iso, é um pouco mais simples:

Para desenvolvimento, você talvez queira um disco para testes. Esse disco pode ser criado com o programa qemu-img.

Então, quando se pensa em um boot, pensa-se em kernel+initrd. Fechado? – Eu respondo:
– Não.

Um boot pode iniciar diversos initrd de uma vez. Vamos a um exemplo, desmantelando um sistema pequeno muito legal chamado SLITaz. Baixa a iso e vamos dissecá-la.

Dissecando um sistema
Alguns sistemas utilizam basicamente o kernel e initrd. Outros utilizam também Cloop, Squashfs, Unionfs, mas não vamos entrar em muitos detalhes sobre isso. De fato é necessário saber que recursos cada peça do sistema está utilizando, portanto entra em ação uma ferramenta do sistema importantíssima – o programa file.
O file é um programa utilizado para recolher informações do arquivo pretendido, seja um programa, um arquivo texto, uma imagem ou qualquer outra coisa hospedada sobre o sistema de arquivos. Vamos iniciar a análise do sistema SLITaz:

Com isso já vemos algumas coisas interessantes:

O arquivo bzImage e o arquivo vmlinuz-2.6.37-slitaz possuem o mesmo tamanho. Presumo que sejam o mesmo arquivo, mas para confirmar, podemos utlizar o programa md5sum para verificar o hash do arquivo:

São o mesmo arquivo. E porque? – não sei. Olhando o arquivo de menu de boot em boot/isolinux/isolinux.cfg Não há referências para o arquivo vmlinuz-2.6.37-slitaz e realmente não vejo o porque, então pelo visto duplicaram sem querer. Mas já que falamos do menu de boot, vamos ver a primeira entrada que referencia os initrd:

Olha que legal! Basta separar os initrds por vírgula!
Isso é útil para modularizar o boot, sendo que a última opção do menu de boot é um sistema mínimo, onde a descompressão é feita apenas com o rootfs1.gz. Para verificar o que a iso oferece, faça um boot com o Qemu em cada uma das entradas.

Agora será necessário descomprimir o rootfs para ver seu conteúdo. Olhando para ele, bastaria usar gzip -d rootfs1.gz, mas na verdade não é bem assim:

E nesse caso o comando file também não ajudou:

Aqui poderia parecer o fim da linha; parece então que o rootfs não está comprido, e foi o que pensei da primeira vez que estava fazendo a descompressão. Esse arquivo sem compressão é um arquivo cpio. Um arquivo gerado com cpio contém metadados; você encontrará mais informações pelo google, mas dê uma lida no manual (digite ‘man 5 cpio’ no terminal).

De fato o arquivo contém uma compressão, que é o novo formato suportado pelo kernel, o lzma. O que causou a confusão foi o sufixo .gz, bastando renomeá-o antes de fazer a descompressão:

E agora, a extração do arquivo resultante, precedido pela verificação do tipo do arquivo:

Observe a descompressão acontecendo e pronto! Uma raiz no diretório taz! Opa, estão faltando diretórios para chamar isso de raiz. Extraia os demais rootfs juntos então e digite o comando ls. Como se pode ver, lá está o init. nesse caso, um script shell que chama o /sbin/init, ou seja, um processo de boot diferente do Phantom.

Explorando um pouco a estrutura, podemos coletar informações sobre a construção do sistema; biblioteca C utilizada e arquitetura, por exemplo:

Ou seja, o sistema é baseado na mesma arquitetura e biblioteca de um desktop 32 bits padrão. Desse modo, é possível incluir seus próprios programas sem precisar compilar nada, apenas copiando-os do seu sistema de 32 bits. Depois disso, basta fechar um arquivo cpio, comprimí-lo, substituí-lo na iso e efetuar o boot.

A reconstrução será explicada no próximo post, onde trataremos de compilar um sistema baseado no buildroot.
Boa diversão com seus testes!

Comments

comments

Djames Suhanko

Djames Suhanko é Perito Forense Digital. Já atuou com deployer em sistemas de missão critica em diversos países pelo mundão. Programador Shell, Python, C, C++ e Qt, tendo contato com embarcados ( ora profissionalmente, ora por lazer ) desde 2009.

2 comentários em “Linux embedded – Introdução a sistemas embarcados – Parte 3

Deixe uma resposta