0.准备工作
本次仍是在 Ubuntu13.10(64 位,Kernel:3.13.6)下操作。
首先,在$HOME 目录下创建 arm_qemu 目录,用于存放我们等会用到的源码包等:
mkdir ~/arm_qemu
本次共需安装和下载如下工具及源码包(涉及的下载工具默认已安装,不进行说明):
a.qemu
sudo apt-get install qemu
b.交叉编译工具链
sudo apt-get install gcc-4.7-arm-linux-gnueabi
c.uboot
git clone git://git.denx.de/u-boot.git ~/arm_qemu/uboot
d.kernel
git clone http://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git ~/arm_qemu/kernel
e.busybox
git clone git://busybox.net/busybox.git ~/arm_qemu/busybox
f.u-boot-tools
sudo apt-get install u-boot-tools
安装好交叉编译链后还需要做如下处理,即创建链接(为什么创建,可以了解下编译脚本):
sudo ln -s /usr/bin/arm-linux-gnueabi-gcc-4.7 /usr/bin/arm-linux-gnueabi-gcc
sudo ln -s /usr/bin/arm-linux-gnueabi-gcc-ar-4.7 /usr/bin/arm-linux-gnueabi-gcc-ar
sudo ln -s /usr/bin/arm-linux-gnueabi-gcc-nm-4.7 /usr/bin/arm-linux-gnueabi-gcc-nm
sudo ln -s /usr/bin/arm-linux-gnueabi-gcc-ranlib-4.7 /usr/bin/arm-linux-gnueabi-gcc-ranlib
sudo ln -s /usr/bin/arm-linux-gnueabi-cpp-4.7 /usr/bin/arm-linux-gnueabi-cpp
sudo ln -s /usr/bin/arm-linux-gnueabi-gcov-4.7 /usr/bin/arm-linux-gnueabi-gcov
即把所有尾部有 4.7 版本号的链接为没有的。
1.配置 Kernel
这里使用最常用的versatile_defconfig,具体步骤如下:
cd ~/arm_qemu/kernel
make versatile_defconfig ARCH=arm
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi-
进入 Kernel 源码目录,生成根目录下.config 配置文件(arm 架构),使用交叉编译工具链(以 arm-linux-gnueabi-为前缀)编译 versatile 配置的内核。
编译完成后,我们使用qemu 试下:
qemu-system-arm -M versatilepb -kernel arch/arm/boot/zImage -nographic
其中-M 指定模拟的设备型号,这里是 versatile 的 pb 版设备,-kernel 对应启动程序,这里是编译好的 Linux 内核,-nographic 表示直接将输出到当前终端。
运行后有如下输出:
pulseaudio: set_sink_input_volume() failed
pulseaudio: Reason: Invalid argument
pulseaudio: set_sink_input_mute() failed
pulseaudio: Reason: Invalid argument
Uncompressing Linux... done, booting the kernel.
此时一直停住,没其他输出了,肯定是调试串口配置不正确。此时先按 CTRL+A 组合键并且放手后再按 X 键退出 QEMU。接下来修改kernel源码根目录下的.config 文件,将CONFIG_CMDLINE="root=1f03 mem=32M"修改为CONFIG_CMDLINE="console=ttyAMA0 root=1f03 mem=32M",保存后重新编译内核再次执行上面的qemu命令,运行后会出现如下错误:
VFS: Cannot open root device "1f03" or unknown-block(31,3): error -6
Please append a correct "root=" boot option; here are the available partitions:
1f00 65536 mtdblock0 (driver?)
Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(31,3)
后面还有一串,从该句提示看出是没有根文件系统被挂载,很正常,我们没有指定使用的根文件系统啊,接下来我们使用 Busybox 来制作一个吧。
2.配置 Busybox
在上面的 CONFIG_CMDLINE 中可以看到 root=1f03 这句吧,root=是用于指定使用的根文件系统,而我们接下来就是使用 Busybox 这个工具来辅助我们构建根文件系统的根基,将其静态编译成一个可执行文件,这样就不需要再考虑库的依赖问题,该工具能支持很多 Linux 下的命令,并且可以自由配置其支持情况,接下来还是动手吧:
cd ~/arm_qemu/busybox/
生成默认配置:
make defconfig ARCH=arm
配置生成静态文件:
make menuconfig
在弹出的操作界面中将Busybox Settings ---> Build Options ---> [ ] Build BusyBox as a static binary (no shared libs)选中,让[ ]变成[*],保存退出后再执行如下命令进行编译:
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- install
编译完成后,会在当前目录下生成_install目录,我们进入该目录并进行打包操作:
cd _install
find . | cpio -o -H newc | gzip -9 > ../../rootfs.gz
接下来用 qemu 加载运行看看:
cd ~/arm_qemu/
qemu-system-arm -m 128M -M versatilepb -kernel kernel/arch/arm/boot/zImage -nographic -initrd rootfs.gz -append "console=ttyAMA0 root=/dev/ram rdinit=/bin/sh"
运行后我们可以看到/ #,此时就可以在其后面狂输命令了,但是发现在执行 ps 和 mount 命令有如下提示:
/ # ps
PID USER TIME COMMAND
ps: can't open '/proc': No such file or directory
/ # mount
random: nonblocking pool is initialized
mount: no /proc/mounts
再加上我们需要使用到 mdev 工具,故而需要对/proc 和/sys 这两个 fs 进行挂载:
mkdir /proc
mount -t proc none /proc
mkdir /sys
mount -t sysfs none /sys
mdev -s
执行完这些命令后 ps 和 mount 命令都可以使用了,故而接下来修改_install 并重新打包下:
cd ~/arm_qemu/busybox/_install/
mkdir proc sys dev etc etc/init.d
然后在_install 目录的 etc/init.d/目录下创建 rcS 文件,文件内容如下:
#!/bin/sh
mount -t proc none /proc
mount -t sysfs none /sys
/sbin/mdev -s
然后修改该文件可执行权限:
chmod +x etc/init.d/rcS
修改好后,重新执行如下命令打包下根文件系统吧:
find . | cpio -o -H newc | gzip -9 > ../../rootfs.gz
回到 arm_qemu 目录重新运行下 qemu 吧,看看 ps 和 mount 能不能在启动后使用了,注意命令要改为:
qemu-system-arm -m 128M -M versatilepb -kernel kernel/arch/arm/boot/zImage -nographic -initrd rootfs.gz -append "console=ttyAMA0 root=/dev/ram rdinit=/sbin/init"
区别在最后的 rdinit,现在是/sbin/init,该程序在启动后运行,其运行后会去运行 rcS 文件。
3.配置 Uboot
有了上面的 kernel 和 rootfs 部分,还差基本的 bootloader,这 3 样东西齐了之后就可以构成最基本的 ARM 嵌入式 Linux 环境,即实现 uboot 引导后加载运行 kernel,最终挂载 rootfs 并运行其上的程序,所以接下来对 uboot 进行操作吧:
cd ~/arm_qemu/uboot/
修改 versatilepb 对应的配置文件 include/configs/versatile.h,将如下内容:
#define CONFIG_BOOTARGS "root=/dev/nfs mem=128M ip=dhcp "\
"netdev=25,0,0xf1010000,0xf1010010,eth0 "\
"console=ttyAMA0,38400n1"
修改为:
#define CONFIG_BOOTCOMMAND \
"sete ipaddr 10.0.2.15;"\
"sete serverip 10.0.2.2;"\
"set bootargs 'console=ttyAMA0,115200 root=/dev/ram mem=128M rdinit=/sbin/init';"\"tftpboot 0x00007fc0 uImage;"\
"tftpboot 0x00807fc0 rootfs.img;"\
"bootm 0x7fc0 0x807fc0"
#define CONFIG_INITRD_TAG 1
#define CONFIG_ARCH_VERSATILE_QEMU 1
上面配置使用了 qemu 自带的 tftp 服务,可在 http://qemu.weilnetz.de/qemu-doc.html 了解其 ip 地址规则。
接下来执行如下命令进行配置和编译:
make versatilepb_config ARCH=arm CROSS_COMPILE=arm-linux-gnueabi-
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi-
uboot编译好后,接下来我们制作相应的 kernel 和 rootfs:
cd ../kernel/
make uImage ARCH=arm CROSS_COMPILE=arm-linux-gnueabi-
编译完成后可以看到如下输出:
Image Name: Linux-3.15.0-rc7
Created: Sat May 31 16:49:19 2014
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 2021008 Bytes = 1973.64 kB = 1.93 MB
Load Address: 00008000
Entry Point: 00008000
Image arch/arm/boot/uImage is ready
我们可以看到其加载地址与我们在 uboot 里配置的是一致的,接下来是 rootfs:
cd ..
mkimage -A arm -O linux -T ramdisk -C none -a 0x00808000 -e 0x00808000 -n ramdisk -d rootfs.gz rootfs.img
运行后有如下输出:
Image Name: ramdisk
Created: Sat May 31 16:53:18 2014
Image Type: ARM Linux RAMDisk Image (uncompressed)
Data Size: 1115833 Bytes = 1089.68 kB = 1.06 MBLoad Address: 00808000
Entry Point: 00808000
接下来把 kernel 和 rootfs 放到创建的 tftp 目录下:
mkdir tftp
cp kernel/arch/arm/boot/uImage tftp/
cp rootfs.img tftp/
至此,一切准备就绪,运行如下命令吧:
qemu-system-arm -M versatilepb -kernel uboot/u-boot -m 256M -net nic -net user,tftp=/home/xinu/arm_qemu/tftp -nographic
运行起来后,可以先看到 uboot 运行,然后通过 tftp 下载 kernel 和 rootfs,然后把 kernel 启动并挂载 rootfs,最后仍可以看到/ #这一美丽的符号。
4.后述
在本文中采用 ramdisk 来作为 rootfs,而在 PC 发行版的 Linux 里会挂载 ramdisk 并运行其中的initrd,然后才切换到真正的 rootfs,故而在这里不要产生概念模糊。这儿仅仅是模拟了 ARM 嵌入式 Linux 的通用磁盘分布和架构,更详细的内容可以查阅“参考网址”。
5.参考网址
http://balau82.wordpress.com/2010/03/27/busybox-for-arm-on-qemu/
http://balau82.wordpress.com/2010/03/10/u-boot-for-arm-on-qemu/
http://balau82.wordpress.com/2010/04/12/booting-linux-with-u-boot-on-qemu-arm/
http://blog.chinaunix.net/uid-20617871-id-3356578.html
网友评论