qemu 编译配置错误及解决方法
QEMU和VMware很像,是一款非常好用的仿真软件,可以仿真一台主机,在上面安装Ubuntu,还可以仿真一块ARM开发板,在上面移植u-boot+Linux嵌入式Linux开发环境。5年前发布的视频教程《使用QEMU搭建U-boot+Linux+NFS嵌入式开发环境》,帮助学员在自己的Ubuntu上搭建一个虚拟开发板,用来学习嵌入式、U-boot和内核驱动。几年下来,大量的学员在搭建过程中会遇到各种各样的问题,作者在答疑过程中,也会把一些常见的错误和解决方法汇总如下,以供后来的学习者参考。
01 qemu源码编译报错原因及解决方法
qemu是一款复杂的系统软件,模拟的是底层的指令和硬件,所以和编译器、操作系统、库的关联很大,依赖性也很大。qemu的维护者在发布新的qemu源码版本时,如果使用的Ubuntu为原生环境,那么在这个Ubuntu版本下可能没问题,如果换作Ubuntu另一个版本,可能就存在库的版本问题,需要库版本升级或者降级,比较麻烦。作者在编译qemu源码的时候,曾尝试不同版本,有些版本会编译阶段出错,比如缺少库,库的版本太低,太高等等;有的可以正常编译,但是在运行阶段出错,最终也就不了了之。
所以,如果你在源码编译安装qemu时,选择版本很重要,如果你的Ubuntu环境是Ubuntu-16.04,建议选择qemu-2.7,如果你是购买《Linux三剑客》的学员,对Linux玩得还不是很溜,按照视频中的版本编译和安装,一般问题都不大,遇到问题可以在答疑群里反馈。建议不要尝试其他版本,遇到各种未知的问题,其他人也没遇到过,可能到时候就帮不了你了(qemu源码很少有人能源码级debug)。所以,最好的方法是,先按照视频教程中的版本走一遍,搭建成功后,熟悉整个流程和套路后,自己有兴趣,再去尝试其他版本。
在编译过程中,如果缺少一些图形库啥的,按照提示安装就可以了。比如:在使用make menuconfig命令配置内核编译选项时,遇到以下错误:
scripts/kconfig/lxdialog/dialog.h:38:20: fatal error:curses.h: no such file or directory
出现这种错的原因是,在使用make menuconfig命令,通过菜单配置Linux内核编译选项时,这个命令依赖图形库:libncurses
在shell环境下安装即可:
# apt-get install libncurses5-dev
02 U-boot使用TFTP命令下载镜像到开发板失败
当在u-boot使用TFTP工具下载uImage镜像到开发板失败时,可能的原因:
1)开发板和虚拟机之间的网络没有通,这一步要看qemu-ifup脚本的IP配置是否正确,然后在开发板端的U-boot命令行交互环境下ping主机,看能否ping通,ping不通的话,使用ifconfig命令,检查桥接网口br0是否设置好
2)网络ping通的话,还不能下载,要看Ubuntu主机的TFTP服务有没有开起来,如果已经关掉的话,要重启这个服务
3)u-boot中配置的ipaddr、serverIP、bootcmd、bootargs是否设置正确,使用# printenv ipaddr 查看.uboot中压根没有ipaddr这个变量 print ipaddr直接说not defined,需要在U-boot源码中定义整个宏,具体可参考视频教程。或者直接在U-boot的命令行环境下设置:setenv ipaddr “xxx.xxx.xxx.xxx”,其他的变量同样可以这样定义。
4)以上无误,还是不能TFTP下载,要看主机的tftpboot目录的权限是否有问题,要设置为普通用户也能访问读写
03 若加载成功,但是无法启动,显示CRC校验错误
Verifying Checksum ... Bad Data CRC
ERROR: can't get kernel image!
有可能是uImage的体积太大,导致加载到内存0x60500000地址处中的vexpress-v2p-ca9.dtb文件,有可能已经覆盖掉了uImage
所以,遇到这种情况,可以修改bootargs试试,将设备树文件加载地址稍后一些(0x60800000),不要覆盖掉uImage的地址空间:
tftp 0x60003000 uImage;tftp 0x60800000 vexpress-v2p-ca9.dtb; setenv bootargs 'root=/dev/nfs rw nfsroot=192.168.33.145:/home/nfs,proto=tcp,nfsvers=4,nolock init=/linuxrc ip=192.168.33.144 console=ttyAMA0';bootm 0x60003000 - 0x60800000;
04 启动后一直卡在 Start kernel …
在qemu实验中,通过u-boot引导Linux内核镜像,已经可以通过TFTP将uImage和dtb文件加载到内存,在启动Linux内核时一直卡在这里:Starting kernel…
原因分析:
实验到了这一步,说明qemu已经安装成功,网络配置已经成功,Linux内核启动卡在这里,常见的有2种原因:
1)bootargs参数设置得不对,导致启动不成功
重新检查bootargs设置是否正确,qemu使用串口作为控制台的话,console要设置为ttyAMA0, 选择重新编译U-boot,记得要把生成的U-boot镜像拷贝到/home/tftpboot目录下
2)console控制台设置得可能不成功,导致在串口打印不出来启动信息
05 挂载NFS根文件系统失败
如果内核可以支持启动,也可以看到启动打印信息,但是在挂载NFS根文件系统时出错,常见的错误信息如下:
random: nonblocking pool is initialized
VFS: Unable to mount root fs via NFS, trying floppy.
VFS: Cannot open root device "nfs" 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?)
b300 32768 mmcblk0 driver: mmcblk
Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(2,0)
CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.4.0+ #2
Hardware name: ARM-Versatile Express
[<80016388>] (unwind_backtrace) from [<80012e60>] (show_stack+0x10/0x14)
[<80012e60>] (show_stack) from [<802451f0>] (dump_stack+0x78/0x88)
[<802451f0>] (dump_stack) from [<800a6698>] (panic+0x9c/0x1f8)
[<800a6698>] (panic) from [<806242d4>] (mount_block_root+0x1c8/0x268)
[<806242d4>] (mount_block_root) from [<80624498>] (mount_root+0x124/0x12c)
[<80624498>] (mount_root) from [<806245f0>] (prepare_namespace+0x150/0x198)
[<806245f0>] (prepare_namespace) from [<80623edc>] (kernel_init_freeable+0x250/0x260)
[<80623edc>] (kernel_init_freeable) from [<8049f410>] (kernel_init+0x8/0xe8)
[<8049f410>] (kernel_init) from [<8000f478>] (ret_from_fork+0x14/0x3c)
---[ end Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(2,0)
1)检查u-boot源码:include/configs/vexpress_common.h,看booargs命令设置是否正确,重新编译u-boot的镜像,要跟uImage拷贝到tftpboot目录下面。
#defineCONFIG_BOOTCOMMAND \
"tftp0x60003000 uImage;tftp 0x60500000 vexpress-v2p-ca9.dtb; \
setenvbootargs 'root=/dev/mmcblk0 console=tty0'; \
bootm 0x60003000 - 0x60500000; "
上面的bootargs是用来挂载SD卡作为根文件系统的,如果想要挂载NFS文件系统,可以使用下面的配置,修改U-boot源码:include/configs/vexpress_common.h,设置ipaddr、serverip、bootargs等参数为以下值:
#define CONFIG_BOOTCOMMAND \
"tftp 0x60003000 uImage;tftp 0x60500000 vexpress-v2p-ca9.dtb;
setenv bootargs 'root=/dev/nfs rw nfsroot=192.168.33.145:/home/nfs
init=/linuxrc console=ttyAMA0 ip=192.168.33.144';
bootm 0x60003000 - 0x60500000; "
#define CONFIG_IPADDR 192.168.33.144
#define CONFIG_NETMASK 255.255.255.0
#define CONFIG_SERVERIP 192.168.33.145
具体可以参考上篇文章:Ubuntu-16.04使用手册
2)确保文件系统镜像测试没有问题,可以使用群共享里的uImage和a9rootfs.ext3镜像,排查是不是内核和文件系统镜像的问题。有不少学员使用自己编译busybox制作的文件系统,挂载失败。使用群共享里的测试文件系统挂载成功。
3)NFS文件系统的版本问题
如果你的Ubuntu版本是Ubuntu-20.04,Ubuntu-20.04默认使用NFSv3 或者v4版本的NFS文件系统,所以在编译uImage时,要记得将内核源码的这个选项配置选上,具体可以参考上篇文章:Ubuntu-20.04使用手册:三、编译Linux内核。
也有一些学员在bootargs中在修改BOOTCOMMAND时,改nfsroot=192.168.244.129:/home/rootfs,v3 也就是在后面加一个v3,也可以正常挂载。
06 Ubuntu-20.04 qemu网络配置
qemu和Ubuntu建立桥接br0,Ubuntu-16.04修改/etc/interfaces文件就可以了,具体可参考视频教程:Linux三剑客
Ubuntu-20.04不再使用这个文件,而是使用/etc/netplan/01-network-manager-all.yaml
# Let NetworkManager manage all devices on this system
network:
version: 2
renderer: networkd
ethernets:
ens33:
dhcp4: no
bridges:
br0:
dhcp4: yes
interfaces:
- ens33
修改好上面的文件后,还要运行netplan命令,让配置文件生效:
# netplan apply
# ifconfig
ntu:/home/zhaixue/Desktop# ifconfig
br0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.230.149 netmask 255.255.255.0 broadcast 192.168.230.255
inet6 fe80::20c:29ff:fed0:7b22 prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:d0:7b:22 txqueuelen 1000 (Ethernet)
RX packets 1352 bytes 99827 (99.8 KB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 244 bytes 24557 (24.5 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
ether 00:0c:29:d0:7b:22 txqueuelen 1000 (Ethernet)
RX packets 2562 bytes 1079828 (1.0 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 244 bytes 24929 (24.9 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
Ubuntu虚拟机的网卡和开发板相连后就无法上网了,如果还想继续上网,需要给你的Ubuntu主机再添加一块网卡,具体配置可参考上一篇文章:Ubuntu-20.04双网卡上网配置