Utilizando o U-Boot na Raspberry Pi

- por Sergio Prado

Categorias: Raspberry Pi, U-Boot Tags: ,

O Das U-Boot é um dos bootloaders mais utilizados em sistemas com Linux embarcado, especialmente em plataformas ARM. É um bootloader recheado de recursos, com opções de boot pela rede, USB, cartão SD, serial, etc. Possui um terminal de comandos bastante completo, suporta variáveis de ambiente e permite a criação de scripts que tornam a configuração do processo de boot bastante flexível.

Porém, a Raspberry Pi não utiliza o U-Boot por padrão. O processo de boot da Raspberry Pi é gerenciado por um bootloader proprietário e fechado da Broadcom, conforme descrevi no artigo “Raspberry Pi e o processo de boot“.

Mas nem tudo está perdido. É possível fazer com que o bootloader da Raspberry Pi execute o U-Boot ao invés do kernel Linux. E o U-Boot por sua vez pode ser configurado para iniciar o kernel Linux e fazer o boot do sistema operacional. Vamos aprender como fazer isso neste artigo.

Os testes foram feitos em uma máquina de 64 bits rodando o Fedora 28 e uma Raspberry Pi 3 com uma distribuição Linux instalada no cartão SD.

Vamos começar criando um diretório de trabalho:

$ mkdir -p ~/uboot-rpi && cd ~/uboot-rpi

O primeiro passo será compilar o U-Boot, e para isso será necessário um toolchain. Vamos utilizar o toolchain da Linaro:

$ wget https://releases.linaro.org/components/toolchain/binaries/6.4-2018.05/arm-linux-gnueabihf/gcc-linaro-6.4.1-2018.05-x86_64_arm-linux-gnueabihf.tar.xz
$ tar xfv gcc-linaro-6.4.1-2018.05-x86_64_arm-linux-gnueabihf.tar.xz

Coloque o diretório de binários do toolchain na variável de ambiente PATH:

$ export PATH=~/uboot-rpi/gcc-linaro-6.4.1-2018.05-x86_64_arm-linux-gnueabihf/bin:$PATH

Agora faça o download do código-fonte do U-Boot (a versão oficial do U-Boot já possui suporte à Raspberry Pi):

$ wget ftp://ftp.denx.de/pub/u-boot/u-boot-2018.05.tar.bz2
$ tar xfv u-boot-2018.05.tar.bz2
$ cd u-boot-2018.05

Configure e compile o U-Boot para a Raspberry Pi 3:

$ make rpi_3_32b_defconfig
$ make CROSS_COMPILE=arm-linux-gnueabihf- -j4

Confirme que a imagem do U-Boot foi gerada com sucesso:

$ ls -la u-boot.bin
-rw-rw-r-- 1 sprado sprado 427520 Jul 24 18:37 u-boot.bin

O U-Boot é capaz de ler um script de boot (*.scr) na inicialização com os comandos que ele deve executar no boot. Vamos então criar este arquivo para que ele possa fazer automaticamente o boot do kernel.

Primeiro crie um arquivo texto com os comandos que ele deverá executar no boot:

$ cat <<"EOF" > boot.cmd
mmc dev 0
fatload mmc 0:1 ${kernel_addr_r} zImage
setenv bootargs console=tty1 console=ttyAMA0,115200 earlyprintk root=/dev/mmcblk0p2 rootwait
bootz ${kernel_addr_r} - ${fdt_addr}
EOF

E gere o arquivo de script de boot com a ferramenta mkimage do U-Boot:

$ tools/mkimage -C none -A arm -T script -d boot.cmd boot.scr

Confirme que o script de boot foi gerado com sucesso:

$ ls -l boot.scr
-rw-rw-r-- 1 sprado sprado 300 Jul 24 20:40 boot.scr

Vamos agora salvar os arquivos na partição de boot do cartão SD da Raspberry Pi. Coloque o cartão SD na sua máquina de desenvolvimento e execute os comandos abaixo para montar a partição de boot (substitua sdX pelo nome do arquivo de dispositivo do cartão SD):

$ cd ~/uboot-rpi && mkdir -p boot
$ sudo mount /dev/sdX1 boot/

Copie a imagem do U-Boot e o script de boot para o cartão SD:

$ sudo cp -v u-boot-2018.05/u-boot.bin boot/
$ sudo cp -v u-boot-2018.05/boot.scr boot/

Agora só falta configurar o bootloader da Raspberry Pi para executar o U-Boot ao invés do kernel Linux. Para isso, basta alterar o arquivo config.txt existente na partição do boot do cartão SD.

Primeiro crie o arquivo de configuração:

$ cat <<"EOF" > config.txt
kernel=u-boot.bin
enable_uart=1
dtoverlay=pi3-miniuart-bt
EOF

E depois copie para o cartão SD, fazendo antes um backup do arquivo anterior:

$ sudo cp -v boot/config.txt boot/config.txt.old
$ sudo cp -v config.txt boot/config.txt

Por fim, desmonte a partição de boot do cartão SD:

$ sudo umount boot/

Agora é só inserir o cartão SD na Raspberry Pi e testar!

U-Boot 2018.05 (Jul 24 2018 - 22:27:24 -0300)
 
DRAM: 948 MiB
RPI 3 Model B (0xa22082)
MMC: mmc@7e202000: 0, sdhci@7e300000: 1
Loading Environment from FAT... *** Warning - bad CRC, using default environment
 
Failed (-5)
In: serial
Out: vidconsole
Err: vidconsole
Net: No ethernet found.
starting USB...
USB0: scanning bus 0 for devices... Timeout poll on interrupt endpoint
Failed to get keyboard state from device 1a2c:0c23
3 USB Device(s) found
scanning usb for storage devices... 0 Storage Device(s) found
Hit any key to stop autoboot: 0
switch to partitions #0, OK
mmc0 is current device
Scanning mmc 0:1...
Found U-Boot script /boot.scr
252 bytes read in 2 ms (123 KiB/s)
## Executing script at 02000000
switch to partitions #0, OK
mmc0 is current device
4571560 bytes read in 216 ms (20.2 MiB/s)
Kernel image @ 0x1000000 [ 0x000000 - 0x45c1a8 ]
## Flattened Device Tree blob at 2effb600
Booting using the fdt blob at 0x2effb600
reserving fdt memory region: addr=0 size=1000
Using Device Tree in place at 2effb600, end 2f002fa0
 
Starting kernel ...
 
[ 0.000000] Booting Linux on physical CPU 0x0
[ 0.000000] Linux version 4.9.59 (oe-user@oe-host) (gcc version 7.3.0 (GCC) ) #1 SMP Tue Apr 3 07:35:10 -03 2018
[ 0.000000] CPU: ARMv7 Processor [410fd034] revision 4 (ARMv7), cr=10c5383d
[ 0.000000] CPU: div instructions available: patching division code
[ 0.000000] CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing instruction cache
[ 0.000000] OF: fdt:Machine model: Raspberry Pi 3 Model B Rev 1.2
[ 0.000000] cma: Reserved 8 MiB at 0x3ac00000
[ 0.000000] Memory policy: Data cache writealloc
[ 0.000000] percpu: Embedded 14 pages/cpu @ba35b000 s25548 r8192 d23604 u57344
[ 0.000000] Built 1 zonelists in Zone order, mobility grouping on. Total pages: 240555
[ 0.000000] Kernel command line: console=tty1 console=ttyAMA0,115200 earlyprintk root=/dev/mmcblk0p2 rootwait
[ 0.000000] PID hash table entries: 4096 (order: 2, 16384 bytes)
[ 0.000000] Dentry cache hash table entries: 131072 (order: 7, 524288 bytes)
[ 0.000000] Inode-cache hash table entries: 65536 (order: 6, 262144 bytes)
[ 0.000000] Memory: 940360K/970752K available (7168K kernel code, 485K rwdata, 2024K rodata, 1024K init, 769K bss, 22200K reserved, 8192K cma-reserved)
[...]

Um abraço,

Sergio Prado

  • Guilherme Costa

    Sérgio, usar o U-Boot dessa forma na Raspberry Pi traz alguma vantagem?

    • Olá Guilherme,

      Sim, principalmente se você quiser fazer o boot do kernel por uma outra interface que não seja o sdcard. Por exemplo, com o U-Boot dá para fazer o boot do kernel pela rede via TFTP.

      Um abraço!

Navegue
Creative Commons Este trabalho de Sergio Prado é licenciado pelo
Creative Commons BY-NC-SA 3.0.