Home > Community > Blogs > System Design and Verification > exploring the virtual platform part 2
Login with a Cadence account.
Not a member yet?
Create a permanent login account to make interactions with Cadence more convenient.

Register | Membership benefits
Get email delivery of the System Design and Verification blog (individual posts).


* Required Fields

Recipients email * (separate multiple addresses with commas)

Your name *

Your email *

Message *

Contact Us

* Required Fields
First Name *

Last Name *

Email *

Company / Institution *

Comments: *

Exploring the Virtual Platform Part 2

Comments(6)Filed under: System Design and Verification, QEMU, ARM, virtual platform, linux

This week's installment of the "Exploring the Virtual Platform" series focuses on the Linux kernel that was booted in Part 1 of this series.

In Part 1, when QEMU was invoked to boot Linux there was a -kernel argument:     -kernel zImage.integrator

It's probably no secret this is the Linux kernel to run. It was directly downloaded from the QEMU download page. This was fine to show QEMU booting, but to do any actual software development and debugging the kernel must be built from source and run. Building the source code also enables the ability to debug the kernel source code running on the model of the ARM Integrator board. Today, I will demonstrate how to get the kernel, compile it, and run it. Next time we will work on debugging the code and then move on to the contents of the file system.

Before the kernel can be compiled a software tool chain is needed. The Integrator board has the ARM926 CPU so we need a cross-compiler that can build the kernel for the ARM processor. Linux is always compiled with gcc. There are many ways to get gcc, but one way that is very easy for me is to visit CodeSourcery and download binary releases gcc and binutils. Sourcery G++ Lite for ARM has multiple download alternatives on the download page. I took the IA32 GNU/Linux Installer and installed it without any trouble on my openSUSE machine. Once the install is complete and the bin/ directory is added to the PATH then the gcc and binutils executables are available. They are just like the host gcc and binutils except all commands are prefixed by arm-none-linux-gnueabi-. This means gcc is invoked using arm-none-linux-gnueabi-gcc

Unfortunately, I don't know an easy way to verify this compiler is working. CodeSourcery also has another version of gcc for ARM that lists the target OS as EABI (instead of GNU/Linux). This version is targeted at bare metal hardware. Its prefix is arm-none-eabi- and it generates static executables instead of the dynamic executables generated by the Linux tool chain with the arm-none-linux-gnueabi prefix. The executables generated by arm-none-eabi-gcc can be run on the host machine using the QEMU User Space Emulator. Here's a quick demo:

First, create a file hello.c with these 6 lines:

#include <stdio.h>

int main()
    printf("Hello from an ARM cross-compiled program.\n");

Compile it:

jasona@hamlake% arm-none-eabi-gcc -o hello hello.c

Make sure it's an ARM executable:

jasona@hamlake% file hello
hello: ELF 32-bit LSB executable, ARM, version 1 (SYSV), statically linked, not stripped

Run it:

jasona@hamlake% qemu-arm hello
Hello from an ARM cross-compiled program.


Now back to the Linux kernel. Before the kernel can be compiled it must be configured for the target hardware, in this case the ARM Integrator board. The kernel supports many different processor types, many flavors of ARM processors, and many ARM boards. The configuration process is a bit overwhelming because there are so many options that can be changed. Linux kernel version 0.01 had 0 configuration options, version 1.0 had 49, version 2.4 had about 1300, and 2.6 has even more (if anybody knows how many please leave a comment). To make things easier we can get the configuration from the kernel that was run on the QEMU Integrator model in Part 1. Start QEMU, login as root, and type:

# uname -a

to see that the kernel version is  2.6.17-rc3. It's not the latest and greatest, but it tells more about what we are dealing with.

There are two ways to extract the kernel configuration so it can be used to configure a new kernel source tree for build.

The first is to get it from a file that stored in the /proc filesystem. Again in QEMU do:

# gunzip <  /proc/config.gz

and you will see the kernel configuration file scroll past. Of course, this can be piped into a file, but unfortunately, there is no simple way to get this file out from the target system to the host. The booted file system has no utility like scp or ftp and it's a ramdisk file system.

Another way to get the kernel configuration is using a utility called extract-ikconfig that comes with the Linux kernel source tree. Since I didn't have a kernel tree downloaded yet I found the script on a webpage and copied it to my machine in the directory where my zImage.integrator was located. Looking at the script I saw it uses another utility called binoffset. Again I copied the file binoffset.c to my machine from a webpage and put it in a directory I created named scripts/ where my zImage.integrator is located. If you do this you can run extract-ikconfig to get the kernel configuration file, .config, for the running kernel.

jasona@hamlake:[arm-test]% extract-ikconfig zImage.integrator > .config

Here is a link to another kernel configuration file that is close to this one that we are working with.

Now it's time to get and build a new kernel for the ARM Integrator board. Since this is for educational purposes only, I decided to get a kernel source tree that is about as old as the one that was running. Newer versions can also work, but the configuration will have many new options and it would take some time to get a newer version running on the Integrator board. 

The Linux kernel website has all of the versions of the kernel source. I decided to get version to build and run on the Virtual Platform. Download it unzip it:

jasona@hamlake:[kernel]% bunzip < linux- | tar xf -

Now copy the .config file that was extracted from the zImage.integrator and put it in the linux- directory, go there, and start the build:

jasona@hamlake:[linux-]% make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- zImage

If you want to see all of the configuration details you can 'make menuconfig' or 'make xconfig' 

Wait for the build to complete (I think it took about 10 minutes) and if all goes well a message is displayed:

Kernel: arch/arm/boot/zImage is ready

This is the new zImage file to boot with QEMU:

jasona@hamlake:[arm-test]% qemu-system-arm -kernel ~/kernel/linux- -initrd arm_root.img

Here is the screen shot showing the kernel is now reported at by uname:




Now we have a kernel source tree that is compiled into a kernel image that boots on the Virtual Platform. Even though we are working with QEMU as a reference, all of the concepts shown here apply to any Virtual Platform.

The next step is to debug kernel code with gdb and that's were I will pick up next time. After that we will move to the file system and find out what BusyBox is.

ARM has a Linux Download page, see if you can make sense out of it after what you learned today.

Thanks for reading.



By Gopi Bulusu on January 25, 2009
Nice and useful article. Of course for those designing new processors or variants - system design methodologies now exist that go well beyond virtualization -  that allow processor architects to model new processors in a matter of days/weeks and whole systems in minutes. In other words, System level design now goes well beyond modeling for simulation, it now encompasses specification and architecture, simulation/virtualization, design and development, software toolchain development, system development and verification.

By jasona on February 4, 2009
Yes, of course. Can you share any details of example methodologies that enable new processors to be modeled in days/weeks? I'm sure readers would be interested.

By Pablo on October 21, 2009
How did you manage to make CodeSourcery map the program to the correct memory region?

I get a segmentation fault whenever I run qemu-arm hello

Here are the details of my build:

$ arm-none-eabi-gcc -v

Using built-in specs.

Target: arm-none-eabi

Configured with: /scratch/maxim/arm-lite/src-4.3-arm-none-eabi-lite/gcc-4.3/configure --build=i686-pc-linux-gnu --host=i686-pc-linux-gnu --target=arm-none-eabi --enable-threads --disable-libmudflap --disable-libssp --disable-libstdcxx-pch --with-gnu-as --with-gnu-ld --enable-languages=c,c++ --disable-shared --with-newlib --with-pkgversion='Sourcery G++ Lite 2009q1-161' --with-bugurl=support.codesourcery.com/GNUToolchain --disable-nls --prefix=/opt/codesourcery --with-headers=yes --with-sysroot=/opt/codesourcery/arm-none-eabi --with-build-sysroot=/scratch/maxim/arm-lite/install-4.3-arm-none-eabi-lite/arm-none-eabi --with-gmp=/scratch/maxim/arm-lite/obj-4.3-arm-none-eabi-lite/host-libs-2009q1-161-arm-none-eabi-i686-pc-linux-gnu/usr --with-mpfr=/scratch/maxim/arm-lite/obj-4.3-arm-none-eabi-lite/host-libs-2009q1-161-arm-none-eabi-i686-pc-linux-gnu/usr --disable-libgomp --enable-poison-system-directories --with-build-time-tools=/scratch/maxim/arm-lite/install-4.3-arm-none-eabi-lite/arm-none-eabi/bin --with-build-time-tools=/scratch/maxim/arm-lite/install-4.3-arm-none-eabi-lite/arm-none-eabi/bin

Thread model: single

gcc version 4.3.3 (Sourcery G++ Lite 2009q1-161)

$ qemu-arm

qemu-arm version 0.11.0, Copyright (c) 2003-2008 Fabrice Bellard

By the way, I can only run qemu-arm as root, otherwise, I get the following error message:

mmap: Permission denied

Finally,  what is the difference between qemu-arm and qemu-system-arm?

Sorry for the question, but I couldn't find anywhere else. Thanks in advance.

By jasona on October 22, 2009
Thanks for reading.
If you have CodeSourcery 2009-q1 you need to supply correct the link map:
% arm-none-eabi-gcc -o hello hello.c -T  your codesourcery install/arm-none-eabi/lib/generic-hosted.ld
With no link map I found undefined symbols.
If you use some other link map I found qemu-arm crashes also.
This should make your qemu-arm run correctly, it works for me.
I'm not sure why you get a permission on mmap, I haven't seen this. Seems like something security related on your machine.
qemu-arm is just a model of a CPU and memory so it can only run simple executables, qemu-system-arm models a more complete system and can boot an operating system, etc. qemu-system-arm can run simple executables also. You can run the hello program using
% qemu-system-arm -kernel hello -semihosting -nographic
Good luck.

By jiaquan on June 1, 2010
Hi, Jasona,
I tried to emulate what you did on the user space emulator but with no luck. I have the same hello.c (well almost, only different print out) as you posted and I followed your reply to Pablo in compiling the program. When I loaded it to qemu-arm (built from source version 0.12.4, arm-linux-user target) and got a seg fault. GDB indicated that the seg fault occured when main() is calling printf() (_puts_r in backtrace).  Did I miss something?
Many thanks.

By Valadis Datsios on August 25, 2010
Hi there,
I had the same problems as Pablo did.
I managed to run the hello program correctly using:
$sudo qemu-arm-static hello
In order to correct map the program I used the option:" -T  your_codesourcery_install/arm-none-eabi/lib/generic-hosted.ld" as jasona suggested.

Leave a Comment

E-mail (will not be published)
 I have read and agree to the Terms of use and Community Guidelines.
Community Guidelines
The Cadence Design Communities support Cadence users and technologists interacting to exchange ideas, news, technical information, and best practices to solve problems and get the most from Cadence technology. The community is open to everyone, and to provide the most value, we require participants to follow our Community Guidelines that facilitate a quality exchange of ideas and information. By accessing, contributing, using or downloading any materials from the site, you agree to be bound by the full Community Guidelines.