基本逻辑
只分析禁止内核抢占的Linux系统。对于这样的系统,在内核态执行时,如果被中断后,中断
执行完后将继续原来的执行流程,在内核态执行,除非内核代码显示让出CPU,否则内核态
的执行流程将持续进行。对于这样的系统,线程调度只发生在:1. 内核态显示让出CPU,2.
内核态返回用户态的调度点。
所以,KVM中当vCPU通过ioctl run进入虚机运行时,vCPU线程被调度出去的时间也只有如上
两个点。具体而言就是:1. vCPU退出到KVM执行时,在KVM里主动让出CPU;2. vCPU一路退出
到qemu时,从host退出到用户态的调度点发生调度。
先分析vCPU在guest运行时会因为什么原因退出来:1. vCPU的相关指令触发了trap,trap
到KVM来模拟,KVM在模拟的时候就可能主线让出CPU,比如WFI的模拟,也可能退到qemu处理,
这样vCPU线程也可能被调度走。2. 处于guest状态的vCPU被host上的中断打断,这种情况下
vCPU先退出到KVM,然后换上host的中断异常向量,开中断后,这个中断会再次被taken,
处理完中断后,继续从KVM进入原来的vCPU。
KVM里让出CPU的点都有: 1. WFI/WFE的模拟逻辑,具体逻辑可以参考这里。
2. ioctl run里进入guest之前,KVM会查下vCPU线程的状态,如果需要调度也会显示进行
调度。
1 | /* linux/arch/arm64/kvm/arm.c */ |
再看kvm退出到qemu的逻辑,需要退出到qemu处理的情况定义到了include/uapi/linux/kvm.h
的KVM_EXIT_XXX。
内核中的一段流程长时间占据CPU就会触发softlockup,那不是可以写一段不触发退出的程序,
在qemu-kvm上运行就会触发softlockup?
对于支持抢占的内核,在如上基础上,凡事内核抢占时都会有vCPU线程的调度。
vCPU上线时间点
vCPU的上线的时间点有:1. vCPU初次运行时上线,2. vCPU线程被调度出物理CPU后,再次
被调度进来执行。后者又分为,vCPU作为host上的一个线程被正常调度到,或者是KVM显示
wakeup对应vCPU线程。
vCPU下线时间点
vCPU下线的可能点在上面已经提到过,注意,vCPU从guest退到KVM并没有下线,我们这里说
的下线是vCPU线程被调度出物理CPU。那么,在禁止内核抢占的内核,vCPU下线只会发生在:
- KVM里主动调度,让出物理CPU,2. KVM退出到qemu时,vCPU线程被调度走。
KVM里使用kvm_vcpu_kick函数使得一个vCPU至少下线一下,一般KVM更新了vCPU对应的资源
需要vCPU重新加载对应的资源的时候,要kick下vCPU,叫它先下线随后再上线。
代码上看,kvm_vcpu_kick的点有: vCPU power off、vCPU suspend、kvm_vm_ioctl_irq_line,
pmu模拟(?),需要给一个vCPU注入中断的时候,GICD_CTLR和vSGI直通的逻辑(?)。
vCPU上下线API
kvm_vcpu_kick/kvm_vcpu_wake_up/kvm_kick_many_cpus
vCPU关中断关抢占逻辑
(todo: vCPU上下线代码有很多关中断和关强占的逻辑,分析下这里的一般逻辑)