diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/kvm/x86.c | 66 |
1 files changed, 66 insertions, 0 deletions
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 8589cc02789e..89313187d7f7 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
@@ -4956,6 +4956,62 @@ static bool retry_instruction(struct x86_emulate_ctxt *ctxt, | |||
4956 | static int complete_emulated_mmio(struct kvm_vcpu *vcpu); | 4956 | static int complete_emulated_mmio(struct kvm_vcpu *vcpu); |
4957 | static int complete_emulated_pio(struct kvm_vcpu *vcpu); | 4957 | static int complete_emulated_pio(struct kvm_vcpu *vcpu); |
4958 | 4958 | ||
4959 | static int kvm_vcpu_check_hw_bp(unsigned long addr, u32 type, u32 dr7, | ||
4960 | unsigned long *db) | ||
4961 | { | ||
4962 | u32 dr6 = 0; | ||
4963 | int i; | ||
4964 | u32 enable, rwlen; | ||
4965 | |||
4966 | enable = dr7; | ||
4967 | rwlen = dr7 >> 16; | ||
4968 | for (i = 0; i < 4; i++, enable >>= 2, rwlen >>= 4) | ||
4969 | if ((enable & 3) && (rwlen & 15) == type && db[i] == addr) | ||
4970 | dr6 |= (1 << i); | ||
4971 | return dr6; | ||
4972 | } | ||
4973 | |||
4974 | static bool kvm_vcpu_check_breakpoint(struct kvm_vcpu *vcpu, int *r) | ||
4975 | { | ||
4976 | struct kvm_run *kvm_run = vcpu->run; | ||
4977 | unsigned long eip = vcpu->arch.emulate_ctxt.eip; | ||
4978 | u32 dr6 = 0; | ||
4979 | |||
4980 | if (unlikely(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP) && | ||
4981 | (vcpu->arch.guest_debug_dr7 & DR7_BP_EN_MASK)) { | ||
4982 | dr6 = kvm_vcpu_check_hw_bp(eip, 0, | ||
4983 | vcpu->arch.guest_debug_dr7, | ||
4984 | vcpu->arch.eff_db); | ||
4985 | |||
4986 | if (dr6 != 0) { | ||
4987 | kvm_run->debug.arch.dr6 = dr6 | DR6_FIXED_1; | ||
4988 | kvm_run->debug.arch.pc = kvm_rip_read(vcpu) + | ||
4989 | get_segment_base(vcpu, VCPU_SREG_CS); | ||
4990 | |||
4991 | kvm_run->debug.arch.exception = DB_VECTOR; | ||
4992 | kvm_run->exit_reason = KVM_EXIT_DEBUG; | ||
4993 | *r = EMULATE_USER_EXIT; | ||
4994 | return true; | ||
4995 | } | ||
4996 | } | ||
4997 | |||
4998 | if (unlikely(vcpu->arch.dr7 & DR7_BP_EN_MASK)) { | ||
4999 | dr6 = kvm_vcpu_check_hw_bp(eip, 0, | ||
5000 | vcpu->arch.dr7, | ||
5001 | vcpu->arch.db); | ||
5002 | |||
5003 | if (dr6 != 0) { | ||
5004 | vcpu->arch.dr6 &= ~15; | ||
5005 | vcpu->arch.dr6 |= dr6; | ||
5006 | kvm_queue_exception(vcpu, DB_VECTOR); | ||
5007 | *r = EMULATE_DONE; | ||
5008 | return true; | ||
5009 | } | ||
5010 | } | ||
5011 | |||
5012 | return false; | ||
5013 | } | ||
5014 | |||
4959 | int x86_emulate_instruction(struct kvm_vcpu *vcpu, | 5015 | int x86_emulate_instruction(struct kvm_vcpu *vcpu, |
4960 | unsigned long cr2, | 5016 | unsigned long cr2, |
4961 | int emulation_type, | 5017 | int emulation_type, |
@@ -4976,6 +5032,16 @@ int x86_emulate_instruction(struct kvm_vcpu *vcpu, | |||
4976 | 5032 | ||
4977 | if (!(emulation_type & EMULTYPE_NO_DECODE)) { | 5033 | if (!(emulation_type & EMULTYPE_NO_DECODE)) { |
4978 | init_emulate_ctxt(vcpu); | 5034 | init_emulate_ctxt(vcpu); |
5035 | |||
5036 | /* | ||
5037 | * We will reenter on the same instruction since | ||
5038 | * we do not set complete_userspace_io. This does not | ||
5039 | * handle watchpoints yet, those would be handled in | ||
5040 | * the emulate_ops. | ||
5041 | */ | ||
5042 | if (kvm_vcpu_check_breakpoint(vcpu, &r)) | ||
5043 | return r; | ||
5044 | |||
4979 | ctxt->interruptibility = 0; | 5045 | ctxt->interruptibility = 0; |
4980 | ctxt->have_exception = false; | 5046 | ctxt->have_exception = false; |
4981 | ctxt->perm_ok = false; | 5047 | ctxt->perm_ok = false; |