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>
This commit is contained in:
Jan Kiszka 2014-01-04 18:47:16 +01:00 committed by Paolo Bonzini
parent 9926c9fdbd
commit 73aaf249ee
4 changed files with 45 additions and 2 deletions

View file

@ -700,6 +700,8 @@ struct kvm_x86_ops {
void (*set_idt)(struct kvm_vcpu *vcpu, struct desc_ptr *dt); void (*set_idt)(struct kvm_vcpu *vcpu, struct desc_ptr *dt);
void (*get_gdt)(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); 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 (*set_dr7)(struct kvm_vcpu *vcpu, unsigned long value);
void (*cache_reg)(struct kvm_vcpu *vcpu, enum kvm_reg reg); void (*cache_reg)(struct kvm_vcpu *vcpu, enum kvm_reg reg);
unsigned long (*get_rflags)(struct kvm_vcpu *vcpu); unsigned long (*get_rflags)(struct kvm_vcpu *vcpu);

View file

@ -1671,6 +1671,19 @@ static void new_asid(struct vcpu_svm *svm, struct svm_cpu_data *sd)
mark_dirty(svm->vmcb, VMCB_ASID); 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) static void svm_set_dr7(struct kvm_vcpu *vcpu, unsigned long value)
{ {
struct vcpu_svm *svm = to_svm(vcpu); struct vcpu_svm *svm = to_svm(vcpu);
@ -4286,6 +4299,8 @@ static struct kvm_x86_ops svm_x86_ops = {
.set_idt = svm_set_idt, .set_idt = svm_set_idt,
.get_gdt = svm_get_gdt, .get_gdt = svm_get_gdt,
.set_gdt = svm_set_gdt, .set_gdt = svm_set_gdt,
.get_dr6 = svm_get_dr6,
.set_dr6 = svm_set_dr6,
.set_dr7 = svm_set_dr7, .set_dr7 = svm_set_dr7,
.cache_reg = svm_cache_reg, .cache_reg = svm_cache_reg,
.get_rflags = svm_get_rflags, .get_rflags = svm_get_rflags,

View file

@ -5149,6 +5149,15 @@ static int handle_dr(struct kvm_vcpu *vcpu)
return 1; 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) static void vmx_set_dr7(struct kvm_vcpu *vcpu, unsigned long val)
{ {
vmcs_writel(GUEST_DR7, val); vmcs_writel(GUEST_DR7, val);
@ -8556,6 +8565,8 @@ static struct kvm_x86_ops vmx_x86_ops = {
.set_idt = vmx_set_idt, .set_idt = vmx_set_idt,
.get_gdt = vmx_get_gdt, .get_gdt = vmx_get_gdt,
.set_gdt = vmx_set_gdt, .set_gdt = vmx_set_gdt,
.get_dr6 = vmx_get_dr6,
.set_dr6 = vmx_set_dr6,
.set_dr7 = vmx_set_dr7, .set_dr7 = vmx_set_dr7,
.cache_reg = vmx_cache_reg, .cache_reg = vmx_cache_reg,
.get_rflags = vmx_get_rflags, .get_rflags = vmx_get_rflags,

View file

@ -722,6 +722,12 @@ unsigned long kvm_get_cr8(struct kvm_vcpu *vcpu)
} }
EXPORT_SYMBOL_GPL(kvm_get_cr8); 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) static void kvm_update_dr7(struct kvm_vcpu *vcpu)
{ {
unsigned long dr7; unsigned long dr7;
@ -750,6 +756,7 @@ static int __kvm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long val)
if (val & 0xffffffff00000000ULL) if (val & 0xffffffff00000000ULL)
return -1; /* #GP */ return -1; /* #GP */
vcpu->arch.dr6 = (val & DR6_VOLATILE) | DR6_FIXED_1; vcpu->arch.dr6 = (val & DR6_VOLATILE) | DR6_FIXED_1;
kvm_update_dr6(vcpu);
break; break;
case 5: case 5:
if (kvm_read_cr4_bits(vcpu, X86_CR4_DE)) 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; return 1;
/* fall through */ /* fall through */
case 6: 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; break;
case 5: case 5:
if (kvm_read_cr4_bits(vcpu, X86_CR4_DE)) 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, static void kvm_vcpu_ioctl_x86_get_debugregs(struct kvm_vcpu *vcpu,
struct kvm_debugregs *dbgregs) struct kvm_debugregs *dbgregs)
{ {
unsigned long val;
memcpy(dbgregs->db, vcpu->arch.db, sizeof(vcpu->arch.db)); 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->dr7 = vcpu->arch.dr7;
dbgregs->flags = 0; dbgregs->flags = 0;
memset(&dbgregs->reserved, 0, sizeof(dbgregs->reserved)); 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)); memcpy(vcpu->arch.db, dbgregs->db, sizeof(vcpu->arch.db));
vcpu->arch.dr6 = dbgregs->dr6; vcpu->arch.dr6 = dbgregs->dr6;
kvm_update_dr6(vcpu);
vcpu->arch.dr7 = dbgregs->dr7; vcpu->arch.dr7 = dbgregs->dr7;
kvm_update_dr7(vcpu); 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)); memset(vcpu->arch.db, 0, sizeof(vcpu->arch.db));
vcpu->arch.dr6 = DR6_FIXED_1; vcpu->arch.dr6 = DR6_FIXED_1;
kvm_update_dr6(vcpu);
vcpu->arch.dr7 = DR7_FIXED_1; vcpu->arch.dr7 = DR7_FIXED_1;
kvm_update_dr7(vcpu); kvm_update_dr7(vcpu);