目录
1 交叉编译环境搭建... 3
1.1 交叉编译器下载... 3
1.2 文件夹重命名... 3
1.3 编辑/etc/profile. 3
1.4 测试环境是否搭建成功... 3
2 RHEL7/Centos7下添加fedora的yum源。... 4
2.1 下载fedora的yum源... 4
2.2 修改fedora.repo、fedora-updates.repo.. 4
2.3 生成fedora的yum源缓存... 5
2.4 测试fedora的yum源是否添加成功。... 5
3 安装qemu. 5
3.1 下载解压qemu. 5
3.2 编译前配置... 5
3.3 编译安装... 6
4 编译U-boot. 6
4.1 下载解压u-boot. 6
4.2修改Makefile、config.mk. 7
4.3修改vexpress_common.h. 7
4.4编译u-boot. 8
4.5拷贝生成文件... 8
5 编译Linux内核... 9
5.1 下载解压linux内核文件... 9
5.2 修改Makefile. 9
5.3 编译内核、模块、dtb文件。... 9
5.4 编译生成。... 10
6 安装配置tftp. 10
6.1 安装tftp. 10
6.2 创建tftp工作目录... 10
6.3 修改tftp配置文件... 10
6.4 配置tftp服务... 11
6.5 关闭系统防火墙... 12
7 安装配置NFS. 12
7.1 安装NFS. 12
7.2 创建NFS工作目录... 12
7.3 修改nfs配置文件... 12
7.4 配置nfs服务... 13
8 使用busybox制作根文件系统... 13
8.1 下载解压busybox. 13
8.2 编译busybox. 13
8.2.1 修改Makefile. 13
8.2.2 编译配置... 14
8.2.3 编译... 14
8.3 制作根文件系统... 14
8.3.1 拷贝busybox命令... 14
8.3.2 创建系统目录... 15
8.3.3拷贝运行库到lib下... 15
8.3.4创建启动脚本文件... 15
8.3.5创建终端设备... 16
8.3.6制作根文件镜像... 17
9 配置qemu与主机网络链接... 17
9.1虚拟机网络配置... 17
9.2创建网桥... 18
9.3修改配置文件... 18
9.4创建qemu-ifup、qemu-ifdown脚本... 19
10 启动qemu. 20
10.1 uImage内核镜像、dtb文件、u-boot文件拷贝。... 20
10.2 创建qemu执行脚本... 20
10.3 执行qemu_start.sh脚本... 20
11 参考... 21
RHEL7/Centos7下使用QEMU搭建u-boot+Linux+NFS嵌入式开发环境
交叉编译器下载链接:
https://releases.linaro.org/components/toolchain/binaries/7.2-2017.11/arm-linux-gnueabi/gcc-linaro-7.2.1-2017.11-i686_arm-linux-gnueabi.tar.xz
将其下载到/usr目录下并解压。
解压命令:
tar -xvf gcc-linaro-7.2.1-2017.11-i686_arm-linux-gnueabi.tar.xz
解压后会在本地生成gcc-linaro-7.2.1-2017.11-i686_arm-linux-gnueabi文件夹,文件夹名太长,将其重命名为toolchain。
重命名命令:
mv gcc-linaro-7.2.1-2017.11-i686_arm-linux-gnueabi toolchain
编辑/etc/profile ,在文件最后追加toolchain下的bin目录的绝对路径。
export PATH=$PATH:/usr/toolchain/bin
保存退出,执行 source /etc/profile使改变生效。
在终端输入arm-后按tab键。出现如下的命令则表示交叉编译环境搭建成功。
arm-linux-gnu-addr2line
arm-linux-gnu-ar
arm-linux-gnu-as
arm-linux-gnu-c++filt
arm-linux-gnu-cpp
arm-linux-gnueabi-addr2line
arm-linux-gnueabi-ar
arm-linux-gnueabi-as
arm-linux-gnueabi-c++
arm-linux-gnueabi-c++filt
arm-linux-gnueabi-cpp
arm-linux-gnueabi-dwp
arm-linux-gnueabi-elfedit
arm-linux-gnueabi-g++
arm-linux-gnueabi-gcc
arm-linux-gnueabi-gcc-7.2.1
…
执行下面的命令进行下载:
(1)fedora.repo
curl -o /etc/yum.repos.d/fedora.repo http://mirrors.aliyun.com/repo/fedora.repo
(2)fedora-updates.repo
curl -o /etc/yum.repos.d/fedora-updates.repo http://mirrors.aliyun.com/repo/fedora-updates.repo
fedora.repo
、
fedora-updates.repo
将文件里所有的$releasever替换成27(fedora27的版本号),所有的$basearch替换成x86_64。gpgcheck=1改为gpgcheck=0
yum clean all
yum makecache
执行yum -y install libfdt libfdt-devel 出现如下信息则表示添加成功。
正在解决依赖关系
--> 正在检查事务
---> 软件包 libfdt.x86_64.0.1.4.6-1.fc27 将被 安装
---> 软件包 libfdt-devel.x86_64.0.1.4.6-1.fc27 将被 安装
--> 解决依赖关系完成
直接使用yum -y install qemu便可安装,如果想要安装新的版本,可参看下面手动编译安装qemu。
下载链接:
https://download.qemu.org/qemu-2.11.1.tar.xz
解压:
tar -xvf qemu-2.11.1.tar.xz
进入上一步解压后的文件夹。执行下面的命令进行编译前配置。
配置命令:
./configure --target-list=arm-softmmu --audio-drv-list=
此时执行会报下面的错误。
ERROR: DTC (libfdt) version >= 1.4.0 not present. Your options:
(1) Preferred: Install the DTC (libfdt) devel package
(2) Fetch the DTC submodule, using:
git submodule update --init dtc
之所以会出错,是因为系统中没有安装libfdt。因为centos的yum源不提供libfdt,所以首先在系统中增加fedora的yum源后(参照第2节),再执行下面的命令安装libfdt。
安装命令:
sudo yum -y install libfdt libfdt-devel
安装后,再执行上面的./configure命令就不会出错了。
make
make install
执行make命令进行编译,编译完成后执行make install命令进行安装。安装完毕后,在终端输入qemu-然后按tab键。出现如下命令列表则表示安装成功。
qemu-ga qemu-io qemu-pr-helper
qemu-img qemu-nbd qemu-system-arm
执行qemu-system-arm –version出现下面的信息,与我们下载安装的qemu版本一致。
QEMU emulator version 2.11.1
Copyright (c) 2003-2017 Fabrice Bellard and the QEMU Project developers
下载链接:
http://ftp.denx.de/pub/u-boot/u-boot-2018.03.tar.bz2
解压:
tar -xvf u-boot-2018.03.tar.bz2
(1) Makefile
ifeq ($(HOSTARCH),$(ARCH))
CROSS_COMPILE ?=
endif
修改为:
ifeq ($(HOSTARCH),$(ARCH))
CROSS_COMPILE ?=
endif
CROSS_COMPILE ?=arm-linux-gnueabi-
(2) config.mk
ARCH := $(CONFIG_SYS_ARCH:"%"=%)
修改为:
ARCH := arm
修改include/configs/vexpress_common.h文件。通过修改bootargs启动参数。让qemu开发板支持tftp, nfs等服务。开机后能自动通过tftp服务从服务器主机下载uImage内核镜像并通过nfs服务找到服务器主机上的根文件系统。并指定qemu开发板ip地址以及服务器主机地址(参照第9.3节网桥网络配置,服务器地址为网桥的IP地址,开发板IP地址设定在同一网段即可。)
(1)终端启动代码:
在源文件“/* Basic environment settings */”下面增加如下代码:
/* 修改bootargs启动参数 2018-04-22 changzehai -------------------- ADD Start -*/
#define CONFIG_BOOTCOMMAND \
"tftp 0x60003000 uImage;tftp 0x60500000 vexpress-v2p-ca9.dtb; \
setenv bootargs 'root=/dev/nfs rw \
nfsroot=172.18.5.138:/home/rootfs,nfsvers=3 init=/linuxrc \
ip=172.18.5.139 console=ttyAMA0';\
bootm 0x60003000 - 0x60500000; "
#define CONFIG_IPADDR 172.18.5.139
#define CONFIG_NETMASK 255.255.255.0
#define CONFIG_SERVERIP 172.18.5.138
/* 修改bootargs启动参数 2018-04-22 changzehai -------------------- ADD End -*/
(2)图形界面启动代码:
如果想要在图形化界面启动,则将上面的console=ttyAMA0 改为console=tty0,然后将qemu启动参数-nographic去掉即可。
特别注意:因为RHEL7/centos7不支持NFS V2版本,而Linux内核默认是NFS V2版本。上面的bootargs参数里如果少了nfsvers=3 (NFS V3版本),则会导致NFS根文件系统挂载失败,出现如下的错误:
VFS: Unable to mount root fs via NFS, trying floppy.
VFS: Cannot open root device "(null)" or unknown-block(2,0): error -6
Please append a correct "root=" boot option; here are the available partitions:
1f00 131072 mtdblock0 (driver?)
1f01 32768 mtdblock1 (driver?)
Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(2,0)
CPU: 0 PID: 1 Comm: swapper/0 Not tainted 3.16.0 #1
[<8001465c>] (unwind_backtrace) from [<800116b4>] (show_stack+0x10/0x14)
[<800116b4>] (show_stack) from [<8045f710>] (dump_stack+0x88/0x98)
[<8045f710>] (dump_stack) from [<8045d8d4>] (panic+0xa0/0x1f8)
[<8045d8d4>] (panic) from [<805ca16c>] (mount_block_root+0x1d0/0x260)
[<805ca16c>] (mount_block_root) from [<805ca304>] (mount_root+0x108/0x110)
[<805ca304>] (mount_root) from [<805ca464>] (prepare_namespace+0x158/0x19c)
[<805ca464>] (prepare_namespace) from [<805c9df8>] (kernel_init_freeable+0x244/0x254)
[<805c9df8>] (kernel_init_freeable) from [<8045be44>] (kernel_init+0xc/0xe8)
[<8045be44>] (kernel_init) from [<8000e3f8>] (ret_from_fork+0x14/0x3c)
---[ end Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(2,0)
make vexpress_ca9x4_defconfig
make
编译完成后会在当前目录下生成u-boot可执行文件,在tools目录下生成相关工具。将u-boot文件拷贝到tools目录下。
如果漏掉这一步,编译Linux内核为uImage格式时会出现错误,参考第5.3节。
(1) 在/usr目录下新建u-boot目录,将tools下的所有文件拷贝到/usr/u-boot目录下。
(2) 修改/etc/profile文件,将/usr/u-boot追加到PATH环境变量后。如下:
export PATH=$PATH:/usr/toolchain/bin:/usr/u-boot
保存退出,执行 source /etc/profile使改变生效。
(3) 在终端输入mki,然后按tab键,如果出现mkimage命令,则表示拷贝配置成功。
下载链接:
https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.4.128.tar.xz
解压:
tar -xvf linux-4.4.128.tar.xz
进入上一步解压后的目录,如下所示修改Makefile。
ARCH ?= $(SUBARCH)
CROSS_COMPILE ?= $(CONFIG_CROSS_COMPILE:"%"=%)
修改为:
ARCH ?=arm
CROSS_COMPILE ?= arm-linux-gnueabi- (注:第1节安装的交叉编译工具)
(1) make vexpress_defconfig
(2)make LOADADDR=0x60003000 uImage (注:u-boot引导的内核镜像格式为uImage, 并且需要指定uImage的加载地址)
这里会出现如下错误,解决办法参照第4.5节。
"mkimage" command not found - U-Boot images will not be built
make[1]: *** [arch/arm/boot/uImage] 错误 1
(3)make modules
(4)make dtbs
编译完成后,会在arch/arm/boot下生成uImage文件,在arch/arm/boot/dts下生成我们需要的vexpress-v2p-ca9.dtb文件。
yum install -y tftp-server xinetd
在/home下创建tftp工作目录tftpboot,并修改其属性。
mkdir -p /home/tftpboot
chmod 777 /home/tftpboot
tftp的配置文件在/etc/xinetd.d/tftp下
service tftp
{
socket_type = dgram
protocol = udp
wait = yes
user = root
server = /usr/sbin/in.tftpd
server_args = -s /var/lib/tftpboot
disable = yes
per_source = 11
cps = 100 2
flags = IPv4
}
修改为:
service tftp
{
socket_type = dgram
protocol = udp
wait = yes
user = root
server = /usr/sbin/in.tftpd
server_args = -s /home/tftpboot -c
disable = no
per_source = 11
cps = 100 2
flags = IPv4
}
重启服务,让修改生效。
systemctl restart xinetd.service
systemctl restart tftp.service
(1) 开放服务
firewall-cmd --add-service=tftp --permanent
(2) 开放69端口
firewall-cmd --add-port=69/tcp --permanent
firewall-cmd --add-port=69/udp --permanent
执行firewall-cmd --reload 命令生效
(3) 开机启动
systemctl enable xinetd.service
systemctl enable tftp.service
如果不关闭系统防火墙,会导致qemu与主机无法通信。
防火墙开机关闭
systemctl disable firewalld
开机关闭SELinux
vi /etc/selinux/config
修改
"SELINUX=disabled"
为
"SELINUX=disabled"
yum install -y nfs-utils rpcbind
在/home下创建nfs工作目录rootfs(根文件系统目录),并修改其属性。
mkdir -p /home/rootfs
chmod 777 /home/rootfs
nfs配置文件为: /etc/exports,修改内容为:
/home/rootfs *(rw,sync,no_subtree_check,no_root_squash)
重启服务,让修改生效。
systemctl restart rpcbind.service
systemctl restart nfs-server.service
(1) 开放服务
firewall-cmd --add-service=nfs --permanent
(2) 开放端口
firewall-cmd --add-port=111/tcp --permanent
firewall-cmd --add-port=111/udp --permanent
firewall-cmd --add-port=2049/tcp --permanent
firewall-cmd --add-port=2049/udp –permanent
(3)开机启动
systemctl enable rpcbind.service
systemctl enable nfs-server.service
下载链接:
http://busybox.net/downloads/busybox-1.28.3.tar.bz2
解压:
tar -xvf busybox-1.28.3.tar.bz2
CROSS_COMPILE ?=
修改为:
CROSS_COMPILE ?= arm-linux-gnueabi-
ARCH ?= $(SUBARCH)
修改为:
ARCH ?= arm
make defconfig
make menuconfig → Settings ---> [ ] Build static binary (no shared libs) (NEW)
选中后[*] Build static binary (no shared libs) 保存退出。
输入menuconfig时可能会出现下面的错误:
HOSTLD scripts/kconfig/mconf
HOSTCC scripts/kconfig/lxdialog/checklist.o
In file included from scripts/kconfig/lxdialog/checklist.c:24:0:
scripts/kconfig/lxdialog/dialog.h:31:20: 致命错误:curses.h:没有那个文件或目录
#include CURSES_LOC
这是因为系统缺少ncurses库,只需执行以下命令即可
yum install ncurses-devel
make
make install
编译安装完成后会生成_install目录。
将第9.2.3节生成的_install目录下的全部文件拷贝到/home/rootfs目录(nfs工作目录)下。
cp -rp _install/* /home/rootfs
进入到/home/rootfs下,创建linux常用目录。
cd /home/rootfs
mkdir etc lib dev tmp sys var proc
从交叉编译工具的运行库目录拷贝所有库文件到lib目录下。
cd /home/rootfs
cp -rp /usr/toolchain/arm-linux-gnueabi/lib/* lib
进入etc目录。创建inittab、init.d\rcS、fstab、profile启动脚本文件,脚本内容如下所示,并修改属性为可执行。
cd /home/rootfs/etc
touch inittab
mkdir init.d
touch init.d/rcS
touch fstab
touch profile
inittab内容:
::sysinit:/etc/init.d/rcS
#::respawn:-/bin/sh
#tty2::askfirst:-/bin/sh
#::ctrlaltdel:/bin/umount -a -r
console::askfirst:-/bin/sh
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r
fstab内容:
proc /proc proc defaults 0 0
tmpfs /tmp tmpfs defaults 0 0
sysfs /sys sysfs defaults 0 0
tmpfs /dev tmpfs defaults 0 0
var /dev tmpfs defaults 0 0
ramfs /dev ramfs defaults 0 0
profile内容:
PS1='changzehai@vexpress-a9:\w# '
export PS1
init.d/rcS内容:
#! /bin/sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin
LD_LIBRARY_PATH=/lib
export LD_LIBRARY_PATH
mount -a
mkdir -p /dev/pts
mount -t devpts devpts /dev/pts
mdev -s
mkdir -p /var/lock
echo "-----------------------------------------------"
echo " Welcome to changzehai's A9 vexpress board"
echo "-----------------------------------------------"
修改为可执行文件:
chmod 777 inittab
chmod 777 fstab
chmod 777 profile
chmod 777 init.d/rcS
进入/home/rootfs/dev目录下,执行下列命令,创建终端设备。
sudo mknod -m 666 tty1 c 4 1
sudo mknod -m 666 tty2 c 4 2
sudo mknod -m 666 tty3 c 4 3
sudo mknod -m 666 tty4 c 4 4
sudo mknod -m 666 console c 5 1
sudo mknod -m 666 null c 1 3
生成镜像:
dd if=/dev/zero of=rootfs.ext3 bs=1M count=256
格式化为ext3文件系统
mkfs.ext3 rootfs.ext3
从rootfs目录拷贝文件到系统镜像中
sudo mount -t ext3 rootfs.ext3 /mnt
sudo cp -rp /home/rootfs/* /mnt
sudo umount /mnt
打开虚拟机,点击“编辑”---“虚拟网络编辑器” 点击“更改设置”就可以看到桥接模式,其中桥接模式选项有多个,这里你可以选择基于以太网的还是无线局域网的。虚拟机的ip地址要与你选择的以太网还是 无线网的ip段对应(即:ip地址的前三部分要一致)。
我这里选择无线局域网,主机网络配置如下, 则虚拟机的网络配置要跟主机网络配置对应。如下:
主机
无线局域网适配器 WLAN:
DNS . . . . . . . . . . . . . . : 172.18.3.80
IPv4 地址 . . . . . . . . . . . . : 172.18.8.36
子网掩码 . . . . . . . . . . . . : 255.255.255.0
默认网关. . . . . . . . . . . . . : 172.18.8.254
虚拟机
DNS . . . . . . . . . . . . . . : 172.18.3.80
IPv4 地址 . . . . . . . . . . . . : 172.18.8.138
子网掩码 . . . . . . . . . . . . : 255.255.255.0
默认网关. . . . . . . . . . . . . : 172.18.8.254
然后再点击“虚拟机”---“设置”,点击“网络适配器”,选择右边的“桥接模式”选项。
然后在虚拟机中Ping主机的IP,能ping通表示虚拟机网络配置成功。
brctl addbr br0 #添加br0这个bridge
brctl addif br0 ens33 #将br0与ens33绑定起来
brctl stp br0 on #将br0设置为启用STP协议
在/etc/sysconfig/network-scripts目录下创建br0网桥的配置文件,并修改ens33的配置文件。
注意:一定要将备份的配置文件,比如ifcfg-br0.20181221、ifcfg-ens33.20181221之类的从/etc/sysconfig/network-scripts目录下移走,不然这些配置文件的内容也会生效,导致修改无效。
创建br0的配置文件ifcfg-br0,内容如下,其中网络参数与第9.1节中虚拟机的网络配置一致。
TYPE=Bridge
DEVICE=br0
BOOTPROTO=static
ONBOOT=yes
IPADDR=172.18.8.138
NETMASK=255.255.255.0
GATEWAY=172.18.8.254
DNS1=172.18.3.80
修改ens33的内容如下:
TYPE=Ethernet
BOOTPROTO=none
DEVICE= ens33
ONBOOT=yes
BRIDGE=br0
重启网络服务
systemctl restart network
执行brctl show命令,如果出现如下信息,表示网桥配置成功。
bridge name bridge id STP enabled interfaces
br0 8000.000c29d591f0 no ens33
在/etc 下创建qemu-ifup、qemu-ifdown脚本。脚本内容如下所示。
qemu-ifup内容:
#!/bin/sh
echo sudo tunctl -u $(id -un) -t $1
sudo tunctl -u $(id -un) -t $1
echo sudo ifconfig $1 0.0.0.0 promisc up
sudo ifconfig $1 0.0.0.0 promisc up
echo sudo brctl addif br0 $1
sudo brctl addif br0 $1
echo brctl show
brctl show
qemu-ifdown内容:
#!/bin/sh
echo sudo brctl delif br0 $1
sudo brctl delif br0 $1
echo sudo tunctl -d $1
sudo tunctl -d $1
echo brctl show
brctl show
:
将第5.4节生成的uImage内核镜像,vexpress-v2p-ca9.dtb文件以及第4.3节生成的u-boot文件拷贝到/home/tftpboot(tftp工作目录)目录下。
cp -rp linux-4.4.128/arch/arm/boot/uImage /home/tftpboot
cp -rp linux-4.4.128/arch/arm/boot/dts/vexpress-v2p-ca9.dtb /home/tftpboot
cp -rp u-boot-2018.03/u-boot /home/tftpboot
在/home/tftpboot目录下创建qemu_start.sh脚本,内容如下所示:
终端启动:
qemu-system-arm \
-M vexpress-a9 \
-m 512M \
-kernel u-boot\
-nographic \
-net nic, -net tap
图形界面启动:
qemu-system-arm \
-M vexpress-a9 \
-m 512M \
-kernel u-boot-lcd\
-net nic, -net tap
u-boot-lcd源代码与u-boot不一样,参照第4.3节。
图形启动若卡在VNC server running on ::1:5901,使用下面的方法解决:
1) 安装SDL开发库
# yum install SDL-devel
2) 重新编译QEMU
# ./configure –target-list=x86_64-softmmu
执行以上指令后,可以从输出中看到:SDL support:yes
# make
# make install
用root权限执行qemu_start.sh脚本,出现以下信息,表示成功挂载NFS根文件系统,进入开发板linu系统。
#0: ARM AC'97 Interface PL041 rev0 at 0x10004000, irq 30
VFS: Mounted root (nfs filesystem) on device 0:13.
Freeing unused kernel memory: 288K
nfs: server 192.168.1.100 not responding, still trying
nfs: server 192.168.1.100 OK
-----------------------------------------------
Welcome to changzehai's A9 vexpress board
-----------------------------------------------
Please press Enter to activate this console.
changzehai@vexpress-a9:/# ls
changzehai@vexpress-a9:/# ls
bin etc linuxrc sbin tmp var
dev lib proc sys usr
至此,成功完成RHEL7/Centos7下使用QEMU搭建u-boot+Linux+NFS嵌入式开发环境。
主要参考下面的王利涛老师的《使用QEMU搭建u-boot+Linux+NFS嵌入式开发环境视频课程》,非常感谢王利涛老师分享这么好的学习视频,给我以极大的帮助。也希望大家能去看看,会有很多收获。
王利涛老师的视频课程链接:
http://edu.51cto.com/course/10445.html