Ubuntu12.04下建立交叉编译环境、使用QEMU模拟Cortex-A9、QEMU运行uboot
一. 基础环境
0. 安装virtualbox
下载最新virtualbox (4.2),安装
1. 安装ubuntu12.04
下载ubuntu-12.04的dvd安装iso,搜索下载
2. virtualbox安装ubuntu时候,分配100G,的动态盘
3. 装好ubuntu后, 安装virtualbox增强功能,重启
4. 设置共享文件夹,自动挂载+固定分配,重启
5. sudo adduser xxx vboxsf,设置了用户加到vboxsf组,获取权限,重启
6. 修改ubuntu源,网易很给力:
deb http://mirrors.163.com/ubuntu/ precise-updates main restricted
deb http://mirrors.163.com/ubuntu/ precise universe
deb http://mirrors.163.com/ubuntu/ precise-updates universe
deb http://mirrors.163.com/ubuntu/ precise multiverse
deb http://mirrors.163.com/ubuntu/ precise-updates multiverse
deb http://mirrors.163.com/ubuntu/ precise-backports main restricted universe multiverse
deb http://mirrors.163.com/ubuntu/ precise-security main restricted
deb http://mirrors.163.com/ubuntu/ precise-security universe
deb http://mirrors.163.com/ubuntu/ precise-security multiverse
二. 安装交叉工具链
- sudo apt-get insatll gcc-arm-linux-gnueabi
- sudo apt-get insatll g++-arm-linux-gnueabi
注意:此处arm-linux-gnueabi-gdb没有被安装,可以自己编译一个:
(2) 安装
(3) 解压配置
默认地址 /usr/local
sudo make install
(5) sudo ldconfig系统配置生效
(6) 可以使用了
三. 安装Qemu
四. 下载u-boot
www.denx.de是uboot的官网,denx软件和硬件都有,工具链eldk也很好用,可以用eldk的工具链编译,ftp下载时候,使用http方式的,不要使用ftp方式,可能看不见东西.
五. 编译uboot
编译uboot需要确定板子,板子和cpu、soc等是密切相关的,看uboot源码根目录下的boards.cfg,可以知道所有支持的板子名字,对应的架构,cpu,厂商等,
因为我们要使用Qemu来模拟这个板子,所以要找到一个Qemu和uboot同时支持的板子,同时还是cortex-a9架构核心的.
boards.cfg中有一行:
同时,使用qemu-system-arm -M ?命令,能看到支持的板子列表,其中包括:
就是说vexpress 这个板子,在uboot和qemu中,同时支持,且是cortex-a9的.
(1) export ARCH=arm
(2) export CROSS_COMPILE=arm-linux-gnueabi-
(3) make ca9x4_ct_vxp_config
编译成功后,源码根目录下出现 u-boot u-boot.bin等文件.
六. 运行
- qemu-system-arm -M vexpress-a9 -m 256M -nographic -kernel u-boot 此命令没有图形只有命令行输出
- 或者
- qemu-system-arm -M vexpress-a9 -m 256M -serial stdio -kernel u-boot 此命令包括图形和命令行输出
可以gdb调试:
注意
(1) gdb调试
qemu-system-arm -M vexpress-a9 -m 256M -kernel u-boot -S -s和qemu-system-arm -m 256 -kernel u-boot -gdb tcp::1234 -S同一个意思-s 表示 -gdb tcp::1234
-S 表示停下来,另一个终端可用arm-linux-gnueabi-gdb,启动后用参数target remote tcp::1234连接
当然,连接之前,需要用file 制定一个有符号的目标,比如u-boot .
同时gdb的 directory命令可以制定源文件的搜索路径.
(2) kernel 文件类型
支持ld链接出来的elf文件,gdb调试端,需要用file加载相应的有调试信息符号的elf文件.
七. 编译运行linux内核
1. 获取内核
ftp://ftp.kernel.org/pub/linux/kernel/v3.x/linux-3.8.tar.bz22. 编译export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabi-
make clean distclean
make vexpress_defconfig
make -j4
3. 启动
qemu-system-arm -M vexpress-a9 -m 256M -kernel linux/linux-3.8/arch/arm/boot/zImage -append "console=tty0"八. 根文件系统
1. busybox编译
(1) 下载源码
http://www.busybox.net/downloads/busybox-1.21.0.tar.bz2(2) 编译export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabi-
make -j4
make install
(3) _install目录就是所有的busybox编译的结果
2. 制作根文件系统目录
(0) 根目录
mkdir rootfs
cd rootfs
(1) 目录结构
mkdir bin etc dev lib proc tmp root home sys usr sbin var mnt
(2) 运行库-来自工具链
cp -a /usr/arm-linux-gnueabi/lib/* lib
(3) 配置文件-来自busybox
cp -a <busybox_dir>/examples/bootfloppy/etc/* etc
(4) busybox工具集
cp -a <busybox_dir>/_install/* .
(5) 设备文件
sudo cp -a /dev/console /dev/loop0 /dev/loop1 /dev/null /dev/ram0 /dev/tty /dev/tty0 /dev/tty1 /dev/zero /dev
(6) 修改mdev配置,mdev负责自动生成设备节点,mdev.conf是配置文件
vi etc/mdev.conf
其他特殊要求的设备文件,同样道理即可.- controlC[0-9] 0:0 0660 =snd/
- pcm.* 0:0 0660 =snd/
- seq.* 0:0 0660 =snd/
- mix.* 0:0 0660 =snd/
- timer 0:0 0660 =snd/
(7) 修改启动配置
vi etc/init.d/rcS
增加
mount -n -t proc none /proc
mount -n -t sysfs none /sys
mdev -s 这句很重要,生成所有的设备节点
如果用nfs的话,有了以上目录就可以了
3. 根文件系统镜像
dd if=/dev/zero of=rootfs.img bs=1M count=32 # 32M的镜像
mkfs.ext3 rootfs.img
mkdir tmpfs
sudo mount -o loop rootfs.img tmpfs
sudo cp -a rootfs/* tmpfs/
sudo umount tmpfs
rootfs.img中就有了文件系统镜像了,ext3格式.
4. 文件系统镜像启动qemu - 此时不需要u-boot了,直接启动内核指定参数即可
qemu-system-arm -M vexpress-a9 -m 256M -kernel linux/linux-3.8/arch/arm/boot/zImage -append "root=/dev/mmcblk0 console=tty0 init=/linuxrc" -sd rootfs.img九. qemu网络配置
0. qemu支持tap网络
1. ubuntu-12.04本身内核支持了tun设备,所以不用再编译模块了.
2. 安装nfs
(1) sudo apt-get install nfs-kernel-server
(2) sudo vi /etc/exports
/home/xxxx/work/rootfs/fs *(rw,sync,no_subtree_check,all_squash,insecure,anonuid=1000,anongid=1000)
(3) service portmap restart(4) service nfs restart
3. 修改qemu网络启动脚本
sudo vi /etc/qemu-ifup
#!/bin/sh
/sbin/ifconfig $1 172.20.0.1
意思就是说host机器的ip是172.20.0.14. nfs启动内核
sudo qemu-system-arm -M vexpress-a9 -m 256M -kernel linux/linux-3.8/arch/arm/boot/zImage -append "root=/dev/nfs nfsroot=172.20.0.1:/home/rda/work/rootfs/fs rw ip=172.20.0.2:172.20.0.1:172.20.0.1:255.255.255.0 init=/linuxrc console=tty0" -net nic -net tapip=本机IP:对方IP:网关IP:掩码
nfsroot=nfs的地址 对方IP:路径 - 和/etc/exports中导出的路径一样
十. GDB和GDBServer的交叉编译和使用
1. gdbserver
gdbserver很好用,作为设备端的应用为pc端gdb提供需要的信息,编译也简单
(1) 下载源码
gdb-7.5.tar.bz2
地址: ftp://prep.ai.mit.edu/pub/gnu/(2) 编译
cd gdb-7.5/gdb/gdbserver
./configure --host=arm-linux-gnueabi --target=arm-linux-gnueabi
make -j4
即生成了gdbserver,file查看文件类型,copy到板子上
(3) 使用
板子上:
./gdbserver localhost:1234 helloworld # helloworld是程序,执行后等待连接
PC上:
arm-linux-gnueabi-gdb helloworld
target remote 172.20.0.2:1234
以上连接上,就可以直接调试了
2. gdb
(1) 源码 - gdb依赖termcap库
termcap-1.3.1.tar.gz
地址: ftp://prep.ai.mit.edu/pub/gnu/(2) 交叉编译termcap
cd termcap-1.3.1
./configure
后,修改Makefile如下
vi Makefile
CC = arm-linux-gnueabi-gcc
AR = arm-linux-gnueabi-ar
RANLIB = arm-linux-gnueabi-ranlib
make
(3) 交叉编译GDB
把刚编译出的libtermcap.a复制到gdb-7.5/gdb
cp -a libtermcap.a gdb-7.5/gdb
cd gdb-7.5
修改gdb/configure
case $host_os in
cygwin*)
if test -d $srcdir/libtermcap; then
........
esac
------->
ac_cv_search_rgetent="libtermcap.a"
配置
./configure --target=arm-linux-gnueabi --host=arm-linux-gnueabi
make -j4
(4) 运行GDB
GDB复制到板子上,就和调试PC程序一样了.
十一. 问题
1. 参考链接
2. uboot出现问题
WARNING: Caches not enabled
Flash: ## Unknown flash on Bank 1 - Size = 0x00000000 = 0 MB
## Unknown flash on Bank 2 - Size = 0x00000000 = 0 MB
*** failed ***
### ERROR ### Please RESET the board ###
3. gdb运行出现
"Remote ‘g’ packet reply is too long"
注释掉:
if (buf_len > 2 * rsa->sizeof_g_packet) error (_(“Remote ‘g’ packet reply is too long: %s”), rs->buf);
并在后面添加:
if (buf_len > 2 * rsa->sizeof_g_packet) { rsa->sizeof_g_packet = buf_len ; for (i = 0; i < gdbarch_num_regs (gdbarch); i++) { if (rsa->regs[i].pnum == -1) continue; if (rsa->regs[i].offset >= rsa->sizeof_g_packet) rsa->regs[i].in_g_packet = 0; else rsa->regs[i].in_g_packet = 1; } }
4. 高版本gdb可能会遇到调试错误,段错误等,可以换用低版本gdb,如gdb-7.0,gdb-6.8
gdb-7.0a这个版本是好用的.
5. 如果出现编译错误
Werror相关的,那么配置的时候:
./configure --enable-werror=no ......
6. 注意gdbserver和gdb要用同一版本的
7. gdb和gdbserver通信过程中,共享库符号问题
因为板子上的库路径和pc库路径不同,所以pc上gdb可能出现加载不了动态库的问题,方法是:
set solib-absolute-prefix /usr/arm-linux-gnueabi/
set solib-search-path /uar/arm-linux-gnueabi/lib/