文章目录
其他相关文章:
从0开始使用QEMU模拟ARM开发环境之编译 uboot、Linux 内核和 busybox 制作 rootfs 并仿真
从0开始使用QEMU模拟ARM开发环境之uboot通过sd卡加载uImage
uboot通过tftp加载uImage
为了通过 tftp 加载有关的文件到指定的内存地址,需要先完成下面2个步骤。
-
在主机搭建tftp服务器
-
QEMU网络功能配置
主机搭建tftp服务器
安装
sudo apt-get install tftp-hpa tftpd-hpa -y
配置
sudo vi /etc/default/tftpd-hpa
或者
sudo gedit /etc/default/tftpd-hpa
根据需求进行修改即可
#/etc/default/tftpd-hpa
TFTP_USERNAME="tftp"
TFTP_DIRECTORY="/home/leacock/tftpboot" # tftpd-hpa的服务目录 /tftpboot
TFTP_ADDRESS="0.0.0.0:69"
TFTP_OPTIONS="-l -c -s" # 这里是选项,-c是可以上传文件的参数,-s是指定tftpd-hpa服务目录,上面已经指定
重启服务
sudo service tftpd-hpa restart # stop ,start
测试
tftp 127.0.0.1
QEMU网络功能配置
为了 让 QEMU 能够与主机 建立网络连接,采用桥接的网络连接与Host通信(需要主机内核tun/tap模块支持)
QEMU中的网络,包含两部分的内容
- 客户机使用的虚拟网络设备
- 和上述虚拟设备通信的网络后端,这些后端负责把虚拟设备的数据包发到宿主机的网络中
QEMU 两种上网方式(不同的网络后端):
user mode network :
这种方式实现虚拟机上网很简单,类似vmware里的nat,qemu启动时加入-user-net参数,虚拟机里使用dhcp方式,即可与互联网通信,但是这种方式虚拟机与主机的通信不方便。
tap/tun network :
这种方式要比user mode复杂一些,但是设置好后 虚拟机<–>互联网 虚拟机<–>主机 通信都很容易
这种方式设置上类似vmware的host-only,qemu使用tun/tap设备在主机上增加一块虚拟网络设备(tun0),然后就可以象真实网卡一样配置它。
TAP后端
QEMU的TAP后端利用宿主机的TAP设备,为客户机提供完整的桥接网络支持,如果外部需要使用标准端口连接到客户机, 或者多个客户机需要相互通信,可以使用该方式。 TAP后端还具有以下优势:
- 非常好的性能
- 可以配置以支持各种网络拓扑
但是,你需要在宿主机上进行网络拓扑的配置,而且各种系统的配置不同。
主机安装工具包:
sudo apt-get install uml-utilities bridge-utils -y
使用TAP后端前,需要确认你的宿主机的内核支持TAP网络接口: /dev/net/tun
文件存在则说明支持。
ls /dev/net
输出
tun
如果没有这样的文件,可以尝试手工创建:
sudo mkdir /dev/net
sudo mknod /dev/net/tun c 10 200
sudo /sbin/modprobe tun
修改网络配置文件(重启生效)
sudo vi /etc/network/interfaces
或者
sudo gedit /etc/network/interfaces
添加以下内容,注意 根据自己的实际情况 修改 bridge_ports
auto br0
iface br0 inet dhcp
bridge_ports ens33
# ens33 通过ifconfig 查看的网卡
如果出现网络问题,ifconfig
可以发现 ens33 网卡 没有 IP
可能是/etc/network/interfaces
中没 配置 ens33,可以如下添加
auto ens33
iface ens33 inet dhcp
如果发现 ens33 网卡与br0网卡 IP相同冲突,可能导致主机网络问题,可使用下面的命令改变IP
sudo ifconfig br0 192.168.100.101
添加qemu有关系统脚本
在 /etc/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
sudo ifconfig br0 192.168.100.101
# 根据自己的实际情况修改 IP地址,注意:uboot 中的 CONFIG_SERVERIP(serverip) 要跟这里一样 见后面
在 /etc/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
给上面的脚本添加执行权限
sudo chmod +x /etc/qemu*
重启网络使生效
sudo service networking restart
ifconfig
查看
运行 /etc/qemu-ifup 使能,br0的ip会变为 192.168.100.101
uboot 修改和重新编译
修改uboot代码
回到u-boot-master 根目录 在include/configs/vexpress_common.h
中加入相应的宏定义
// 根据自己的实际情况修改对应的地址
#define CONFIG_IPADDR 192.168.100.100
#define CONFIG_NETMASK 255.255.255.0
#define CONFIG_SERVERIP 192.168.100.101
/* 指定启动文件为uImage */
#define CONFIG_BOOTFILE "uImage"
/* 指定启动命令 */
#define CONFIG_BOOTCOMMAND "tftp 0x60003000 uImage;tftp 0x60500000 vexpress-v2p-ca9.dtb; setenv bootargs'root=/dev/mmcblk0 console=ttyAMA0'; bootm 0x60003000 - 0x60500000"
实际上,CONFIG_BOOTCOMMAND的值会在uboot启动以后自动执行,相当于在下载模式输入下面的指令
tftp 0x60003000 uImage
tftp 0x60500000 vexpress-v2p-ca9.dtb
setenv bootargs'root=/dev/mmcblk0 console=ttyAMA0'
bootm 0x60003000 - 0x60500000
重新编译uboot
export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabihf-
# make clean && make vexpress_ca9x4_defconfig # 不需要改配置
make -j6
仿真uboot
qemu-system-arm -M vexpress-a9 -m 256 -kernel u-boot -nographic
启动后print打印看是否有
=> print
...
arch=arm
bootcmd=tftp 0x60003000 uImage;tftp 0x60500000 vexpress-v2p-ca9.dtb; setenv bootargs'root=/dev/mmcblk0 console=ttyAMA0'; bootm 0x60003000 - 0x60500000
...
bootfile=uImage
...
ipaddr=192.168.100.100
...
netmask=255.255.255.0
...
serverip=192.168.100.101
指定编译 kernel 与 dtb
回到 linux-5.4.95 根目录
LOADADDR(运行地址) 和uboot的启动加载位置一致 , 见 修改uboot代码
export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabihf-
make dtbs -j6
make uImage LOADADDR=0x60003000 -j6
如果出现如下问题
执行命令 sudo apt-get install u-boot-tools
安装tools 后,再执行
进行仿真
把uImage
与 vexpress-v2p-ca9.dtb
放到tftp目录下,vexpress-v2p-ca9.dtb
在 arch/arm/boot/dts/
tftp 目录中文件如下
回到u-boot-master 根目录 ,拷贝 文件 a9rootfs.ext3
到u-boot-master 根目录下,在其中执行命令
sudo qemu-system-arm -M vexpress-a9 -m 256 -kernel u-boot -nographic -net nic,macaddr=00:16:3e:00:00:01 -net tap -sd ./a9rootfs.ext3
会卡住提示
—[ end Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0) ]—
这需要 uboot指定nfs挂载根文件系统 见下
配置uboot指定nfs挂载根文件系统
在内核配置编译时需要Linux内核对nfs文件系统的支持
开启nfs服务(开发机)
sudo apt-get install nfs-kernel-server -y
配置好 /etc/exports
sudo gedit /etc/exports
添加
/nfsroot/rootfs *(rw,async,no_root_squash,no_subtree_check)
创建目录
sudo mkdir -p /nfsroot/rootfs
重启nfs-kernel-server或者重启机器
sudo service nfs-kernel-server restart
uboot修改bootargs
回到u-boot-master 根目录 在include/configs/vexpress_common.h
中修改
备份好bootargs
原
#define CONFIG_BOOTCOMMAND "tftp 0x60003000 uImage;tftp 0x60500000 vexpress-v2p-ca9.dtb; setenv bootargs'root=/dev/mmcblk0 console=ttyAMA0'; bootm 0x60003000 - 0x60500000"
修改为
#define CONFIG_BOOTCOMMAND "tftp 0x60003000 uImage;tftp 0x60500000 vexpress-v2p-ca9.dtb;setenv bootargs 'root=/dev/nfs nfsroot=${serverip}:/nfsroot/rootfs,tcp rw ip=${ipaddr}:${serverip}:${gatewayip}:${netmask} ::eth0:on init=/linuxrc console=ttyAMA0,115200';bootm 0x60003000 - 0x60500000"
需要替换具体值
#define CONFIG_BOOTCOMMAND "tftp 0x60003000 uImage;tftp 0x60500000 vexpress-v2p-ca9.dtb;setenv bootargs 'root=/dev/nfs nfsroot=192.168.100.101:/nfsroot/rootfs,tcp rw ip=192.168.100.100:192.168.100.101:192.168.100.1:255.255.255.0::eth0:on init=/linuxrc console=ttyAMA0,115200';bootm 0x60003000 - 0x60500000"
注意 没有换行
注:
${ipaddr} 开发板本身的地址
${serverip} tftp及nfs目录所在系统的地址
${gatewayip} 网关
${netmask} 子网掩码
其中:
root=/dev/nfs
/dev/nfs并非真的设备,而是一个告诉内核要通过网络取得根文件系统。
nfsroot=<server-ip>:<root-dir>
参数nfsroot这个参数告诉内核以哪一台机器的哪个目录以及哪个网络文件系统选项作为根文件系统使用。
<server-ip> 指定网络文件系统服务端的IP地址。如果没有指定定,则使用nfsaddrs变量指定的值。
<root-dir> 服务端上要作为根文件系统要挂载的目录名称。
ip=<my-ip>:<serv-ip>:<gw-ip>:<netmask>:<name>:<dev>:<auto>
参数ip设定网络通讯所需的各种网络接口地址。
如果没有给定这个参数,则内核核会试着使用反向地址解析协议或是启动协议(BOOTP)以找出这些参数。
<ipaddr> 客户端的IP地址。
<serverip> 网络文件系统服务端的IP地址。
<gatewayip> 网关(gateway)的IP地址。
<netmask> 本地网络的网络掩码。如果为空白,则掩码由客户端的IP地址导出。
<name> 客户端的名称。如果空白,则使用客户端IP地址的ASCII标记值。
<dev> 要使用的网络设备名称。如果你只有一个设备,那么你可以不管它。一般指定为eth0。
<auto> 用以作为自动配置的方法。,可以是on可以是off
init=/linuxrc 指定初始化文件
console=ttySAC2,115200 控制台选择
然后 重新编译uboot
export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabihf-
# make clean && make vexpress_ca9x4_defconfig # 不需要改配置
make -j6
拷贝 busybox 制作rootfs 到 nfs挂载 的目录中,也就是下图中所有文件拷贝到 /nfsroot/rootfs
中
启动模拟器
回到u-boot-master 根目录 ,在其中执行命令
sudo qemu-system-arm -M vexpress-a9 -m 256 -kernel u-boot -nographic -net nic,macaddr=00:16:3e:00:00:01 -net tap
如果出现 下面报错
end Kernel panic - not syncing: Requested init /linuxrc failed (error -2).
原因1,可能是 基于 busybox 制作rootfs并仿真 是 未勾选 Settings-> [*] Build static binary (no shared libs) 重新 制作rootfs就行
原因2,busybox 制作rootfs 时拷贝库文件有缺失
系统成功启动,测试 nfs挂载根文件系统是否成功,在挂载目录中创建新文件(我在 /nfsroot/rootfs
创建名为 nft_mount_test.txt
的文件) 然后 在启动的系统中 查看
QEMU参数
参见: qemu参数大全
希望我的文章对于大家有帮助,由于个人能力的局限性,文中可能存在一些问题,欢迎指正、补充!