静态编译qemu_x86 kvm和qemu虚拟化介绍

本文探讨了x86体系结构和操作系统原理在虚拟化中的作用,强调了理解CPU虚拟化、内存虚拟化和外设中断的重要性。通过静态编译qemu_x86和kvm,介绍了如何实现虚拟化,包括CPU的ring 0和ring 3权限管理、Intel VT-x硬件辅助虚拟化技术、内存地址转换以及中断模拟。最后,讨论了虚拟化技术面临的挑战和未来的学习方向。
摘要由CSDN通过智能技术生成

简单说一下自己对x86平台虚拟化的理解,intel有SDM手册,代码都是公开的,难度比较大,理解起来困难,网上有大量优秀博客讲解虚拟化,引用了大量手册和代码,还是很难看懂。个人觉得理解虚拟化不能一上来就看很详细的手册和代码,虚拟化有点绕,先闭上眼睛想想大的道理,掌握了大的道理,再看手册和代码加深理解,否则很容易迷失,对虚拟化的理解只流于表面。

X86体系结构和OS

要理解虚拟化一定要回顾x86体系结构和OS原理,其实这两门课上大学时就学过,当时理解的很肤浅,随着工作的时间越长,理解的越深刻。计算机运转起来飞快,控制的非常精细,表面上给人很多假象,功能越来越复杂,集成度越来越高,不需要掌握很一个细节,但要能简化出一个最简单模型,通过个模型去深入理解背后的原理,思考时要站在不同的角度看问题,CPU的角度,guest的角度,外设的角度,进程的角度,内核的角度,不同角度看问题能让软件逻辑走通。也要不断提出问题,然后试着查资料解答自己的问题,计算机已经复杂到让一个人已经不可能掌握了所有细节,但要形成自己的抽象,各方面逻辑能成环,能自圆其说,只知道一些概念最不可取。

CPU(一堆寄存器)/Cache/Timer

physical memory map, segment and page,MMU and TLB

pci and device,driver and interrupt

kernel space and user space,context and process scheduler

软件和硬件的边界?

对x86和OS回顾后,那么得问自己一个问题,让自己写一个hypervisor怎么实现?guest是不能动的,linux和windows已经编译好的,还是物理机上跑的那些OS,那么是不是得借鉴物理机,哪个厂商什么型号的主板?什么型号的CPU几个核多少G内存?先构造一套假想的硬件,芯片组是什么型号,连接关系什么样的,就想象出下面这张图,这样guest就可以自动识别出这套硬件。

2da609d067551b530b341a3f695439e2.png

有那些bus,那些device,之间连接关系怎么表示?device的参数(virtio-net queue数量)等怎么表示?bus和device的状态怎么表示?硬件是主板电路连接好的,qemu怎么统一处理?还能支持hotplug?答案就是qdev和QOM(qemu object model)。

静态的东西已经出来了,guest是要运行的,动态怎么办?

CPU分为ring 0和ring 3不同权限,一条条指令执行,有些指令要在ring 3执行,有些要在ring 0执行,指令中包含的地址是虚拟地址。由于guest是事先编译好的,原来在物理机上怎么运行,现在要在虚拟机中一模一样运行,里面该ring 0还是ring 0,该ring 3还是ring 3,该虚拟地址还是原来的虚拟地址,所以得给guest制造假象,但guest的运行最终要落实到真正的硬件CPU和内存上,guest运行于host ring 3,要落实到真正的硬件qemu得做很多工作,那么qemu干什么呢,简单想象guest ring 3指令只要把guest的虚拟地址替换成host的虚拟地址,ring 0指令由于权限太高,得通过host模拟得出个结果然后把这个结果给了guest,这就是软件翻译,太慢了,intel vt-x技术就登场了。

intel vt-x vmx硬件实现了哪些功能?

VMCS(virtual machine controle structure)

non-root(guest)模式和root(host)模式,增加一个ring给guest,让guest指令直接上物理CPU执行,guest指令直接上物理CPU,那么指令中的地址肯定得用MMU硬件单元直接翻译(shadow page和EPT),当然不是guest的任何一条指令都能顺顺当当执行的,尤其是guest操作它以为的真正硬件的指令,因为是假象,其实是不存在的,所以得拦截和模拟,得vmexit然后再vmentry。qemu是host上的进程,ioctl到kvm内核后会vmentry到guest模式,执行guest代码,特权指令trap住vmexit回host模式模拟执行,然后再vmentry到guest模式

CPU虚拟化

一个vcpu在qemu中是一个线程,qemu通过ioctl调用kvm创建vcpu的资源

host调度这些线程,vcpu线程vcpu_run进入kvm内核,然后load_vcpu进入guest模式执行guest的代码

vcpu进入guest模式时从VMCS加载寄存器等,退出guest模式时把寄存器等保存到VMCS上

vcpu_enter_guest->vmx_vcpu_run->__vmx_vcpu_run调用汇编进入guest模式

vmx_handle_exit根据exit_reason来有不同的处理,kvm搞不定就再退回到qemu

vcpu占用了pcpu,host上其它进程要用pcpu,怎么抢占?

vcpu之间cache怎么同步,尤其是一个vcpu在运行,另一个没有运行?

pcpu进入或者退出guest时cache和TLB要不要做处理?

内存虚拟化

x86上物理内存空间大概是这样的。

cb94295b95f077e90f5beae9eef9b7c1.png

x86上物理地址空间是怎么组成的那么qemu就要拿自己的进程虚拟空间的内存拼凑出一个空间仍给guest,让guest当作自己的物理地址空间。

67b66e8c864a7f87676cee7e2052a18b.png

在qemu monitor上可以看

a7a3c0f32aba78c9fb44116127488921.png

虚拟出一块内存给guest用,GVA(guest virtual address)->GPA(guest physical address)->HVA(host virtual address)->HPA(host physical address)

cpu_exec_init_all–>io_mem_init

-->memory_map_init

pc_init1->pc_memory_init ->memory_region_allocate_system_memory->allocate_system_memory_nonnuma->

memory_region_init_ram_shared_nomigrate->qemu_ram_alloc->qemu_ram_alloc_internal->ram_block_add->

phys_mem_alloc(qemu_anon_ram_alloc)->qemu_ram_mmap->mmap


kvm_init->kvm_memory_listener_register->memory_listener_register->listener_add_address_space->kvm_region_add->kvm_set_phys_mem

memory_region_transaction_begin

memory_region_transaction_commit

AddressSpaceDispatch从GPA转到HVA

guest从IO地址空间的一个port读一个数到内存

kvm_mmu_create创建guest MMU的页表,但内容为空

vcpu_enter_guest => kvm_mmu_reload加载guest的页表到VMCS结构的对应字段

EPT_VOLATION和EPT_MISCONFIG

外设和中断

host上driver和硬件外设有明确的接口,硬件外设是个黑盒子。guest中driver是没有变的,那qemu得保持这些接口不变,否则guest里的driver就跑不起来了,接口后面的功能和动作那qemu就随便实现了,最终的结果一样就行了。guest中driver读寄存器那qemu就给一个结果,guest发起DMA操作,qemu就从guest的物理内存搬东西到自己的虚拟空间。

PIC(8259 chip)/APIC(IOAPIC和LAPIC)

INTx/NMI/SMI/SMI-X

qemu和kvm分别模拟中断芯片,混合模拟(on, off, split)

个人认为中断模拟是最难的,host上中断处理流程已经够复杂的了。PIC给CPU发送一个电信号就给CPU一个中断,APIC直接给一个物理地址写,CPU的LAPIC就收中断了,物理机上中断是由硬件发起的,现在只能由hypervisor发起,硬件的中断路由得hypervisor模拟。中断来了OS是怎么取中断号的?怎么操作LAPIC的?中断处理结束了OS怎么操作中断芯片,有哪些指令,这些指令都得trap住然后模拟。

vcpu正在pcpu上运行,ovs把一个数据包放在virtio ring上,怎么打断vcpu运行?中断到底是怎么注入的?kvm运行在一个pcpu A上,vcpu在另一个pcpu B上,难道pcpu A给pcpu B发送一个IPI打断pcpu B?这个IPI和正常的两个pcpu之间的IPI有什么不同没?

vcpu没有运行时来的中断怎么保存的?(pending_event)处理不及时中断会不会丢失?

enter guest时guest是怎么知道有中断在pending?enter guest时不是延着上次执行的地方继续执行吗?为什么要执行中断服务例程呢?难道是硬件搞的?

中断来了要不要exit?怎么减少exit次数?硬件辅助(vAPIC还是APICv)?

总结

虚拟化水很深,大的方面理解了,再看代码深入理解,最后再解决实际碰到的问题,如windows虚拟机中DPC Latency太高怎么解决,嵌套虚拟化的问题。

抛砖引玉,很多问题是不知道答案的,如果你感兴趣,不防想一想找一下答案,找到了答案那么恭喜你,你对虚拟化的理解又上了一个台阶。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值