Este é o segundo post da série sobre Linux Device Drivers Dev. O primeiro você pode conferir neste link.

Neste post vou mostrar como configurar o seu host para hospedar uma versão cross-compilada da kernel, para ser “bootada” pela Raspberry Pi através de uma rede.

Let’s hack it?!

Configuração

No diagrama da figura abaixo, exemplifico uma maneira de criar uma rede entre a Rpi e o host. Como pode-se notar, configurei um IP fixo para a porta ethernet do meu PC e um IP fixo (mostrarei mais adiante como fazer isso) para a Rpi, ligados diretamente um ou outro através de um cabo de rede comum.

Raspberry_PC

TFTP

Vamos preparar o nosso host para hospedar a kernel compilada.

O primeir passo é instalar o tftp-server:

# dnf install tftp-server

Agora, vamos checar se o serviço tftp está liberado no firewall do Fedora, para isso digite no terminal:

$ firewall-cmd --zone=public --list-all

Na linha services procure por tftp. Se você não encontrar, então precisamos liberar esse serviço:

# firewall-cmd --zone=public --add-service=tftp

NOTA: Para não precisar adicionar essa regra ao firewall toda vez que quisermos bootar pelo tftp, adicione o parâmetro –permanent ao comando acima.

Clonando a kernel

Para testarmos nosso setup do tftp, vamos compilar uma versão da kernel.

Primeiro, vamos clonar uma versão do repositório.

NOTA: Como você deve estar seguindo o linux-kernel-labs.pdf da free-electrons (assim como eu),  sugiro que você siga as instruções de lá. Vou reproduzi-las aqui com algum atalho, mas sugiro fortemente que você dê uma olhada nos capítulos “Downloading kernel source code” e “Kernel source code” daquele pdf.

$ git clone http://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
$ cd linux
$ git remote add stable git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git
$ git fetch stable

Esse processo deve demorar um pouco, dependendo da velocidade da sua conexão com a internet.

Confira as branches disponíveis:

$ git branch -a

Nós vamos utilizar a versão estável (stable) 4.1  :

$ git checkout -b 4.1.y stable/linux-4.1.y

Compilando a kernel

Vamos compilar a kernel clonada no passo anterior para podermos testar nosso setup.

Como no post anterior sobre o U-boot, precisamos setar a variável CROSS_COMPILE. Também precisamos setar a variável ARCH, que indica para qual arquitetura a kernel será cross-compilada.

 $ export ARCH=arm $ export CROSS_COMPILE=arm-linux-gnu- 

Estamos prontos para cross-compilar a kernel Linux.

$ make bcm2835_defconfig
$ make -j4 zImage dtbs

O primeiro make cria um arquivo de configuração específica para nossa Rpi (BCM2835 é o SOC da Raspberry Pi model B).
O segundo make cross-compila a kernel, gerando um arquivo compactado zImage e o arquivo do dtb (Device Tree Blob).

Por fim, copie os artefatos gerados para o diretório /var/lib/tftpboot/:

# cp ./arch/arm/boot/zImage /var/lib/tftpboot
# cp ./arch/arm/boot/dts/bcm2835-rpi-b.dtb /var/lib/tftpboot/

Bootando pela rede com U-boot

Abra seu terminal serial e ligue a Rpi a energia. Pressione Enter para interromper o U-boot.

Você deverá ver o terminal d U-boot (U-Boot>_).

Primeiro vamos configurar a rede, inicializando os dispositivos USB (a porta ethernet está conectada pelo barramento USB da Rpi), e indicando o IP da Rpi e do servidor tftp:

U-Boot> usb start
U-Boot> setenv ipaddr 192.168.0.2
U-Boot> setenv serverip 192.168.0.1

Em seguida, vamos fazer o download dos artefatos hospedados no nosso host (servidor tftp):

U-Boot> tftpboot ${scriptaddr} bcm2835-rpi-b.dtb
...
U-Boot> tftpboot ${kernel_addr_r} zImage
...

Se tudo ocorreu certo você deve ter recebido mensangens como “Bytes transferred = 3967 (f7f hex)”, sendo que o número pode variar, dependendo se você mexeu nas configurações da kernel, dentre outros fatores.

E finalmente, vamos “bootar” a kernel. Primeiro setamos a variável bootargs, que contém os parâmetros da kernel, como o qual porta serial (UART) a kernel deve direcionar suas mensagens, e, ainda, indicar a localização do rootfs. Neste exemplo, eu estou utilizando o rootfs do SDCard que criei com o ArchLinux.

U-Boot> setenv bootargs console=ttyAMA0 console=tty1 root=/dev/mmcblk0p2 rootwait
U-Boot> bootz ${kernel_addr_r} - ${scriptaddr}

O comando setenv configura variáveis no U-boot, e o comando bootz carrega a kernel que está armezanada na memória (o armazenamanto ocorreu no passo do tftpboot, mais acima no post).

Se tudo ocorreu corretamente, você deve ver as mensagens de boot da kernel:

Kernel image @ 0x1000000 [ 0x000000 - 0x371b28 ]
## Flattened Device Tree blob at 02000000
   Booting using the fdt blob at 0x2000000
   Using Device Tree in place at 02000000, end 02003f7e

Starting kernel ...

Uncompressing Linux... done, booting the kernel.
[    0.000000] Booting Linux on physical CPU 0x0
[    0.000000] Initializing cgroup subsys cpuset
[    0.000000] Initializing cgroup subsys cpu
[    0.000000] Initializing cgroup subsys cpuacct
[    0.000000] Linux version 4.1.20 (rnunez@localhost.localdomain) (gcc version 5.3.1 20160212 (Red Hat Cross 5.3.1-2) (GCC) ) #2 Sun Apr 3 16:34:18 BRT 2016
[    0.000000] CPU: ARMv6-compatible processor [410fb767] revision 7 (ARMv7), cr=00c5387d
[    0.000000] CPU: PIPT / VIPT nonaliasing data cache, VIPT nonaliasing instruction cache
[    0.000000] Machine model: Raspberry Pi Model B
[    0.000000] Memory policy: Data cache writeback
...

No próximo post iremos criar um módulo para kernel. Até lá! 😉

Referências:

[1] http://wiki.beyondlogic.org/index.php?title=Raspberry_Pi_Building_Mainline_Kernel
[2] http://blog.christophersmart.com/2014/01/15/add-permanent-rules-to-firewalld/
[3] http://www.informit.com/articles/article.aspx?p=1647051&seqNum=5

Anúncios