ubuntu24.04上使用qemu+buildroot+uboot+linux+tftp+nfs模拟搭建vexpress-ca9嵌入式linux开发环境
1 准备工作
1.1 安装依赖工具
sudo apt-get update && sudo apt-get install build-essential git bc flex libncurses5-dev libssl-dev device-tree-compiler
1.2 安装arm交叉编译工具链
sudo apt install gcc-arm-linux-gnueabihf
安装之后,在终端输入arm-linux- gnueabihf- 后按TAB键,出现下列命令,表示安装成功。
1.3 安装qemu-system-arm
sudo apt install qemu-system-arm
安装完毕后,在终端输入: qemu- 后按TAB键,弹出下列命令证明安装成功。
2 u-boot配置编译
2.1 下载u-boot
wget http://ftp.denx.de/pub/u-boot/u-boot-2018.03.tar.bz2
2.2 配置u-boot
解压并进入u-boot。
tar -xvf u-boot-2023.10.tar.bz2 && cd u-boot-2023.10
使用vexpress-ca9x4的默认配置进行配置。
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- vexpress_ca9x4_defconfig
2.3 修改u-boot
qemu模拟开发板,无法将u-boot环境变量固化到flash,所以每次启动需要重新设置环境变量,为了方便可以将相关环境变量写死在源码里,具体为include/configs/vexpress_common.h中的CFG_EXTRA_ENV_SETTINGS宏。
修改define CFG_EXTRA_ENV_SETTINGS 如下。其中10.211.55.10为QEMU模拟的开发板的IP,10.211.55.100为宿主系统ubuntu24.04的IP,需要根据实际环境IP进行修改。
#define CFG_EXTRA_ENV_SETTINGS \"ipaddr=10.211.55.10\0" \"serverip=10.211.55.100\0" \"bootcmd=tftp 0x60003000 uImage; \tftp 0x61000000 vexpress-v2p-ca9.dtb; \bootm 0x60003000 - 0x61000000\0" \"bootargs=root=/dev/nfs rw \nfsroot=10.211.55.100:/nfs/rootfs,nfsvers=4 init=/linuxrc \ip=10.211.55.10 console=ttyAMA0\0"
2.4 编译u-boot
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j8
编译成功后,会在当前目录生成u-boot。
3 linux内核配置编译
3.1 下载linux内核
wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.14.2.tar.xz
3.2 配置linux内核
解压并进入linux内核主目录。
tar -xvf linux-6.14.2.tar.xz && cd linux-6.14.2
3.2.1 使用vexpress-ca9开发板默认配置。
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- vexpress_defconfig
3.2.2 关键自定义配置
使用menuconfig进行自定义配置。
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
- 启用 VirtIO 网络
Device Drivers ---> Network device support ---> Virtio network driver
- 启用 NFS 客户端
File systems ---> Network File Systems ---> NFS client support
把能选的client版本v2、v3、v4等都选了。
选中Root file system on NFS
- 支持自动挂载devtmpfs到/dev
Device Drivers ---> Generic Driver Options ---> Automount devtmpfs at /dev, after the kernel mounted the rootfs
不选中Automount devtmpfs at /dev, after the kernel mounted the rootfs, 后续buildroot制作的根文件系统无法生成/dev/ttyAMA0节点,导致无法进行系统,报下面的错误。
3.3 编译linux内核
编译u-boot的内核镜像,需要指定LOADADDR=0x60003000(即uboot通过tftp加载uImage的地址),以及生成的镜像格式为uImage.
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- LOADADDR=0x60003000 uImage dtbs -j8
编译完成后,会在下面路径生成zImage内核镜像和dtb设备树文件。
arch/arm/boot/uImage # 内核镜像
arch/arm/boot/dts/arm/vexpress-v2p-ca9.dtb # 设备树
将uImage和vexpress-v2p-ca9.dtb拷贝到tfp服务器工作目录/tftpboot下,tftpboot在地5.2章节进行说明。
4 配置编译buildroot
4.1 下载buildroot
wget https://buildroot.org/downloads/buildroot-2024.02.tar.gz
4.2 配置buildroot
解压并进入buildroot主目录。
tar -xvf buildroot-2024.02.tar.gz && cd buildroot-2024.02
4.2.1 使用vexpress-ca9默认配置
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- qemu_arm_vexpress_defconfig
4.2.2 关键自定义配置
使用menuconfig进行自定义配置。
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
- 文件系统
Filesystem images ---> ext2/3/4 root filesystem---> ext2/3/4 variant
- mdev支持
System configuration ---> dev management ---> Dynamic using devtmpfs + mdev
- nfs-utils
Target packages ---> Filesystem and flash utilities ---> nfs-utils---> NFSv4/NFSv4.1
4.3 编译根文件系统
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j8
编译完成后,会生成根文件镜像
output/images/rootfs.ext4 # ext4格式镜像
5 宿主机上配置tftp服务器
5.1 安装tftp服务器
sudo apt-get install tftpd-hpa
5.2 设置tftp服务器工作目录
sudo mkdir -p /tftpboot && sudo chmod -R 777 /tftpboot
5.3 配置tftp服务
sudo vi /etc/default/tftpd-hpa
修改配置如下:
TFTP_DIRECTORY="/tftpboot"
TFTP_OPTIONS="-l -c -s"
修改保存配置文件后,重启tftp服务使配置生效。
sudo systemctl restart tftpd-hpa
5.4 验证tftp服务
在tftp服务器目录创建一个测试文件,在其他文件夹下通过tftp get这个问题,get成功则说明tftp服务配置成功。
6 宿主机上配置NFS服务器
6.1 安装nfs服务
sudo apt-get install nfs-kernel-server
6.2 配置nfs服务
6.2.1 配置nfs根文件系统
- 创建rootfs文件夹
sudo mkdir -p /nfs/rootfs
- 拷贝根文件系统到rootfs文件夹
讲buildroot制作的rootfs拷贝到/nfs/rootfs文件夹。
sudo mount -t ext4 /home/cat/work/drv/buildroot-2024.02/output/images/rootfs.ext4 /mnt
sudo cp -rp /mnt/* /nfs/rootfs
sudo umount /mnt
6.2.2 修改nfs服务配置文件
sudo vi /etc/exports # 配置内容:
/nfs/rootfs *(rw,sync,no_root_squash,no_subtree_check,insecure)
注意,一定要加上no_root_squash,否则后面使用nfs加载根文件系统后,重复弹出让输用户名和密码,进不去系统,如下:
修改好exports文件后,执行
source /exports
使配置生效,然后重启nfs服务。
sudo systemctl restart nfs-kernel-server
6.3 验证nfs服务是否生效
使用如下命令将/nfs/rootfs挂载到/mnt,如果挂载成功则表示生效。
sudo mount -t nfs 127.0.0.1:/nfs/rootfs /mnt/
7 使用qemu模拟vexpress-ca9开发板
7.1 创建网桥
创建网桥用于开发板和ubuntu宿主机通信。
创建 /etc/netplan/01-netcfg.yaml配置文件,内容如下:
network:version: 2renderer: networkdethernets:enp0s5: #替换为你的物理网卡名(用 `ip a` 查看)dhcp4: nobridges:br0:interfaces: [enp0s5]dhcp4: no# 如果使用静态 IP:addresses: 10.211.55.100/24 #u-boot指定的serverip# gateway4: 192.168.1.1# nameservers:# addresses: [8.8.8.8, 1.1.1.1]
然后执行下面的命令,执行上面的配置
sudo netplan apply
然后执行
ip addr show br0
确认网桥是否生效。
7.2 使用qemu启动脚本启动开发板
#!/bin/bash# 随机生成 TAP 接口名(格式:tap-<随机4位16进制>)
TAP_IF="tap-$(openssl rand -hex 2 | cut -c1-4)"
BRIDGE_IF="br0" # 宿主机桥接接口名
USER=$(whoami)# 创建 TAP 接口并加入桥接
echo "Creating TAP interface: $TAP_IF"
sudo ip tuntap add dev $TAP_IF mode tap user $USER
sudo ip link set $TAP_IF up
sudo ip link set $TAP_IF master $BRIDGE_IF# 启动 QEMU(传递 TAP 接口名给 U-Boot)
echo "Starting QEMU with U-Boot..."
sudo qemu-system-arm -M vexpress-a9 -m 512M -kernel u-boot -net nic -net tap,ifname=$TAP_IF,script=no,downscript=no -nographic# QEMU 退出后自动清理 TAP 接口
echo "Cleaning up TAP interface: $TAP_IF"
sudo ip link set $TAP_IF down
sudo ip tuntap del dev $TAP_IF mode tap
保存为qemu.sh脚本,该脚本用于启动模拟开发板,其中u-boot第2节的u-boot镜像。该脚本动态创建TAP设备,可以实现启动多个开发板。
7.3 启动过程
启动过程如下图。
- 通过tftp下载uImage
- 通过tftp下载dtb
- 内核启动
- 使用nfs挂载根文件系统
- 成功进入系统
到此本文完毕,由于本人水平有限,难免有误,请各位大佬不吝指正,谢谢。