使用qemu搭建arm嵌入式linux开发环境

qemu搭建arm虚拟嵌入式linux开发环境

  • 1.前言
  • 1.安装qemu与arm交叉编译工具
  • 2.Linux内核与设备树编译
  • 3.busybox根文件系统制作
  • 4.使用u-boot加载Linux内核
  • 5.搭建网络开发环境
  • 6.挂载NFS网络文件系统

1.前言

对于很多新手来说,上手嵌入式Linux开发是有一定的难度的——往往是各种名词听了一大堆,真正去操作的时候,对着开发板一脸茫然,不知从何下手。其实作为初学者,我们完全可以通过虚拟机来掌握嵌入式Linux的开发框架和基本流程,从而避免硬件上的一些坑。等到我们对整个开发过程比较了解之后,再去上手开发板就会事半功倍。
首先,我们需要了解一些基本概念:
arm交叉编译器:在主机上编译能够在arm开发板上运行的代码。
linux内核:linux运行的核心代码。
linux内核模块:动态可加载内核模块,执行时依赖于内核,可以看做是内核的一个拓展,包含各种驱动程序(驱动开发就主要是这一块)。
linux设备树:与硬件相关,用来描述芯片平台及板级差异的。
根文件系统:内核启动时挂载的第一个文件系统,用来访问各种目录和文件,与内核互相独立。
bootloader:开发板启动时的引导程序,一般使用u-boot来制作。
所以,为了在arm开发板上成功运行Linux系统,我们有如下三个方面的任务:

  1. 制作bootloader;
  2. 编译linux内核、linux内核模块、linux设备树;
  3. 制作根文件系统。
    下面,我们使用qemu虚拟机来上手嵌入式linux的开发。

1.安装qemu与arm交叉编译工具

在命令行输入以下内容安装ARM交叉编译工具:

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

安装qemu:

sudo apt-get install qemu

若需要安装较新版本的qemu,可以自行下载源码手动编译安装)
使用qemu-system-命令可以查看qemu支持的CPU架构。
使用qemu-system-arm --version命令可以查看qemu的版本。
使用qemu-system-arm -M help命令可以查看支持的开发板类别。

2.Linux内核与设备树编译

下载Linux内核:https://www.kernel.org/
选择长期维护的4.4版本 ,点击tarball进行下载:
linux内核下载
将下载下来的Linux内核拷贝到home目录,使用tar xvf linux-4.4.232.tar.xz进行解压缩。
解压好后输入cd linux-4.4.232/进入linux内核目录下
linux内核目录
修改Makefile:vim Makefile
搜索交叉编译关键字,在vim编辑器中输入:/CROSS_COMPILE,然后回车
向下移动光标,找到关键字ARCHCROSS_COMPILE,按i键进入插入文本模式,将其修改为如下内容:
关键字内容修改
按Esc键切换为一般模式,输入:wq保存并退出。

这里我们选择vexpress系列作为我们虚拟开发板,在linux内核目录下,输入make vexpress_defconfig对开发板进行配置,编译后生成.config文件:
使用qemu搭建arm嵌入式linux开发环境_第1张图片
配置好后,编译内核,生成zImage镜像文件:make zImage -j6(多线程编译)
编译内核模块make modules -j4
编译设备树,获得dtb文件:make dtbs
在linux内核目录下,使用qemu运行内核:qemu-system-arm -M vexpress-a9 -m 512M -kernel arch/arm/boot/zImage -dtb arch/arm/boot/dts/vexpress-v2p-ca9.dtb -nographic -append "console=ttyAMA0",该命令指定了开发板类别、内存大小、内核zImage文件、dtb文件、无图形界面、串口。
可以看到内核开始运行起来:
使用qemu搭建arm嵌入式linux开发环境_第2张图片
但是卡在了挂载根文件系统处,别急,接着往下看。

3.busybox根文件系统制作

使用ps命令查看qemu进程:ps -a
qemu进程
使用kill命令结束qemu进程:kill 25906
接下来,使用busybox制作根文件系统。
下载源码:https://busybox.net/downloads/,下载最新版本即可。
busybox下载
解压缩:tar xvf busybox-1.32.0.tar.bz2
进入busybox源码目录:cd busybox-1.32.0/
修改Makefile:vim Makefile
在vim编辑器中输入/CROSS_COMPILE查找关键字CROSS_COMPILE
向下移动光标,找到关键字所在处,按i键切换到插入模式,并将值修改为arm-linux-gnueabi-
CROSS_COMPILE修改值
按Esc退出插入模式,输入/ARCH查找关键字ARCH
向下移动光标,找到关键字,按i切换到插入模式,并将值修改为arm
ARCH修改值
按Esc键,输入:wq保存退出。
接着,输入命令make defconfig回车等待配置完毕。
也可以使用图形化配置make menuconfig,按回车然后进入Settings选项,找到Build Options,点y键将选项Build static binary(编译成静态)选中,然后退出:
使用qemu搭建arm嵌入式linux开发环境_第3张图片
回到命令行,直接编译:make -j4
然后执行make install,生成一个**_install文件夹。
准备好后,下一步开始制作根文件系统。
输入cd回到home目录,新建目录mkdir rootfs,进入该目录cd rootfs/,将刚才生成的
_install**目录里的所有文件拷贝到该目录下:

cp -r /home/zvcv/Downloads/busybox-1.32.0/_install/* ./

新建目录mkdir lib,将arm交叉编译器的库复制过来:

cp -r /usr/arm-linux-gnueabi/lib/* lib/

在rootfs目录下新建目录mkdir dev/,进入该目录cd dev/,创建节点sudo mknod -m 666 tty1 c 4 1(这里创建了一个串口字符设备,主设备号为4,从设备号为1)。
重复创建多个串口设备,注意分配好从设备号:
创建一个控制台节点:mknod -m 666 console c 5 1
创建一个空节点:mknod -m 666 null c 1 3
创建好的字符设备用ls查看:
创建字符设备
回到home目录,输入命令dd if=/dev/zero of=rootfs.ext3 bs=1M count=32生成虚拟SD卡系统镜像,可以得到一个rootfs.ext3文件。
格式化该镜像:mkfs.ext3 rootfs.ext3
挂载该镜像到本地:mount -t ext3 rootfs.ext3 /mnt -o loop
将之前准备的rootfs目录下的所有文件都拷贝到该镜像挂载点:cp -r /home/zvcv/rootfs/* /mnt/
卸载:umount /mnt/
进入linux源码目录: cd linux/
使用qemu启动内核:qemu-system-arm -M vexpress-a9 -m 512M -kernel arch/arm/boot/zImage -dtb arch/arm/boot/dts/vexpress-v2p-ca9.dtb -nographic -append "root=/dev/mmcblk0 rw console=ttyAMA0" -sd /home/zvcv/rootfs.ext3,这里比之前多指定了一个sd镜像。
点击回车,进入命令行,linux启动完毕。
启动命令行
若要图形化启动,使用命令:qemu-system-arm -M vexpress-a9 -m 512M -kernel arch/arm/boot/zImage -dtb arch/arm/boot/dts/vexpress-v2p-ca9.dtb -append "root=/dev/mmcblk0 rw console=tty0" -sd rootfs.ext3
使用qemu搭建arm嵌入式linux开发环境_第4张图片

4.使用u-boot加载Linux内核

下载源码:u-boot下载,选择合适的版本即可。
(较新版本的u-boot需要更高版本的gcc来编译,为了方便起见,可以选用较早版本的u-boot)
选择合适的u-boot

下载后解压缩:tar xvf u-boot-2020.07.tar.bz2
切换到目录:cd u-boot-2020.07
编辑Makefile文件:vim Makefile
查找关键字:/CROSS_COMPILE
向下翻,找到CROSS_COMPILE,按i键切换模式,修改为如下内容:
使用qemu搭建arm嵌入式linux开发环境_第5张图片
按Esc键退出插入模式,输入:wq保存并退出。
命令行输入vim config.mk
查找关键字:/ARCH
按i键切换模式,修改关键字的值:
修改关键字值
按Esc键退出插入模式,输入:wq保存并退出。
命令行输入命令进行配置:make vexpress_ca9x4_defconfig
配置好后,编译:make -j4
若make时出现下图中的问题,可能是交叉编译gcc的版本太低,下载新版本点击下载。

编译出错
先移除旧版:sudo apt-get remove gcc-arm-linux-gnueabi
解压:tar -vxf gcc-linaro-7.2.1-2017.11-x86_64_arm-linux-gnueabi.tar.xz
拷贝:sudo cp -r ./gcc-linaro-7.2.1-2017.11-x86_64_arm-linux-gnueabi /opt/
编辑环境变量:sudo vim /etc/bash.bashrc,文件末尾添加如下内容:

PATH="$PATH:/opt/gcc-linaro-7.2.1-2017.11-x86_64_arm-linux-gnueabi/bin"

使路径生效:source /etc/bash.bashrc
使用arm-linux-gnueabi-gcc -v查看编译器版本

若make时出现如下错误:
出现错误
则编辑环境变量:vim ~/.bashrc
按G跳到文件结尾,按i键输入,添加如下内容:

export CROSS_COMPILE=arm-linux-gnueabi-
export ARCH=arm

更新环镜变量:source ~/.bashrc
然后再次执行即可:

make vexpress_ca9x4_defconfig
make -j4

若make时又出现如下错误:
make出现错误
则需要安装device-tree-compiler:sudo apt-get install device-tree-compiler

make完成后,启动u-boot:qemu-system-arm -M vexpress-a9 -m 512M -nographic -kernel u-boot(注意:按下enter键后,会出现一个2s倒计时,询问你是否停止自动启动,直接回车就可以跳过启动过程中各种外设的加载)
输入命令测试:help,可以查看支持的命令。
运行成功后,删除该qemu进程:ps -a查找PID号,kill命令删除

5.搭建网络开发环境

qemu通过tftp工具下载内核镜像。
接下来配置主机和qemu之间的网络连接。
安装工具包:sudo apt-get install uml-utilities bridge-utils
查看主机网口,命令行输入:ifconfig ,记下网口名和IP地址
使用qemu搭建arm嵌入式linux开发环境_第6张图片

然后,修改网络接口文件:vim /etc/network/interfaces
添加虚拟网口,配置为桥接模式,添加信息如下:

auto ens33
auto br0
iface br0 inet dhcp
  bridge_ports ens33

保存退出,使用命令重启网络:service networking restart
若失败,则重启Ubuntu:reboot
使用ifconfig命令查看生成的虚拟网口br0:
使用qemu搭建arm嵌入式linux开发环境_第7张图片
检查无误后,进入linux内核目录:cd linux-4.4.232/
将内核编译为uImage模式:make LOADADDR=0x60003000 uImage -j4
查看生成的镜像文件:ls arch/arm/boot/
生成uImage
可以看到多了一个uImage。
在主机上安装TFTP工具sudo apt-get install tftp-hpa tftpd-hpa xinetd
修改文件权限:chmod 777 /etc/default/tftpd-hpa
再修改配置文件:vim /etc/default/tftpd-hpa,如下图所示:
使用qemu搭建arm嵌入式linux开发环境_第8张图片
在主目录创建tftp文件夹:mkdir /home/zvcv/tftpboot,一定要和上面的一致,不然会出错。
修改权限:chmod 777 tftpboot
重启tftp服务:

sudo /etc/init.d/tftpd-hpa restart

把之前生成的的uImage和dtb文件拷贝到刚创建的目录下:

cp -p ./arch/arm/boot/uImage /home/zvcv/tftpboot/
cp -p ./arch/arm/boot/dts/vexpress-v2p-ca9.dtb /home/zvcv/tftpboot/

自动引导设置
进入u-boot-2017.05目录:cd u-boot-2017.05/
修改配置文件:vim include/configs/vexpress_common.h
查找关键字:/BOOTCOMMAND
注释宏定义CONFIG_BOOTCOMMAND,并添加如下内容(190~197行):
使用qemu搭建arm嵌入式linux开发环境_第9张图片

其中,CONFIG_SERVERIP地址根据你主机ifconfig的结果来设置,比如我的是192.168.155.128。
CONFIG_IPADDRCONFIG_SERVERIP设置为同一网段(不冲突就行),如192.168.155.129。
然后,保存退出即可。
如果用ifconfig命令查看ens33网口时,发现没有显示ip地址,可以通过命令ifconfig ens33 192.168.155.128来手动配置ip地址。同样,也可以用ifconfig br0 192.168.155.129来设置br0网口ip地址。

用ping命令测试是否配置成功:

ping 192.168.155.128
ping 192.168.155.129

能够ping通则说明配置成功:
在这里插入图片描述
可以按ctrl+c来停止ping的运行。

接着,在u-boot-2017.05目录下重新编译生成u-boot:

make -j4

拷贝u-boot文件到创建的tftpboot目录下:

cp -p ./u-boot /home/zvcv/tftpboot/

tftpboot目录包含的文件如下图所示:
使用qemu搭建arm嵌入式linux开发环境_第10张图片

拷贝完成后,进入刚才创建的目录:cd /home/zvcv/tftpboot
启动u-boot引导uImage:qemu-system-arm -M vexpress-a9 -kernel u-boot -nographic -m 512M -net nic,vlan=0 -net tap,vlan=0,ifname=tap0 -sd /home/zvcv/rootfs.ext3,其中rootfs.ext3是前面制作的文件系统。
正常启动如下图所示:
使用qemu搭建arm嵌入式linux开发环境_第11张图片

如果启动失败,可以reboot重启一下主机,再执行上述命令。
为了方便起见,可以把上述命令放进一个脚本文件。
创建并编辑文件:vim boot-script.sh,添加内容如下图所示:
使用qemu搭建arm嵌入式linux开发环境_第12张图片
保存退出后,就可以通过输入./boot-script直接调用该启动命令了。

启动完后,可以输入命令进行测试:
使用qemu搭建arm嵌入式linux开发环境_第13张图片

可以看到,u-boot引导的linux内核能正常工作了。

6.挂载NFS网络文件系统

安装NFS服务:sudo apt-get install nfs-kernel-server
配置NFS挂载目录:vim /etc/exports,添加下面一行内容:
使用qemu搭建arm嵌入式linux开发环境_第14张图片
其中rootfs是前面小节创建的用于制作跟文件系统的目录。
开启NFS服务:

/etc/init.d/rpcbind restart
/etc/init.d/nfs-kernel-server restart

切换到内核目录,图形化配置内核,使其支持NFS: make menuconfig
然后重新编译内核:make -j4
切换到u-boot目录,编辑文件:vim include/configs/vexpress_common.h
修改关键字:

#define CONFIG_BOOTCOMMAND \
	"tftp 0x60003000 uImage;tftp 0x60500000 vexpress-v2p-ca9.dtb; \
	setenv bootargs 'root=/dev/nfs rw\
	nfsroot=192.168.232.20:/home/qemu-test/rootfs init=/linuxrc \
	ip=192.168.232.21\
	console=ttyAMA0'; \
	bootm 0x60003000 - 0x60500000;"

qemu启动u-boot:

qemu-system-arm \
	-M vexpress-a9 \
	-kernel u-boot \
	-m 512M \
	-nographic \
	-net nic,vlan=0 -net tap,vlan=0,ifname=tap0 \
	-append "root=/dev/mmcblk0 rw console=ttyAMA0"\

教程参考来自《嵌入式工程师自我修养》系列视频。

你可能感兴趣的:(笔记,linux,嵌入式,内核,qemu)