aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAvi Kivity <avi@redhat.com>2011-02-03 08:29:52 -0500
committerMarcelo Tosatti <mtosatti@redhat.com>2011-03-17 12:08:30 -0400
commitbd3d1ec3d26b61120bb4f60b18ee99aa81839e6b (patch)
tree1da67e2ea45cad2b8460906820bf5cad15671b32
parentf86368493ec038218e8663cc1b6e5393cd8e008a (diff)
KVM: SVM: check for progress after IRET interception
When we enable an NMI window, we ask for an IRET intercept, since the IRET re-enables NMIs. However, the IRET intercept happens before the instruction executes, while the NMI window architecturally opens afterwards. To compensate for this mismatch, we only open the NMI window in the following exit, assuming that the IRET has by then executed; however, this assumption is not always correct; we may exit due to a host interrupt or page fault, without having executed the instruction. Fix by checking for forward progress by recording and comparing the IRET's rip. This is somewhat of a hack, since an unchaging rip does not mean that no forward progress has been made, but is the simplest fix for now. Signed-off-by: Avi Kivity <avi@redhat.com>
-rw-r--r--arch/x86/kvm/svm.c10
1 files changed, 9 insertions, 1 deletions
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index bfb49489566e..8d61df4a02c7 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -135,6 +135,8 @@ struct vcpu_svm {
135 135
136 u32 *msrpm; 136 u32 *msrpm;
137 137
138 ulong nmi_iret_rip;
139
138 struct nested_state nested; 140 struct nested_state nested;
139 141
140 bool nmi_singlestep; 142 bool nmi_singlestep;
@@ -2653,6 +2655,7 @@ static int iret_interception(struct vcpu_svm *svm)
2653 ++svm->vcpu.stat.nmi_window_exits; 2655 ++svm->vcpu.stat.nmi_window_exits;
2654 clr_intercept(svm, INTERCEPT_IRET); 2656 clr_intercept(svm, INTERCEPT_IRET);
2655 svm->vcpu.arch.hflags |= HF_IRET_MASK; 2657 svm->vcpu.arch.hflags |= HF_IRET_MASK;
2658 svm->nmi_iret_rip = kvm_rip_read(&svm->vcpu);
2656 return 1; 2659 return 1;
2657} 2660}
2658 2661
@@ -3474,7 +3477,12 @@ static void svm_complete_interrupts(struct vcpu_svm *svm)
3474 3477
3475 svm->int3_injected = 0; 3478 svm->int3_injected = 0;
3476 3479
3477 if (svm->vcpu.arch.hflags & HF_IRET_MASK) { 3480 /*
3481 * If we've made progress since setting HF_IRET_MASK, we've
3482 * executed an IRET and can allow NMI injection.
3483 */
3484 if ((svm->vcpu.arch.hflags & HF_IRET_MASK)
3485 && kvm_rip_read(&svm->vcpu) != svm->nmi_iret_rip) {
3478 svm->vcpu.arch.hflags &= ~(HF_NMI_MASK | HF_IRET_MASK); 3486 svm->vcpu.arch.hflags &= ~(HF_NMI_MASK | HF_IRET_MASK);
3479 kvm_make_request(KVM_REQ_EVENT, &svm->vcpu); 3487 kvm_make_request(KVM_REQ_EVENT, &svm->vcpu);
3480 } 3488 }