接前一篇文章:
本文内容参考:
《 QEMU /KVM》 源码 解析与应用 —— 李强,机械工业出版社
《深度探索 Linux 系统 虚拟化 原理与实现》—— 王柏生 谢广军, 机械工业出版社
特此致谢!
前边几回又再次讲了一下VMX,本回开始讲解VCPU的生命周期。
二、x86架构CPU虚拟化
4. VCPU生命周期
对于每个虚拟处理器(VCPU),VMM使用一个线程来代表VCPU这个实体 。在Guest运转过程中,每个VCPU基本都在下图所示的状态中不断地转换。
(1) 在用户空间准备好后,VCPU所在线程向(Linux)内核中KVM模块发起一个ioctl请求KVM_RUN 。告知内核中的KVM模块,用户空间的操作已经完成,可以切入Guest模式运行Guest了。
(2) 在进入内核态后,KVM模块将调用CPU提供的虚拟化指令切入Guest模式 。如果是首次运行Guest,则使用VMLaunch命令,否则使用VMResume命令。
在这个切换过程中:
1)首先,CPU的状态(即Host的状态)将被保存到VMCS中存储Host状态的区域,非CPU自动保存的状态由KVM负责保存。
2)然后,加载存储在VMCS中的Guest的状态到物理CPU,非CPU自动恢复的状态则由KVM负责恢复。
(3)物理CPU切入Guest模式,运行Guest指令。 当执行Guest指令遇到敏感指令时,CPU将从Guest模式切换回Host模式的ring 0,进入Host内核的KVM模块 。
在这个切换过程中:
1)首先,CPU的状态(也就是Guest的状态)将会保存到VMCS中存储Guest状态的区域。
2)然后,加载存储在VMCS中的Host的状态到物理CPU。同样的,非CPU自动保存的状态由KVM模块负责保存。
(4) 处于内核态的KVM模块从VMCS中读取虚拟机退出的原因,尝试在内核中处理 。如果内核中可以处理,那么 虚拟机 就不必再切换到Host模式的用户态了,处理完后,直接快速切回Guest。这种退出也称为 轻量级虚拟机退出 。
(5) 如果内核态的KVM模块不能处理虚拟机退出,那么VCPU将再进行一次上下文切换,从Host的内核态切换到Host的用户态,由VMM的用户空间部分进行处理 。
(6) VMM用户空间处理完毕,再次发起切入Guest模式的指令 。在整个虚拟机的运行过程中,步骤(1)~(6)循环往复。
QEMU示例代码如下(对应以上过程):
- while (1)
- {
- ret = ioctl(vcpufd, KVM_RUN, NULL);
- if (ret == -1)
- {
- printf("exit unknown\n");
- return -1;
- }
- switch(run->exit_reason)
- {
- case KVM_EXIT_HLT:
- puts("KVM_EXIT_HLT");
- return 0;
- case KVM_EXIT_IO:
- putchar( ((char *)run) + run->io.data_offset));
- break;
- case KVM_EXIT_FAIL_ENTRY:
- puts("entry error");
- return -1;
- default:
- puts("other error");
- printf("exit_reason: %d\n, run->exit_reason");
- return -1;
- }
-
- }
更多内容请看下回。