From patchwork Fri Sep 4 12:51:20 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Kiszka X-Patchwork-Id: 45681 Received: from vger.kernel.org (vger.kernel.org [209.132.176.167]) by demeter.kernel.org (8.14.2/8.14.2) with ESMTP id n84CruXq005068 for ; Fri, 4 Sep 2009 12:53:57 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756834AbZIDMxw (ORCPT ); Fri, 4 Sep 2009 08:53:52 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1756831AbZIDMxw (ORCPT ); Fri, 4 Sep 2009 08:53:52 -0400 Received: from david.siemens.de ([192.35.17.14]:22265 "EHLO david.siemens.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756830AbZIDMxu (ORCPT ); Fri, 4 Sep 2009 08:53:50 -0400 Received: from mail1.siemens.de (localhost [127.0.0.1]) by david.siemens.de (8.12.11.20060308/8.12.11) with ESMTP id n84CrdeU003197; Fri, 4 Sep 2009 14:53:39 +0200 Received: from [139.25.109.167] (mchn012c.ww002.siemens.net [139.25.109.167] (may be forged)) by mail1.siemens.de (8.12.11.20060308/8.12.11) with ESMTP id n84Crd2a002570; Fri, 4 Sep 2009 14:53:39 +0200 From: Jan Kiszka Subject: [PATCH 5/6] KVM: SVM: Enable full MOV DR emulation To: Avi Kivity , Marcelo Tosatti Cc: kvm@vger.kernel.org, Jan Kiszka Date: Fri, 04 Sep 2009 14:51:20 +0200 Message-ID: <20090904125120.18939.85555.stgit@mchn012c.ww002.siemens.net> In-Reply-To: <20090904125119.18939.89733.stgit@mchn012c.ww002.siemens.net> References: <20090904125119.18939.89733.stgit@mchn012c.ww002.siemens.net> User-Agent: StGIT/0.14.3 MIME-Version: 1.0 Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org Enhance MOV DR instruction emulation used by SVM so that it properly injects faults and handles DR4/5 correctly. Signed-off-by: Jan Kiszka --- arch/x86/include/asm/kvm_host.h | 5 +-- arch/x86/kvm/svm.c | 72 ++++++++++++++++++++++----------------- arch/x86/kvm/x86.c | 19 +--------- 3 files changed, 45 insertions(+), 51 deletions(-) -- 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 --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 6046e6f..38eef27 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -498,9 +498,8 @@ struct kvm_x86_ops { void (*set_idt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt); void (*get_gdt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt); void (*set_gdt)(struct kvm_vcpu *vcpu, struct descriptor_table *dt); - unsigned long (*get_dr)(struct kvm_vcpu *vcpu, int dr); - void (*set_dr)(struct kvm_vcpu *vcpu, int dr, unsigned long value, - int *exception); + int (*get_dr)(struct kvm_vcpu *vcpu, int dr, unsigned long *dest); + int (*set_dr)(struct kvm_vcpu *vcpu, int dr, unsigned long value); void (*cache_reg)(struct kvm_vcpu *vcpu, enum kvm_reg reg); unsigned long (*get_rflags)(struct kvm_vcpu *vcpu); void (*set_rflags)(struct kvm_vcpu *vcpu, unsigned long rflags); diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 2df9b45..4305969 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -1106,76 +1106,86 @@ static void new_asid(struct vcpu_svm *svm, struct svm_cpu_data *svm_data) svm->vmcb->control.asid = svm_data->next_asid++; } -static unsigned long svm_get_dr(struct kvm_vcpu *vcpu, int dr) +static int svm_get_dr(struct kvm_vcpu *vcpu, int dr, unsigned long *dest) { struct vcpu_svm *svm = to_svm(vcpu); - unsigned long val; switch (dr) { case 0 ... 3: - val = vcpu->arch.db[dr]; + *dest = vcpu->arch.db[dr]; break; + case 4: + if (vcpu->arch.cr4 & X86_CR4_DE) { + kvm_queue_exception(vcpu, UD_VECTOR); + return -1; + } + /* fall through */ case 6: if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP) - val = vcpu->arch.dr6; + *dest = vcpu->arch.dr6; else - val = svm->vmcb->save.dr6; + *dest = svm->vmcb->save.dr6; break; + case 5: + if (vcpu->arch.cr4 & X86_CR4_DE) { + kvm_queue_exception(vcpu, UD_VECTOR); + return -1; + } + /* fall through */ case 7: if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP) - val = vcpu->arch.dr7; + *dest = vcpu->arch.dr7; else - val = svm->vmcb->save.dr7; + *dest = svm->vmcb->save.dr7; break; - default: - val = 0; } - return val; + return 0; } -static void svm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long value, - int *exception) +static int svm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long value) { struct vcpu_svm *svm = to_svm(vcpu); - *exception = 0; - switch (dr) { case 0 ... 3: vcpu->arch.db[dr] = value; if (!(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP)) vcpu->arch.eff_db[dr] = value; - return; - case 4 ... 5: - if (vcpu->arch.cr4 & X86_CR4_DE) - *exception = UD_VECTOR; - return; + break; + case 4: + if (vcpu->arch.cr4 & X86_CR4_DE) { + kvm_queue_exception(vcpu, UD_VECTOR); + return -1; + } + /* fall through */ case 6: if (value & 0xffffffff00000000ULL) { - *exception = GP_VECTOR; - return; + kvm_inject_gp(vcpu, 0); + return -1; } vcpu->arch.dr6 = (value & DR6_VOLATILE) | DR6_FIXED_1; - return; + break; + case 5: + if (vcpu->arch.cr4 & X86_CR4_DE) { + kvm_queue_exception(vcpu, UD_VECTOR); + return -1; + } + /* fall through */ case 7: if (value & 0xffffffff00000000ULL) { - *exception = GP_VECTOR; - return; + kvm_inject_gp(vcpu, 0); + return -1; } vcpu->arch.dr7 = (value & DR7_VOLATILE) | DR7_FIXED_1; if (!(vcpu->guest_debug & KVM_GUESTDBG_USE_HW_BP)) { svm->vmcb->save.dr7 = vcpu->arch.dr7; vcpu->arch.switch_db_regs = (value & DR7_BP_EN_MASK); } - return; - default: - /* FIXME: Possible case? */ - printk(KERN_DEBUG "%s: unexpected dr %u\n", - __func__, dr); - *exception = UD_VECTOR; - return; + break; } + + return 0; } static int pf_interception(struct vcpu_svm *svm) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 036a2c5..2ca7a1d 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2695,29 +2695,14 @@ int emulate_clts(struct kvm_vcpu *vcpu) int emulator_get_dr(struct x86_emulate_ctxt *ctxt, int dr, unsigned long *dest) { - struct kvm_vcpu *vcpu = ctxt->vcpu; - - switch (dr) { - case 0 ... 3: - *dest = kvm_x86_ops->get_dr(vcpu, dr); - return X86EMUL_CONTINUE; - default: - pr_unimpl(vcpu, "%s: unexpected dr %u\n", __func__, dr); - return X86EMUL_UNHANDLEABLE; - } + return kvm_x86_ops->get_dr(ctxt->vcpu, dr, dest); } int emulator_set_dr(struct x86_emulate_ctxt *ctxt, int dr, unsigned long value) { unsigned long mask = (ctxt->mode == X86EMUL_MODE_PROT64) ? ~0ULL : ~0U; - int exception; - kvm_x86_ops->set_dr(ctxt->vcpu, dr, value & mask, &exception); - if (exception) { - /* FIXME: better handling */ - return X86EMUL_UNHANDLEABLE; - } - return X86EMUL_CONTINUE; + return kvm_x86_ops->set_dr(ctxt->vcpu, dr, value & mask); } void kvm_report_emulation_failure(struct kvm_vcpu *vcpu, const char *context)