• Ladi Prosek's avatar
    KVM: x86: fix emulation of RSM and IRET instructions · 1eeb7942
    Ladi Prosek authored
    commit 6ed071f0 upstream.
    
    On AMD, the effect of set_nmi_mask called by emulate_iret_real and em_rsm
    on hflags is reverted later on in x86_emulate_instruction where hflags are
    overwritten with ctxt->emul_flags (the kvm_set_hflags call). This manifests
    as a hang when rebooting Windows VMs with QEMU, OVMF, and >1 vcpu.
    
    Instead of trying to merge ctxt->emul_flags into vcpu->arch.hflags after
    an instruction is emulated, this commit deletes emul_flags altogether and
    makes the emulator access vcpu->arch.hflags using two new accessors. This
    way all changes, on the emulator side as well as in functions called from
    the emulator and accessing vcpu state with emul_to_vcpu, are preserved.
    
    More details on the bug and its manifestation with Windows and OVMF:
    
      It's a KVM bug in the interaction between SMI/SMM and NMI, specific to AMD.
      I believe that the SMM part explains why we started seeing this only with
      OVMF.
    
      KVM masks and unmasks NMI when entering and leaving SMM. When KVM emulates
      the RSM instruction in em_rsm, the set_nmi_mask call doesn't stick because
      later on in x86_emulate_instruction we overwrite arch.hflags with
      ctxt->emul_flags, effectively reverting the effect of the set_nmi_mask call.
      The AMD-specific hflag of interest here is HF_NMI_MASK.
    
      When rebooting the system, Windows sends an NMI IPI to all but the current
      cpu to shut them down. Only after all of them are parked in HLT will the
      initiating cpu finish the restart. If NMI is masked, other cpus never get
      the memo and the initiating cpu spins forever, waiting for
      hal!HalpInterruptProcessorsStarted to drop. That's the symptom we observe.
    
    Fixes: a584539b ("KVM: x86: pass the whole hflags field to emulator and back")
    Signed-off-by: default avatarLadi Prosek <lprosek@redhat.com>
    Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
    Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
    1eeb7942
kvm_emulate.h 15 KB