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:
parent
9926c9fdbd
commit
73aaf249ee
4 changed files with 45 additions and 2 deletions
|
@ -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);
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue