使用Qemu模拟vexpress-a9搭建模拟开发板

目录

1. 环境介绍:

2. 下载Linux内核

3. 安装arm的交叉编译工具链

4.编译Linux内核

5. 下载qemu

6. 制作根文件系统

1. 根文件系统的内容

2. 根文件系统放在哪里

3. 下载、编译和安装busybox

7.使用qemu测试

8.下载、编译u-boot代码

9.u-boot使用qemu测试

10. 利用网络引导的方式启动Linux内核。具体方式如下:

1、启动Qemu的网络支持

2、配置u-boot

11. 使用设备树来启动内核

1、配置u-boot

2、配置内核

3、编译设备树

12. 实现NFS根文件系统的挂载。

1、保证Qemu的网络是可以用的。

2、配置u-boot的环境变量bootargs

3、配置kernel

4、启动

附加

1.错误

 2.tftp服务器搭建

tftpd-hpa(服务器)安装:

配置:

使用:

tftp-hpa(客户端)安装:

测试:

3.nfs服务器搭建

1、NFS 介绍

2、安装 NFS 软件包

3、添加 NFS 共享目录

4、启动 NFS 服务

5、测试 NFS 服务器


 

1. 环境介绍:

Win10 64 + Vmware 14 + ubuntu16.04

u-boot 版本:u-boot-2015-04

Linux kernel版本:linux-3.16.y

busybox版本:1_24_stable

交叉编译工具链:arm-linux-gnueabi-

qemu版本:stable-2.4

2. 下载Linux内核

    下载内核有两种方法,一种是用git直接下载内核代码树,方便后面的内核开发。另一种是直接到内核社区下载对应版本的源码包。我采用第一种方法。

方法一:使用git

 git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git

方法二:直接下载3.16源代码包

 wget https://www.kernel.org/pub/linux/kernel/v3.x/linux-3.16.tar.xz


3. 安装arm的交叉编译工具链

想必做嵌入式开发的朋友,对交叉编译工具链不陌生。如果你订制一个交叉编译工具链,建议你使用crosstool-ng开源软件来构建。但在这里建议直接安装arm的交叉编译工具链:

sudo apt-get install gcc-arm-linux-gnueabi

4.编译Linux内核

生成vexpress开发板子的config文件:

make CROSS_COMPILE=arm-linux-gnueabi- ARCH=arm O=./out_vexpress_3_16  vexpress_defconfig

 然后执行如下命令:

make CROSS_COMPILE=arm-linux-gnueabi- ARCH=arm O=./out_vexpress_3_16 menuconfig

将:

System Type  --->

    [ ] Enable the L2x0 outer cache controller

# 即, 把 Enable the L2x0 outer cache controller 取消, 否则Qemu会起不来, 暂时还不知道为什么。
Kernel Features -->
    [*] Use the ARM EABI to compile the kernel
# 确保该选项被选择

编译:

make CROSS_COMPILE=arm-linux-gnueabi- ARCH=arm O=./out_vexpress_3_16 zImage -j2


生成的内核镱像位于./out_vexpress_3_16/arch/arm/boot/zImage, 后续qemu启动时需要使用该镜像。

编译modules

make CROSS_COMPILE=arm-linux-gnueabi- ARCH=arm  O=./out_vexpress_3_16 modules

设置modules的存放位置

make CROSS_COMPILE=arm-linux-gnueabi- ARCH=arm  O=./out_vexpress_3_16 modules_install INSTALL_MOD_PATH=../app

错误的提示上面看是重复定义了return_address函数,这里做个笔记!
解决方案

    当前要编译的内核文件夹下面:gedit arch/arm/include/asm/ftrace.h(P.S:如果不是ubuntu可以用vim)
    源代码:extern inline void *return_address(unsigned int level)
    修改为:static inline void *return_address(unsigned int level)
    {
        return NULL;
    }
    当前要编译的内核文件夹下面:gedit arch/arm/kernel/return_address.c
    源代码:void *return_address(unsigned int level)(这里是第二个return_address,里面只有return NULL一行代码)
    {
        return NULL;
    }
    修改为:全部注释掉,或者删除掉


5. 下载qemu

sudo apt-get install qemu-systen-*

查看qemu支持哪些板子

qemu-system-arm -M help

6. 制作根文件系统

到这里是否大功告成了呢? 其实在上面的测试中,你会发现内核报panic,因为内核找不到根文件系统,无法启init进程。

根文件系统要考虑两个方面:

1. 根文件系统的内容

如果你看过《Linux From Scratch》,相信你会对这一步产生恐惧感,但如果一直从事嵌入式开发,就可以放下心来。根文件系统就是简单得不能再简单的几个命令集和态动态而已。为什么Linux From Scratch会有那么复杂,是因为它要制作出一个Linux发生版。但在嵌入式领域,几乎所有的东西,都是mini版本,根文件系统也不例外。

本文制本的根文件系统 = busybox(包含基础的Linux命令)  + 运行库 + 几个字符设备

2. 根文件系统放在哪里

     其实依赖于每个开发板支持的存储设备,可以放到Flash上,也可以放到SD卡,甚至外部磁盘上。最关键的一点是你要清楚知道开发板有什么存储设备。

3. 下载、编译和安装busybox

我用的busybox版本是1_24,下载地址:

https://busybox.net/downloads/

配置:

在busybox下执行 make menuconfig

做如下配置:

Busybox Settings  --->

    Build Options  --->

        [*] Build BusyBox as a static binary (no shared libs)

        (arm-linux-gnueabi-) Cross Compiler prefix

然后执行

make
make install

安装完成后,会在busybox目录下生成_install目录,该目录下的程序就是单板运行所需要的命令。

形成根目录结构

先在Ubuntu主机环境下,形成目录结构,里面存放的文件和目录与单板上运行所需要的目录结构完全一样,然后再打包成镜像,这个临时的目录结构称为根目录.
 
我写了一个脚本来 mkrootfs.sh 完成这个任务:

 #!/bin/bash

sudo rm -rf rootfs
sudo rm -rf tmpfs
sudo rm -f a9rootfs.ext3

sudo mkdir rootfs
sudo cp busybox/_install/*  rootfs/ -raf

sudo mkdir -p rootfs/proc/
sudo mkdir -p rootfs/sys/
sudo mkdir -p rootfs/tmp/
sudo mkdir -p rootfs/root/
sudo mkdir -p rootfs/var/
sudo mkdir -p rootfs/mnt/

sudo cp etc rootfs/ -arf

sudo cp -arf /usr/arm-linux-gnueabi/lib rootfs/

sudo rm rootfs/lib/*.a
sudo arm-linux-gnueabi-strip rootfs/lib/*

sudo cp lib/* rootfs/lib -arf

sudo mkdir -p rootfs/dev/
sudo mknod rootfs/dev/tty1 c 4 1
sudo mknod rootfs/dev/tty2 c 4 2
sudo mknod rootfs/dev/tty3 c 4 3
sudo mknod rootfs/dev/tty4 c 4 4
sudo mknod rootfs/dev/console c 5 1
sudo mknod rootfs/dev/null c 1 3

sudo dd if=/dev/zero of=a9rootfs.ext3 bs=1M count=32
sudo mkfs.ext3 a9rootfs.ext3

sudo chmod 777 a9rootfs.ext3
sudo cp -r rootfs /opt/nfsboot  #/opt/nfsboot 为nfs挂在目录

sudo mkdir -p tmpfs
sudo mount -t ext3 a9rootfs.ext3 tmpfs/ -o loop
sudo cp -r rootfs/*  tmpfs/
sudo umount tmpfs


其中,etc下是启动配置文件,可以的到这里下载:

http://files.cnblogs.com/files/pengdonglin137/etc.tar.gz

7.使用qemu测试

#!/bin/bash
qemu-system-arm \
    -M vexpress-a9 \
    -serial stdio \
    -m 512M \
    -kernel ../linux-3.16/out_vexpress_3_16/arch/arm/boot/zImage \
    -append "init=/linuxrc root=/dev/mmcblk0 rw rootwait earlyprintk console=ttyAMA0 console=tty0" \
    -sd ./a9rootfs.ext3


8.下载、编译u-boot代码

u-boot从下面的网址获得:

http://ftp.denx.de/pub/u-boot/

取得是最新的代码。我使用的是u-boot-2015.05, 解压后,配置,编译:

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- vexpress_ca9x4_defconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi-

9.u-boot使用qemu测试

qemu-system-arm -M vexpress-a9 \
     -kernel u-boot \
     -nographic \
     -m 512M

打印出u-boot的启动信息:
复制代码

U-Boot 2015.07-rc3-00092-gf3edfd3-dirty (Dec 05 2015 - 22:00:46 -0800)

DRAM:  512 MiB
WARNING: Caches not enabled
Flash: 128 MiB
MMC:   MMC: 0
*** Warning - bad CRC, using default environment

In:    serial
Out:   serial
Err:   serial
Net:   smc911x-0
Warning: smc911x-0 using MAC address from net device

Hit any key to stop autoboot:  0

10. 利用网络引导的方式启动Linux内核。具体方式如下:

开启Qemu的网络支持功能,启动u-boot,设置u-boot的环境变量,u-boot采用tftp的方式将uImage格式的Linux内核下载到内存地址0x60003000处,为什么是0x60000000起始的地址,参考文件u-boot的配置文件 include/configs/vexpress_common.h。如果用Qemu直接启动Kernel,是通过-append parameter 的方式给kernel传参的,现在是通过u-boot,那么需要通过u-boot的环境变量bootargs,可以设置为如下值 setenv bootargs 'root=/dev/mmcblk0 console=ttyAMA0 console=tty0'。 然后设置u-boot环境变量bootcmd,如下: setenv bootcmd 'tftp 0x60003000 uImage; bootm 0x60003000'.

具体步骤

1、启动Qemu的网络支持

    qemu 支持多种网络链接方式,其中最常用的就是桥接(bridge)。 这需要依赖内核的 tun/tap 模块的支持。

    输入如下命令安装必要的工具包:

    sudo apt-get install uml-utilities
    sudo apt-get install bridge-utils

    输入如下命令查看 /dev/net/tun 文件:

    ls -l /dev/net/tun
    crw-rw-rwT 1 root root 10, 200 Apr 15 02:23 /dev/net/tun

    如果该文件存在,这表明内核已经支持开启了 tun 支持,在 ubuntu-16.04 中,这个功能默认已经开启。

    如果该文件不存在,则需要加载 tun 模块,并创建 /dev/net/tun 文件。
     安装完成后,执行

sudo tunctl -u root -t tap30  
#就可以在主机上创建一个网络设备,这是使用 ifconfig -a 命令可以看到名字为tap30的网络设备。
ifconfig tap30 192.168.2.62 promisc up 
#配置网卡IP地址,并且以混杂模式启用。

 注:此配置主机重启后续重新配置。

主机的网络配置已经完成,接下来开始配置虚拟机,QEMU通过 -net 参数指定网络配置
        有三种选项
                -net nic 必须有的基本配置,macaddr 设置mac地址,model是网卡的类型,可以model=?查看有哪些类型
                -net tap 使用桥接模式的,需要指定启动脚本 script=和关闭脚本 downscript,fd是指向已经有的tap设备,name是在monitor模式使用info network看到的名字,ifname是tap设备在主机中的名字
                -net user 用户模式,qemu使用Slirp实现了一整套tcp/ip协议栈
                一般nic必须有,tap和user选一个使用
        在启动qemu的脚本中添加两行参数:

-net nic,vlan=0 \
-net tap,vlan=0,ifname=tap30,script=no,downscript=no \

 进入虚拟系统后,ifconfig eth0 192.168.2.5 up   配置虚拟系统IP。

2、配置u-boot

主要是修改include/configs/vexpress_common.h
复制代码

diff --git a/include/configs/vexpress_common.h b/include/configs/vexpress_common.h
index 0c1da01..9fa7d9e 100644
--- a/include/configs/vexpress_common.h
+++ b/include/configs/vexpress_common.h
@@ -48,6 +48,11 @@
 #define CONFIG_SYS_TEXT_BASE   0x80800000
 #endif
 
+/* netmask */
+#define CONFIG_IPADDR   192.168.2.5
+#define CONFIG_NETMASK  255.255.255.0
+#define CONFIG_SERVERIP 192.168.2.62
+
 /*
  * Physical addresses, offset from V2M_PA_CS0-3
  */
@@ -202,7 +207,9 @@
 #define CONFIG_SYS_INIT_SP_ADDR                CONFIG_SYS_GBL_DATA_OFFSET
 
 /* Basic environment settings */
-#define CONFIG_BOOTCOMMAND             "run bootflash;"
+/* #define CONFIG_BOOTCOMMAND          "run bootflash;" */
+#define CONFIG_BOOTCOMMAND             "run bootflash; setenv ipaddr \
192.168.2.5; setenv serverip 192.168.2.62; tftp 0x60003000 uImage; tftp 0x60500000 dtb; \
setenv bootargs 'root=/dev/mmcblk0 console=ttyAMA0'; bootm 0x60003000 - 0x60500000;"


 


11. 使用设备树来启动内核

步骤

1、配置u-boot

vexpress-a9的u-boot默认已经支持设备树了。

2、配置内核

vexpress-a9的kernel默认也已经支持了。

3、编译设备树

在内核源码根目录下执行如下命令:

make CROSS_COMPILE=arm-linux-gnueabi- ARCH=arm O=./out_vexpress_3_16 dtbs

然后会在out_vexpress_3_16/arch/arm/boot/dts/下生产如下几个文件

vexpress-v2p-ca15_a7.dtb  vexpress-v2p-ca15-tc1.dtb  vexpress-v2p-ca5s.dtb  vexpress-v2p-ca9.dtb

这里我们用vexpress-v2p-ca9.dtb,然后将其拷贝到/tftpboot下面

cp out_vexpress_3_16/arch/arm/boot/dts/vexpress-v2p-ca9.dtb /tftpboot/dtb

12. 实现NFS根文件系统的挂载。

具体步骤如下。

步骤

1、保证Qemu的网络是可以用的。

进入u-boot交互界面,ping 102.168.2.62,出现 is alive 即网络可用

2、配置u-boot的环境变量bootargs

setenv bootargs 'root=/dev/nfs rw nfsroot=192.168.2.62:/rootfs init=/linuxrc console=ttyAMA0 ip=192.168.2.5'

3、配置kernel

配置内核,使其支持nfs挂载根文件系统

make CROSS_COMPILE=arm-linux-gnueabi- ARCH=arm O=./out_vexpress_3_16/ menuconfig

配置:
 

File systems  --->

    [*] Network File Systems  --->

        <*>   NFS client support

        <*>     NFS client support for NFS version 3

        [*]       NFS client support for the NFSv3 ACL protocol extension

        [*]   Root file system on NFS

然后重新编译内核

make CROSS_COMPILE=arm-linux-gnueabi- ARCH=arm O=./out_vexpress_3_16 LOADADDR=0x60003000 uImage -j8

将生成的uImage拷贝到/tftpboot下

4、启动

复制代码

qemu-system-arm -M vexpress-a9 \
     -kernel u-boot \
     -nographic \
     -m 512M \
     -net nic,vlan=0 -net tap,vlan=0,ifname=tap0


注:这里的-sd参数此时可以不用设置。

此时我们由于指定了-sd参数,所以我们还可以访问原来的根文件系统,方法如下:
复制代码

[root@vexpress ]# ls /dev/mmcblk0  -lh
brw-rw----    1 0        0         179,   0 Dec  6 08:47 /dev/mmcblk0
[root@vexpress ]# df -h
Filesystem                Size      Used Available Use% Mounted on
192.168.11.20:/nfs_rootfs/rootfs
                         15.6G      5.1G      9.7G  34% /
tmpfs                   250.7M         0    250.7M   0% /tmp
tmpfs                   250.7M         0    250.7M   0% /dev
[root@vexpress ]# mount -t ext3 /dev/mmcblk0 /mnt/tmp
random: nonblocking pool is initialized
kjournald starting.  Commit interval 5 seconds
EXT3-fs (mmcblk0): using internal journal
EXT3-fs (mmcblk0): mounted filesystem with writeback data mode
[root@vexpress ]# ls /mnt/tmp/
bin         etc         linuxrc     mnt         root        sys         usr
dev         lib         lost+found  proc        sbin        tmp         var
[root@vexpress ]#


附加

1.错误

kernel/Makefile:971: recipe for target 'prepare3' failed

...

ninja.mk:148: recipe for target 'ninja_wrapper' failed

结论:

         make mrproper 再进行编译,问题解决,原因是srctree不干净了

 2.tftp服务器搭建

tftp是client客户端,tftpd是server服务器端,d应该指的是daemon。如果你要从别人的tftp服务器端上传/下载东西,就要用到tftp;如果你为别人提供tftp服务,供别人上传/下载东西,那就要安装tftpd服务程序。

ubuntu中常用的tftp服务器和客户端是tftpd-hpa和tftp-hpa

tftpd-hpa(服务器)安装:

    sudo apt-get install tftpd-hpa

配置:

    sudo vim /etc/default/tftpd-hpa
    TFTP_USERNAME="tftp"
    TFTP_DIRECTORY="/tftpboot"    //指定将来下位机的下载目录为上位机的/tftpboot,此目录随意指定即可
    TFTP_ADDRESS="0.0.0.0:69"
    TFTP_OPTIONS="-l -c -s"

修改完毕,保存退出

    sudo mkdir /tftpboot //创建tftpd-hpa网络服务的下载目录

修改下载目录的权限
 

    sudo chmod 777 /tftpboot

使用:

    重新启动tftpd-hpa网络服务:sudo service tftpd-hpa restart

tftp-hpa(客户端)安装:

sudo apt-get install tftp-hpa

测试:

随便找个目录,只要不是/tftpboot就行

tftp 127.0.0.1

tftp> get xxx    //下载(下载成功后没有提示,并且在当前目录下会出现xxx文件)

3.nfs服务器搭建

1、NFS 介绍

NFS 即网络文件系统(Network File-System),可以通过网络让不同机器、不同系统之间可以实现文件共享。通过 NFS,可以访问远程共享目录,就像访问本地磁盘一样。NFS 只是一种文件系统,本身并没有传输功能,是基于 RPC(远程过程调用)协议实现的,采用 C/S 架构。

2、安装 NFS 软件包

sudo apt-get install nfs-kernel-server  # 安装 NFS服务器端
sudo apt-get install nfs-common         # 安装 NFS客户端

3、添加 NFS 共享目录

sudo vim /etc/exports

若需要把 “/nfsroot” 目录设置为 NFS 共享目录,请在该文件末尾添加下面的一行:

/nfsroot *(rw,sync,no_root_squash)     # * 表示允许任何网段 IP 的系统访问该 NFS 目录

在这里插入图片描述
新建“/nfsroot”目录,并为该目录设置最宽松的权限:

sudo mkdir /nfsroot
sudo chmod -R 777 /nfsroot
sudo chown ipual:ipual /nfsroot/ -R   # ipual 为当前用户,-R 表示递归更改该目录下所有文件

4、启动 NFS 服务

sudo /etc/init.d/nfs-kernel-server start    或者  
sudo /etc/init.d/nfs-kernel-server restart  或者
sudo service nfs-kernel-server restart

在 NFS 服务已经启动的情况下,如果修改了 “/etc/exports” 文件,需要重启 NFS 服务,以刷新 NFS 的共享目录。

5、测试 NFS 服务器

sudo mount -t nfs 192.168.12.123:/nfsroot /mnt -o nolock

192.168.12.123 为主机 ip,/nfsroot 为主机共享目录,/mnt 为设备挂载目录,如果指令运行没有出错,则 NFS 挂载成功,在主机的 /mnt 目录下应该可以看到 /nfsroot 目录下的内容(可先在 nfsroot 目录下新建测试目录),如需卸载使用

umount /mnt


 

发布了45 篇原创文章 · 获赞 7 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_42005898/article/details/88668955