基本逻辑
这里的WFX指令指WFI/WFE/WFIT/WFET,带T后缀的指令是对应指令带超时的版本。
ARM KVM整体的逻辑可以参考这里。WFI指令的语意是把core进入低功耗,等待中断唤醒继续
执行,所以,guest里执行到WFI时,系统完全可以把vCPU线程调度出去,换host上的其它线程
执行,直到有中断发到vCPU上,KVM再把vCPU线程调度回来执行。
WFI在EL1执行可以trap到EL2,完成如上的逻辑。在支持GICv4.0/v4.1的系统上,直接注入
guest的vLPI中断支持附带host doorbell中断的功能,当被注入vLPI的vCPU线程不在线时,
硬件可以给host发doorbell中断,这样KVM就可以及时的把vCPU上线,注入的vLPI中断也就
被及时的响应了。
WFE的虚拟化处理逻辑和WFI的逻辑基本一致,不过WFE是直接换一个vCPU的线程来跑。
当物理核上只有一个vCPU线程在跑的时候,wfe没有必要再做trap,trap出去也没有另外的
vCPU线程可以换进来跑;wfi在GIC支持vLPI/vSGI直通的时候,也不trap到KVM,这里似乎是
更倾向保证vLPI/vSGI的性能,注意wfi在host是GICv3的时候,还是要trap的,反正GICv3时,
所有虚机中断都要先trap的KVM里,再注入到虚机。这样如果把wfe/wfi都配置为不再trap,
那么它们是实际执行的,从host上看就是vCPU线程一直有指令在运行,不管是正常跑还是做
wfi/wfe,所以,host上看到vCPU线程的CPU占用率是100%。
WFxT编码了一个通用寄存器,软件可以把一个counter数值放到这个寄存器里,当超时发生时,
硬件触发唤醒事件,WFxT被唤醒。对于WFxT,虚拟化下如果发生了trap,KVM中只是加了查询
超时的一个动作,如果trap到KVM里处理的时候已经超时,就不处理直接返回了,如果没有
超时就和如上wfe/wfi的处理逻辑一样。注意,WFX trap的逻辑和timeout超时逻辑是正交的,
WFX trap后,这个指令已经执行完毕,所以KVM要有模拟WFX超时的逻辑。(todo: 怎么模拟?)
WFE相关的还有一个特性FEAT_TWED,这个特性使得WFE trap之前可以加一段delay时间。如果
trap之前被唤醒,WFE执行完毕,不会再trap。
KVM里还有一堆和WFX相关的软件微调逻辑。KVM在处理WFI trap时,不是马上调度其它host
线程运行,而是等待一个软件配置的时间(vcpu->halt_poll_ns),如果在这个时间内,vCPU
有中断、timer等要处理,将继续执行当前vCPU线程。KVM里加了一堆这个微调对应的配置和
统计参数。
代码分析
WFI的调用链是: handle_exit -> handle_trap_exceptions -> kvm_handle_wfx,虽然是
系统指令的trap模拟,ARM还是转门给WFI做了标记。(不是在公用的kvm_handle_sys_reg里处理)
1 | kvm_handle_wfx |
doorbell中断处理函数在arch/arm64/kvm/vgic/vgic-v4.c里注册。
1 | vgic_v4_init |
doorbell中断处理里触发vCPU上线,vCPU上线后就会马上响应pending的中断。
1 | vgic_v4_doorbell_handler |
上面提到的,wfe/wfi开关trap的逻辑在vCPU上线的时候:
1 | kvm_arch_vcpu_load |
相关问题
host调度vCPU线程上下线的时候,会调用到kvm注册给调度器的回调函数kvm_sched_out/in。
host上中断处理中,是否会调用kvm_sched_out/in? 对于非抢占内核,中断打断当前的内核
执行流程,在中断执行完成后,应该继续返回被打断的点执行,而不执行内核抢占,所以应
该不会调用kvm_sched_out/in?