diff options
| author | Jan Kiszka <jan.kiszka@siemens.com> | 2014-01-04 12:47:16 -0500 |
|---|---|---|
| committer | Paolo Bonzini <pbonzini@redhat.com> | 2014-01-17 04:22:10 -0500 |
| commit | 73aaf249ee2287b4686ff079dcbdbbb658156e64 (patch) | |
| tree | 6b32cc40f12e7a91827b77e5648e7bcff1e4efd6 | |
| parent | 9926c9fdbdd54bb229fe6fdbd15ca3af2b8425ae (diff) | |
KVM: SVM: Fix reading of DR6
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>
| -rw-r--r-- | arch/x86/include/asm/kvm_host.h | 2 | ||||
| -rw-r--r-- | arch/x86/kvm/svm.c | 15 | ||||
| -rw-r--r-- | arch/x86/kvm/vmx.c | 11 | ||||
| -rw-r--r-- | arch/x86/kvm/x86.c | 19 |
4 files changed, 45 insertions, 2 deletions
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 33fef0738a29..fdf83afbb7d9 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h | |||
| @@ -700,6 +700,8 @@ struct kvm_x86_ops { | |||
| 700 | void (*set_idt)(struct kvm_vcpu *vcpu, struct desc_ptr *dt); | 700 | void (*set_idt)(struct kvm_vcpu *vcpu, struct desc_ptr *dt); |
| 701 | void (*get_gdt)(struct kvm_vcpu *vcpu, struct desc_ptr *dt); | 701 | void (*get_gdt)(struct kvm_vcpu *vcpu, struct desc_ptr *dt); |
| 702 | void (*set_gdt)(struct kvm_vcpu *vcpu, struct desc_ptr *dt); | 702 | void (*set_gdt)(struct kvm_vcpu *vcpu, struct desc_ptr *dt); |
| 703 | u64 (*get_dr6)(struct kvm_vcpu *vcpu); | ||
| 704 | void (*set_dr6)(struct kvm_vcpu *vcpu, unsigned long value); | ||
| 703 | void (*set_dr7)(struct kvm_vcpu *vcpu, unsigned long value); | 705 | void (*set_dr7)(struct kvm_vcpu *vcpu, unsigned long value); |
| 704 | void (*cache_reg)(struct kvm_vcpu *vcpu, enum kvm_reg reg); | 706 | void (*cache_reg)(struct kvm_vcpu *vcpu, enum kvm_reg reg); |
| 705 | unsigned long (*get_rflags)(struct kvm_vcpu *vcpu); | 707 | unsigned long (*get_rflags)(struct kvm_vcpu *vcpu); |
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index c7168a5cff1b..e81df8fce027 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c | |||
| @@ -1671,6 +1671,19 @@ static void new_asid(struct vcpu_svm *svm, struct svm_cpu_data *sd) | |||
| 1671 | mark_dirty(svm->vmcb, VMCB_ASID); | 1671 | mark_dirty(svm->vmcb, VMCB_ASID); |
| 1672 | } | 1672 | } |
| 1673 | 1673 | ||
| 1674 | static u64 svm_get_dr6(struct kvm_vcpu *vcpu) | ||
| 1675 | { | ||
| 1676 | return to_svm(vcpu)->vmcb->save.dr6; | ||
| 1677 | } | ||
| 1678 | |||
| 1679 | static void svm_set_dr6(struct kvm_vcpu *vcpu, unsigned long value) | ||
| 1680 | { | ||
| 1681 | struct vcpu_svm *svm = to_svm(vcpu); | ||
| 1682 | |||
| 1683 | svm->vmcb->save.dr6 = value; | ||
| 1684 | mark_dirty(svm->vmcb, VMCB_DR); | ||
| 1685 | } | ||
| 1686 | |||
| 1674 | static void svm_set_dr7(struct kvm_vcpu *vcpu, unsigned long value) | 1687 | static void svm_set_dr7(struct kvm_vcpu *vcpu, unsigned long value) |
| 1675 | { | 1688 | { |
| 1676 | struct vcpu_svm *svm = to_svm(vcpu); | 1689 | struct vcpu_svm *svm = to_svm(vcpu); |
| @@ -4286,6 +4299,8 @@ static struct kvm_x86_ops svm_x86_ops = { | |||
| 4286 | .set_idt = svm_set_idt, | 4299 | .set_idt = svm_set_idt, |
| 4287 | .get_gdt = svm_get_gdt, | 4300 | .get_gdt = svm_get_gdt, |
| 4288 | .set_gdt = svm_set_gdt, | 4301 | .set_gdt = svm_set_gdt, |
| 4302 | .get_dr6 = svm_get_dr6, | ||
| 4303 | .set_dr6 = svm_set_dr6, | ||
| 4289 | .set_dr7 = svm_set_dr7, | 4304 | .set_dr7 = svm_set_dr7, |
| 4290 | .cache_reg = svm_cache_reg, | 4305 | .cache_reg = svm_cache_reg, |
| 4291 | .get_rflags = svm_get_rflags, | 4306 | .get_rflags = svm_get_rflags, |
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 7661eb171936..79b360e4fed1 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c | |||
| @@ -5149,6 +5149,15 @@ static int handle_dr(struct kvm_vcpu *vcpu) | |||
| 5149 | return 1; | 5149 | return 1; |
| 5150 | } | 5150 | } |
| 5151 | 5151 | ||
| 5152 | static u64 vmx_get_dr6(struct kvm_vcpu *vcpu) | ||
| 5153 | { | ||
| 5154 | return vcpu->arch.dr6; | ||
| 5155 | } | ||
| 5156 | |||
| 5157 | static void vmx_set_dr6(struct kvm_vcpu *vcpu, unsigned long val) | ||
| 5158 | { | ||
| 5159 | } | ||
| 5160 | |||
| 5152 | static void vmx_set_dr7(struct kvm_vcpu *vcpu, unsigned long val) | 5161 | static void vmx_set_dr7(struct kvm_vcpu *vcpu, unsigned long val) |
| 5153 | { | 5162 | { |
| 5154 | vmcs_writel(GUEST_DR7, val); | 5163 | vmcs_writel(GUEST_DR7, val); |
| @@ -8556,6 +8565,8 @@ static struct kvm_x86_ops vmx_x86_ops = { | |||
| 8556 | .set_idt = vmx_set_idt, | 8565 | .set_idt = vmx_set_idt, |
| 8557 | .get_gdt = vmx_get_gdt, | 8566 | .get_gdt = vmx_get_gdt, |
| 8558 | .set_gdt = vmx_set_gdt, | 8567 | .set_gdt = vmx_set_gdt, |
| 8568 | .get_dr6 = vmx_get_dr6, | ||
| 8569 | .set_dr6 = vmx_set_dr6, | ||
| 8559 | .set_dr7 = vmx_set_dr7, | 8570 | .set_dr7 = vmx_set_dr7, |
| 8560 | .cache_reg = vmx_cache_reg, | 8571 | .cache_reg = vmx_cache_reg, |
| 8561 | .get_rflags = vmx_get_rflags, | 8572 | .get_rflags = vmx_get_rflags, |
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 59907c9a9d05..59b95b1a04dc 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
| @@ -722,6 +722,12 @@ unsigned long kvm_get_cr8(struct kvm_vcpu *vcpu) | |||
| 722 | } | 722 | } |
| 723 | EXPORT_SYMBOL_GPL(kvm_get_cr8); | 723 | EXPORT_SYMBOL_GPL(kvm_get_cr8); |
| 724 | 724 | ||
| 725 | static void kvm_update_dr6(struct kvm_vcpu *vcpu) | ||
| 726 | { | ||
| 727 | if (!(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP)) | ||
| 728 | kvm_x86_ops->set_dr6(vcpu, vcpu->arch.dr6); | ||
| 729 | } | ||
| 730 | |||
| 725 | static void kvm_update_dr7(struct kvm_vcpu *vcpu) | 731 | static void kvm_update_dr7(struct kvm_vcpu *vcpu) |
| 726 | { | 732 | { |
| 727 | unsigned long dr7; | 733 | unsigned long dr7; |
| @@ -750,6 +756,7 @@ static int __kvm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long val) | |||
| 750 | if (val & 0xffffffff00000000ULL) | 756 | if (val & 0xffffffff00000000ULL) |
| 751 | return -1; /* #GP */ | 757 | return -1; /* #GP */ |
| 752 | vcpu->arch.dr6 = (val & DR6_VOLATILE) | DR6_FIXED_1; | 758 | vcpu->arch.dr6 = (val & DR6_VOLATILE) | DR6_FIXED_1; |
| 759 | kvm_update_dr6(vcpu); | ||
| 753 | break; | 760 | break; |
| 754 | case 5: | 761 | case 5: |
| 755 | if (kvm_read_cr4_bits(vcpu, X86_CR4_DE)) | 762 | 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) | |||
| 791 | return 1; | 798 | return 1; |
| 792 | /* fall through */ | 799 | /* fall through */ |
| 793 | case 6: | 800 | case 6: |
| 794 | *val = vcpu->arch.dr6; | 801 | if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP) |
| 802 | *val = vcpu->arch.dr6; | ||
| 803 | else | ||
| 804 | *val = kvm_x86_ops->get_dr6(vcpu); | ||
| 795 | break; | 805 | break; |
| 796 | case 5: | 806 | case 5: |
| 797 | if (kvm_read_cr4_bits(vcpu, X86_CR4_DE)) | 807 | 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, | |||
| 2960 | static void kvm_vcpu_ioctl_x86_get_debugregs(struct kvm_vcpu *vcpu, | 2970 | static void kvm_vcpu_ioctl_x86_get_debugregs(struct kvm_vcpu *vcpu, |
| 2961 | struct kvm_debugregs *dbgregs) | 2971 | struct kvm_debugregs *dbgregs) |
| 2962 | { | 2972 | { |
| 2973 | unsigned long val; | ||
| 2974 | |||
| 2963 | memcpy(dbgregs->db, vcpu->arch.db, sizeof(vcpu->arch.db)); | 2975 | memcpy(dbgregs->db, vcpu->arch.db, sizeof(vcpu->arch.db)); |
| 2964 | dbgregs->dr6 = vcpu->arch.dr6; | 2976 | _kvm_get_dr(vcpu, 6, &val); |
| 2977 | dbgregs->dr6 = val; | ||
| 2965 | dbgregs->dr7 = vcpu->arch.dr7; | 2978 | dbgregs->dr7 = vcpu->arch.dr7; |
| 2966 | dbgregs->flags = 0; | 2979 | dbgregs->flags = 0; |
| 2967 | memset(&dbgregs->reserved, 0, sizeof(dbgregs->reserved)); | 2980 | memset(&dbgregs->reserved, 0, sizeof(dbgregs->reserved)); |
| @@ -2975,6 +2988,7 @@ static int kvm_vcpu_ioctl_x86_set_debugregs(struct kvm_vcpu *vcpu, | |||
| 2975 | 2988 | ||
| 2976 | memcpy(vcpu->arch.db, dbgregs->db, sizeof(vcpu->arch.db)); | 2989 | memcpy(vcpu->arch.db, dbgregs->db, sizeof(vcpu->arch.db)); |
| 2977 | vcpu->arch.dr6 = dbgregs->dr6; | 2990 | vcpu->arch.dr6 = dbgregs->dr6; |
| 2991 | kvm_update_dr6(vcpu); | ||
| 2978 | vcpu->arch.dr7 = dbgregs->dr7; | 2992 | vcpu->arch.dr7 = dbgregs->dr7; |
| 2979 | kvm_update_dr7(vcpu); | 2993 | kvm_update_dr7(vcpu); |
| 2980 | 2994 | ||
| @@ -6749,6 +6763,7 @@ void kvm_vcpu_reset(struct kvm_vcpu *vcpu) | |||
| 6749 | 6763 | ||
| 6750 | memset(vcpu->arch.db, 0, sizeof(vcpu->arch.db)); | 6764 | memset(vcpu->arch.db, 0, sizeof(vcpu->arch.db)); |
| 6751 | vcpu->arch.dr6 = DR6_FIXED_1; | 6765 | vcpu->arch.dr6 = DR6_FIXED_1; |
| 6766 | kvm_update_dr6(vcpu); | ||
| 6752 | vcpu->arch.dr7 = DR7_FIXED_1; | 6767 | vcpu->arch.dr7 = DR7_FIXED_1; |
| 6753 | kvm_update_dr7(vcpu); | 6768 | kvm_update_dr7(vcpu); |
| 6754 | 6769 | ||
