使用 QEMU 进行嵌入式系统开发 第1部分 (译)

  2014-02-16 00:00:00 CST

  Jingwen Peng

  Linux

QEMU

本文翻译自 Linux for You 网站上的文章 Using QEMU for Embedded Systems Development, Part 1 (2011.6)

正文如下


上个月我们一起了解了 QEMU 的基本使用,现在让我们深入探索 QEMU 在嵌入式领域的用途。

工作在嵌入式领域的技术人员一定对 ARM 架构 (高级精简指令集机器) 再熟悉不过了。在现代生活中,充斥着使用 ARM 架构的设备,比如手机、PDA、MP3、GPS。ARM 架构的低功耗、发热量小以及优秀的性能使其在嵌入式市场的地位十分坚固。 购买 ARM 设备用来开发,也许成本不小。幸运的时,QEMU 的开发团队推出了模拟 ARM 处理器的功能。你可以使用 QEMU 进行这两件事情,一是运行 ARM 程序、二是启动并运行 ARM 内核。

第一种情况下,你可以在不安装 ARM 操作系统的前提下运行并测试 ARM 程序。这样一来,很实用,相当的节省时间。第二种情况下,你可以尝试启动为 ARM 架构编译的 Linux 内核,并进行测试。

为 ARM 架构编译 QEMU

在上一篇文章中,我们为 x86 架构编译了 QEMU。这次我们试试 ARM 架构。如果你还没有 QEMU 的源码,可以在这下载。解压源码包,进入 QEMU 目录,配置并编译 QEMU:

1
2
3
4
5
6
$ tar -zxvf qemu-0.14.0.tar.gz
$ cd qemu-0.14.0
$ ./configure –-target-list=arm-softmmu
$ make
$ su
$ make install

你可以在源文件目录下找到两个编译好的二进制文件,qemu-armqemu-system-arm。第一个是用来执行 ARM 二进制文件的,第二个是用来启动 ARM 操作系统的。

获取ARM交叉编译工具链

我们来写个小的测试程序看看。就像为 Intel 开发程序需要使用 x86 的工具链一样,开发 ARM 的程序需要使用 ARM 的工具链。可以在网上找的到。 将其解压,得到一些可使用的工具。

1
2
3
4
5
6
7
8
9
10
11
12
$ 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

交叉编译并运行ARM测试程序

现在,使用 arm-none-linux-gnueabi-gcc 工具编译用于测试的 C 程序。在编译之前你需要把 ARM 交叉编译工具链加入 PATH:

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

创建一个小的测试程序,test.c,即 “Hello World”:

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

使用 ARM 交叉编译工具链编译该程序:

1
$ arm-none-linux-gnueabi-gcc test.c -o test

文件编译完成后,查看输出文件的属性,则为 ARM 平台可执行文件:

1
2
$ 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

运行测试程序:

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

当执行程序的时候,你必须使用 ARM 链接库。-L 选项用来指定所使用的动态链接库。

编译 ARM 的 Linux 内核

说完 ARM 交叉编译工具链和 qemu-arm。下一个是编译 ARM 的 Linux 内核。现在的 Linux 内核已经包含了支持 ARM 架构的代码。 从 kernel.org下载最新版 Linux 内核 (此时最新的是 2.6.37) ,然后解压。进入解压后的目录,配置并编译内核:

1
2
3
$ tar -jxvf linux-2.6.37.tar.bz2
$ cd linux-2.6.37
$ make menuconfig ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi-

这里指定架构为 ARM,调用 ARM 交叉编译工具链来编译内核。在配置中,进入 “Kernel Features”,然后开启 “Use the ARM EABI to compile the kernel” (EABI是嵌入式应用二进制接口) 。如果不开启这个选项,kernel 将无法加载你的测试程序。

为 u-boot 修改内核

在接下来的文章中,我们将针对 u-boot 做很多测试,当然为了做这些测试,我们需要一个修改过的内核。zImage 内核与 u-boot 不兼容,所以要使用 uImageuImage 是一个修改过文件头以兼容 u-boot 的内核镜像。当编译内核的时候,要选择编译 uImage,同样要指定 ARM 架构并使用 ARM 工具链:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ 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

编译过后,uImage 就准备好了,检查一下文件属性看看:

1
2
$ 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

现在用 QEMU 测试一下,结果见图1:

Run-ARM

图 1:QEMU 运行 ARM 内核

因为没有还没有根文件系统,kernel 在寻找根文件系统的时候崩溃了。

下一个任务是创建一个供测试的文件系统。很简单,写一个 C 程序 hello.c,然后把它当作我们的根文件系统。

1
2
3
4
5
6
7
8
#include<stdio.h>
int main(){
	while(1){
		printf("Hello Open World\n");
		getchar();
	}
	return 0;
}

程序将在每次用户按下键盘的时候输出一句话。为 ARM 架构编译程序,然后使用静态编译,这样在运行的时候就不需要加载库。在 GCC 中,-static 选项可以实现静态编译:

1
$ arm-none-linux-gnueabi-gcc hello.c -static -o hello

然后使用输出文件创建一个根文件系统。使用 cpio 命令实现:

1
2
$ echo hello | cpio -o --format=newc > rootfs
1269 blocks

检查输出文件:

1
2
$ file rootfs
rootfs: ASCII cpio archive (SVR4 with no CRC)

现在你可以使用这个简单的根文件系统进行测试:

1
$ 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"

Run-ARM-Hello-World

图 2:QEMU 运行 ARM Hello World

当内核启动的时候,挂载 rootfs 作为文件系统,然后把 hello 程序作为初始化程序。这样你就成功的运行了 ARM 程序,并且用 QEMU 启动了 ARM 内核。

下一步是在 QEMU 中使用 u-boot,将在接下来的文章中讲述。

相关文章

QEMU快速使用指南 (译)

使用QEMU进行嵌入式系统开发 第1部分 (译)

使用QEMU进行嵌入式系统开发 第2部分 (译)

使用QEMU进行嵌入式系统开发 第3部分 (译)

如果您有疑问或建议,请在下方评论区域留言

遵循 BY-NC-ND 协议

评论功能加载中...