KVMのゲスト実行中に物理割り込みはかかるのか
もしゲスト実行中に割り込みがかからないとクロック割り込みもかからない事になるので、ゲストカーネルがいつまでも制御を離したがらず、VMEXITが起きるような命令を実行したりしない場合に二度とゲストから帰ってこなくなる、もしくはqemuのcpuスレッドだけがスケジューリング周期を大幅に過ぎた時点で初めて他のプロセスへ制御を明け渡すというような事になりかねないのではないか。
VMLAUNCHの手前辺りのコードを読んでみる(vcpu_enter_guest):
local_irq_disable(); if (vcpu->mode == EXITING_GUEST_MODE || vcpu->requests || need_resched() || signal_pending(current)) { vcpu->mode = OUTSIDE_GUEST_MODE; smp_wmb(); local_irq_enable(); preempt_enable(); kvm_x86_ops->cancel_injection(vcpu); r = 1; goto out; }
(中略)
trace_kvm_entry(vcpu->vcpu_id); kvm_x86_ops->run(vcpu);
local_irq_disable()でcliしてからkvm_x86_ops->run(vcpu)するまでstiしてなさそう、なのでこの間は割り込み無効。
static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu) {
(中略)
asm( /* Store host registers */ "push %%"R"dx; push %%"R"bp;" "push %%"R"cx \n\t" /* placeholder for guest rcx */ "push %%"R"cx \n\t" "cmp %%"R"sp, %c[host_rsp](%0) \n\t" "je 1f \n\t" "mov %%"R"sp, %c[host_rsp](%0) \n\t" __ex(ASM_VMX_VMWRITE_RSP_RDX) "\n\t" "1: \n\t" /* Reload cr2 if changed */ "mov %c[cr2](%0), %%"R"ax \n\t" "mov %%cr2, %%"R"dx \n\t" "cmp %%"R"ax, %%"R"dx \n\t" "je 2f \n\t" "mov %%"R"ax, %%cr2 \n\t" "2: \n\t" /* Check if vmlaunch of vmresume is needed */ "cmpl $0, %c[launched](%0) \n\t" /* Load guest registers. Don't clobber flags. */ "mov %c[rax](%0), %%"R"ax \n\t" "mov %c[rbx](%0), %%"R"bx \n\t" "mov %c[rdx](%0), %%"R"dx \n\t" "mov %c[rsi](%0), %%"R"si \n\t" "mov %c[rdi](%0), %%"R"di \n\t" "mov %c[rbp](%0), %%"R"bp \n\t" #ifdef CONFIG_X86_64 "mov %c[r8](%0), %%r8 \n\t" "mov %c[r9](%0), %%r9 \n\t" "mov %c[r10](%0), %%r10 \n\t" "mov %c[r11](%0), %%r11 \n\t" "mov %c[r12](%0), %%r12 \n\t" "mov %c[r13](%0), %%r13 \n\t" "mov %c[r14](%0), %%r14 \n\t" "mov %c[r15](%0), %%r15 \n\t" #endif "mov %c[rcx](%0), %%"R"cx \n\t" /* kills %0 (ecx) */ /* Enter guest mode */ "jne .Llaunched \n\t" __ex(ASM_VMX_VMLAUNCH) "\n\t" "jmp .Lkvm_vmx_return \n\t"
kvm_x86_ops->runの関数である vmx_vcpu_run()がVMRAUNCH実行するまでにstiしている事もなさそう。
ということは、VMRAUNCHする瞬間、ホスト側は割り込み無効なのだろう。
では、ゲスト実行中はどうだろう?ホストが割り込み禁止でもゲスト実行中に割り込みがかかる事はあるのだろうか?
Intel SDMの「24.6.1 Pin-Based VM-Execution Controls」を読むと、こんなのがあった: PINBASED_CTLSの0ビット目(External-interrupt exiting)
ここでは、ビットが立っていたらexternal interrupt来た時点で、RFLAGS.IFの値に関わらず、VM exitすると書いてある。
で、よく他のコードを探すと、setup_vmcs_configのところに
min = PIN_BASED_EXT_INTR_MASK | PIN_BASED_NMI_EXITING; opt = PIN_BASED_VIRTUAL_NMIS; if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PINBASED_CTLS, &_pin_based_exec_control) < 0)
となっていて、このビットが立っているように見える。
というわけで、external interruptについてはホストでcliしててもゲストモード実行中にVM exitがかかり、ハンドル可能に見える。