From patchwork Mon Jan 13 22:10:51 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oliver Upton X-Patchwork-Id: 11331009 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 4D3B36C1 for ; Mon, 13 Jan 2020 22:11:01 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 2175D2084D for ; Mon, 13 Jan 2020 22:11:01 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="cIhcoFTd" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728872AbgAMWLA (ORCPT ); Mon, 13 Jan 2020 17:11:00 -0500 Received: from mail-pj1-f74.google.com ([209.85.216.74]:44194 "EHLO mail-pj1-f74.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727382AbgAMWK7 (ORCPT ); Mon, 13 Jan 2020 17:10:59 -0500 Received: by mail-pj1-f74.google.com with SMTP id c31so7550322pje.9 for ; Mon, 13 Jan 2020 14:10:58 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=m/qOsq+wdtuQutrd4owz9XAVpuoAS5ct18Ghp0jkcFg=; b=cIhcoFTduW7s3DvTZHusTuz8xxLfFLk/Olb5FJxQOUrbd3nb2CYZrB/IhHQFlPSqKW FE06w0x6T4R/9stBfD09QDSgAIIJA7el+2Q0mhrjdZO9//IQi//Ye8TiDKXeCc4tfvNP gdUtv0LHa0itmn9QZjr5MogldoqqyaOEhMAHJ25hIBpK1/T5mT95zKfMVDQiPanjzbDV ee7XSByDxZsgoh/67ZCkC3Xr68Y5sNVJHK//uDhs57/y5yRAEzgwiw8k12YrCO+yAgns Fc/AaddyQbYl2vVcJwpGuoKHzD6GoB2P1qJs6pDdmWp+P26ozUF+uO17Ha8yZCO0rvGy Csiw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=m/qOsq+wdtuQutrd4owz9XAVpuoAS5ct18Ghp0jkcFg=; b=txV2x8DKZxNFrMsDmYj51PDlDMh9Z6cxyZZsWUH+nuYR3CYYyuBRyVsfajwS6bLRal ACr0LVclVgtIDr8OOGgw3OoJKfL/Kg960giJMpLJQXX7DluFo9Pl3lBNgJklCrJgTE2f x8GiqHXwGqNp8xEnzKa//NXe+66FV8dt8phLQc0xuNC6BX/WCSBrrYBvXpwrnBfqGB+R YFI74I+fWaRLRHNeKT83L21yPO/pMQasDJVxEkgc0/vM64m9k9hgr53LrWuQGgqBZKGj qPZqXFX4/oMxV0BJNcZ5FW7X/qcP51FFhI/gYftmHlpQJEXAEXDtiI+BeoO326cYkFlR 3OnA== X-Gm-Message-State: APjAAAWdd2gj7z82HhLZBgJe/B+HWfnB38XsCGVdUife+QWdDi81kk4D ptRcAh9lU+stBV7g/YZhQVqkFDcjexHQj9UZXoqFbafyfTGBP2HjlhpRijg3cmNX1QBcgWDcyot itPt8jHLbTkFafiBKmzXni0zWfWtGR1dVzhHyqmw+dj9Zu9cKs4HpfEZnuw== X-Google-Smtp-Source: APXvYqyJITlnAOKB0VRr6bEvGfITZUgjTa7u1NdRTLHuDGLsl3FrgSiC04j3UHkZcmm1Q8ZVS/TnsSgPF8k= X-Received: by 2002:a63:de4a:: with SMTP id y10mr23244878pgi.367.1578953458112; Mon, 13 Jan 2020 14:10:58 -0800 (PST) Date: Mon, 13 Jan 2020 14:10:51 -0800 In-Reply-To: <20200113221053.22053-1-oupton@google.com> Message-Id: <20200113221053.22053-2-oupton@google.com> Mime-Version: 1.0 References: <20200113221053.22053-1-oupton@google.com> X-Mailer: git-send-email 2.25.0.rc1.283.g88dfdc4193-goog Subject: [PATCH 1/3] KVM: x86: Add vendor-specific #DB payload delivery From: Oliver Upton To: kvm@vger.kernel.org Cc: Paolo Bonzini , Oliver Upton , Peter Shier , Jim Mattson Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org VMX and SVM differ slightly in the handling of #DB debug-trap exceptions upon VM-entry. VMX defines the 'pending debug exceptions' field in the VMCS for hardware to inject the event and update debug register state upon VM-entry. SVM provides no such mechanism for maintaining the state of a pending debug exception, as the debug register state is updated before delivery of #VMEXIT. Lastly, while KVM defines the exception payload for debug-trap exceptions as compatible with the 'pending debug exceptions' VMCS field, it is not compatible with the DR6 register across both vendors. Split the #DB payload delivery between SVM and VMX to capture the nuanced differences in instruction emulation. Utilize the 'pending debug exceptions' field on VMX to deliver the payload. On SVM, directly update register state with the appropriate requested bits from the exception payload. Fixes: f10c729ff965 ("kvm: vmx: Defer setting of DR6 until #DB delivery") Signed-off-by: Oliver Upton Reviewed-by: Peter Shier Reviewed-by: Jim Mattson --- arch/x86/include/asm/kvm_host.h | 1 + arch/x86/kvm/svm.c | 20 ++++++++++++++++++++ arch/x86/kvm/vmx/vmx.c | 20 +++++++++++++++++++- arch/x86/kvm/x86.c | 21 +-------------------- 4 files changed, 41 insertions(+), 21 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index b79cd6aa4075..4739ca11885d 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1100,6 +1100,7 @@ struct kvm_x86_ops { void (*set_nmi)(struct kvm_vcpu *vcpu); void (*queue_exception)(struct kvm_vcpu *vcpu); void (*cancel_injection)(struct kvm_vcpu *vcpu); + void (*deliver_db_payload)(struct kvm_vcpu *vcpu, + unsigned long payload); int (*interrupt_allowed)(struct kvm_vcpu *vcpu); int (*nmi_allowed)(struct kvm_vcpu *vcpu); bool (*get_nmi_mask)(struct kvm_vcpu *vcpu); diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 122d4ce3b1ab..16ded16af997 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -5615,6 +5615,25 @@ static void svm_cancel_injection(struct kvm_vcpu *vcpu) svm_complete_interrupts(svm); } +static void svm_deliver_db_payload(struct kvm_vcpu *vcpu, unsigned long payload) +{ + /* + * The exception payload is defined as compatible with the 'pending + * debug exceptions' field in VMX, not the DR6 register. Clear bit 12 + * (enabled breakpoint) in the payload, which is reserved MBZ in DR6. + */ + payload &= ~BIT(12); + + /* + * The processor updates bits 3:0 according to the matched breakpoint + * conditions on every debug breakpoint or general-detect condition. + * Hardware will not clear any other bits in DR6. Clear bits 3:0 and set + * the bits requested in the exception payload. + */ + vcpu->arch.dr6 &= ~DR_TRAP_BITS; + vcpu->arch.dr6 |= payload; +} + static void svm_vcpu_run(struct kvm_vcpu *vcpu) { struct vcpu_svm *svm = to_svm(vcpu); @@ -7308,6 +7327,7 @@ static struct kvm_x86_ops svm_x86_ops __ro_after_init = { .set_nmi = svm_inject_nmi, .queue_exception = svm_queue_exception, .cancel_injection = svm_cancel_injection, + .deliver_db_payload = svm_deliver_db_payload, .interrupt_allowed = svm_interrupt_allowed, .nmi_allowed = svm_nmi_allowed, .get_nmi_mask = svm_get_nmi_mask, diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index e3394c839dea..148696199c88 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -1613,6 +1613,7 @@ static void vmx_queue_exception(struct kvm_vcpu *vcpu) struct vcpu_vmx *vmx = to_vmx(vcpu); unsigned nr = vcpu->arch.exception.nr; bool has_error_code = vcpu->arch.exception.has_error_code; + bool has_payload = vcpu->arch.exception.has_payload; u32 error_code = vcpu->arch.exception.error_code; u32 intr_info = nr | INTR_INFO_VALID_MASK; @@ -1640,7 +1641,13 @@ static void vmx_queue_exception(struct kvm_vcpu *vcpu) } else intr_info |= INTR_TYPE_HARD_EXCEPTION; - vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, intr_info); + /* + * Debug-trap exceptions are injected into the guest via the 'pending + * debug exceptions' vmcs field and thus should not be injected into the + * guest using the general event injection mechanism. + */ + if (nr != DB_VECTOR || !has_payload) + vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, intr_info); vmx_clear_hlt(vcpu); } @@ -6398,6 +6405,16 @@ static void vmx_cancel_injection(struct kvm_vcpu *vcpu) vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, 0); } +static void vmx_deliver_db_payload(struct kvm_vcpu *vcpu, unsigned long payload) +{ + /* + * Synthesized debug exceptions that have an associated payload must be + * traps, and thus the 'pending debug exceptions' field can be used to + * allow hardware to inject the event upon VM-entry. + */ + vmcs_writel(GUEST_PENDING_DBG_EXCEPTIONS, payload); +} + static void atomic_switch_perf_msrs(struct vcpu_vmx *vmx) { int i, nr_msrs; @@ -7821,6 +7838,7 @@ static struct kvm_x86_ops vmx_x86_ops __ro_after_init = { .set_nmi = vmx_inject_nmi, .queue_exception = vmx_queue_exception, .cancel_injection = vmx_cancel_injection, + .deliver_db_payload = vmx_deliver_db_payload, .interrupt_allowed = vmx_interrupt_allowed, .nmi_allowed = vmx_nmi_allowed, .get_nmi_mask = vmx_get_nmi_mask, diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index cf917139de6b..c14174c033e4 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -415,26 +415,7 @@ void kvm_deliver_exception_payload(struct kvm_vcpu *vcpu) switch (nr) { case DB_VECTOR: - /* - * "Certain debug exceptions may clear bit 0-3. The - * remaining contents of the DR6 register are never - * cleared by the processor". - */ - vcpu->arch.dr6 &= ~DR_TRAP_BITS; - /* - * DR6.RTM is set by all #DB exceptions that don't clear it. - */ - vcpu->arch.dr6 |= DR6_RTM; - vcpu->arch.dr6 |= payload; - /* - * Bit 16 should be set in the payload whenever the #DB - * exception should clear DR6.RTM. This makes the payload - * compatible with the pending debug exceptions under VMX. - * Though not currently documented in the SDM, this also - * makes the payload compatible with the exit qualification - * for #DB exceptions under VMX. - */ - vcpu->arch.dr6 ^= payload & DR6_RTM; + kvm_x86_ops->deliver_db_payload(vcpu, payload); break; case PF_VECTOR: vcpu->arch.cr2 = payload; From patchwork Mon Jan 13 22:10:52 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oliver Upton X-Patchwork-Id: 11331011 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 2188F6C1 for ; Mon, 13 Jan 2020 22:11:03 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id EA29220CC7 for ; Mon, 13 Jan 2020 22:11:02 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="KrBkp4Vm" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728905AbgAMWLB (ORCPT ); Mon, 13 Jan 2020 17:11:01 -0500 Received: from mail-pg1-f202.google.com ([209.85.215.202]:33321 "EHLO mail-pg1-f202.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728864AbgAMWLB (ORCPT ); Mon, 13 Jan 2020 17:11:01 -0500 Received: by mail-pg1-f202.google.com with SMTP id s23so7238045pgg.0 for ; Mon, 13 Jan 2020 14:11:00 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=oNXTuZEEPOxvvJWf9w6Dwwhmjs7WBQSfN0wXaDn0P54=; b=KrBkp4Vm6/962Hh8vwtUiqeuYmOgI0Df89o9QWtAqyKf9wdc2iDejmkTArjVu7DZfu 3sKQv7M0fDsgJgUJAgDMASNxNG2YRj6Qj0WOGv634fr/J3bwppK3c+yDXwxFRKfRMv0a 2C1EH5lSp9IkKm495i1DRNyB7D6VPBiJWvM5KRNe4Q5SDM+VrEiSC/5z6PJqYaLaqpHa M+qkRXevDtS2HR1NXGX8pms07Phrh1uTi21hn3qQWeTMMNOnv5W8wDNKFtJTciNtKMfn wNkVieGFdDP3161pOluNCRydNTa5+SYr7FzNiiWhvgLvhrCJ2jQ8UaXDrBs/T7Ix2vcn NA8g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=oNXTuZEEPOxvvJWf9w6Dwwhmjs7WBQSfN0wXaDn0P54=; b=rDXRDIWPrlivCPWPh8fMWlUMbrbI+tmxDfcXq+gQd5ZbWL3iIFXjoKUjYI7xv0UZ4A 237XDEcgWuXZ7vSoUYl7bFF6GWm5N9h3rduJ5hZKml1auTy/+4SfYlZc46v/pQoiJLlB rpAJi/SC3Fh17rZrz5de2vvCBVUNGu6THrsx1sJ1g8OPritGABdv12b6LMyPiMCqlJMj 07pYC6FuMCRNmXU3XZc4HRo9SelAsguRyovElMFJROOXs5zjQaj0fnYnF/brEkVCoDHR YfL2p3J724cGqu8htDz88F7mJa4NrpCOqbhcbHHrw/FGoPm3m+tIPWwiK0uOdLvwi/pm 1mtA== X-Gm-Message-State: APjAAAVHETTHeWeaAR6L/X2M91WaJCw2sz6MEgPeTcinoEz6b28gqC+P zp48geYVO3apM1VYV8cdlSpDEsqO4fKm52TsktSvryqyqEs4smSVv+FXnsnJtT4r5W80GcigII1 ggEUXgsZqAq3L/rQZKgSTxG1wo/A5o/UXch6RwXo7hXkWqm6hs96kVPBGCA== X-Google-Smtp-Source: APXvYqzYV2qHtOYe5nDUO0RqixnYpOHnA4RBJ8501ZaLgE2sQygje2GJyJ5bmPBl3uuVZYPmq2W9BmagDw4= X-Received: by 2002:a65:4109:: with SMTP id w9mr22922880pgp.383.1578953460042; Mon, 13 Jan 2020 14:11:00 -0800 (PST) Date: Mon, 13 Jan 2020 14:10:52 -0800 In-Reply-To: <20200113221053.22053-1-oupton@google.com> Message-Id: <20200113221053.22053-3-oupton@google.com> Mime-Version: 1.0 References: <20200113221053.22053-1-oupton@google.com> X-Mailer: git-send-email 2.25.0.rc1.283.g88dfdc4193-goog Subject: [PATCH 2/3] KVM: x86: Emulate MTF when performing instruction emulation From: Oliver Upton To: kvm@vger.kernel.org Cc: Paolo Bonzini , Oliver Upton , Peter Shier , Jim Mattson Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org Since commit 5f3d45e7f282 ("kvm/x86: add support for MONITOR_TRAP_FLAG"), KVM has allowed an L1 guest to use the monitor trap flag processor-based execution control for its L2 guest. KVM simply forwards any MTF VM-exits to the L1 guest, which works for normal instruction execution. However, when KVM needs to emulate an instruction on the behalf of an L2 guest, the monitor trap flag is not emulated. Add the necessary logic to kvm_skip_emulated_instruction() to synthesize an MTF VM-exit to L1 upon instruction emulation for L2. Fixes: 5f3d45e7f282 ("kvm/x86: add support for MONITOR_TRAP_FLAG") Signed-off-by: Oliver Upton Reviewed-by: Peter Shier Reviewed-by: Jim Mattson --- arch/x86/include/asm/kvm_host.h | 1 + arch/x86/kvm/svm.c | 5 +++++ arch/x86/kvm/vmx/nested.c | 2 +- arch/x86/kvm/vmx/nested.h | 5 +++++ arch/x86/kvm/vmx/vmx.c | 19 +++++++++++++++++++ arch/x86/kvm/x86.c | 6 ++++++ 6 files changed, 37 insertions(+), 1 deletion(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 4739ca11885d..89dcdc7201ae 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1092,6 +1092,7 @@ struct kvm_x86_ops { void (*run)(struct kvm_vcpu *vcpu); int (*handle_exit)(struct kvm_vcpu *vcpu); int (*skip_emulated_instruction)(struct kvm_vcpu *vcpu); + void (*emulation_complete)(struct kvm_vcpu *vcpu); void (*set_interrupt_shadow)(struct kvm_vcpu *vcpu, int mask); u32 (*get_interrupt_shadow)(struct kvm_vcpu *vcpu); void (*patch_hypercall)(struct kvm_vcpu *vcpu, diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 16ded16af997..f21eec4443d5 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -802,6 +802,10 @@ static int skip_emulated_instruction(struct kvm_vcpu *vcpu) return 1; } +static void svm_emulation_complete(struct kvm_vcpu *vcpu) +{ +} + static void svm_queue_exception(struct kvm_vcpu *vcpu) { struct vcpu_svm *svm = to_svm(vcpu); @@ -7320,6 +7324,7 @@ static struct kvm_x86_ops svm_x86_ops __ro_after_init = { .run = svm_vcpu_run, .handle_exit = handle_exit, .skip_emulated_instruction = skip_emulated_instruction, + .emulation_complete = svm_emulation_complete, .set_interrupt_shadow = svm_set_interrupt_shadow, .get_interrupt_shadow = svm_get_interrupt_shadow, .patch_hypercall = svm_patch_hypercall, diff --git a/arch/x86/kvm/vmx/nested.c b/arch/x86/kvm/vmx/nested.c index 4aea7d304beb..ee26f2d10a09 100644 --- a/arch/x86/kvm/vmx/nested.c +++ b/arch/x86/kvm/vmx/nested.c @@ -5578,7 +5578,7 @@ bool nested_vmx_exit_reflected(struct kvm_vcpu *vcpu, u32 exit_reason) case EXIT_REASON_MWAIT_INSTRUCTION: return nested_cpu_has(vmcs12, CPU_BASED_MWAIT_EXITING); case EXIT_REASON_MONITOR_TRAP_FLAG: - return nested_cpu_has(vmcs12, CPU_BASED_MONITOR_TRAP_FLAG); + return nested_cpu_has_mtf(vmcs12); case EXIT_REASON_MONITOR_INSTRUCTION: return nested_cpu_has(vmcs12, CPU_BASED_MONITOR_EXITING); case EXIT_REASON_PAUSE_INSTRUCTION: diff --git a/arch/x86/kvm/vmx/nested.h b/arch/x86/kvm/vmx/nested.h index fc874d4ead0f..901d2745bc93 100644 --- a/arch/x86/kvm/vmx/nested.h +++ b/arch/x86/kvm/vmx/nested.h @@ -238,6 +238,11 @@ static inline bool nested_cpu_has_save_preemption_timer(struct vmcs12 *vmcs12) VM_EXIT_SAVE_VMX_PREEMPTION_TIMER; } +static inline bool nested_cpu_has_mtf(struct vmcs12 *vmcs12) +{ + return nested_cpu_has(vmcs12, CPU_BASED_MONITOR_TRAP_FLAG); +} + /* * In nested virtualization, check if L1 asked to exit on external interrupts. * For most existing hypervisors, this will always return true. diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index 148696199c88..8d3b693c3d3a 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -1595,6 +1595,24 @@ static int skip_emulated_instruction(struct kvm_vcpu *vcpu) return 1; } +static void vmx_emulation_complete(struct kvm_vcpu *vcpu) +{ + if (!(is_guest_mode(vcpu) && + nested_cpu_has_mtf(get_vmcs12(vcpu)))) + return; + + /* + * Per the SDM, MTF takes priority over debug-trap instructions. As + * instruction emulation is completed (i.e. at the instruction + * boundary), any #DB exception must be a trap. Emulate an MTF VM-exit + * into L1 should there be a debug-trap exception pending or no + * exception pending. + */ + if (!vcpu->arch.exception.pending || + vcpu->arch.exception.nr == DB_VECTOR) + nested_vmx_vmexit(vcpu, EXIT_REASON_MONITOR_TRAP_FLAG, 0, 0); +} + static void vmx_clear_hlt(struct kvm_vcpu *vcpu) { /* @@ -7831,6 +7849,7 @@ static struct kvm_x86_ops vmx_x86_ops __ro_after_init = { .run = vmx_vcpu_run, .handle_exit = vmx_handle_exit, .skip_emulated_instruction = skip_emulated_instruction, + .emulation_complete = vmx_emulation_complete, .set_interrupt_shadow = vmx_set_interrupt_shadow, .get_interrupt_shadow = vmx_get_interrupt_shadow, .patch_hypercall = vmx_patch_hypercall, diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index c14174c033e4..d3af7a8a3c4b 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -6546,6 +6546,12 @@ int kvm_skip_emulated_instruction(struct kvm_vcpu *vcpu) */ if (unlikely(rflags & X86_EFLAGS_TF)) r = kvm_vcpu_do_singlestep(vcpu); + /* + * Allow for vendor-specific handling of completed emulation before + * returning. + */ + if (r) + kvm_x86_ops->emulation_complete(vcpu); return r; } EXPORT_SYMBOL_GPL(kvm_skip_emulated_instruction); From patchwork Mon Jan 13 22:10:53 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oliver Upton X-Patchwork-Id: 11331013 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 25D43138D for ; Mon, 13 Jan 2020 22:11:05 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id EEF5C20CC7 for ; Mon, 13 Jan 2020 22:11:04 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="rlqd4qDh" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728911AbgAMWLD (ORCPT ); Mon, 13 Jan 2020 17:11:03 -0500 Received: from mail-qv1-f73.google.com ([209.85.219.73]:57055 "EHLO mail-qv1-f73.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728873AbgAMWLD (ORCPT ); Mon, 13 Jan 2020 17:11:03 -0500 Received: by mail-qv1-f73.google.com with SMTP id a14so7344197qvy.23 for ; Mon, 13 Jan 2020 14:11:02 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=tIDWZSQZq4Ja8lWBVps0YxaVqw+QXFvw/jnBfVCtMmQ=; b=rlqd4qDh/pKTZICksZYt+82Ov6dcy8mAI83MtFhOc1Gu/srdwvGkZgVGI7hJw+AxCC Khm0tukzbkg88KZoypqPUECVeJIRSFz4853Rb6pCLxp2TnUDyaukrfbP1eLO63CuZqIu FQbsdJxxOZK/G6gGqgbjBLTKwUqi4R6uxKav7DtN/2iI0XETpXIEHnFFG6AJY4gMplxl ind8EUR1l7JKRbC+k2XIoJlHZq3SDAj7OlgM8hsN19uPaHHkTHvpwa/w/cf+aKeRLHpF 7aSuU1kPwuy2fcX3ZQPHQ8BZSMfB9jNjFUCgO+gjBpPrEtoa7ON8GYg6JvlQIsvq5VaN f0BQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=tIDWZSQZq4Ja8lWBVps0YxaVqw+QXFvw/jnBfVCtMmQ=; b=CgbJI9TQcDDwU23qoJbX0i1xY8bX331O3KP6jE+40JdY3HP6jD94zQmkilAJvY4cIY lR1CG+wiRRQj9b5BnSfoQvvRyJWybQ/4BZJItBXJseuq+gXid6q2zBVR4FfJqACgaYRA 7JO+H4CkC26qXUJXifq3DgC4bT/K6tB4A+f/eYN9I49UHZr0IBVJ8bGNIEGdottnoeTe 6BwX8sHOPT6L77aPXJfnfNyaEX/4e6bk+YQZYMeZq6hlkAAOuzQcm/N13wedBDRSEVQe YB7JAigN75+IcNucx16INFdaDAbEFA5kt9s7h3ginV/n0iN6I/aLIVZUPYBJ3UQd6obV R7PQ== X-Gm-Message-State: APjAAAWc7PO3V/HOSFjNF7qw5slce1xxDoVgTJqYmcS+WWRjenw3wpk4 Fm6qajgVNX8OXbNrF9UHvdGVv1dWcDewVynWM61+SBQVvMuB/kJS+wTnuiaS2NenPJqIaMp8/K1 oT8RS/8taFxLdsI1nBoY0TN3VwqVVfbpBu5T55y8le/EY3/ErfFHFGJlETg== X-Google-Smtp-Source: APXvYqwEXFDd0pOxLPZgEYTXZs4O/sOuCBb0xbEwzfAX5+m0uY517NZx9SM7gJUVUJytdUFXLI2/mQkYzus= X-Received: by 2002:ad4:47ad:: with SMTP id a13mr17874781qvz.29.1578953462182; Mon, 13 Jan 2020 14:11:02 -0800 (PST) Date: Mon, 13 Jan 2020 14:10:53 -0800 In-Reply-To: <20200113221053.22053-1-oupton@google.com> Message-Id: <20200113221053.22053-4-oupton@google.com> Mime-Version: 1.0 References: <20200113221053.22053-1-oupton@google.com> X-Mailer: git-send-email 2.25.0.rc1.283.g88dfdc4193-goog Subject: [kvm-unit-tests PATCH 3/3] x86: VMX: Add tests for monitor trap flag From: Oliver Upton To: kvm@vger.kernel.org Cc: Paolo Bonzini , Oliver Upton , Peter Shier , Jim Mattson Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org Test to verify that MTF VM-exits into host are synthesized when the 'monitor trap flag' processor-based VM-execution control is set under various conditions. Expect an MTF VM-exit if instruction execution produces no events other than MTF. Should instruction execution produce a concurrent debug-trap and MTF event, expect an MTF VM-exit with the 'pending debug exceptions' VMCS field set. Expect an MTF VM-exit to follow event delivery should instruction execution generate a higher-priority event, such as a general-protection fault. Lastly, expect an MTF VM-exit to follow delivery of a debug-trap software exception (INT1/INT3/INTO/INT n). Signed-off-by: Oliver Upton Reviewed-by: Peter Shier Reviewed-by: Jim Mattson --- x86/vmx.h | 1 + x86/vmx_tests.c | 157 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 158 insertions(+) diff --git a/x86/vmx.h b/x86/vmx.h index 6214400f2b53..6adf0916564b 100644 --- a/x86/vmx.h +++ b/x86/vmx.h @@ -399,6 +399,7 @@ enum Ctrl0 { CPU_NMI_WINDOW = 1ul << 22, CPU_IO = 1ul << 24, CPU_IO_BITMAP = 1ul << 25, + CPU_MTF = 1ul << 27, CPU_MSR_BITMAP = 1ul << 28, CPU_MONITOR = 1ul << 29, CPU_PAUSE = 1ul << 30, diff --git a/x86/vmx_tests.c b/x86/vmx_tests.c index fce773c18b8b..5beed8e29b4b 100644 --- a/x86/vmx_tests.c +++ b/x86/vmx_tests.c @@ -4952,6 +4952,162 @@ static void test_vmx_preemption_timer(void) vmcs_write(EXI_CONTROLS, saved_exit); } +extern unsigned char test_mtf1; +extern unsigned char test_mtf2; +extern unsigned char test_mtf3; + +__attribute__((noclone)) static void test_mtf_guest(void) +{ + asm ("vmcall;\n\t" + "out %al, $0x80;\n\t" + "test_mtf1:\n\t" + "vmcall;\n\t" + "out %al, $0x80;\n\t" + "test_mtf2:\n\t" + /* + * Prepare for the 'MOV CR3' test. Attempt to induce a + * general-protection fault by moving a non-canonical address into + * CR3. The 'MOV CR3' instruction does not take an imm64 operand, + * so we must MOV the desired value into a register first. + * + * MOV RAX is done before the VMCALL such that MTF is only enabled + * for the instruction under test. + */ + "mov $0x8000000000000000, %rax;\n\t" + "vmcall;\n\t" + "mov %rax, %cr3;\n\t" + "test_mtf3:\n\t" + "vmcall;\n\t" + /* + * ICEBP/INT1 instruction. Though the instruction is now + * documented, don't rely on assemblers enumerating the + * instruction. Resort to hand assembly. + */ + ".byte 0xf1;\n\t"); +} + +static void test_mtf_gp_handler(struct ex_regs *regs) +{ + regs->rip = (unsigned long) &test_mtf3; +} + +static void test_mtf_db_handler(struct ex_regs *regs) +{ +} + +static void enable_mtf(void) +{ + u32 ctrl0 = vmcs_read(CPU_EXEC_CTRL0); + + vmcs_write(CPU_EXEC_CTRL0, ctrl0 | CPU_MTF); +} + +static void disable_mtf(void) +{ + u32 ctrl0 = vmcs_read(CPU_EXEC_CTRL0); + + vmcs_write(CPU_EXEC_CTRL0, ctrl0 & ~CPU_MTF); +} + +static void enable_tf(void) +{ + unsigned long rflags = vmcs_read(GUEST_RFLAGS); + + vmcs_write(GUEST_RFLAGS, rflags | X86_EFLAGS_TF); +} + +static void disable_tf(void) +{ + unsigned long rflags = vmcs_read(GUEST_RFLAGS); + + vmcs_write(GUEST_RFLAGS, rflags & ~X86_EFLAGS_TF); +} + +static void report_mtf(const char *insn_name, unsigned long exp_rip) +{ + unsigned long rip = vmcs_read(GUEST_RIP); + + assert_exit_reason(VMX_MTF); + report(rip == exp_rip, "MTF VM-exit after %s instruction. RIP: 0x%lx (expected 0x%lx)", + insn_name, rip, exp_rip); +} + +static void vmx_mtf_test(void) +{ + unsigned long pending_dbg; + handler old_gp, old_db; + + if (!(ctrl_cpu_rev[0].clr & CPU_MTF)) { + printf("CPU does not support the 'monitor trap flag' processor-based VM-execution control.\n"); + return; + } + + test_set_guest(test_mtf_guest); + + /* Expect an MTF VM-exit after OUT instruction */ + enter_guest(); + skip_exit_vmcall(); + + enable_mtf(); + enter_guest(); + report_mtf("OUT", (unsigned long) &test_mtf1); + disable_mtf(); + + /* + * Concurrent #DB trap and MTF on instruction boundary. Expect MTF + * VM-exit with populated 'pending debug exceptions' VMCS field. + */ + enter_guest(); + skip_exit_vmcall(); + + enable_mtf(); + enable_tf(); + + enter_guest(); + report_mtf("OUT", (unsigned long) &test_mtf2); + pending_dbg = vmcs_read(GUEST_PENDING_DEBUG); + report(pending_dbg & DR_STEP, + "'pending debug exceptions' field after MTF VM-exit: 0x%lx (expected 0x%lx)", + pending_dbg, (unsigned long) DR_STEP); + + disable_mtf(); + disable_tf(); + vmcs_write(GUEST_PENDING_DEBUG, 0); + + /* + * #GP exception takes priority over MTF. Expect MTF VM-exit with rIP + * advanced to first instruction of #GP handler. + */ + enter_guest(); + skip_exit_vmcall(); + + old_gp = handle_exception(GP_VECTOR, test_mtf_gp_handler); + + enable_mtf(); + enter_guest(); + report_mtf("MOV CR3", (unsigned long) get_idt_addr(&boot_idt[GP_VECTOR])); + disable_mtf(); + + /* + * Concurrent MTF and privileged software exception (i.e. ICEBP/INT1). + * MTF should follow the delivery of #DB trap, though the SDM doesn't + * provide clear indication of the relative priority. + */ + enter_guest(); + skip_exit_vmcall(); + + handle_exception(GP_VECTOR, old_gp); + old_db = handle_exception(DB_VECTOR, test_mtf_db_handler); + + enable_mtf(); + enter_guest(); + report_mtf("INT1", (unsigned long) get_idt_addr(&boot_idt[DB_VECTOR])); + disable_mtf(); + + enter_guest(); + handle_exception(DB_VECTOR, old_db); +} + /* * Tests for VM-execution control fields */ @@ -9443,5 +9599,6 @@ struct vmx_test vmx_tests[] = { TEST(atomic_switch_max_msrs_test), TEST(atomic_switch_overflow_msrs_test), TEST(rdtsc_vmexit_diff_test), + TEST(vmx_mtf_test), { NULL, NULL, NULL, NULL, NULL, {0} }, };