aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kvm/svm.c
diff options
context:
space:
mode:
authorLadi Prosek <lprosek@redhat.com>2017-06-21 03:06:58 -0400
committerPaolo Bonzini <pbonzini@redhat.com>2017-06-27 10:34:47 -0400
commitab2f4d73ebc33487930e7adf1dd8ed671c72827c (patch)
tree97b0ee57c804a6c432044aeb0e567df85c309b38 /arch/x86/kvm/svm.c
parent4aebd0e9ca3776368813239018287021002b8973 (diff)
KVM: nSVM: do not forward NMI window singlestep VM exits to L1
Nested hypervisor should not see singlestep VM exits if singlestepping was enabled internally by KVM. Windows is particularly sensitive to this and known to bluescreen on unexpected VM exits. Signed-off-by: Ladi Prosek <lprosek@redhat.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'arch/x86/kvm/svm.c')
-rw-r--r--arch/x86/kvm/svm.c45
1 files changed, 40 insertions, 5 deletions
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 7dda9c4ee485..1a854ce6025e 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -189,6 +189,7 @@ struct vcpu_svm {
189 struct nested_state nested; 189 struct nested_state nested;
190 190
191 bool nmi_singlestep; 191 bool nmi_singlestep;
192 u64 nmi_singlestep_guest_rflags;
192 193
193 unsigned int3_injected; 194 unsigned int3_injected;
194 unsigned long int3_rip; 195 unsigned long int3_rip;
@@ -966,9 +967,13 @@ static void svm_disable_lbrv(struct vcpu_svm *svm)
966static void disable_nmi_singlestep(struct vcpu_svm *svm) 967static void disable_nmi_singlestep(struct vcpu_svm *svm)
967{ 968{
968 svm->nmi_singlestep = false; 969 svm->nmi_singlestep = false;
969 if (!(svm->vcpu.guest_debug & KVM_GUESTDBG_SINGLESTEP)) 970 if (!(svm->vcpu.guest_debug & KVM_GUESTDBG_SINGLESTEP)) {
970 svm->vmcb->save.rflags &= 971 /* Clear our flags if they were not set by the guest */
971 ~(X86_EFLAGS_TF | X86_EFLAGS_RF); 972 if (!(svm->nmi_singlestep_guest_rflags & X86_EFLAGS_TF))
973 svm->vmcb->save.rflags &= ~X86_EFLAGS_TF;
974 if (!(svm->nmi_singlestep_guest_rflags & X86_EFLAGS_RF))
975 svm->vmcb->save.rflags &= ~X86_EFLAGS_RF;
976 }
972} 977}
973 978
974/* Note: 979/* Note:
@@ -2538,6 +2543,31 @@ static int nested_svm_exit_handled_msr(struct vcpu_svm *svm)
2538 return (value & mask) ? NESTED_EXIT_DONE : NESTED_EXIT_HOST; 2543 return (value & mask) ? NESTED_EXIT_DONE : NESTED_EXIT_HOST;
2539} 2544}
2540 2545
2546/* DB exceptions for our internal use must not cause vmexit */
2547static int nested_svm_intercept_db(struct vcpu_svm *svm)
2548{
2549 unsigned long dr6;
2550
2551 /* if we're not singlestepping, it's not ours */
2552 if (!svm->nmi_singlestep)
2553 return NESTED_EXIT_DONE;
2554
2555 /* if it's not a singlestep exception, it's not ours */
2556 if (kvm_get_dr(&svm->vcpu, 6, &dr6))
2557 return NESTED_EXIT_DONE;
2558 if (!(dr6 & DR6_BS))
2559 return NESTED_EXIT_DONE;
2560
2561 /* if the guest is singlestepping, it should get the vmexit */
2562 if (svm->nmi_singlestep_guest_rflags & X86_EFLAGS_TF) {
2563 disable_nmi_singlestep(svm);
2564 return NESTED_EXIT_DONE;
2565 }
2566
2567 /* it's ours, the nested hypervisor must not see this one */
2568 return NESTED_EXIT_HOST;
2569}
2570
2541static int nested_svm_exit_special(struct vcpu_svm *svm) 2571static int nested_svm_exit_special(struct vcpu_svm *svm)
2542{ 2572{
2543 u32 exit_code = svm->vmcb->control.exit_code; 2573 u32 exit_code = svm->vmcb->control.exit_code;
@@ -2593,8 +2623,12 @@ static int nested_svm_intercept(struct vcpu_svm *svm)
2593 } 2623 }
2594 case SVM_EXIT_EXCP_BASE ... SVM_EXIT_EXCP_BASE + 0x1f: { 2624 case SVM_EXIT_EXCP_BASE ... SVM_EXIT_EXCP_BASE + 0x1f: {
2595 u32 excp_bits = 1 << (exit_code - SVM_EXIT_EXCP_BASE); 2625 u32 excp_bits = 1 << (exit_code - SVM_EXIT_EXCP_BASE);
2596 if (svm->nested.intercept_exceptions & excp_bits) 2626 if (svm->nested.intercept_exceptions & excp_bits) {
2597 vmexit = NESTED_EXIT_DONE; 2627 if (exit_code == SVM_EXIT_EXCP_BASE + DB_VECTOR)
2628 vmexit = nested_svm_intercept_db(svm);
2629 else
2630 vmexit = NESTED_EXIT_DONE;
2631 }
2598 /* async page fault always cause vmexit */ 2632 /* async page fault always cause vmexit */
2599 else if ((exit_code == SVM_EXIT_EXCP_BASE + PF_VECTOR) && 2633 else if ((exit_code == SVM_EXIT_EXCP_BASE + PF_VECTOR) &&
2600 svm->apf_reason != 0) 2634 svm->apf_reason != 0)
@@ -4635,6 +4669,7 @@ static void enable_nmi_window(struct kvm_vcpu *vcpu)
4635 * Something prevents NMI from been injected. Single step over possible 4669 * Something prevents NMI from been injected. Single step over possible
4636 * problem (IRET or exception injection or interrupt shadow) 4670 * problem (IRET or exception injection or interrupt shadow)
4637 */ 4671 */
4672 svm->nmi_singlestep_guest_rflags = svm_get_rflags(vcpu);
4638 svm->nmi_singlestep = true; 4673 svm->nmi_singlestep = true;
4639 svm->vmcb->save.rflags |= (X86_EFLAGS_TF | X86_EFLAGS_RF); 4674 svm->vmcb->save.rflags |= (X86_EFLAGS_TF | X86_EFLAGS_RF);
4640} 4675}