The problem of KVM checking Alternate Injection guest events
Melody Wang <[email protected]> Sun, 17 Aug 2025 12:50:28 -0700
| Newsgroups | dev.linux.lists.coconut-svsm |
|---|---|
| Message-ID | <[email protected]> |
I found one issue when multiple interrupts are being handled in the SVSM but I think it can happen also with a single one. The gist of the observation is, that SVSM queues the interrupt into the VMPL2 guest's VMSA but if the hypervisor doesn't run the VMPL2 guest due to a lack of pending events - it cannot know that - then that interrupt won't get injected, leading to a stop. Below are the details: Interrupt 33 and 236 are in the doorbell page as multiple interrupts, 12796.893994: sev_snp_ai_update_doorbell: vector: 236, no_further: 1, ai_vector: 80, si_vector: 33 12796.893994: sev_snp_ai_update_doorbell: doorbell after: 12796.893994: dump_hvdb: pending_events: 12796.893995: dump_hvdb: vector: 80, nmi: 0, mce: 0, no_further_signal: 1 12796.893995: dump_hvdb: second_word: 0x200 12796.893995: dump_hvdb: VMPL IRQs: 1: 0 2: 1 3: 0 12796.893997: dump_hvdb: irq_info: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 12796.893997: print_ext_irq_desc.constprop.0: VMPL2 12796.893997: print_ext_irq_desc.constprop.0: ext_word0: 0x4000, si_vec: 0x0, mult: 1, ext_word1: 0x0, counter: 1226 12796.893998: print_ext_irq_desc.constprop.0: irq_vec: 0002 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 1000 0000 These two interrupts will be delivered to the SVSM, SVSM consumes these two interrupts, and marks them in the emulated IRR in the SVSM APIC: 12796.894031: __kvm_set_msr: guest: post_interrupt(33) 12796.894036: __kvm_set_msr: guest: post_interrupt(236) Then the SVSM injects 236 which is the highest priority interrupt, which will be cleared in the IRR and moved to the ISR until the eoi is sent back from the guest, i.e. the interrupt has been serviced: 12796.894046: __kvm_set_msr: guest: deliver_immed: shadow: 0, irqs_enabled: 0, irq: 236 12796.894051: __kvm_set_msr: guest: queue_interrupt(236) into VintrCtrl: v_irq: 1 12796.894055: __kvm_set_msr: guest: Mark ISR, queued: 1, ISR idx: 1, delivered: 0 After 236 is written into the VintrCtrl, the SVSM will switch to VMPL2: 12796.894067: sev_handle_vmgexit: vmpl: 0, ghcb_info: 0x16 12796.894067: __sev_run_vmpl_vmsa: parent: 0xff445aee23690ac0, current: 0xff445aee2cb83940, current_vmpl: 0 12796.894068: __sev_run_vmpl_vmsa: new_vmpl: 2 And VMPL2 runs: 12796.894069: svm_vcpu_run: VMPL switch: 0 -> 2, immed_ex: 0 12796.894071: svm_vcpu_run: parent: 0xff445aee23690ac0, clear switch_pending 12796.894071: kvm_exit: vcpu 0 reason npf rip 0x0 info1 0x0000000500000014 info2 0x0000000001881000 intr_info 0x00000000 error_code 0x00000000 12796.894071: kvm_page_fault: vcpu 0 rip 0x0 address 0x0000000001881000 error_code 0x2000500000014 12796.894071: apic_has_pending_timer: lapic_timer.pending: 0 12796.894072: kvm_entry: vcpu 0, rip 0x0, vcpu_vmpl 2, current_vmpl 2, target_vmpl 2 12796.894073: kvm_exit: vcpu 0 reason npf rip 0x0 info1 0x0000000500000006 info2 0x0000000277c1f000 intr_info 0x00000000 error_code 0x00000000 12796.894073: kvm_page_fault: vcpu 0 rip 0x0 address 0x0000000277c1f000 error_code 0x2000500000006 12796.894074: apic_has_pending_timer: lapic_timer.pending: 0 12796.894074: kvm_entry: vcpu 0, rip 0x0, vcpu_vmpl 2, current_vmpl 2, target_vmpl 2 12796.894076: kvm_exit: vcpu 0 reason npf rip 0x0 info1 0x0000000500000014 info2 0x0000000002297000 intr_info 0x00000000 error_code 0x00000000 12796.894076: kvm_page_fault: vcpu 0 rip 0x0 address 0x0000000002297000 error_code 0x2000500000014 12796.894077: apic_has_pending_timer: lapic_timer.pending: 0 12796.894077: kvm_entry: vcpu 0, rip 0x0, vcpu_vmpl 2, current_vmpl 2, target_vmpl 2 12796.894079: kvm_exit: vcpu 0 reason hlt rip 0x0 info1 0x0000000000000000 info2 0x0000000000000000 intr_info 0x00000000 error_code 0x00000000 12796.894079: apic_has_pending_timer: lapic_timer.pending: 0 kvm_vcpu_has_events() is KVM's way to ask whether the guest needs to be run. It did not find there is any event in IRR (encrypted in the SVSM), so KVM does not run VMPL2 anymore even the interrupt is not handled. But in fact 33 is in SVSM's irr now which KVM does not know now, otherwise it will be able to trigger VMPL2 to run. 12796.894086: kvm_vcpu_has_events: none So KVM needs a way to know whether to run the guests again - SVSM or VMPL2. I don't think we have such a provision in the spec so maybe we need something there. Right? -- Thanks, Melody