首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

KVM 虚拟化技术在 AMD 平台上的实现(4)

KVM 虚拟化技术在 AMD 平台上的实现(4)

重要的数据结构和接口  一个快速分析,理解 KVM 实现的方法是了解其代码中一些重要数据结构和接口函数 :
1.struct kvm 和 struct kvm_arch。 用来描述单个虚拟机全局的状态, 如代表虚拟机物理内存区域的 memslots, 代表当前需要仿真的 Coalesced MMIO 的 coalesced_mmio_ring, 用来仿真平台设备 PIC, IOAPIC, PIT, KVMCLOCK 的数据结构, 用来组织 Shadow 页表的数据结构等等。
2.struct kvm_vcpu 和 struct kvm_vcpu_arch。 用来描述单个虚拟 CPU 的状态, 如需要仿真的虚拟 CPU 的特征位 ( 客操作系统 CPUID 看到的东西 ), 当前尚未处理完的 PIO,等待注入的异常和中断事件,用来仿真 Local APIC 的数据结构,尚未同步到 VMCB 中的修改过的寄存器的缓存等等。
3.struct vmcb。  用来实现 AMD-V 的 VMCB 的数据结构。 其中的字段的格式和长度当然需要严格遵守 VMCB 的规范。 两个子结构 struct vmcb_control_area 和 struct vmcb_save_area 分别代表物理上的 VMCB.CONTROL 和 VMCB.SAVE。
4.Struct vcpu_svm。用来代表 AMD-V 实现下的 VCPU, 除关联 struct kvm_vcpu 和 struct vmcb 外, 还用来实现一些 AMD-V 特定的东西,如 ASID 和 Sysenter 的支持。
5.Struct kvm_memslots。 该结构挂在 struct kvm 下,用来描述虚拟机的全部物理内存区域, 每个区域对应一个 struct kvm_memory_slot 结构,其中包含该区域的 gpa 起点,大小及在 qemu-kvm 用户空间的 hva 起点。
6.Struct kvm_x86_ops。该接口定义了若干操作,规定 KVM 在 x86 平台上的基本实现方式,svm.c 中提供了大部分操作的独立实现,其中多数函数以 “svm_xxx”方式命名,读者可直接查找 svm_x86_ops 变量了解每个操作在 svm.c 中对应的函数。
7.Struct kvm_io_dev_ops。该接口定义了三个操作 (read,write,destructor),规定了在 KVM 内核中 PIO 或 MMIO 仿真的实现结构,目前平台设备 PIT, PIC, IOAPIC 的 PIO/MMIO 仿真处理都是按该接口的方式实现的。有趣的是,Ioeventfd 机制也使用了该接口, Ioeventfd 实现该接口的 write 操作,当 KVM 截取客操作系统向某特定的 PIO 或 MMIO 地址写入某特定的值时,Ioeventfd 实现的 ioeventfd_write() 操作就会执行, 唤醒等待在指定的文件描述符上的 qemu-kvm 线程。RHEL6.2 上 qemu-kvm 实现的 virtIO 设备的后端,已经使用了 ioeventfd 的功能。
重要的执行路径介绍为了帮助读者了解 kvm 及 qemu-kvm 代码的主体结构,我们可以看一下代表一个 VCPU 的 qemu-kvm 线程的重要执行路径,如图三所示 :
图 3. 执行路径   在此图中,最左侧的执行路径是 qemu-kvm 的代码建立一个虚拟机的过程, 起点是 pc_init_rhel620, 该函数的代码在 hw/pc.c 中,“rhel620”代表 qemu-kvm 对虚拟机的定义,  hw/pc.c 中提供了多个虚拟机定义,“rhel620” 是保留选用的定义,“rhel620”定义采用“cpu64-rhel6” CPU 模型,支持最大 255 个虚拟 CPU。一个 CPU 模型定义了虚拟的 CPU 所支持的特征列, qemu-kvm 定义的全部 CPU 模型在 sysconfigs/target/cpu-x86_64.conf 文件下。函数 pc_init1 是 qemu-kvm 用户空间很关键的一个函数,其代码中需要创建虚拟机的 PC 硬件,如分配物理内存,加载 BIOS, 分配 IO 端口空间,创建平台设备,创建 VGA 设备等。 pc_init1 然后要做的工作就是为每个 VCPU 创建一个线程。
VCPU 线程的启动函数为 ap_main_loop, 其代码在 qemu-kvm.c 中,该函数的代码需要从内核中创建 VCPU 抽象及单个 VCPU 相关的硬件,然后调用 kvm_main_loop_cpu。  kvm_main_loop_cpu 中包含 while 循环,除非 VCPU 关闭,否则 VCPU 的线程就不会退出该循环。kvm_rum 中调用 ioctl(,KVM_RUN) 进入 KVM 内核,在内核代码中切换进入客操作系统的代码执行,真正运行起一个 VCPU。一般只有当有 IO 操作需要用户空间仿真时,kvm_run 才会从 ioctl(,KVM_RUN) 中返回,执行 handle_mmio 等一些 IO 操作仿真的代码。
在内核空间,KVM 的 ioctl 功能分派函数会调用 __vcpu_run, 该函数也是一个包含 while 循环的函数,在每次工作的开始调用 vcpu_enter_guest, vcpu_enter_guest 做一些检查工作后调用 svm 特定的 svm_vcpu_run 函数, svm_vcpu_run 是进行客主模式切换的地方, 这里调用 VMRUM 指令加载 VMCB 的内容,进入“guest”模式。 客操作系统的代码运行在“guest”模式,遇到任何中断,异常或其他需要被捕获的事件,硬件就会执行 VMEXIT 而退出“guest”模式,退出后从 svm_vcpu_run 中位于 VMRUN 后的一条语句开始执行。 退出 svm_vcpu_run 后在 vcpu_enter_guest 中会调用 svm 特定的函数 handle_exit, 做退出事件的处理。 如果 handle_exit 处理的结果表明立即需要用户空间继续处理,如外部设备 IO_Memory 的仿真, 则从 vcpu_enter_guest 返回后的代码会退出 __vcpu_run, 进而退出到用户空间,从 ioctl(,KVM_RUN) 返回,执行 handle_mmio 等用户空间的仿真工作, 并在用户空间 kvm_main_loop_cpu 的主循环中重新调用 ioctl(,KVM_RUN) 进入 KVM, 进而重新进入客操作系统。
返回列表