Qemu 学习笔记
Qemu
开门见山,Qemu可以看成一款虚拟机,他可以模拟很多CPU架构。比如Alpha, ARM, Cris, i386, M68K, PPC, Sparc, Mips等;以及大部分的硬件设备,也就可以模拟出不同的目标系统。
Qemu的主要原理与机制
Qemu可以实现目标平台的仿真,但是arm平台的程序怎么能在我们电脑上运行呢?这是Qemu主要要做的事情,翻译,那如何进行翻译呢。大致上就是下面这样:
客户代码 ——>中间代码 ——> 主机代码
那就会有人问了为什么要转换成中间代码,直接转换成主机代码不香吗?问得好。
在Qemu中执行翻译这部分流程的是TCG模块,因为Qemu是支持跨平台的,他不仅可以在linux下执行arm的程序还可以在ppc下等等不同的平台下执行,这里为了通用性方面的考虑,先转换成中间代码,在将中间代码转换成主机代码。
Qemu的两种运行模式
Qemu 有两种运行模式,一种是全系统模拟(system mode),一种是用户态模拟(user mode)。
从名字就可以看出来system mode肯定是模拟全了,可以直接跑操作系统之类的。user mode肯定就弱一点,跑个进程之类的。
放个图吧,两种用户态模式:
Qemu的主要执行流程
我的Qemu版本是2.7.0,这里的执行流程是user mode
1.入口函数在vl.c
main()函数,这是qemu的入口,包含了虚拟机的初始化过程
2.在main()函数中有一个main_loop()的函数,这就是我们的主进程
qemu里面每模拟一个架构就会生成一个线程,由main_loop函数进行监视
3.接下来就是我们如何生成这个线程,qemu会自动根据运行程序的架构来判断进行CPU的初始化,这块有兴趣可以了解一下binfmt_misc,这块我以arm为例
3.1 进入cpu_arm_int()这里就是进行CPU的初始化
3.2这里不涉及到kvm,具体想了解什么是kvm的可以自行百度
3.3 创建一个cpu线程,且在线程中循环执行tcg_exec_all(),这里就正式步入翻译流程
4.进入tcg_cpu_exec(),这几步都是设置cpu的状态所以就跳过了,
tcg_cpu_exec() ——>cpu_exec().
5.进入正题cpu_exec(),这里主要是处理中断异常, 找到代码翻译块。tcg每次的翻译都是以TB为单位进行,也就是说如果一个TB中有跳转的话,也是最后一条指令。TCG会将翻译好的块存起来放到cache中,在需要的时候先从cache中找,如果找不到的话在执行翻译过程。
处理这一步的函数是tb_find_fast()
tb_find_slow属于没有在cache中找到对应的TB,所以执行翻译的程序,当cache满掉后会清空整个cache重新生成。在tb_find_slow()中有一个tb_gen_code() 这个函数执行翻译过程,先设置tb得上下文,主要得翻译函数为gen_intermediate_code();
调用该函数将客户代码转换为TCG操作码
接下来是tcg_gen_code()太长了,我就截个名吧,就在gen_intermediate_code()后顺序执行就可以找到。
这个函数就是个因果函数我把客户代码转换成中间代码了,接下来就需要将中间代码转化为主机代码 tcg_gen_code就是实现了这个作用。
6.在执行完tb_find_slow()之后会继续执行tb_find_fast()进行查找然后就是执行部分了
调用了cpu_loop_exec_tb()这部分开始就是执行了
之后我们下次在分析,休息休息。