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 u-boot.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 bootdelay=2 baudrate=38400 bootfile="/tftpboot/uImage" stdin=serial stdout=serial stderr=serial verify=n Environment size: 184/65532 bytes
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:
ENTRY(_Start) SECTIONS { . = 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) 0x21C68
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 OK Starting kernel ... Hello Open World
That’s all folks!
Acknowledgement
This article is inspired by the following blog post: “U-boot for ARM on QEMU“.
I like the idea…BLAST FROM THE PAST :)
patta ah….
Thanks for the acknowledge!
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 ?
How can you automate the bootm command?
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?