diff mbox

KVM: SVM: Fix reading of DR6

Message ID 52B2F3AB.9050101@siemens.com (mailing list archive)
State New, archived
Headers show

Commit Message

Jan Kiszka Dec. 19, 2013, 1:24 p.m. UTC
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.

Fixes a regression of 020df0794f.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---

Should go to stable as well.

 arch/x86/include/asm/kvm_host.h | 1 +
 arch/x86/kvm/svm.c              | 9 +++++++++
 arch/x86/kvm/vmx.c              | 6 ++++++
 arch/x86/kvm/x86.c              | 2 +-
 4 files changed, 17 insertions(+), 1 deletion(-)

Comments

Marcelo Tosatti Dec. 27, 2013, 5:21 p.m. UTC | #1
On Thu, Dec 19, 2013 at 02:24:59PM +0100, Jan Kiszka wrote:
> 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.
> 
> Fixes a regression of 020df0794f.
> 
> Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
> ---
> 
> Should go to stable as well.
> 
>  arch/x86/include/asm/kvm_host.h | 1 +
>  arch/x86/kvm/svm.c              | 9 +++++++++
>  arch/x86/kvm/vmx.c              | 6 ++++++
>  arch/x86/kvm/x86.c              | 2 +-
>  4 files changed, 17 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
> index ae5d783..f115f46 100644
> --- a/arch/x86/include/asm/kvm_host.h
> +++ b/arch/x86/include/asm/kvm_host.h
> @@ -699,6 +699,7 @@ 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_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);
> diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
> index c7168a5..48fa63e 100644
> --- a/arch/x86/kvm/svm.c
> +++ b/arch/x86/kvm/svm.c
> @@ -1671,6 +1671,14 @@ 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)
> +{
> +	if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP)
> +		return vcpu->arch.dr6;
> +	else
> +		return to_svm(vcpu)->vmcb->save.dr6;
> +}
> +
>  static void svm_set_dr7(struct kvm_vcpu *vcpu, unsigned long value)
>  {
>  	struct vcpu_svm *svm = to_svm(vcpu);
> @@ -4286,6 +4294,7 @@ 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_dr7 = svm_set_dr7,
>  	.cache_reg = svm_cache_reg,
>  	.get_rflags = svm_get_rflags,
> diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
> index ee3bf54..c5c7e62 100644
> --- a/arch/x86/kvm/vmx.c
> +++ b/arch/x86/kvm/vmx.c
> @@ -5153,6 +5153,11 @@ 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_dr7(struct kvm_vcpu *vcpu, unsigned long val)
>  {
>  	vmcs_writel(GUEST_DR7, val);
> @@ -8573,6 +8578,7 @@ 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_dr7 = vmx_set_dr7,
>  	.cache_reg = vmx_cache_reg,
>  	.get_rflags = vmx_get_rflags,
> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> index 1dc0359..8fe227c 100644
> --- a/arch/x86/kvm/x86.c
> +++ b/arch/x86/kvm/x86.c
> @@ -788,7 +788,7 @@ static int _kvm_get_dr(struct kvm_vcpu *vcpu, int dr, unsigned long *val)
>  			return 1;
>  		/* fall through */
>  	case 6:
> -		*val = vcpu->arch.dr6;
> +		*val = kvm_x86_ops->get_dr6(vcpu);
>  		break;
>  	case 5:
>  		if (kvm_read_cr4_bits(vcpu, X86_CR4_DE))
> -- 
> 1.8.1.1.298.ge7eed54

It allows 

kvm_set_dr(a)
val = kvm_get_dr()

to have 'val' different than a. 

Is this OK ? (its certainly counter intuitive).

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index ae5d783..f115f46 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -699,6 +699,7 @@  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_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);
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index c7168a5..48fa63e 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -1671,6 +1671,14 @@  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)
+{
+	if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP)
+		return vcpu->arch.dr6;
+	else
+		return to_svm(vcpu)->vmcb->save.dr6;
+}
+
 static void svm_set_dr7(struct kvm_vcpu *vcpu, unsigned long value)
 {
 	struct vcpu_svm *svm = to_svm(vcpu);
@@ -4286,6 +4294,7 @@  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_dr7 = svm_set_dr7,
 	.cache_reg = svm_cache_reg,
 	.get_rflags = svm_get_rflags,
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index ee3bf54..c5c7e62 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -5153,6 +5153,11 @@  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_dr7(struct kvm_vcpu *vcpu, unsigned long val)
 {
 	vmcs_writel(GUEST_DR7, val);
@@ -8573,6 +8578,7 @@  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_dr7 = vmx_set_dr7,
 	.cache_reg = vmx_cache_reg,
 	.get_rflags = vmx_get_rflags,
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 1dc0359..8fe227c 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -788,7 +788,7 @@  static int _kvm_get_dr(struct kvm_vcpu *vcpu, int dr, unsigned long *val)
 			return 1;
 		/* fall through */
 	case 6:
-		*val = vcpu->arch.dr6;
+		*val = kvm_x86_ops->get_dr6(vcpu);
 		break;
 	case 5:
 		if (kvm_read_cr4_bits(vcpu, X86_CR4_DE))