栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

qemu 启动ARM虚拟机的几点释惑

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

qemu 启动ARM虚拟机的几点释惑

参考博客

linux4.15 arm qemu @ubuntu18.04环境搭建_papaofdoudou的博客-CSDN博客

问题1:针对启动命令
qemu-system-arm -M vexpress-a9 -m 1024M -kernel arch/arm/boot/zImage -append "rdinit=/linuxrc console=ttyAMA0 loglevel=8" -dtb arch/arm/boot/dts/vexpress-v2p-ca9.dtb -nographic

的启动流程是怎样的?

回答:命令行启动的是zImage,而zImage的来源是zImage,而zImage包含压缩的内和和解压程序

通过makefile可以知道zImage的来源是vmlinux经过objcopy得到:

要注意这个vmlinux并非是顶层目录那个内和ELF文件的vmlinux,两个名字文件相同,但是差别巨大,简单来说,内通过编译zImage产生了两个vmlinux,这里的vmlinux包含了内和顶层的vmliunx压缩文件和解压程序,虽然它们都是ELF格式,但是前者相当于一级火箭,首先点火,解压内部的vmlinux后,后者作为二级火箭完成内核启动。

关于linux vmlinux,zImage vmlinux, Image以及zImage的关系,可以表示如下:

至此,可执行程序的结构解释的通了。

qemu启动流程,有没有灌入bootrom?

答案是肯定的,我们通过如下命令启动调试的时候:

qemu-system-arm -M vexpress-a9 -m 1024M -kernel arch/arm/boot/zImage -append "rdinit=/linuxrc earlyprintk console=ttyAMA0" -dtb arch/arm/boot/dts/vexpress-v2p-ca9.dtb -nographic -s -S

发现执行的第一条指令,虽然是vexpress-a9板子的物理内存初始地址,但是这个运行地址却并不在任何一个vmlinux中。

这就说明,这里执行的指令是qemu准备的,我们试着单步执行一下:

可以看到,开始0x60000000执行的四条指令,其中最重要的是0x6000000c处的指令,就是他将PC指针引导向一个新的位置0x60010000,这个位置还会使QEMU安插的指令吗?经过对比,我们得出结论,它不属于QEMU安插的启动指令,而是属于一级火箭助推器压缩的vmlinux,证据是可以通过反编译vmlinux看出来,指令码完全一样: 

所以,真正QEMU安插的指令只有0x60000000到0x6000000C安插的几条,后面就开始执行Linux环境生成的代码了。

一个问题解决了,但是又由上面的问题因出来一个新的疑问,我们看到所谓的的一级火箭助推器的第一条指令是从0x60010000开始的。

 但是,上上图中展示的同样的指令确是从0地址开始的,这种运行地址和加载地址不一致的现象不是不可能,只是需要编译的时候做一个特殊处理,就是将代码编译为地址无关指令,GCC中就需要在编译的是时候加入-fpic选项才行,打开一级火箭助推器vmlinux的构建,我们看一下是这样吗?

我们的猜测是对的,确实如此:

QEMU是在那里灌入BOOTROM启动指令的?

这就要从QEMU中查找原因了,下载一份QEMU代码,我们在qemu-7.0.0/hw/arm/boot.c中找到了线索:

可能是QEMU版本的原因,我们先忽略前面两行指令,后面的指令不恰好就是0x60000000开始的指令么?

FIXUP_BOARDID,FIXUP_ARGPTR_LO,FIXUP_ENTRYPOINT_LO,FIXUP_TERMINATOR分别表示如下:

BOARDID是0x000008e0,跳转地址是0x60010000,还有一个比较重要的是,devicetree blob文件,是0x68000000,也即是说,启动命令中的DTB文件将会被加载到物理地址的0x68000000。

 这一点,可以在内核调试中得到印证,传入内核的DTB,物理地址是0x68000000,虚拟地址是0xC8000000

关于BROM后的启动入口为什么是0x60010000,可以从下面代码得到解释,KERNEL_LOAD_ADDR为0x10000.

所以启动指令这块也得到了圆满解释。

对比RT-THREAD的 QEMU启动命令,为何RTT可以启动 ELF格式的RTT固件,而当我将启动命令该为
qemu-system-arm -M vexpress-a9 -m 1024M -kernel vmlinux -append "rdinit=/linuxrc earlyprintk console=ttyAMA0" -dtb arch/arm/boot/dts/vexpress-v2p-ca9.dtb -nographic
时,启动却失败?
qemu-system-arm -M vexpress-a9 -m 1024M -kernel vmlinux -append "rdinit=/linuxrc earlyprintk console=ttyAMA0" -dtb arch/arm/boot/dts/vexpress-v2p-ca9.dtb -nographic

回答:RTT的启动命令为:

qemu-system-arm -M vexpress-a9 -kernel rtthread.elf -serial vc -serial vc -sd sd.bin -S -s

 对比可以看到,和我们调试LINUX的启动命令非常相似,唯一的区别是-kernel选项,在RTT情况下直接指定了RTT可启动固件。

为何Linux做不到呢?线索来自于对Linux的调试,调试如下命令发现,第一条指令执行的地址是0xc0008000,他是VMLINUX的entry地址,而不再是正常情况下的0x60000000。而0xc0008000这个时候还没有映射呢!

qemu-system-arm -M vexpress-a9 -m 1024M -kernel vmlinux -append "rdinit=/linuxrc earlyprintk console=ttyAMA0" -dtb arch/arm/boot/dts/vexpress-v2p-ca9.dtb -nographic -s -S

实际的映射在VMLINUX的启动程序中:

所以当然不能正常运行。

看RTT的表现,RTT的连接运行地址直接是物理地址,无需做这样的翻译:


总结

QEMU虚拟机本身对系统行为的模拟是完备的,不需要修改GUEST内核,所以基本上,QEMU启动命令的每个选项,背后都有文章,主要分成两个方面进行模拟,第一是对CPU的模拟,这是靠TCG翻译完成的,对于算力密集型程序,TCG会很忙很忙。第二个是对IO行为的模拟,而这个是依赖对各类IO支持完成的。


结束
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/849515.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号