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 arm1176 | cpu型号 |
-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 |
默认下载(或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 制作内核镜像、文件系统启动 *** 作系统。
- 内核下载和编译
# 安装交叉编译链工具,有的话直接引入或忽略
# 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"
- 文件系统下载和制作
# 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
- 制作根文件系统镜像
# 有点不明白,感觉直接把文件当成一个磁盘来用了,待研究
# 新建一个文件夹进行 *** 作
# 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
- 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,为什么是这个不清楚。
- windows 10 下使用虚拟机Linux ubuntu 5.11.0-27-generic进行测试。
- QEMU仿真树莓派1和3B-保姆级教程
- QEMU 3.1.0安装手记
- 龙芯杯无开发板如何开发和调试linux
- qemu模拟arm嵌入式环境
- Ubuntu通过apt-get安装指定版本和查询指定软件有多少个版本
- 搭建基于qemu的仿真环境与应用
- Kernel panic - not syncing: Requested init /linuxrc failed (error -13)
- mount -o loop 解释
- linux创建回环设备的方法
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)