A Handy U-Boot Trick
Embedded developers working on kernels or bare-metal programs often go through several development cycles. Each time the developer modifies the code, the code has to be compiled, the ELF (Executable and Linkable Format)/kernel image has to be copied onto the SD card, and the card then has to be transferred from the PC to the development board and rebooted. In my experience as a developer, I found the last two steps to be a major bottleneck. Even copying files to the fastest SD cards is slower than copying files between hard drives and sometimes between computers across the network.
Moreover, by frequently inserting and removing the SD card from the slot, one incurs the risk of damaging the fragile connectors on the development boards. Believe me! I lost a BeagleBoard by accidentally applying too much force while holding the board and pulling out the SD card. The pressure caused the I2C bus to fail. Because the power management chip was controlled by I2C, nothing other than the serial terminal worked after that. Setting aside the cost of the board, a board failure at a critical time during a project is catastrophic if you do not have a backup board.
After losing the BeagleBoard, I hit upon the idea to load my bare-metal code over the LAN via bootp and TFTP and leave the board untouched. This not only reduced the risk of mechanically damaging my board, but it also improved on my turn-around times. I no longer needed to copy files to the SD card and move it around.
In this article, I present a brief introduction to U-Boot and then describe the necessary configurations to set up a development environment using DHCP and TFTP. The setup I present here will let you deploy and test new builds quickly with no more than rebooting the board. I use the BeagleBone Black as the target platform and Ubuntu as the development platform for my examples in this article. You may, however, use the methods presented here to work with any board that uses U-Boot or Barebox as its stage-2 bootloader.
U-Boot is a popular bootloader used by many development platforms. It supports multiple architectures including ARM, MIPS, AVR32, Nios, Microblaze, 68K and x86. U-Boot has support for several filesystems as well, including FAT32, ext2, ext3, ext4 and Cramfs built in to it. It also has a shell where it interactively can take input from users, and it supports scripting. It is distributed under the GPLv2 license. U-Boot is a stage-2 bootloader.
The U-Boot project also includes the x-loader. The x-loader is a small stage-1 bootloader for ARM. Most modern chips have the ability to read a FAT32 filesystem built in to the ROM. The x-loader loads the U-Boot into memory and transfers control to it. U-Boot is a pretty advanced bootloader that is capable of loading the kernel and ramdisk image from the NAND, SD card, USB drive and even the Ethernet via bootp, DHCP and TFTP.
Figure 1 shows the default boot sequence of the BeagleBone Black.
This sequence is more or less applicable to most
embedded systems. The x-loader and U-Boot executables are stored in the
files called MLO and uboot.img, respectively. These files are stored in
a FAT32 partition. The serial port outputs of the BeagleBone are shown
in Listings 1–3. The x-loader is responsible for the output shown in
Listing 1. Once the execution is handed over to U-Boot, it offers you a
few seconds to interrupt the boot sequence, as shown in Listing 2. If you
choose not to interrupt, U-Boot executes an environment variable called
bootcmd holds the search sequence for
a file called
uImage. This is the kernel image. The kernel
image is loaded into the memory, and the execution finally is transferred
to the kernel, as shown in Listing 3.
Figure 1. Boot Sequence
Listing 1. The Serial Console Output from the Stage-1 Bootloader
U-Boot SPL 2013.04-rc1-14237-g90639fe-dirty (Apr 13 2013 - 13:57:11) musb-hdrc: ConfigData=0xde (UTMI-8, dyn FIFOs, HB-ISO Rx, ↪HB-ISO Tx, SoftConn) musb-hdrc: MHDRC RTL version 2.0 musb-hdrc: setup fifo_mode 4 musb-hdrc: 28/31 max ep, 16384/16384 memory USB Peripheral mode controller at 47401000 using PIO, IRQ 0 musb-hdrc: ConfigData=0xde (UTMI-8, dyn FIFOs, HB-ISO Rx, ↪HB-ISO Tx, SoftConn) musb-hdrc: MHDRC RTL version 2.0 musb-hdrc: setup fifo_mode 4 musb-hdrc: 28/31 max ep, 16384/16384 memory USB Host mode controller at 47401800 using PIO, IRQ 0 OMAP SD/MMC: 0 mmc_send_cmd : timeout: No status update reading u-boot.img reading u-boot.img
Listing 2. The Serial Console Output from the Stage-2 Bootloader
U-Boot 2013.04-rc1-14237-g90639fe-dirty (Apr 13 2013 - 13:57:11) I2C: ready DRAM: 512 MiB WARNING: Caches not enabled NAND: No NAND device found!!! 0 MiB MMC: OMAP SD/MMC: 0, OMAP SD/MMC: 1 *** Warning - readenv() failed, using default environment musb-hdrc: ConfigData=0xde (UTMI-8, dyn FIFOs, HB-ISO Rx, ↪HB-ISO Tx, SoftConn) musb-hdrc: MHDRC RTL version 2.0 musb-hdrc: setup fifo_mode 4 musb-hdrc: 28/31 max ep, 16384/16384 memory USB Peripheral mode controller at 47401000 using PIO, IRQ 0 musb-hdrc: ConfigData=0xde (UTMI-8, dyn FIFOs, HB-ISO Rx, ↪HB-ISO Tx, SoftConn) musb-hdrc: MHDRC RTL version 2.0 musb-hdrc: setup fifo_mode 4 musb-hdrc: 28/31 max ep, 16384/16384 memory USB Host mode controller at 47401800 using PIO, IRQ 0 Net: <ethaddr> not set. Validating first E-fuse MAC cpsw, usb_ether Hit any key to stop autoboot: 0
Listing 3. The Serial Console Output from the Stage-2 Bootloader and Kernel
gpio: pin 53 (gpio 53) value is 1 Card did not respond to voltage select! . . . gpio: pin 54 (gpio 54) value is 1 SD/MMC found on device 1 reading uEnv.txt 58 bytes read in 4 ms (13.7 KiB/s) Loaded environment from uEnv.txt Importing environment from mmc ... Running uenvcmd ... Booting the bone from emmc... gpio: pin 55 (gpio 55) value is 1 4215264 bytes read in 778 ms (5.2 MiB/s) gpio: pin 56 (gpio 56) value is 1 22780 bytes read in 40 ms (555.7 KiB/s) Booting from mmc ... ## Booting kernel from Legacy Image at 80007fc0 ... Image Name: Angstrom/3.8.6/beaglebone Image Type: ARM Linux Kernel Image (uncompressed) Data Size: 4215200 Bytes = 4 MiB Load Address: 80008000 Entry Point: 80008000 Verifying Checksum ... OK ## Flattened Device Tree blob at 80f80000 Booting using the fdt blob at 0x80f80000 XIP Kernel Image ... OK OK Using Device Tree in place at 80f80000, end 80f888fb Starting kernel ... Uncompressing Linux... done, booting the kernel. [ 0.106033] pinctrl-single 44e10800.pinmux: prop pinctrl-0 ↪index 0 invalid phandle . . . [ 9.638448] net eth0: phy 4a101000.mdio:01 not found on slave 1 .---O---. | | .-. o o | | |-----.-----.-----.| | .----..-----.-----. | | | __ | ---'| '--.| .-'| | | | | | | | |--- || --'| | | ' | | | | '---'---'--'--'--. |-----''----''--' '-----'-'-'-' -' | '---' The Angstrom Distribution beaglebone ttyO0 Angstrom v2012.12 - Kernel 3.8.6 beaglebone login:
The search sequence defined in the
bootcmd variable and
the filename (uImage) are hard-coded in the U-Boot source code (see Listing 9).
Listing 4 shows the formatted content of the
bootcmd. The interesting parts of
bootcmd are lines 19–28. This part of the script checks
for the existence of a file called uEnv.txt. If the file is
found, the file is loaded into the memory (line 19). Then, it is imported
to the environment ready to be read or executed (line 22). After this,
the script checks to see if the variable
uenvcmd is defined
(line 24). If it is defined, the script in the variable is executed.
uEnv.txt file is a method for users to insert scripts into the
environment. Here, we'll use this to override the default search sequence
and load the kernel image or an ELF file from the TFTP server.
Bharath Bhushan Lohray is a PhD student working on his dissertation on image compression techniques at the Department of Electrical and Computer Engineering, Texas Tech University.