]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
KVM: SVM: Fix reading of DR6
authorJan Kiszka <jan.kiszka@siemens.com>
Sat, 4 Jan 2014 17:47:16 +0000 (18:47 +0100)
committerPaolo Bonzini <pbonzini@redhat.com>
Fri, 17 Jan 2014 09:22:10 +0000 (10:22 +0100)
In contrast to VMX, SVM dose not automatically transfer DR6 into the
VCPU's arch.dr6. So if we face a DR6 read, we must consult a new vendor
hook to obtain the current value. And as SVM now picks the DR6 state
from its VMCB, we also need a set callback in order to write updates of
DR6 back.

Fixes a regression of 020df0794f.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
arch/x86/include/asm/kvm_host.h
arch/x86/kvm/svm.c
arch/x86/kvm/vmx.c
arch/x86/kvm/x86.c

index 33fef0738a297470b414b14ba21c6db668dcf12d..fdf83afbb7d9af3b5c1f55468fe1e1dcdf1af54b 100644 (file)
@@ -700,6 +700,8 @@ struct kvm_x86_ops {
        void (*set_idt)(struct kvm_vcpu *vcpu, struct desc_ptr *dt);
        void (*get_gdt)(struct kvm_vcpu *vcpu, struct desc_ptr *dt);
        void (*set_gdt)(struct kvm_vcpu *vcpu, struct desc_ptr *dt);
+       u64 (*get_dr6)(struct kvm_vcpu *vcpu);
+       void (*set_dr6)(struct kvm_vcpu *vcpu, unsigned long value);
        void (*set_dr7)(struct kvm_vcpu *vcpu, unsigned long value);
        void (*cache_reg)(struct kvm_vcpu *vcpu, enum kvm_reg reg);
        unsigned long (*get_rflags)(struct kvm_vcpu *vcpu);
index c7168a5cff1b33ad454cc85176695cb0c7394dfc..e81df8fce0275781a654f356fe77e38129d5210a 100644 (file)
@@ -1671,6 +1671,19 @@ static void new_asid(struct vcpu_svm *svm, struct svm_cpu_data *sd)
        mark_dirty(svm->vmcb, VMCB_ASID);
 }
 
+static u64 svm_get_dr6(struct kvm_vcpu *vcpu)
+{
+       return to_svm(vcpu)->vmcb->save.dr6;
+}
+
+static void svm_set_dr6(struct kvm_vcpu *vcpu, unsigned long value)
+{
+       struct vcpu_svm *svm = to_svm(vcpu);
+
+       svm->vmcb->save.dr6 = value;
+       mark_dirty(svm->vmcb, VMCB_DR);
+}
+
 static void svm_set_dr7(struct kvm_vcpu *vcpu, unsigned long value)
 {
        struct vcpu_svm *svm = to_svm(vcpu);
@@ -4286,6 +4299,8 @@ static struct kvm_x86_ops svm_x86_ops = {
        .set_idt = svm_set_idt,
        .get_gdt = svm_get_gdt,
        .set_gdt = svm_set_gdt,
+       .get_dr6 = svm_get_dr6,
+       .set_dr6 = svm_set_dr6,
        .set_dr7 = svm_set_dr7,
        .cache_reg = svm_cache_reg,
        .get_rflags = svm_get_rflags,
index 7661eb17193643b0a5b89446f4a8491b1bb7a04c..79b360e4fed12b63b97e508469fea92d22af9d0f 100644 (file)
@@ -5149,6 +5149,15 @@ static int handle_dr(struct kvm_vcpu *vcpu)
        return 1;
 }
 
+static u64 vmx_get_dr6(struct kvm_vcpu *vcpu)
+{
+       return vcpu->arch.dr6;
+}
+
+static void vmx_set_dr6(struct kvm_vcpu *vcpu, unsigned long val)
+{
+}
+
 static void vmx_set_dr7(struct kvm_vcpu *vcpu, unsigned long val)
 {
        vmcs_writel(GUEST_DR7, val);
@@ -8556,6 +8565,8 @@ static struct kvm_x86_ops vmx_x86_ops = {
        .set_idt = vmx_set_idt,
        .get_gdt = vmx_get_gdt,
        .set_gdt = vmx_set_gdt,
+       .get_dr6 = vmx_get_dr6,
+       .set_dr6 = vmx_set_dr6,
        .set_dr7 = vmx_set_dr7,
        .cache_reg = vmx_cache_reg,
        .get_rflags = vmx_get_rflags,
index 59907c9a9d05c7b3d1a6ed90a05b4992cc5e0db2..59b95b1a04dc213a98aa53312193a07bf11227f3 100644 (file)
@@ -722,6 +722,12 @@ unsigned long kvm_get_cr8(struct kvm_vcpu *vcpu)
 }
 EXPORT_SYMBOL_GPL(kvm_get_cr8);
 
+static void kvm_update_dr6(struct kvm_vcpu *vcpu)
+{
+       if (!(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP))
+               kvm_x86_ops->set_dr6(vcpu, vcpu->arch.dr6);
+}
+
 static void kvm_update_dr7(struct kvm_vcpu *vcpu)
 {
        unsigned long dr7;
@@ -750,6 +756,7 @@ static int __kvm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long val)
                if (val & 0xffffffff00000000ULL)
                        return -1; /* #GP */
                vcpu->arch.dr6 = (val & DR6_VOLATILE) | DR6_FIXED_1;
+               kvm_update_dr6(vcpu);
                break;
        case 5:
                if (kvm_read_cr4_bits(vcpu, X86_CR4_DE))
@@ -791,7 +798,10 @@ static int _kvm_get_dr(struct kvm_vcpu *vcpu, int dr, unsigned long *val)
                        return 1;
                /* fall through */
        case 6:
-               *val = vcpu->arch.dr6;
+               if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP)
+                       *val = vcpu->arch.dr6;
+               else
+                       *val = kvm_x86_ops->get_dr6(vcpu);
                break;
        case 5:
                if (kvm_read_cr4_bits(vcpu, X86_CR4_DE))
@@ -2960,8 +2970,11 @@ static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu,
 static void kvm_vcpu_ioctl_x86_get_debugregs(struct kvm_vcpu *vcpu,
                                             struct kvm_debugregs *dbgregs)
 {
+       unsigned long val;
+
        memcpy(dbgregs->db, vcpu->arch.db, sizeof(vcpu->arch.db));
-       dbgregs->dr6 = vcpu->arch.dr6;
+       _kvm_get_dr(vcpu, 6, &val);
+       dbgregs->dr6 = val;
        dbgregs->dr7 = vcpu->arch.dr7;
        dbgregs->flags = 0;
        memset(&dbgregs->reserved, 0, sizeof(dbgregs->reserved));
@@ -2975,6 +2988,7 @@ static int kvm_vcpu_ioctl_x86_set_debugregs(struct kvm_vcpu *vcpu,
 
        memcpy(vcpu->arch.db, dbgregs->db, sizeof(vcpu->arch.db));
        vcpu->arch.dr6 = dbgregs->dr6;
+       kvm_update_dr6(vcpu);
        vcpu->arch.dr7 = dbgregs->dr7;
        kvm_update_dr7(vcpu);
 
@@ -6749,6 +6763,7 @@ void kvm_vcpu_reset(struct kvm_vcpu *vcpu)
 
        memset(vcpu->arch.db, 0, sizeof(vcpu->arch.db));
        vcpu->arch.dr6 = DR6_FIXED_1;
+       kvm_update_dr6(vcpu);
        vcpu->arch.dr7 = DR7_FIXED_1;
        kvm_update_dr7(vcpu);