[LAB] Bootloader (U-Boot)

Baixando o U-Boot

Assim como nas atividades anteriores, os fontes do U-Boot foram previamente baixados e encontram-se no diretĆ³rio āˆ¼/dsle20/dl/bootloader. Crie um diretĆ³rio chamado bootloader dentro da pasta āˆ¼/dsle20 e, em seguida, extraia o U-boot no diretĆ³rio criado:

cd ~/dsle20/
mkdir bootloader && cd bootloader
unzip ~/dsle20/dl/bootloader/u-boot-master.zip

Acesse o diretĆ³rio do U-Boot e liste as configuraƧƵes prĆ©-definidas para as diversas plataformas suportadas pelo U-Boot. Devido Ć  extensĆ£o da lista de configuraƧƵes, Ć© recomendado a utilizaĆ§Ć£o do comando less. Este comando permite a visualizaĆ§Ć£o do conteĆŗdo de um arquivo ou output de algum comando, por meio de pĆ”ginas do tamanho da tela:

cd u-boot-master
ls configs/ | less
10m50_defconfig
3c120_defconfig
A10-OLinuXino-Lime_defconfig
A10s-OLinuXino-M_defconfig
A13-OLinuXino_defconfig
A13-OLinuXinoM_defconfig
A20-Olimex-SOM204-EVB_defconfig
A20-Olimex-SOM204-EVB-eMMC_defconfig
A20-Olimex-SOM-EVB_defconfig
A20-OLinuXino-Lime2_defconfig
A20-OLinuXino-Lime2-eMMC_defconfig
A20-OLinuXino-Lime_defconfig
A20-OLinuXino_MICRO_defconfig
A20-OLinuXino_MICRO-eMMC_defconfig
A33-OLinuXino_defconfig
a64-olinuxino_defconfig
adp-ae3xx_defconfig
adp-ag101p_defconfig
Ainol_AW1_defconfig
alt_defconfig
am335x_baltos_defconfig
am335x_boneblack_defconfig
am335x_boneblack_vboot_defconfig
:

Use as teclas espaƧo, b e q para exibir a prĆ³xima pĆ”gina, a pĆ”gina anterior ou encerrar a visualizaĆ§Ć£o, respectivamente. Uma vez que o U-Boot suporta diversas arquiteturas de hardware diferentes, Ć© necessĆ”rio selecionar uma delas antes de compilar o programa. Selecione a configuraĆ§Ć£o rpi_3_32b_defconfig e compile o U-Boot, indicando o prefixo do cross-compilador conforme configurado anteriormente:

make rpi_3_32b_defconfig
make -j2 CROSS_COMPILE=arm-linux-

Verifique o arquivo criado, u-boot.bin, atravƩs do comando:

ls -l u-boot.bin

Gravando o U-Boot

O processo de gravaĆ§Ć£o do bootloader Ć© dependente de hardware, especĆ­fico para cada plataforma. Conforme visto em aula, a RPi 3 busca o bootloader e firmwares relacionados ao processo de boot na partiĆ§Ć£o boot do cartĆ£o micro SD. Assim, dois procedimentos sĆ£o necessĆ”rios para gravar e ativar o U-Boot no processo de boot da RPi:

  1. Copiar o binĆ”rio u-boot.bin para a partiĆ§Ć£o boot do cartĆ£o micro SD;

  2. Configurar o arquivo config.txt para que o firmware da GPU, start.elf, execute o U-Boot no lugar do kernel Linux;

Ɖ possĆ­vel copiar o arquivo u-boot.bin para o cartĆ£o micro SD de vĆ”rias maneiras. Visto que jĆ” existe uma configuraĆ§Ć£o de rede entre a mĆ”quina de desenvolvimento e a RPi, realizada em atividades anteriores, o arquivo serĆ” copiado via comando scp:

scp u-boot.bin pi@10.1.1.100:/home/pi/

Logue na RPi, via SSH, e copie o arquivo do diretĆ³rio home para o diretĆ³rio boot com privilĆ©gios de administrador:

ssh pi@10.1.1.100
sudo cp u-boot.bin /boot/
ls /boot
bcm2708-rpi-0-w.dtb
bcm2710-rpi-cm3.dtb
bcm2708-rpi-b.dtb
bootcode.bin
bcm2708-rpi-b-plus.dtb cmdline.txt
bcm2708-rpi-cm.dtb
bcm2709-rpi-2-b.dtb
bcm2710-rpi-3-b.dtb
config . txt
COPYING.linux
fixup_cd.dat
bcm2710-rpi-3-b-plus.dtb fixup .dat
fixup_db.dat
overlays
fixup_x.dat
start_cd. elf
issue. txt
start_db. elf
kernel7.img
start . elf
kernel.img
start_x . elf
LICENCE.broadcom 
u-boot.bin

Feito isso, adicione a seguinte linha no final do arquivo config.txt:

sudo nano /boot/config. txt
[..]
dtparam=audio=on
enable_uart=1
kernel=u-boot.bin

O parĆ¢metro acima especifica qual imagem do kernel, o firmware start.elf deve carregar. Neste caso, a imagem Ć© o prĆ³prio U-Boot. ApĆ³s salvar as alteraƧƵes no arquivo, renicie a RPi (sudo reboot).

AtenĆ§Ć£o, sĆ³ reinicie a RPi se vocĆŖ possui uma conexĆ£o serial funcional entre ela e a mĆ”quina de desenvolvimento, pois a Ćŗnica interaĆ§Ć£o com o menu do U-Boot, por enquanto, Ć© via serial.

Por Ćŗltimo, interrompa o processo de boot do U-Boot pressionando uma tecla para entrar no shell:

U-Boot 2018.07-rc1 (Oct 3 2019 - 19:50:41 -0300)
DRAM: 948 MiB
RPI 3 Model B (0xa02082)
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 ... 3 USB Device(s) found
scanning usb for storage devices ... 0 Storage Device(s) found
Hit any key to stop autoboot: 0
U-Boot>

Configurando variƔveis de ambiente no U-Boot

ApĆ³s obter acesso ao shell do U-Boot, configure algumas variĆ”veis de ambiente bĆ”sicas para manter o sistema da RPi bootĆ”vel, pois por padrĆ£o, o U-Boot nĆ£o identifica a imagem do kernel automaticamente. Inicialmente, desative o processo de autoboot:

U-Boot
setenv bootdelay -1

Futuramente, o U-Boot serƔ configurado para carregar o kernel pela rede, de uma pasta de sua mƔquina de desenvolvimento. Portanto, configure o endereƧo IP da RPi e mƔquina de desenvolvimento:

U-Boot
setenv ipaddr 10.1.1.100
setenv serverip 10.1.1.1

Por fim, salve as alteraƧƵes realizados no disco, de tal forma que elas estejam disponĆ­veis na prĆ³xima inicializaĆ§Ć£o, e reinicie o RPi:

U-Boot
saveenv
reset

ApĆ³s enviar o comando saveenv, o U-Boot cria um arquivo de configuraĆ§Ć£o chamado u-boot.env que contĆ©m todas as variĆ”veis de ambiente definidas. ApĆ³s reiniciar novamente a RPi, o processo de autoboot nĆ£o deve ser inicializado e o controle do shell exibido logo em seguida. Para ā€œbootarā€ o Raspbian novamente, pelo U-Boot, algumas configuraƧƵes adicionais sĆ£o necessĆ”rias. O primeiro passo, Ć© carregar um arquivo (imagem do kernel) do cartĆ£o micro SD para a RAM em um endereƧo especĆ­fico. Utilize o seguinte comando:

U-Boot
fatload mmc 0:1 ${kernel_addr_r} kernel7.img

O comando acima carrega um arquivo binĆ”rio de um sistema de arquivos FAT (fatload). Os parĆ¢metros sĆ£o:

  • mmc: o dispositivo de armazenamento onde se encontra o binĆ”rio (cartĆ£o SD);

  • 0: o nĆŗmero do dispositivo, pois muitas vezes o seu target pode possuir mais de um dispositivo de armazenamento;

  • 1: o nĆŗmero da partiĆ§Ć£o no dispositivo (partiƧƵes sĆ£o enumeradas a partir de 1);

  • ${kernel_addr_r}: o endereƧo inicial na RAM onde deseja-se carregar o binĆ”rio, neste caso a configuraĆ§Ć£o do U-Boot jĆ” fornece uma variĆ”vel de ambiente com o endereƧo inicial da RAM, para carregar o kernel (${kernel_addr_r});

  • kernel7.img: o binĆ”rio que se deseja carregar. Lembrando que por padrĆ£o, a partiĆ§Ć£o boot do Raspbian fornece duas imagens: kernel.img e kernel7.img. A primeira Ć© para as versƵes de hw anteriores (RPi e RPi 2) e a Ćŗltima (kernel7.img) Ć© a imagem para as placas da RPi 3 em diante;

Algumas plataformas possuem dispositivos de hardware que nĆ£o podem ser identificados dinamicamente pelo kernel. Em tais casos, Ć© necessĆ”rio um mecanismo para informar o kernel sobre dispositivos presentes no sistema. Atualmente, o mecanismo utilizado para tal funĆ§Ć£o Ć© chamado de Device Tree, que Ć© uma estrutura de dados que descreve a topologia e configuraĆ§Ć£o de hardware no sistema. Analisaremos esse mecanismo em breve durante o curso.

A RPI 3 Ć© um tipo de plataforma que utiliza esse recurso e bootloader Ć© o responsĆ”vel por passar o Device Tree para o kernel e, portanto, Ć© necessĆ”rio fazer o loading desse arquivo no U-Boot. O processo Ć© o mesmo anterior, porĆ©m com algumas alteraƧƵes nos parĆ¢metros:

Caso esteja utilizando a RPi 3B+ substitua o device tree utilizado pelo device tree bcm2710-rpi-3-b-plus.dtb, ao longo do treinamento.

U-Boot
fatload mmc 0:1 ${fdt_addr_r} bcm2710-rpi-3-b.dtb
  • mmc: o dispositivo de armazenamento onde se encontra o binĆ”rio (cartĆ£o SD);

  • 0: o nĆŗmero do dispositivo, pois muitas vezes o seu target pode possuir mais de um dispositivo de armazenamento;

  • 1: o nĆŗmero da partiĆ§Ć£o no dispositivo (partiƧƵes sĆ£o enumeradas a partir de 1);

  • ${fdt_addr_r}: o endereƧo inicial na RAM onde deseja-se carregar o binĆ”rio, neste caso a configuraĆ§Ć£o do U-Boot jĆ” fornece uma variĆ”vel de ambiente com o endereƧo inicial da RAM, para carregar o Flattened Device Tree (${fdt_addr_r});

  • bcm2710-rpi-3-b.dtb: arquivo compilado do Device Tree (dtb) referente Ć  RPi 3 B;

Estes sĆ£o basicamente os Ćŗnicos arquivos necessĆ”rios para realizar o boot do Raspbian via U-Boot. Entretanto, alĆ©m dos arquivos, ainda Ć© necessĆ”rio configurar alguns parĆ¢metros do kernel. Configure a variĆ”vel de ambiente bootargs, responsĆ”vel por armazenar parĆ¢metros para serem passados ao kernel:

U-Boot
setenv bootargs 8250.nr_uarts=1 root=/dev/mmcblk0p2 rootwait console=ttyS0,115200
  • 8250.nr_uarts=1: nĆŗmero de portas seriais para serem registradas (utilizadas);

  • root=/dev/mmcblk0p2: path para a localizaĆ§Ć£o do RootFS (Root FileSystem);

  • rootwait: espera (indefinidamente) a inicializaĆ§Ć£o dispositivo onde o RootFS estĆ” localizado. mmcblk0 refere-se ao micro SD e p2 Ć  partiĆ§Ć£o nĆŗmero 2, visto que a primeira Ć© a partiĆ§Ć£o de boot;

  • console=ttyS0,115200: redireciona um console para a porta serial ttyS0 (mini UART da RPi 3), e seu respectivo baudrate;

Finalmente, com as configuraƧƵes acima realizadas, ā€œbastaā€ dar o comando de boot:

U-Boot
bootz ${kernel_addr_r} - ${fdt_addr_r}

onde:

  • kernel_addr_r: Ć© o endereƧo na RAM onde estĆ” carregada a imagem do kernel;

  • -: seria o endereƧo na RAM da imagem initrd, que Ć© uma imagem do RootFS. Ɖ possĆ­vel carrega-lo na RAM, assim como kernel e Device Tree. No entanto, no momento a RPi nĆ£o possui nenhuma imagem desse tipo. Ela serĆ” gerada em atividades futuras. Este parĆ¢metro Ć© opcional;

  • fdt_addr_r Ć© o endereƧo na RAM onde estĆ” carregado o compilado do Device Tree;

Se os comandos acima foram executados corretamente, vocĆŖ deverĆ” enxergar o loading do kernel pela serial.

Criando um script de inicializaĆ§Ć£o no U-Boot

O U-Boot possui uma funcionalidade que permite que o usuĆ”rio crie scripts contendo sequĆŖncia de comandos, como os executados acima. Na sua mĆ”quina de desenvolvimento, navegue atĆ© o diretĆ³rio do U-Boot e crie o seguinte arquivo:

cd ~/dsle20/bootloader/u-boot-master
gedit rpi3scr.txt

Digite (copie) todos os comandos novamente no arquivo aberto e em seguida salve-o:

fatload mmc 0:1 ${kernel_addr_r} kernel7.img
fatload mmc 0:1 ${fdt_addr_r} bcm2710-rpi-3-b.dtb
setenv bootargs 8250.nr_uarts=1 root=/dev/mmcblk0p2 rootwait console=ttyS0,115200
bootz ${kernel_addr_r} - ${fdt_addr_r}

Em seguida, dentro da pasta tools no diretĆ³rio do U-Boot, existe uma ferramenta chamada mkimage capaz de criar imagens do U-Boot, kernel, RootFS e inclusive scripts para o U-Boot. Digite o seguinte comando:

tools/mkimage -A arm -O linux -T script -d rpi3scr.txt boot.scr

onde os argumentos representam: arquitetura do executƔvel (-A), sistema operacional (-O), tipo da imagem (-T), arquivo de entrada com os comandos digitados no gedit (-d) e arquivo de saƭda (boot.src), que Ʃ uma imagem do script.

ApĆ³s a execuĆ§Ć£o do comando, copie o arquivo boot.scr para o diretĆ³rio boot da RPi via scp. Se tudo foi realizado corretamente, reinicie a RPi e digite o comando boot no shell do U-Boot.

Ɖ possĆ­vel ativar o autoboot atravĆ©s da modificaĆ§Ć£o da variĆ”vel de ambiente bootdelay, que representa o delay em segundos antes de iniciar o boot pelo script boot.scr. Se desejar, altera-a, salve as variĆ”veis de ambiente no cartĆ£o SD (saveen) e reinicie o U-Boot.

Last updated