aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kvm/vmx.c
diff options
context:
space:
mode:
authorNadav Amit <namit@cs.technion.ac.il>2014-10-02 18:10:05 -0400
committerPaolo Bonzini <pbonzini@redhat.com>2014-11-03 06:07:26 -0500
commit16f8a6f9798ab9a1fd593b06b78925d02525ab81 (patch)
treebacce115367ea875e4549d535fba9fbf429a2760 /arch/x86/kvm/vmx.c
parentc49c759f7a68b70d2fed019760a66843b3df39b8 (diff)
KVM: vmx: Unavailable DR4/5 is checked before CPL
If DR4/5 is accessed when it is unavailable (since CR4.DE is set), then #UD should be generated even if CPL>0. This is according to Intel SDM Table 6-2: "Priority Among Simultaneous Exceptions and Interrupts". Note, that this may happen on the first DR access, even if the host does not sets debug breakpoints. Obviously, it occurs when the host debugs the guest. This patch moves the DR4/5 checks from __kvm_set_dr/_kvm_get_dr to handle_dr. The emulator already checks DR4/5 availability in check_dr_read. Nested virutalization related calls to kvm_set_dr/kvm_get_dr would not like to inject exceptions to the guest. As for SVM, the patch follows the previous logic as much as possible. Anyhow, it appears the DR interception code might be buggy - even if the DR access may cause an exception, the instruction is skipped. Signed-off-by: Nadav Amit <namit@cs.technion.ac.il> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'arch/x86/kvm/vmx.c')
-rw-r--r--arch/x86/kvm/vmx.c17
1 files changed, 11 insertions, 6 deletions
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 30e6e184ff09..0cd99d8405f8 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -5163,13 +5163,20 @@ static int handle_cr(struct kvm_vcpu *vcpu)
5163static int handle_dr(struct kvm_vcpu *vcpu) 5163static int handle_dr(struct kvm_vcpu *vcpu)
5164{ 5164{
5165 unsigned long exit_qualification; 5165 unsigned long exit_qualification;
5166 int dr, reg; 5166 int dr, dr7, reg;
5167
5168 exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
5169 dr = exit_qualification & DEBUG_REG_ACCESS_NUM;
5170
5171 /* First, if DR does not exist, trigger UD */
5172 if (!kvm_require_dr(vcpu, dr))
5173 return 1;
5167 5174
5168 /* Do not handle if the CPL > 0, will trigger GP on re-entry */ 5175 /* Do not handle if the CPL > 0, will trigger GP on re-entry */
5169 if (!kvm_require_cpl(vcpu, 0)) 5176 if (!kvm_require_cpl(vcpu, 0))
5170 return 1; 5177 return 1;
5171 dr = vmcs_readl(GUEST_DR7); 5178 dr7 = vmcs_readl(GUEST_DR7);
5172 if (dr & DR7_GD) { 5179 if (dr7 & DR7_GD) {
5173 /* 5180 /*
5174 * As the vm-exit takes precedence over the debug trap, we 5181 * As the vm-exit takes precedence over the debug trap, we
5175 * need to emulate the latter, either for the host or the 5182 * need to emulate the latter, either for the host or the
@@ -5177,7 +5184,7 @@ static int handle_dr(struct kvm_vcpu *vcpu)
5177 */ 5184 */
5178 if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP) { 5185 if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP) {
5179 vcpu->run->debug.arch.dr6 = vcpu->arch.dr6; 5186 vcpu->run->debug.arch.dr6 = vcpu->arch.dr6;
5180 vcpu->run->debug.arch.dr7 = dr; 5187 vcpu->run->debug.arch.dr7 = dr7;
5181 vcpu->run->debug.arch.pc = 5188 vcpu->run->debug.arch.pc =
5182 vmcs_readl(GUEST_CS_BASE) + 5189 vmcs_readl(GUEST_CS_BASE) +
5183 vmcs_readl(GUEST_RIP); 5190 vmcs_readl(GUEST_RIP);
@@ -5207,8 +5214,6 @@ static int handle_dr(struct kvm_vcpu *vcpu)
5207 return 1; 5214 return 1;
5208 } 5215 }
5209 5216
5210 exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
5211 dr = exit_qualification & DEBUG_REG_ACCESS_NUM;
5212 reg = DEBUG_REG_ACCESS_REG(exit_qualification); 5217 reg = DEBUG_REG_ACCESS_REG(exit_qualification);
5213 if (exit_qualification & TYPE_MOV_FROM_DR) { 5218 if (exit_qualification & TYPE_MOV_FROM_DR) {
5214 unsigned long val; 5219 unsigned long val;