Using QEMU for Embedded Systems Development, Part 3

It's time to u-boot

It's time to u-boot

This is the last article of this series on QEMU. In the previous article, we worked on bare-metal programming, and discussed the need for a bootloader. Most GNU/Linux distros use GRUB as their boot-loader (earlier, LILO was the choice). In this article, we will test the famous U-Boot (Universal BootLoader).

In embedded systems, especially in mobile devices, ARM processor-based devices are leading the market. For ARM, U-Boot is the best choice for a bootloader. The good thing about it is that we can use it for different architectures like PPC, MIPS, x86, etc. So let’s get started.

Download and compile U-Boot

U-Boot is released under a GPL licence. Download it from this FTP server, which has every version of U-Boot available. For this article, I got version 1.2.0 (u-boot-1.2.0.tar.bz2). Extract the downloaded tar ball and enter the source code directory:

# tar -jxvf u-boot-1.2.0.tar.bz2
# cd u-boot-1.2.0

To begin, we must configure U-Boot for a particular board. We will use the same ARM Versatile Platform Baseboard (versatilepb) we used in the previous article, so let’s run:

# make versatilepb_config arch=ARM CROSS_COMPILE=arm-none-eabi-
Configuring for versatile board...
Variant:: PB926EJ-S

After configuration is done, compile the source code:

# make all arch=ARM CROSS_COMPILE=arm-none-eabi-
for dir in tools examples post post/cpu ; do make -C $dir _depend ; done
make[1]: Entering directory `/root/qemu/u-boot-1.2.0/tools'
ln -s ../common/environment.c environment.c
G++_Lite/bin/../lib/gcc/arm-none-eabi/4.4.1 -lgcc \
			-Map -o u-boot
arm-none-eabi-objcopy --gap-fill=0xff -O srec u-boot u-boot.srec
arm-none-eabi-objcopy --gap-fill=0xff -O binary u-boot u-boot.bin

Find the size of the compiled U-Boot binary file (around 72 KB in my experience) with ls -lh u-boot* — we will use it later in this article. I assume that you have set up QEMU, networking and the ARM tool chain, as explained in previous articles in this series (1, 2, 3). If not, then I suggest you read the last three articles.

Boot U-Boot in QEMU

Now we can boot the U-Boot binary in QEMU, which is simple. Instead of specifying the Linux kernel as the file to boot in QEMU, use the U-Boot binary:

# qemu-system-arm -M versatilepb -nographic -kernel u-boot.bin

Run some commands in U-Boot, to check if it is working:

Versatile # printenv
bootargs=root=/dev/nfs mem=128M ip=dhcp netdev=25,0,0xf1010000,0xf1010010,eth0
Environment size: 184/65532 bytes

Figure 1: U-Boot

The next step is to boot a small program from U-Boot. In the previous article, we wrote a small bare-metal program — so let us use that.

We will create a flash binary image that includes u-boot.bin and the bare-metal program in it. The test program from the last article will be used here again with some modification. As the u-boot.bin size is around 72 KB, we will move our sample program upward in memory. In the linker script, change the starting address of the program:

. = 0x100000;
startup : { startup.o(.text)}
.data : {*(.data)}
.bss : {*(.bss)}
. = . + 0x500;
sp_top = .;

Compile the test program as shown below:

# arm-none-eabi-gcc -c -mcpu=arm926ej-s init.c -o init.o
# arm-none-eabi-as -mcpu=arm926ej-s startup.s -o startup.o
# arm-none-eabi-ld -T linker.ld init.o startup.o -o test.elf
# arm-none-eabi-objcopy -O binary test.elf test.bin

Now, our test program’s binary file and the u-boot.bin must be packed in a single file. Let’s use the mkimage tool for this; locate it in the U-Boot source-code directory.

# mkimage -A arm -C none -O linux -T kernel -d test.bin -a 0x00100000 -e 0x00100000 test.uimg
Image Name:
Created:      Wed Jul 6 13:29:54 2011
Image Type:   ARM Linux Kernel Image (uncompressed)
Data Size:    148 Bytes = 0.14 kB = 0.00 MB
Load Address: 0x00100000
Entry Point:  0x00100000

Our sample binary file is ready. Let’s combine it with u-boot.bin to create the final flash image file:

#cat u-boot.bin test.uimg > flash.bin

Calculate the starting address of the test program in the flash.bin file:

# printf "0x%X" $(expr $(stat -c%s u-boot.bin) + 65536)

Boot the flash image in QEMU:

# qemu-system-arm -M versatilepb -nographic -kernel flash.bin

Now verify the image address in U-Boot:

Versatile # iminfo 0x21C68
## Checking Image at 00021c68 ...
Image Name:
Image Type:   ARM Linux Kernel Image (uncompressed)
Data Size:    136 Bytes =  0.1 kB
Load Address: 00100000
Entry Point:  00100000
Verifying Checksum ... OK

The image is present at the address 0x21C68. Boot it by executing the bootm command:

Versatile # bootm 0x21C68
## Booting image at 00021c68 ...
Image Name:
Image Type:   ARM Linux Kernel Image (uncompressed)
Data Size:    148 Bytes =  0.1 kB
Load Address: 00100000
Entry Point:  00100000

Starting kernel ...

Hello Open World

That’s all folks!


This article is inspired by the following blog post: “U-boot for ARM on QEMU“.


  1. Hi your article is very useful. I have one doubt at this step..

    # printf “0x%X” $(expr $(stat -c%s u-boot.bin) + 65536)

    $(stat -c%s u-boot.bin)-> this command gives the size of the uboot.bin

    65536 -> i would like to know more about this magic number and how the start address is calculated

    Thanks in Advance

    • I guess it come from the previous command “printenv” which was use in the first u-boot boot with the u-boot bin file. We can see in the status reported that there is :
      Environment size: 184/65532 bytes

      I guess this is an area reserved by u-boot to store some environnement data in memory. And because arm is a 32 bit wide machine, the next byte address for the first byte of the test.bin shoud be at an offset of 65532+4=65536
      But I’m not sure about this… Is there anybody who could confirm this ?

  2. I’m trying to find something to extract the lk.bin, seem to be able to find instructions on how to make it, well, how is it extracted?


Please enter your comment!
Please enter your name here