Qemu使用及常见开发板的模拟

Qemu使用及常见开发板的模拟,第1张

Qemu的使用及一些开发板的模拟 介绍

Qemu可以对许多架构的CPU或开发板进行模拟。在我们没有开发板的时候,可以通过其进行一些开发板的模拟,便于学习。

安装
sudo apt-get install qemu
sudo apt install qemu-utils
# 使用不同架构的CPU,这个安装方式要再次安装相应命令
sudo apt install qemu-system-x86
sudo apt install qemu-system-arm
sudo apt install qemu-system-mips

如果需要源码(源码好像可以安装全部指令):

git clone git://git.qemu-project.org/qemu.git
或者
wget http://wiki.qemu-project.org/download/qemu-2.0.0.tar.bz2
使用

创建镜像文件

qemu-img create -f qcow2 test-vm-1.qcow2 10G

-f : 选项用于指定镜像的格式
qcow2 : 格式是 Qemu 最常用的镜像格式,采用来写时复制技术来优化性能
test-vm-1.qcow2 : 是镜像文件的名字
10G:镜像文件大小

镜像文件创建完成后,可使用 qemu-system-x86 来启动x86 架构的虚拟机(当然,其他架构也有相应的命令):

qemu-system-x86_64 test-vm-1.qcow2

因为没有安装 *** 作系统,会出现下面的界面:

安装镜像命令:

qemu-system-x86_64 \
	-boot d \
	-cdrom ubuntu-16.04.7-desktop-amd64.iso \
	-hda test-vm-1.qcow2 \
	-m 2048

当然也可以把hda选项去掉仅仅做测试。

测试

其实不仅仅是x86-x64的架构的镜像,像arm等体系架构都可以使用qemu来模拟,不过命令不相同。

树莓派1代

树莓派CPU是arm架构的,所以下面使用arm相关的启动指令。
下载地址:
https://github.com/dhruvvyas90/qemu-rpi-kernel
实际使用两个文件:kernel-qemu-4.19.50-buster 、 versatile-pb-buster.dtb。前者是1代内核镜像,后者是versatile开发板类型的设备树(没有树莓派1代的开发版版本,这里用来替代,设备树描述的就是开发板的硬件信息)。
img镜像下载地址:
http://downloads.raspberrypi.org/raspbian_lite/images/
这里选择在2019-09-30目录下面的镜像,下载压缩包解压后得到2019-09-26-raspbian-buster-lite.img。
启动命令:

qemu-system-arm  \
    -M versatilepb \
    -cpu arm1176 \
    -drive format=raw,file=./pi/2019-09-26-raspbian-buster-lite.img \
    -net nic  \
    -net user,hostfwd=tcp::5022-:22 \
    -dtb ./pi/versatile-pb-buster.dtb \
    -kernel ./pi/kernel-qemu-4.19.50-buster \
    -append  "root=/dev/sda2 panic=1 rootfstype=ext4 rw" \
    -serial stdio \
    -usb 
qemu-system-arm \
  -M versatilepb \
  -cpu arm1176 \
  -m 256 \
  -hda ./pi/2019-09-26-raspbian-buster-lite.img \
  -net user,hostfwd=tcp::5022-:22 \
  -dtb ./pi/versatile-pb-buster.dtb \
  -kernel ./pi/kernel-qemu-4.19.50-buster \
  -append 'root=/dev/sda2 panic=1' \
  -no-reboot

上面两条指令都可以正常启动系统,但是使用时会有些区别,感兴趣的可以自己测试一下。
下面以第一条指令的参数进行解释:

参数说明
-M versatilepb模拟的电路板,versatilepb
-cpu arm1176cpu型号
-m 256内存256M
-drive format=raw,file=加载的镜像格式和位置
-net user,hostfwd=tcp::5022-:22网卡使用NAT模式,将主机的5022映射到虚拟机22口便于SSH
-dtb 设备树文件
-kernel
-append附加命令,内核命令行
-serial stdio将CMD命令行用作标准输入输出,可以通过CMD命令行对虚拟机发送命令,而不必使用虚拟机的显示和输入
-usb支持usb

龙芯2K1000

默认下载(或qemu官方)的qemu内置支持的开发板没有龙芯的,需要使用龙芯提供的。
龙芯开放的Qemu源代码 : https://gitee.com/loongsonlab/qemu
安装:

cd <qemu-source-path>/
mkdir ./build
cd ./build
../configure --target-list=mipsel-softmmu,mips64el-softmmu --disable-werror
make

编译依赖库:

Python
libpixman-1-dev

编译时链接报了stime未定义的错误,解决办法:

/* qemu-version/linux-user/syscall.c中 */return get_errno(stime(&host_time));
修改为:
return get_errno(clock_settime(CLOCK_REALTIME, &host_time));

运行pmon,注意下面的pmon镜像是最终的(这里包含设备树,否则无法正常启动):

./mips64el-softmmu/qemu-system-mips64el    \
    -M ls2k \
    -m 256  \
    -smp 1  \
    -serial stdio   \
    -bios ../../../ls2k/gzrom-dtb.bin \
    -net nic \
	-nic user,net=192.168.1.55/24,host=192.168.1.5,tftp=/srv/tftp

运行结果:

简单的测试指令:

@todo 制作内核镜像、文件系统启动 *** 作系统。

vexpress-a9
  1. 内核下载和编译
# 安装交叉编译链工具,有的话直接引入或忽略
# 32位
sudo apt install gcc-arm-linux-gnueabi
# 64位
sudo apt-get install gcc-aarch64-linux-gnu

# 获取内核镜像,其它版本也可以,一般都有vexpress的默认配置,速度慢的话可以windows下直接访问网站下载
wget https://mirror.bjtu.edu.cn/kernel/linux/kernel/v5.x/linux-5.10.tar.xz
# 解压
tar xf linux-5.10.tar.xz
cd  linux-5.10
# 配置,要指定ARCH=arm(也可以设置环境变量),才会从arm架构中找配置文件
make ARCH=arm  vexpress_defconfig
# 编译,可以使用参数zImage,modules,dtbs编译指定的部分,默认全部编译
make CROSS_COMPILE=arm-linux-gnueabi- ARCH=arm -j8
# 生成的文件位于arch/arm/boot下
# qemu单独启动kernel
# 因为没有文件系统会报错
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"
  1. 文件系统下载和制作
# busybox下载
wget https://busybox.net/downloads/busybox-1.32.0.tar.bz2
# 解压
tar jxf busybox-1.32.0.tar.bz2 
cd busybox-1.32.0
# 使用默认配置
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- defconfig
# 编译
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- -j4
# 安装,默认安装当前的__install文件夹下
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- install
# 至此文件系统的编译已完成,剩下的任务是设置文件系统的内容
# 建立文件夹存放 *** 作系统,然后拷贝需要的文件到里面
mkdir rootfs
cp -ra _install/* rootfs/
# (里面的 *.a 其实可以删掉,只用 .so)
mkdir -p rootfs/lib
cp -ra /usr/arm-linux-gnueabi/lib/* rootfs/lib/ 
cd rootfs
# 全是空文件夹
mkdir dev proc sys tmp root var mnt
# 制作设备节点,一些设备的节点号是固定的,参看 ubuntu 主机中的
cd 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
  1. 制作根文件系统镜像
# 有点不明白,感觉直接把文件当成一个磁盘来用了,待研究
# 新建一个文件夹进行 *** 作
# 64M空间,空间不够也可以把它改大点
dd if=/dev/zero of=a9rootfs.ext3 bs=1M count=64
mkfs.ext3 a9rootfs.ext3
sudo mount -t ext3 a9rootfs.ext3 /mnt -o loop
sudo cp -ra ../busybox-1.32.0/rootfs/* /mnt
sudo chown -R root.root /mnt/*
sudo umount /mnt
qemu-system-arm \
	-M vexpress-a9 \
 	-m 512M \
	-kernel ./arch/arm/boot/zImage \
	-dtb  ./arch/arm/boot/dts/vexpress-v2p-ca9.dtb \
    -nographic \
    -append "init=/linuxrc root=/dev/mmcblk0 rw console=ttyAMA0" \
    -sd ../rootfs/a9rootfs.ext3
# 报错:end Kernel panic - not syncing: Requested init /linuxrc failed (error -8)
# 查看错误码-8,为执行文件格式错误,文件系统bin下程序在x64虚拟机上也可以运行,原因是编译时未指定交叉编译链
# 激动!!!重新编译后,可以正常启动,进到终端
# 文件系统还可以再优化
# 图形界面启动
qemu-system-arm \
	-M vexpress-a9 \
 	-m 512M \
	-kernel ./arch/arm/boot/zImage \
	-dtb  ./arch/arm/boot/dts/vexpress-v2p-ca9.dtb \
    -append "init=/linuxrc root=/dev/mmcblk0 rw console=tty0" \
    -sd ../rootfs/a9rootfs.ext3

  1. u-boot编译
wget https://ftp.denx.de/pub/u-boot/u-boot-2022.04.tar.bz2
tar xjf u-boot-2022.04.tar.bz2
cd u-boot-2022.04
make ARCH=arm vexpress_ca9x4_defconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- all
# 报错:fatal error: openssl/evp.h: No such file or directory
# 安装下面的库
sudo apt-get install libssl-dev
# 生成的u-boot为可执行文件,u-boot.bin为二进制文件
# 单独启动u-boot
qemu-system-arm \
	-M vexpress-a9 \
	-m 512M \
	-kernel ./u-boot \
	-nographic
# 制作多分区的SD卡(文件模拟的)
# 这里要使用uImage进行启动,所以内核要重新编译一下
# uImage也可以用mkimage工具生成,下面的命令其实也是用mkimage工具
# uImage是u-boot的专用的启动镜像,可以由不同格式的u-boot镜像通过工具生成,只是加了一个文件头便于启动
sudo apt install u-boot-tools
make CROSS_COMPILE=arm-linux-gnueabi- ARCH=arm  LOADADDR=0x60003000 uImage -j8
# 一个分区存放kernel,一个分区存放镜像
# 前面分区放置文件系统镜像的时候其实是创建回环设备,用文件模拟块设备
# 使用losetup可以查看所有的回环设备,我们把它直接当成SD卡就行
# 这里只是把文件名字叫做SD,可以用任何名字
# dd if=/dev/zero of=SD  bs=1M count=64
# 回环设备名字不能重复,使用未使用的名字
# sudo losetup /dev/loop15 SD
dd if=/dev/zero of=SD  bs=1M count=64
sudo parted SD --script -- mklabel msdos  
# 这里和2048对齐一下,减少一个警告 
sudo parted SD --script -- mkpart primary fat32 2048s 40956s
sudo parted SD --script -- mkpart primary ext4 40960s -1

# 建立映射,然后格式化两个分区
sudo losetup --show /dev/loop15 SD
# sudo apt install kpartx
sudo kpartx -va /dev/loop15
sudo mkfs.vfat /dev/mapper/loop15p1
sudo mkfs.ext4 /dev/mapper/loop15p2
 ​
# 拷贝内核zImage、vexpress-v2p-ca9.dtb到第一个分区
sudo mount /dev/mapper/loop15p1 /mnt
sudo cp ../linux-5.10/arch/arm/boot/uImage  /mnt
sudo cp ../linux-5.10/arch/arm/boot/dts/vexpress-v2p-ca9.dtb /mnt
# 拷贝文件系统内的所有文件到第二个分区
sudo mount /dev/mapper/loop15p2 /media
sudo cp -r ../busybox-1.32.0/rootfs/* /media
sudo chown -R root.root /media/*
# 卸载
sudo umount /mnt
sudo umount /media​
# u-boot启动SD卡中的kernel和文件系统
qemu-system-arm \
	-M vexpress-a9 \
	-m 512M \
	-kernel ./u-boot-2022.04/u-boot \
	-nographic \
	-append "root=/dev/mmcblk0 console=ttyAMA0" \
	-sd ./rootfs/SD

# 启动
fatls mmc 0:1
fatload mmc 0:1 60003000 uImage
fatload mmc 0:1 60500000 vexpress-v2p-ca9.dtb
setenv bootargs 'init=/linuxrc root=/dev/mmcblk0p2 rw rootwait earlyprintk console=ttyAMA0'
bootm 60003000 - 60500000

# tips
这里对文件系统的修改会保存

# u-boot tftp网络启动内核
qemu-system-arm \
	-M vexpress-a9 \
	-m 512M \
	-kernel ./u-boot-2022.04/u-boot \
	-nographic \
	-append "root=/dev/mmcblk0 console=ttyAMA0" \
	-sd ./rootfs/SD \
	-net nic \
	-nic user,net=192.168.1.55/24,host=192.168.1.5,tftp=/srv/tftp

# 启动
# 测试网络
setenv ipaddr 192.168.1.56
ping 192.168.1.5
# tftpboot 加载镜像
setenv serverip 192.168.1.5
tftpboot 60003000 uImage
tftpboot 60500000 vexpress-v2p-ca9.dtb
setenv bootargs 'init=/linuxrc root=/dev/mmcblk0p2 rw rootwait earlyprintk console=ttyAMA0'
bootm 60003000 - 60500000

# 其它
内核下使用ifconfig时提示缺少文件,创建即可(可以使用touch命令),然后直接设置eth0网卡的ip,就应该和主机之间就可以进行网络通信了。

说明:无论是从SD卡启动,还是网络启动,过程都是一样的,都是将内核镜像加载到内存,然后启动(其它启动方式大同小异),区别在于下载内核镜像的位置。这里文件系统在bootargs里面指定,位于SD卡中,也可以使用网络挂载文件系统。

错误记录

1.fatal error: linux/compiler-gcc9.h: No such file or directory
原因:gcc版本和内核版本不匹配
解决办法:
更换内核版本
2. multiple (or no) load addresses: This is incompatible with uImages
解决办法:
指定LOADADDR参数
3. “mkimage” command not found
安装u-boot-tools
4. 卡在Start Kernel …
修改生成uImage时的LOADADDR地址为0x60003000,为什么是这个不清楚。

测试环境
  1. windows 10 下使用虚拟机Linux ubuntu 5.11.0-27-generic进行测试。
参考文章:
  1. QEMU仿真树莓派1和3B-保姆级教程
  2. QEMU 3.1.0安装手记
  3. 龙芯杯无开发板如何开发和调试linux
  4. qemu模拟arm嵌入式环境
  5. Ubuntu通过apt-get安装指定版本和查询指定软件有多少个版本
  6. 搭建基于qemu的仿真环境与应用
  7. Kernel panic - not syncing: Requested init /linuxrc failed (error -13)
  8. mount -o loop 解释
  9. linux创建回环设备的方法

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/790117.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-05
下一篇 2022-05-05

发表评论

登录后才能评论

评论列表(0条)

保存