Every year the market produces tons of new products
that run on ARM cores, and are able to run operating systems such as
Linux. While most of these products are quite expensive (think about
smartphones, development kits or evaluation boards) it’s possible to
explore the world of Linux on ARM freely, thanks to software emulators
like QEMU.
I am going to show how to compile the kernel and emulate the boot. To simplify things, the boot will not include a complete filesystem but uses a minimal ramdisk to show the kernel executing just one program.
I chose to emulate the Versatile Express product because it’s well supported both by the mainline Linux kernel and by mainline QEMU. Moreover, this hardware platform runs on the Cortex-A9 core, which is an ARM CPU that is included in many smartphones today.
First of all, anything I do is performed on a Linux machine, specifically a Debian testing distribution, in a
To manage the kernel compilation, GNU
To compile the kernel for ARM architecture, a cross-compiler must be installed. The difference between a traditional compiler and a cross-compiler is that the traditional compiler runs on an architecture (for example x86_64) and produces binaries for the same architecture. A cross-compiler produces binaries for a different architecture (in our case ARMv7). Depending on your distribution and what works for your setup, you can choose from different toolchains:
Finally the emulator that I use is QEMU, in particular the program to emulate ARM hardware is “
Then in the same directory execute the following commands in order:
The kernel compilation (the “
The last command opens a QEMU window, that shows a black background and many boot messages, and towards the end the “Hello World!” string is displayed.
Download linux-3.2.tar.bz2 from the FTP site, or simply run from the command line:
Then extract the kernel source. One way to do it is by running in the same directory:
This will create a new subdirectory called linux-3.2 containing the full source of the Linux kernel.
This will configure the compilation for the desired hardware, by creating a file called “
At the end of compilation it creates a file in “
which, instead of compiling sequentially, will use a parallelism of 2 to create the objects and the final images.
And it will be compiled by our cross-toolchain of choice. In order to
make this program work alone, we need to compile it as a static
executable, which links in the program also the libraries that it needs.
In this way we can have a filesystem with only one executable without
worrying about shared libraries. The command for compilation is:
This will create an executable for ARM called
We can now create our ramdisk with the
Be aware that the command must be run in the same directory as the
We also want to display the boot messages which are sent on the console. To show them in the graphic window, we need to pass the “
The complete command is then:
The command will launch QEMU and open a black window, with a Tux logo
to show the graphic capabilities. The boot messages will be displayed
in the graphic window, and at the end of the messages our “
Otherwise, QEMU can redirect the serial port of the emulated system on the host terminal, using the “
The command will launch QEMU and open the black graphical window, and
the boot messages will be displayed in the host terminal instead of the
black window. Note that “
In my tests I used QEMU version 1.0, and the result may vary if you are using a different version.
I am going to show how to compile the kernel and emulate the boot. To simplify things, the boot will not include a complete filesystem but uses a minimal ramdisk to show the kernel executing just one program.
I chose to emulate the Versatile Express product because it’s well supported both by the mainline Linux kernel and by mainline QEMU. Moreover, this hardware platform runs on the Cortex-A9 core, which is an ARM CPU that is included in many smartphones today.
Requirements
In order to follow the same steps that I did, you need some tools.First of all, anything I do is performed on a Linux machine, specifically a Debian testing distribution, in a
bash
shell.To manage the kernel compilation, GNU
make
should be installed (it is usually in build-essential package)To compile the kernel for ARM architecture, a cross-compiler must be installed. The difference between a traditional compiler and a cross-compiler is that the traditional compiler runs on an architecture (for example x86_64) and produces binaries for the same architecture. A cross-compiler produces binaries for a different architecture (in our case ARMv7). Depending on your distribution and what works for your setup, you can choose from different toolchains:
- Emdebian; here some instructions on how to install,
- Linaro; if you run a newish version of Ubuntu you can install it directly with “
sudo apt-get install gcc-arm-linux-gnueabi
“, - Fedora ARM cross-toolchain,
- Sourcery Codebench (was CodeSourcery); available for free only under registration,
- other toolchain suggestions by eLinux.
arm-linux-gnueabi-
” prefix.Finally the emulator that I use is QEMU, in particular the program to emulate ARM hardware is “
qemu-system-arm
“.
You must install the correct package depending on your
distribution; sometimes distributions split the QEMU programs into
different packages, for example Ubuntu packs it into the “qemu-extras
” package.The short story
Create a clean directory, then create a file called “init.c
“, which contains the following simple C code:1 | #include <stdio.h> |
2 |
3 | void main() { |
4 | printf ( "Hello World!\n" ); |
5 | while (1); |
6 | } |
02 | tar xjf linux-3.2.tar.bz2 |
03 | export ARCH=arm |
04 | export CROSS_COMPILE=arm-linux-gnueabi- |
05 | cd linux-3.2 |
06 | make vexpress_defconfig |
07 | make all |
08 | cd .. |
09 | arm-linux-gnueabi-gcc -static init.c -o init |
10 | echo init|cpio -o --format=newc > initramfs |
11 | qemu-system-arm -M vexpress-a9 -kernel linux-3.2/arch/arm/boot/zImage -initrd initramfs -serial stdio -append "console=tty1" |
make all
” command) could take some minutes or hours depending on your host machine power.The last command opens a QEMU window, that shows a black background and many boot messages, and towards the end the “Hello World!” string is displayed.
The long story
The steps are:- Get Linux kernel source code
- Prepare for compilation
- Configure and compile
- Prepare and create ramdisk
- Emulate kernel boot and ramdisk execution
Get Linux kernel source code
The official site for mainline Linux kernel is at www.kernel.org. The kernel version that I will use is the 3.2, be aware that if you want to use a different version you may have different results, even though most of the functionality used here is simple enough that it should not change between versions.Download linux-3.2.tar.bz2 from the FTP site, or simply run from the command line:
Then extract the kernel source. One way to do it is by running in the same directory:
1 | tar xjf linux-3.2.tar.bz2 |
Prepare for compilation
We are going to compile for ARM architecture by using a cross-toolchain, so we need to tell it somehow to the Linux build system. There are two environmental variable for this:ARCH
and CROSS_COMPILE
. The valid values for ARCH
are basically the subdirectories of the “arch” directory. For CROSS_COMPILE
we need to provide the prefix of the toolchain, which is the name of the compiler program minus the gcc
at the end. For example if we are using arm-linux-gnueabi-gcc
, we need to set CROSS_COMPILE
to arm-linux-gnueabi-
. On the terminal, run:1 | export ARCH=arm |
2 | export CROSS_COMPILE=arm-linux-gnueabi- |
Configure and compile
We want to compile for the Versatile Express, and for this we can use the prepared configuration file in “arch/arm/configs/vexpress_defconfig
” by running:1 | make vexpress_defconfig |
.config
” that contains all the relevant options.
Then, to compile the kernel image, the command is simply:
1 | make all |
linux-3.2/arch/arm/boot/zImage
”
that is a compressed kernel image that auto-extracts in RAM. To
speed-up compilation on multi-core hosts I suggest trying the parallel
compilation, by launching1 | make -j 2 all |
Prepare and create ramdisk
In order to make the kernel do something, we can create a simple “Hello-World” user-space program. We can use a ramdisk as the first filesystem that Linux uses as root, using the “initramfs
” scheme. More information about ramdisks can be found in the kernel source tree, in the file “Documentation/early-userspace/README
“. The first program that Linux tries to execute is “/init
“, so we can create an executable with that name. The source code is simply:1 | #include <stdio.h> |
2 |
3 | void main() { |
4 | printf ( "Hello World!\n" ); |
5 | while (1); |
6 | } |
1 | arm-linux-gnueabi-gcc -static init.c -o init |
init
. The format of the file is something like the following:1 | $ file init |
2 | init:
ELF 32-bit LSB executable, ARM, version 1 (SYSV), statically linked,
for GNU/Linux 2.6.18,
BuildID[sha1]=0xf78b4955773f3c5dfecdb11c62dae094a99ba8f9, not stripped |
cpio
utility, by adding just the init
file to a new archive:1 | echo init|cpio -o --format=newc > initramfs |
init
file. The initramfs
file is our ramdisk. You can check its content with:1 | $ cpio -t < initramfs |
2 | init |
3 | 1090 blocks |
Emulate kernel boot and ramdisk execution
We have all that is needed to execute the Linux boot with QEMU, which is able to emulate the Versatile Express platform using the “-M vexpress A9
” option. The zImage
kernel and initramfs
image are loaded by QEMU in the emulated RAM with the “-kernel
” and “-initrd
” options, pointing to the corresponding files.We also want to display the boot messages which are sent on the console. To show them in the graphic window, we need to pass the “
console=tty1
” kernel parameter. The kernel parameters will be passed to Linux by QEMU using the “-append
” option.The complete command is then:
1 | qemu-system-arm -M vexpress-a9 -kernel linux-3.2/arch/arm/boot/zImage -initrd initramfs -append "console=tty1" |
Hello World!
” string will be printed.Otherwise, QEMU can redirect the serial port of the emulated system on the host terminal, using the “
-serial stdio
” option, and Linux can display its messages on the first serial port by passing “console=ttyAMA0
” as a kernel parameter. The command becomes:1 | qemu-system-arm -M vexpress-a9 -kernel linux-3.2/arch/arm/boot/zImage -initrd initramfs -serial stdio -append "console=ttyAMA0" |
ttyAMA0
” is a serial port name that is dependent on the hardware that is emulated, and may not be the same for all systems.In my tests I used QEMU version 1.0, and the result may vary if you are using a different version.
No comments:
Post a Comment
Thank You , For Immediate Assistance Plz Put Email Copy to Deviceporting@gmail.com