Utilizando o U-Boot na Raspberry Pi
- por Sergio Prado
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