KVM: VMX: Fix emulation of DR4 and DR5
authorJan Kiszka <jan.kiszka@siemens.com>
Wed, 20 Jan 2010 17:20:20 +0000 (18:20 +0100)
committerMarcelo Tosatti <mtosatti@redhat.com>
Mon, 1 Mar 2010 15:36:01 +0000 (12:36 -0300)
Make sure DR4 and DR5 are aliased to DR6 and DR7, respectively, if
CR4.DE is not set.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
arch/x86/kvm/vmx.c

index 9727773..c7b99e1 100644 (file)
@@ -3039,6 +3039,15 @@ static int handle_cr(struct kvm_vcpu *vcpu)
        return 0;
 }
 
        return 0;
 }
 
+static int check_dr_alias(struct kvm_vcpu *vcpu)
+{
+       if (kvm_read_cr4_bits(vcpu, X86_CR4_DE)) {
+               kvm_queue_exception(vcpu, UD_VECTOR);
+               return -1;
+       }
+       return 0;
+}
+
 static int handle_dr(struct kvm_vcpu *vcpu)
 {
        unsigned long exit_qualification;
 static int handle_dr(struct kvm_vcpu *vcpu)
 {
        unsigned long exit_qualification;
@@ -3081,14 +3090,20 @@ static int handle_dr(struct kvm_vcpu *vcpu)
                case 0 ... 3:
                        val = vcpu->arch.db[dr];
                        break;
                case 0 ... 3:
                        val = vcpu->arch.db[dr];
                        break;
+               case 4:
+                       if (check_dr_alias(vcpu) < 0)
+                               return 1;
+                       /* fall through */
                case 6:
                        val = vcpu->arch.dr6;
                        break;
                case 6:
                        val = vcpu->arch.dr6;
                        break;
-               case 7:
+               case 5:
+                       if (check_dr_alias(vcpu) < 0)
+                               return 1;
+                       /* fall through */
+               default: /* 7 */
                        val = vcpu->arch.dr7;
                        break;
                        val = vcpu->arch.dr7;
                        break;
-               default:
-                       val = 0;
                }
                kvm_register_write(vcpu, reg, val);
        } else {
                }
                kvm_register_write(vcpu, reg, val);
        } else {
@@ -3099,12 +3114,10 @@ static int handle_dr(struct kvm_vcpu *vcpu)
                        if (!(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP))
                                vcpu->arch.eff_db[dr] = val;
                        break;
                        if (!(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP))
                                vcpu->arch.eff_db[dr] = val;
                        break;
-               case 4 ... 5:
-                       if (kvm_read_cr4_bits(vcpu, X86_CR4_DE)) {
-                               kvm_queue_exception(vcpu, UD_VECTOR);
+               case 4:
+                       if (check_dr_alias(vcpu) < 0)
                                return 1;
                                return 1;
-                       }
-                       break;
+                       /* fall through */
                case 6:
                        if (val & 0xffffffff00000000ULL) {
                                kvm_inject_gp(vcpu, 0);
                case 6:
                        if (val & 0xffffffff00000000ULL) {
                                kvm_inject_gp(vcpu, 0);
@@ -3112,7 +3125,11 @@ static int handle_dr(struct kvm_vcpu *vcpu)
                        }
                        vcpu->arch.dr6 = (val & DR6_VOLATILE) | DR6_FIXED_1;
                        break;
                        }
                        vcpu->arch.dr6 = (val & DR6_VOLATILE) | DR6_FIXED_1;
                        break;
-               case 7:
+               case 5:
+                       if (check_dr_alias(vcpu) < 0)
+                               return 1;
+                       /* fall through */
+               default: /* 7 */
                        if (val & 0xffffffff00000000ULL) {
                                kvm_inject_gp(vcpu, 0);
                                return 1;
                        if (val & 0xffffffff00000000ULL) {
                                kvm_inject_gp(vcpu, 0);
                                return 1;