/* * Send interrupt to vcpu via posted interrupt way. * 1. If target vcpu is running(non-root mode), send posted interrupt * notification to vcpu and hardware will sync PIR to vIRR atomically. * 2. If target vcpu isn't running(root mode), kick it to pick up the * interrupt from PIR in next vmentry. */ staticintvmx_deliver_posted_interrupt(struct kvm_vcpu *vcpu, intvector) { structvcpu_vmx *vmx = to_vmx(vcpu); int r;
...
if (!vcpu->arch.apicv_active) return-1;
if (pi_test_and_set_pir(vector, &vmx->pi_desc)) return0;
/* If a previous notification has sent the IPI, nothing to do. */ if (pi_test_and_set_on(&vmx->pi_desc)) return0;
if (vcpu != kvm_get_running_vcpu() && !kvm_vcpu_trigger_posted_interrupt(vcpu, false)) // Kick a sleeping VCPU, or a guest VCPU in guest mode, into host kernel mode. kvm_vcpu_kick(vcpu);
If target vcpu isn’t running(root mode), kick it(kvm_vcpu_kick(vcpu)) to pick up the interrupt from PIR in next vmentry.
vmx_sync_pir_to_irr
pick up the interrupt from PIR in the next vmentry这一步的代码解析如下:
1 2 3 4 5 6 7 8 9 10 11 12 13
intvcpu_enter_guest(struct kvm_vcpu *vcpu) { ...
/* * This handles the case where a posted interrupt was * notified with kvm_vcpu_kick. */ if (kvm_lapic_enabled(vcpu) && vcpu->arch.apicv_active) // vmx_sync_pir_to_irr(vcpu) is called static_call(kvm_x86_sync_pir_to_irr)(vcpu); ... }