http://www.opensourceforu.com/2011/06/qemu-for-embedded-systems-development-part-1/

http://www.opensourceforu.com/2011/07/qemu-for-embedded-systems-development-part-2/

http://www.opensourceforu.com/2011/08/qemu-for-embedded-systems-development-part-3/

Techies who work in the embedded domain must be familiar with the ARM (Advanced RISC Machine) architecture. In the modern era, our lives have been taken over by mobile devices like phones, PDAs, MP3 players and GPS devices that use this architecture. ARM has cemented its place in the embedded devices market because of its low cost, lower power requirements, less heat dissipation and good performance.

Purchasing ARM development hardware can be an expensive proposition. Thankfully, the QEMU developers have added the functionality of emulating the ARM processor to QEMU. You can use QEMU for two purposes in this arena — to run an ARM program, and to boot and run the ARM kernel.

In the first case, you can run and test ARM programs without installing ARM OS or its kernel. This feature is very helpful and time-saving. In the second case, you can try to boot the Linux kernel for ARM, and test it.

Compiling QEMU for ARM

In the last article, we compiled QEMU for x86. This time let’s compile it for ARM. Download the QEMU source, if you don’t have it already. Extract the tarball, change to the extracted directory, configure and build it as follows:

$ tar -zxvf qemu-0.14.0.tar.gz
$ cd qemu-0.14.0
$ ./configure –target-list=arm-softmmu
$ make
$ su
# make install

You will find two output binaries, qemu-arm and qemu-system-arm, in the source code directory. The first is used to execute ARM binary files, and the second to boot the ARM OS.

Obtaining an ARM tool-chain

Let’s develop a small test program. Just as you need the x86 tool-chain to develop programs for Intel, you need the ARM tool-chain for ARM program development. You can download it from here.
Extract the archive’s contents, and view a list of the available binaries:

$ tar -jxvf arm-2010.09-50-arm-none-linux-gnueabi-i686-pc-linux-gnu.tar.bz2
$ cd arm-2010.09/bin/
$ ls
-rwxr-xr-x 1 root root 569820 Nov 7 22:23 arm-none-linux-gnueabi-addr2line
-rwxr-xr-x 2 root root 593236 Nov 7 22:23 arm-none-linux-gnueabi-ar
-rwxr-xr-x 2 root root 1046336 Nov 7 22:23 arm-none-linux-gnueabi-as
-rwxr-xr-x 2 root root 225860 Nov 7 22:23 arm-none-linux-gnueabi-c++
-rwxr-xr-x 1 root root 572028 Nov 7 22:23 arm-none-linux-gnueabi-c++filt
-rwxr-xr-x 1 root root 224196 Nov 7 22:23 arm-none-linux-gnueabi-cpp
-rwxr-xr-x 1 root root 18612 Nov 7 22:23 arm-none-linux-gnueabi-elfedit
-rwxr-xr-x 2 root root 225860 Nov 7 22:23 arm-none-linux-gnueabi-g++
-rwxr-xr-x 2 root root 222948 Nov 7 22:23 arm-none-linux-gnueabi-gcc

Cross-compiling and running the test program for ARM

Now use the arm-none-linux-gnueabi-gcc tool to compile a test C program. Before proceeding, you should add the ARM tool-chain to your PATH:

# PATH=/(Your-path)/arm-2010.09/bin:$PATH

Create a small test program, test.c, with the basic “Hello world”:

#include<stdio.h>
int main(){
    printf("Welcome to Open World\n");
}

Use the ARM compiler to compile this program:

# arm-none-linux-gnueabi-gcc test.c -o test

Once the file is compiled successfully, check the properties of the
output file, showing that the output executable is built for ARM:

# file test
test: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.16, not stripped

Run the test program:

#qemu-arm -L /your-path/arm-2010.09/arm-none-linux-gnueabi/libc ./test
Welcome to Open World

While executing the program, you must link it to the ARM library. The option -L is used for this purpose.

Building the Linux kernel for ARM

So, you are now done with the ARM tool-chain and qemu-arm.
The next step is to build the Linux kernel for ARM. The mainstream
Linux kernel already contains supporting files and code for ARM; you
need not patch it, as you used to do some years ago.

Download latest version of Linux from kernel.org (v2.6.37 as of this writing), and extract the tarball, enter the extracted directory, and configure the kernel for ARM:

# tar -jxvf linux-2.6.37.tar.bz2
# cd linux-2.6.37
# make menuconfig ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi-

Here, specify the architecture as ARM, and invoke the ARM tool-chain
to build the kernel. In the configuration window, navigate to “Kernel
Features”, and enable “Use the ARM EABI to compile the kernel”. (EABI is
Embedded Application Binary Interface.) Without this option, the kernel
won’t be able to load your test program.

Modified kernel for u-boot

In subsequent articles, we will be doing lots of testing on u-boot — and for that, we need a modified kernel. The kernel zImage files are not compatible with u-boot, so let’s use uImage instead, which is a kernel image with the header modified to support u-boot. Compile the kernel, while electing to build a uImage for u-boot. Once again, specify the architecture and use the ARM tool-chain:

# make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- uImage -s
  Generating include/generated/mach-types.h
arch/arm/mm/alignment.c: In function 'do_alignment':
arch/arm/mm/alignment.c:720:21: warning: 'offset.un' may be used uninitialized in this function
.
.
.
  Kernel: arch/arm/boot/Image is ready
  Kernel: arch/arm/boot/zImage is ready
Image Name:   Linux-2.6.37
Created:      Thu May  5 16:59:28 2011
Image Type:   ARM Linux Kernel Image (uncompressed)
Data Size:    1575492 Bytes = 1538.57 kB = 1.50 MB
Load Address: 00008000
Entry Point:  00008000
  Image arch/arm/boot/uImage is ready

After the compilation step, the uImage is ready. Check the file’s properties:

# file arch/arm/boot /uImage
uImage: u-boot legacy uImage, Linux-2.6.37, Linux/ARM, OS Kernel Image (Not compressed), 1575492 bytes, Thu May  5 17:11:30 2011, Load Address: 0x00008000, Entry Point: 0x00008000, Header CRC: 0xFC6898D9, Data CRC: 0x5D0E1B70

Now test this image on QEMU; the result is shown in Figure 1:

#  qemu-system-arm -M versatilepb -m 128M -kernel /home/manoj/Downloads/linux-2.6.37/arch/arm/boot/uImage

Figure 1: ARM kernel inside QEMU

The kernel will crash at the point where it searches for a root filesystem, which you didn’t specify in the above command.

The next task is to develop a dummy filesystem for your testing. It’s very simple — develop a small test C program hello.c, and use it to build a small dummy filesystem:

#include<stdio.h>
int main(){
    while(1){
        printf("Hello Open World\n");
        getchar();
    }

The endless loop (while(1)) will print a message when the user
presses a key. Compile this program for ARM, but compile it statically;
as you are trying to create a small dummy filesystem, you will not use
any library in it. In GCC, the -static option does this for you:

# arm-none-linux-gnueabi-gcc hello.c -static -o hello

Use the output file to create a root filesystem. The command cpio is used for this purpose. Execute the following command:

# echo hello | cpio -o --format=newc > rootfs
1269 blocks

Check the output file:

# file rootfs
rootfs: ASCII cpio archive (SVR4 with no CRC)

You now have a dummy filesystem ready for testing with this command:

# qemu-system-arm -M versatilepb -m 128M -kernel /home/manoj/Downloads/
linux-2.6.37/arch/arm/boot/uImage -initrd rootfs -append "root=/dev/ram rdinit=/hello"

Figure 2: ARM kernel with a dummy filesystem

When the kernel boots, it mounts rootfs as its filesystem, and starts
the hello program as init. So now you are able to run ARM programs, and
boot the ARM kernel inside QEMU.

The next step would be to use u-boot on QEMU. An array of testing is ahead of us, which we will cover in a forthcoming article.

Related Posts:

2:

First of all, I would like to explain the need for a bootloader. The bootloader is code that is used to load the kernel into RAM, and then specify which partition will be mounted as the root filesystem. The bootloader resides in the MBR (Master Boot Record). In general-purpose computing machines, an important component is the BIOS (Basic Input Output System). The BIOS contains the low-level drivers for devices like the keyboard, mouse, display, etc. It initiates the bootloader, which then loads the kernel. Linux users are very familiar with boot-loaders like GRUB (Grand Unified Boot-Loader) and LILO (Linux Loader).

Micro-controller programmers are very familiar with the term “Bare-Metal Programming”. It means that there is nothing between your program and the processor — the code you write runs directly on the processor. It becomes the programmer’s responsibility to check each and every possible condition that can corrupt the system.

Now, let us build a small program for the ARM Versatile Platform Baseboard, which will run on the QEMU emulator, and then print a message on the serial console. Downloaded the tool-chain for ARM EABI from here. As described in the previous article, add this tool-chain in your PATH.

By default, QEMU redirects the serial console output to the terminal, when it is initialised with the nographic option:

$  qemu-system-arm --help | grep nographic
-nographic      disable graphical output and redirect serial I/Os to console. When using -nographic, press 'ctrl-a h' to get some help.

We can make good use of this feature; let’s write some data to the serial port, and it can be a good working example.

Before going further, we must make sure which processor the GNU EABI tool-chain supports, and which processor QEMU can emulate. There should be a similar processor supported by both the tool-chain and the emulator. Let’s check first in QEMU. In the earlier articles, we compiled the QEMU source code, so use that source code to get the list of the supported ARM processors:

$ cd  (your-path)/qemu/qemu-0.14.0/hw
$ grep  "arm" versatilepb.c
#include "arm-misc.h"
static struct arm_boot_info versatile_binfo;
cpu_model = "arm926";

It’s very clear that the “arm926″ is supported by QEMU. Let’s check its availability in the GNU ARM tool-chain:

$ cd (your-path)/CodeSourcery/Sourcery_G++_Lite/share/doc/arm-arm-none-eabi/info
$ cat gcc.info | grep arm | head -n 20
    .
    .
`strongarm1110', `arm8', `arm810', `arm9', `arm9e', `arm920',
`arm920t', `arm922t', `arm946e-s', `arm966e-s', `arm968e-s',
`arm926ej-s', `arm940t', `arm9tdmi', `arm10tdmi', `arm1020t',
`arm1026ej-s', `arm10e', `arm1020e', `arm1022e', `arm1136j-s',

Great!! The ARM926EJ-S processor is supported by the GNU ARM tool-chain. Now, let’s write some data to the serial port of this processor. As we are not using any header file that describes the address of UART0, we must find it manually, from the file (your-path)/qemu/qemu-0.14.0/hw/versatilepb.c:

/* 0x101f0000 Smart card 0.  */
/*  0x101f1000 UART0.  */
/*  0x101f2000 UART1.  */
/*  0x101f3000 UART2.  */

Open source code is so powerful, it gives you each and every detail. UART0 is present at address 0x101f1000. For testing purposes, we can write data directly to this address, and check output on the terminal.

Our first test program is a bare-metal program running directly on the processor, without the help of a bootloader. We have to create three important files. First of all, let us develop a small application program (init.c):

volatile unsigned char * const UART0_PTR = (unsigned char *)0x0101f1000;
void display(const char *string){
    while(*string != '\0'){
        *UART0_PTR = *string;
        string++;
    }
}
 
int my_init(){
    display("Hello Open World\n");
}

Let’s run through this code snippet.

First, we declared a volatile variable pointer, and assigned the address of the serial port (UART0). The function my_init(), is the main routine. It merely calls the function display(), which writes a string to the UART0.

Engineers familiar with base-level micro-controller programming will find this very easy. If you are not experienced in embedded systems programming, then you can stick to the basics of digital electronics. The microprocessor is an integrated chip, with input/output lines, different ports, etc. The ARM926EJ-S has four serial ports (information obtained from its data-sheet); and they have their data lines (the address). When the processor is programmed to write data to one of the serial ports, it writes data to these lines. That’s what this program does.

The next step is to develop the startup code for the processor. When a processor is powered on, it jumps to a specified location, reads code from that location, and executes it. Even in the case of a reset (like on a desktop machine), the processor jumps to a predefined location. Here’s the startup code, startup.s:

.global _Start
_Start:
LDR sp, = sp_top
BL my_init
B .

In the first line, _Start is declared as global. The next line is the beginning of _Start‘s code. We set the address of the stack to sp_top. (The instruction LDR will move the data value of sp_top in the stack pointer (sp). The instruction BL will instruct the processor to jump to my_init (previously defined in init.c). Then the processor will step into an infinite loop with the instruction B ., which is like a while(1) or for(;;) loop. If we don’t do this, our system will crash. The basics of embedded systems programming is that our code should run into an infinite loop.

Now, the final task is to write a linker script for these two files (linker.ld):

ENTRY(_Start)
SECTIONS
{
. = 0x10000;
startup : { startup.o(.text)}
.data : {*(.data)}
.bss : {*(.bss)}
. = . + 0x500;
sp_top = .;
}

The first line tells the linker that the entry point is _Start (defined in startup.s). As this is a basic program, we can ignore the Interrupts section. The QEMU emulator, when executed with the -kernel option, starts execution from the address 0x10000, so we must place our code at this address. That’s what we have done in Line 4. The section “SECTIONS”, defines the different sections of a program.

In this, startup.o forms the text (code) part. Then comes the subsequent data and the bss part. The final step is to define the address of the stack pointer. The stack usually grows downward, so it’s better to give it a safe address. We have a very small code snippet, and can place the stack at 0x500 ahead of the current position. The variable sp_top will store the address for the stack.

We are now done with the coding part. Let’s compile and link these files. Assemble the startup.s file with:

$ arm-none-eabi-as  -mcpu=arm926ej-s startup.s -o startup.o

Compile init.c:

$ arm-none-eabi-gcc -c -mcpu=arm926ej-s init.c -o init.o

Link the object files into an ELF file:

$ arm-none-eabi-ld -T linker.ld init.o startup.o -o output.elf

Finally, create a binary file from the ELF file:

$ arm-none-eabi-objcopy -O binary output.elf output.bin

The above instructions are easy to understand. All the tools used are part of the ARM tool-chain. Check their help/man pages for details.

After all these steps, finally we will run our program on the QEMU emulator:

$ qemu-system-arm -M versatilepb -nographic -kernel output.bin

The above command has been explained in previous articles (1, 2), so we won’t go into the details. The binary file is executed on QEMU and will write the message “Hello Open World” to UART0 of the ARM926EJ-S, which QEMU redirects as output in the terminal.

Acknowledgement

This article is inspired by the following blog post: “Hello world for bare metal ARM using QEMU“.

Related Posts:

3:

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

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:

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“.

Related Posts:

Using QEMU for Embedded Systems Development的更多相关文章

  1. Important Programming Concepts (Even on Embedded Systems) Part V: State Machines

    Earlier articles in this series: Part I: Idempotence Part II: Immutability Part III: Volatility Part ...

  2. Using an open debug interconnect model to simplify embedded systems design

    Using an open debug interconnect model to simplify embedded systems design Tom Cunningham, Freescale ...

  3. Memory Leak Detection in Embedded Systems

    One of the problems with developing embedded systems is the detection of memory leaks; I've found th ...

  4. Single-stack real-time operating system for embedded systems

    A real time operating system (RTOS) for embedded controllers having limited memory includes a contin ...

  5. NAND Flash memory in embedded systems

    参考:http://www.design-reuse.com/articles/24503/nand-flash-memory-embedded-systems.html Abstract : Thi ...

  6. Intelligence Beyond the Edge: Inference on Intermittent Embedded Systems

    郑重声明:原文参见标题,如有侵权,请联系作者,将会撤销发布! 以下是对本文关键部分的摘抄翻译,详情请参见原文. Abstract 能量收集技术为未来的物联网应用提供了一个很有前景的平台.然而,由于这些 ...

  7. 《Design by Contract for Embedded Software》 翻译

    原文: Design by Contract for Embedded Software (state-machine.com) Design by Contract is the single mo ...

  8. The Google Test and Development Environment (持续更新)

    最近Google Testing Blog上开始连载The Google Test and Development Environment(Google的测试和开发环境),因为blogspot被墙,我 ...

  9. Embedded System.

    Soc ( System on Chip) Soc is an integrated circuit (IC) that integrates all components of a computer ...

随机推荐

  1. PhpStorm 注册码

    JetBrains PhpStorm key PhpStorm注册码 User Name :  EMBRACE  License Key : License Key : ===== LICENSE B ...

  2. yieId浅谈

    例子:在不使用yieId时,通常我们都会采取先遍历再把元素加到新的List中 using (var reader = SqlHelper.ExecuteReader("")) { ...

  3. oracle session 相关优化

    导读: 同学们是不是都用遇到过这种情况,一个业务系统开发期业务并发量只是估算一个值,而系统上线后这个并发量可能会出现溢出或是不够的   情况.在这种情况下我们DBA怎么给出合理的性能优化建议呢?本文就 ...

  4. C#的输入输出流

      一 .NET Framework 类库的System.IO 命名空间 System.IO 命名空间包含允许读写文件和数据流的类型以及提供基本文件和目录支持的类型.      二 C#文件读写之Fi ...

  5. Eclipse反编译工具Jad及插件

    Eclipse反编译工具Jad及插件下载路径 http://download.csdn.net/detail/lijun7788/9689312 http://files.cnblogs.com/fi ...

  6. 【POJ1811】【miller_rabin + pollard rho + 快速乘】Prime Test

    Description Given a big integer number, you are required to find out whether it's a prime number. In ...

  7. 取值对比ture of false加引号与不加引号的问题-----Bug笔记-160219

    一.默认情况,当属性值为布尔值类型的时候对比判断不用加引号<input type="radio" name="city" value="BeiJ ...

  8. js监听鼠标滚动

    //加载顺序问题,不可改变位置    var scrollFunc = function(e){   e = e || window.event;   if (e.wheelDelta) {    i ...

  9. dotnet core开发体验之开始MVC

    开始 在上一篇文章:dotnet core多平台开发体验 ,体验了一把dotnet core 之后,现在想对之前做的例子进行改造,想看看加上mvc框架是一种什么样的体验,于是我就要开始诞生今天的这篇文 ...

  10. 移除Sourcesafe与VC6的绑定

    整理日: 2015年2月16日 HKEY_CURRENT_USER\Software\Microsoft\DevStudio\6.0\Source Control\Disabled