关于Linux虚拟化技术KVM的科普 科普二(KVM虚拟机代码揭秘)
代码分析文章《KVM虚拟机代码揭秘——QEMU代码结构分析》、《KVM虚拟机代码揭秘——中断虚拟化》、《KVM虚拟机代码揭秘——设备IO虚拟化》、《KVM虚拟机代码揭秘——QEMU的PCI总线与设备(上)》、《KVM虚拟机代码揭秘——QEMU的PCI总线与设备(下)》。先从大的方面分析代码结构,然后分中断、IO、PCI总线与设备详细介绍。
KVM虚拟机代码揭秘——QEMU代码结构分析
关于TCG的解释:TCG(Tiny Code Generator),QEMU的官方解释在http://wiki.qemu-project.org/Documentation/TCG。
TCG的作用就是将Target的指令通过TCG前端转换成TCG ops,进而通过TCG后端转换成Host上运行的指令。
需要将QEMU移植到一个新CPU上运行,需要关注TCG后端。需要基于QEMU模拟一个新CPU,需要关注TCG前端。
qemu-img
在根目录生成,参照Makefile可知有如下文件组成:
|
qemu-img$(EXESUF): qemu-img.o $(block-obj-y) $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) $(COMMON_LDADDS) |
qemu-system-x86_64
由于target比较多,编译也费时。可以指定便以特定的target:
| ./configure --target-list=x86_64-softmmu |
qemu-system-x86_64的入口定义在vl.c的main中:
| main ->main_loop ->main_loop_wait ->os_host_main_loop_wait |
1.代码结构
QEMU的main函数定义在vl.c中,是执行程序的起点,主要功能是建立一个虚拟的硬件环境。
|
. |
2.TCG
QEMU是一个模拟器,它能够动态模拟特定架构CPU指令,QEMU模拟的架构叫目标架构;运行QEMU的系统架构叫主机架构。
QEMU中有一个模块叫微型代码生成器,将目标代码翻译成主机代码。

运行在虚拟CPU上的代码叫做客户机代码,QEMU主要功能就是不断提取客户机代码并且转化成主机代码。
整个翻译分成两部分:将目标代码(TB)转化成TCG中间代码,然后再将中间代码转化成主机代码。
当新的代码从TB(Translation Block)中生成以后,将会保存到一个cache中,因为很多相同的TB会被反复的进行操作,所以这样类似于内存的cache,能够提高使用效率。而cache的刷新使用LRU算法。

| tb_gen_code ->gen_intermediate_code ->tcg_gen_code |
由tb_gen_code调用,将客户机代码转换成主机代码。gen_intermediate_code之前是客户及代码,tcg_gen_code之后是主机代码,两者之间是TCG中间代码。



3.QEMU中的TCG代码分析
| x86_cpu_realizefn 架构相关初始化函数 ->qemu_init_vcpu ->qemu_tcg_init_vcpu ->qemu_tcg_cpu_thread_fn vcpu线程函数 ->tcg_cpu_exec ->cpu_exec 这个函数是主要的执行循环,这里第一次翻译TB,然后不停的执行异常处理。 ->tb_find 首先在Hash表中查找,如果找不到则调用tb_gen_code创建一个TB。 ->tb_gen_code 分配一个新的TB。 ->gen_intermediate_code ->tcg_gen_code 将TCG代码转换成主机代码。 ->cpu_loop_exec_tb ->cpu_tb_exec 执行TB主机代码 ->tcg_qemu_tb_exec |
KVM虚拟机代码揭秘——中断虚拟化
KVM中断虚拟化主要依赖于VT-x技术,VT-x主要提供了两种中断事件机制,分别是中断退出和中断注入。
中断退出:指虚拟机发生中断时,主动式的客户机发生VM-Exit,这样能够在主机中实现对客户机中断的注入。
中断注入:是指将中断写入VMCS对应的中断信息位,来实现中断的注入,当中断完成后通过读取中断的返回信息来分析中断是否正确。
中断注入的标志性函数kvm_set_irq,是中断注入的最开始。
第一个参数s,传递设置IRQ需要的vmfd句柄,以及IRQ的ioctl类型。
第二、三参数,是IRQ中断号,以及触发类型。
|
int kvm_set_irq(KVMState *s, int irq, int level) assert(kvm_async_interrupts_enabled()); event.level = level; return (s->irq_set_ioctl == KVM_IRQ_LINE) ? 1 : event.status; |
上面的ioctl对应内核中的kvm_vm_ioctl,内核首先case到KVM_IRQ_LINE。然后解析
|
static long kvm_vm_ioctl(struct file *filp, r = -EFAULT; r = kvm_vm_ioctl_irq_line(kvm, &irq_event, r = -EFAULT; r = 0; … |
KVM中断路由(何为?)
| kvm_arch_vm_ioctl ->KVM_CREATE_IRQCHIP(kvm_setup_default_irq_routing) ->kvm_set_irq_routing ->setup_routing_entry ->kvm_set_routing_entry ->KVM_IRQCHIP_PIC_MASTER(kvm_set_pic_irq) ->KVM_IRQCHIP_PIC_SLAVE(kvm_set_pic_irq) ->KVM_IRQCHIP_IOAPIC(kvm_set_ioapic_irq) ->KVM_IRQ_ROUTING_MSI(kvm_set_msi) ->KVM_IRQ_ROUTING_HV_SINT(kvm_hv_set_sint) |
从上可以看出针对不同类型的ROUTING方式和IRQCHIP,跳转到对应的中断注入函数。IRQCHIP类型的中断路由有PIC和IOAPIC;还有MSI和SINT类型。
PIC全称 Programmable Interrupt Controller,通常是指Intel 8259A双片级联构成的最多支持15个interrupts的中断控制系统。
APIC全称Advanced Programmable Interrupt Controller,APIC是为了多核平台而设计的。它由两个部分组成IOAPIC和LAPIC,其中IOAPIC通常位于南桥中用于处理桥上的设备所产生的各种中断,LAPIC则是每个CPU都会有一个。IOAPIC通过APICBUS(现在都是通过FSB/QPI)将中断信息分 派给每颗CPU的LAPIC,CPU上的LAPIC能够智能的决定是否接受系统总线上传递过来的中断信息,而且它还可以处理Local端中断的 pending、nesting、masking,以及IOAPIC于Local CPU的交互处理。
设置好虚拟中断控制器之后,在KVM_RUN退出以后,就开始遍历虚拟中断控制器,如果发现中断,就将中断写入中断信息位.
| vcpu_run ->vcpu_enter_guest ->inject_pending_event |
inject_pending_event在进入Guest之前被调用。
KVM虚拟机代码揭秘——设备IO虚拟化
虚拟设备的IO地址注册
KVM虚拟机设备模拟实在QEMU中实现的,而KVM实现的实质上只是IO的拦截。真正的虚拟设备IO地址注册实在QEMU代码里面实现的。
QEMU中,初始化硬件设备的时候需要注册IO空间,有两种方法:
- PIO(Port IO) 端口IO
- MIO(Memory IO) 内存映射IO
PS:发觉这里面介绍的代码和最新的4.x已经很大差异,所以略过。
KVM虚拟机代码揭秘——QEMU的PCI总线与设备(上)
QEMU的PCI总线
QEMU在初始化硬件的时候,最开始的函数就是pc_init1。在这个函数里面会相继的初始化CPU、中断控制器、ISA总线,然后就要判断是否需要支持PCI。如果支持则调用i440fx_init初始化PCI总线。
|
static void pc_init1(MachineState *machine, |
i440fx_init函数主要参数就是之前初始化好的ISA总线以及中断控制器,返回值就是PCI总线,之后我们就可以将设备统统挂载在这个上面。
QEMU的PCI-PCI桥
在QEMU中,所有的设备包括总线,桥,一般设备都对应一个设备结构,通过register函数将所有的设备链接起来,就像Linux的模块一样,在QEMU启动的时候会初始化所有的QEMU设备,而对于PCI设备来说,QEMU在初始化以后还会进行一次RESET,将所有的PCI bar上的地址清空,然后进行统一分配。
QEMU(x86)里面的PCI的默认PCI设都是挂载主总线上的,貌似没有看到PCI-PCI桥,而桥的作用一般也就是连接两个总线,然后进行终端和IO的映射。
QEMU的PCI设备
一般的PCI设备其实和桥很像,甚至更简单,关键区分桥和一般设备的地方就是class属性和bar地址。
struct PCIDevice表示了PCI设备的信息。
pci_register_bat主要给bar分配IO地址。
|
void pci_register_bar(PCIDevice *pci_dev, int region_num, assert(region_num >= 0); r = &pci_dev->io_regions[region_num]; wmask = ~(size - 1); addr = pci_bar(pci_dev, region_num); if (!(r->type & PCI_BASE_ADDRESS_SPACE_IO) && |
KVM虚拟机代码揭秘——QEMU的PCI总线与设备(下)
代码对不上,略过。
关于Linux虚拟化技术KVM的科普 科普二(KVM虚拟机代码揭秘)的更多相关文章
- 关于Linux虚拟化技术KVM的科普
虚拟化技术应用越来越广泛,虚拟化技术需求越来越强劲.KVM.XEN.Docker等比较热门,尤其是KVM技术越来越受欢迎. 基于此背景,了解一下KVM+QEMU就有点必要了. 从网上收集了一些资料进行 ...
- 关于Linux虚拟化技术KVM的科普 科普一(先用起来!)
是骡子是马是拉出来溜溜,通过<KVM虚拟化技术之使用Qemu-kvm创建和管理虚拟机>跑一遍,就会对KVM.QEMU-KVM有个大概的认识了. qemu-kvm已经不单独存在,qemu加上 ...
- Linux虚拟化技术KVM、QEMU与libvirt的关系(转)
说明:个人理解,KVM是内核虚拟化技术,而内核是不能使用在界面上使用的,那么此时QEMU提供了用户级别的使用界面,相互辅助.当然,单独使用QEMU也是可以实现一整套虚拟机,不过QEMU+KVM基本是标 ...
- 关于Linux虚拟化技术KVM的科普 科普三(From OenHan)
http://oenhan.com/archives,包括<KVM源代码分析1:基本工作原理>.<KVM源代码分析2:虚拟机的创建与运行>.<KVM源代码分析3:CPU虚 ...
- 关于Linux虚拟化技术KVM的科普 科普四(From humjb_1983)
另一组关于KVM的分析文档,虚拟化相关概念.KVM基本原理和架构一-概念和术语.KVM基本原理和架构二-基本原理.KVM基本原理及架构三-CPU虚拟化.KVM基本原理及架构四-内存虚拟化.KVM基本原 ...
- 【原创】Linux虚拟化KVM-Qemu分析(三)之KVM源码(1)
背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: KVM版本:5.9 ...
- 虚拟化技术学习(一)在VMware虚拟机中安装KVM
近期一直研究虚拟化技术,曾经对VMware虚拟机有一定的了解,近期突发奇想,能不能在VMware虚拟机中再装一个虚拟机呢? 那么问题就来了,首先,你须要一台电脑,vmware软件,(本人的电脑配置渣渣 ...
- 主流服务器虚拟化技术简单使用——Hyper-V(二)
当在多台Windows Server上部署了hyper-v的时候,需要采用合适的方法管理这些hyper-v节点. 远程桌面 最简单的方法就是逐台远程桌面登陆Windows Server,再使用每台本地 ...
- 关于Linux虚拟化技术KVM的科普 科普五(From 世民谈云计算)
另一位大神写到KVM文章,KVM 介绍(1):简介及安装.KVM 介绍(2):CPU 和内存虚拟化.KVM 介绍(3):I/O 全虚拟化和准虚拟化 [KVM I/O QEMU Full-Virtual ...
随机推荐
- LeetCode之“链表”:Remove Nth Node From End of List
题目链接 题目要求: Given a linked list, remove the nth node from the end of list and return its head. For ex ...
- ubuntu下eclipse新建项目没有java project的解决办法
装好了eclipse之后却发现新建项目没有java project的选项,大致搜索了一下,并没有发现很好的解决方案(大都是让你重新安装什么的),于是开始瞎鼓捣,并且找到了一个方案: 在终端切换到roo ...
- Java 条形码生成(一维条形码)
utl:http://mianhuaman.iteye.com/blog/1013945 在这里给大家介绍一个java 生成条形码 jbarcode.jar 生成条形码 支持EAN13, EAN8, ...
- linux socket编程之TCP与UDP
转:http://blog.csdn.net/gaoxin1076/article/details/7262482 TCP/IP协议叫做传输控制/网际协议,又叫网络通信协议 TCP/IP虽然叫传输控制 ...
- Linux下的 .o、.a、.so文件
http://blog.sina.com.cn/s/blog_656681710100qzmy.html 工程里很多函数只是有声明,找不到实现的代码.因为那些实现代码已经编译成库所以看不见,我所看见的 ...
- C语言实现某年某月某日是某年的第几天
看到这个标题,想实现这样的功能其实挺简单的,用C语言的switch语句加上闰年,平年条件的判断,再加上一定的逻辑可以轻松实现这样的函数,在linux内核中,存在判断闰年平年的接口,我将它移植出来后,写 ...
- PS 色调——老照片效果
这就是通过调色使照片显得发黄. R_new=0.393*R+0.769*G+0.189*B; G_new=0.349*R+0.686*G+0.168*B; B_new=0.272*R+0.534*G+ ...
- plsql使用
本文由jay8605162432贡献 本课重点: 1.写 SELECT 语句进行数据库查询 2.进行数学运算 3.处理空值 4.使用别名 ALIASES 5.连接列 6.在 SQL PLUS 中编辑缓 ...
- tomcat 工作原理
Tomcat原理 分类: TOMCAT2009-05-17 22:25 4366人阅读 评论(3) 收藏 举报 tomcatexceptionsocketstringservernull Tomcat ...
- HashMap在高并发下如果没有处理线程安全会有怎样的安全隐患,具体表现是什么
Hashmap在并发环境下,可能出现的问题: 1.多线程put时可能会导致get无限循环,具体表现为CPU使用率100%: 原因:在向HashMap put元素时,会检查HashMap的容量是否足够, ...