上篇博文中我们分析了kvm_cmd_run_init函数,该函数主要是用于创建VM以及创建VCPU的。
这篇博文主要分析kvm_cmd_run_work
kvm_cmd_run_work
为每个vcpu 创建了一个线程,并利用pthread_join阻塞等待vpcu0
所以核心就要看线程函数
kvm_cpu_thread
注意这个current_kvm_cpu变量,这是个被__thread关键字修饰的全局变量,所以虽然是全局变量,但却是每个线程一份。
关键函数是kvm_cpu_start
kvm_cpu_start
将vcpu中的变量初始化,内核使用了ioctrl来真正设置VCPU
核心是kvm_cpu_run
通过ioctrl执行KVM_RUN, 该函数会阻塞一直到guest因某种原因产生来vm_exit 且该exit不能被KVM模块自身解决。
当kvm_cpu_run退出时,KVM模块会将退出的原因以及相关数据放在kvm_run中,回忆一下,kvm_run是通过mmap得到的一块内存区域。
然后根据退出原因进行不同的处理
如果是退出的原因是IO,则进行IO模拟,具体的模拟不是我们现在所关心的,不深入研究。
注意这段代码在switch外面,也就是每次处理完kvm退出事件都要处理coalesced_mmio。
整个kvm_cpu__run和退出事件处理都被包裹在一个while循环中,只要cpu-
>
is_running满足,就会一直进行kvm_cpu__run和退出事件处理。。
kvm_cmd_run_work总结
这篇博文主要分析了kvm_cmd_run_work函数,该函数主要做的事情就是创建vcpu线程,有KVM学习经验的朋友一定知道,一个vcpu线程就代表一个虚拟机CPU。在线程中,主要完成以下
1. 初始化vcpu寄存器
2. 利用ioctrl进入guest
3. 针对KVM_EXIT的原因进行设备模拟
4. 处理coalesced_mmio
5. 回到2
所用到的核心ioctrl主要有
ioctl(vcpu-
>
kvm-
>
sys_fd, KVM_GET_SUPPORTED_CPUID, kvm_cpuid)
ioctl(vcpu-
>
vcpu_fd, KVM_SET_CPUID2, kvm_cpuid)
ioctl(vcpu-
>
vcpu_fd, KVM_GET_SREGS,
&
vcpu-
>
sregs)
ioctl(vcpu-
>
vcpu_fd, KVM_SET_SREGS,
&
vcpu-
>
sregs)
ioctl(vcpu-
>
vcpu_fd, KVM_SET_REGS,
&
vcpu-
>
regs)
ioctl(vcpu-
>
vcpu_fd, KVM_SET_FPU,
&
vcpu-
>
fpu)
ioctl(vcpu-
>
vcpu_fd, KVM_SET_MSRS, vcpu-
>
msrs)
ioctl(vcpu-
>
vcpu_fd, KVM_RUN, 0)