diff options
Diffstat (limited to 'arch/x86/kvm/svm.c')
-rw-r--r-- | arch/x86/kvm/svm.c | 50 |
1 files changed, 48 insertions, 2 deletions
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 0fbbde54ecae..88d9062f4545 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c | |||
@@ -968,9 +968,32 @@ static void svm_set_segment(struct kvm_vcpu *vcpu, | |||
968 | 968 | ||
969 | } | 969 | } |
970 | 970 | ||
971 | static int svm_guest_debug(struct kvm_vcpu *vcpu, struct kvm_debug_guest *dbg) | 971 | static int svm_guest_debug(struct kvm_vcpu *vcpu, struct kvm_guest_debug *dbg) |
972 | { | 972 | { |
973 | return -EOPNOTSUPP; | 973 | int old_debug = vcpu->guest_debug; |
974 | struct vcpu_svm *svm = to_svm(vcpu); | ||
975 | |||
976 | vcpu->guest_debug = dbg->control; | ||
977 | |||
978 | svm->vmcb->control.intercept_exceptions &= | ||
979 | ~((1 << DB_VECTOR) | (1 << BP_VECTOR)); | ||
980 | if (vcpu->guest_debug & KVM_GUESTDBG_ENABLE) { | ||
981 | if (vcpu->guest_debug & | ||
982 | (KVM_GUESTDBG_SINGLESTEP | KVM_GUESTDBG_USE_HW_BP)) | ||
983 | svm->vmcb->control.intercept_exceptions |= | ||
984 | 1 << DB_VECTOR; | ||
985 | if (vcpu->guest_debug & KVM_GUESTDBG_USE_SW_BP) | ||
986 | svm->vmcb->control.intercept_exceptions |= | ||
987 | 1 << BP_VECTOR; | ||
988 | } else | ||
989 | vcpu->guest_debug = 0; | ||
990 | |||
991 | if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) | ||
992 | svm->vmcb->save.rflags |= X86_EFLAGS_TF | X86_EFLAGS_RF; | ||
993 | else if (old_debug & KVM_GUESTDBG_SINGLESTEP) | ||
994 | svm->vmcb->save.rflags &= ~(X86_EFLAGS_TF | X86_EFLAGS_RF); | ||
995 | |||
996 | return 0; | ||
974 | } | 997 | } |
975 | 998 | ||
976 | static int svm_get_irq(struct kvm_vcpu *vcpu) | 999 | static int svm_get_irq(struct kvm_vcpu *vcpu) |
@@ -1094,6 +1117,27 @@ static int pf_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) | |||
1094 | return kvm_mmu_page_fault(&svm->vcpu, fault_address, error_code); | 1117 | return kvm_mmu_page_fault(&svm->vcpu, fault_address, error_code); |
1095 | } | 1118 | } |
1096 | 1119 | ||
1120 | static int db_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) | ||
1121 | { | ||
1122 | if (!(svm->vcpu.guest_debug & | ||
1123 | (KVM_GUESTDBG_SINGLESTEP | KVM_GUESTDBG_USE_HW_BP))) { | ||
1124 | kvm_queue_exception(&svm->vcpu, DB_VECTOR); | ||
1125 | return 1; | ||
1126 | } | ||
1127 | kvm_run->exit_reason = KVM_EXIT_DEBUG; | ||
1128 | kvm_run->debug.arch.pc = svm->vmcb->save.cs.base + svm->vmcb->save.rip; | ||
1129 | kvm_run->debug.arch.exception = DB_VECTOR; | ||
1130 | return 0; | ||
1131 | } | ||
1132 | |||
1133 | static int bp_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) | ||
1134 | { | ||
1135 | kvm_run->exit_reason = KVM_EXIT_DEBUG; | ||
1136 | kvm_run->debug.arch.pc = svm->vmcb->save.cs.base + svm->vmcb->save.rip; | ||
1137 | kvm_run->debug.arch.exception = BP_VECTOR; | ||
1138 | return 0; | ||
1139 | } | ||
1140 | |||
1097 | static int ud_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) | 1141 | static int ud_interception(struct vcpu_svm *svm, struct kvm_run *kvm_run) |
1098 | { | 1142 | { |
1099 | int er; | 1143 | int er; |
@@ -2050,6 +2094,8 @@ static int (*svm_exit_handlers[])(struct vcpu_svm *svm, | |||
2050 | [SVM_EXIT_WRITE_DR3] = emulate_on_interception, | 2094 | [SVM_EXIT_WRITE_DR3] = emulate_on_interception, |
2051 | [SVM_EXIT_WRITE_DR5] = emulate_on_interception, | 2095 | [SVM_EXIT_WRITE_DR5] = emulate_on_interception, |
2052 | [SVM_EXIT_WRITE_DR7] = emulate_on_interception, | 2096 | [SVM_EXIT_WRITE_DR7] = emulate_on_interception, |
2097 | [SVM_EXIT_EXCP_BASE + DB_VECTOR] = db_interception, | ||
2098 | [SVM_EXIT_EXCP_BASE + BP_VECTOR] = bp_interception, | ||
2053 | [SVM_EXIT_EXCP_BASE + UD_VECTOR] = ud_interception, | 2099 | [SVM_EXIT_EXCP_BASE + UD_VECTOR] = ud_interception, |
2054 | [SVM_EXIT_EXCP_BASE + PF_VECTOR] = pf_interception, | 2100 | [SVM_EXIT_EXCP_BASE + PF_VECTOR] = pf_interception, |
2055 | [SVM_EXIT_EXCP_BASE + NM_VECTOR] = nm_interception, | 2101 | [SVM_EXIT_EXCP_BASE + NM_VECTOR] = nm_interception, |