From patchwork Tue Feb 12 23:04:02 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sean Christopherson X-Patchwork-Id: 10808883 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 8450113A4 for ; Tue, 12 Feb 2019 23:04:09 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 663062C1A1 for ; Tue, 12 Feb 2019 23:04:09 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 53FEC29489; Tue, 12 Feb 2019 23:04:09 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B0CAD29489 for ; Tue, 12 Feb 2019 23:04:08 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730712AbfBLXEH (ORCPT ); Tue, 12 Feb 2019 18:04:07 -0500 Received: from mga02.intel.com ([134.134.136.20]:46049 "EHLO mga02.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730432AbfBLXEH (ORCPT ); Tue, 12 Feb 2019 18:04:07 -0500 X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga004.fm.intel.com ([10.253.24.48]) by orsmga101.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 12 Feb 2019 15:04:06 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.58,362,1544515200"; d="scan'208";a="143735711" Received: from sjchrist-coffee.jf.intel.com ([10.54.74.14]) by fmsmga004.fm.intel.com with ESMTP; 12 Feb 2019 15:04:06 -0800 From: Sean Christopherson To: Paolo Bonzini , =?utf-8?b?UmFkaW0gS3LEjW3DocWZ?= Cc: kvm@vger.kernel.org, Krish Sadhukhan , Marc Orr Subject: [kvm-unit-tests PATCH 3/3] KVM: nVMX: Properly configured unrestricted guest for event injection Date: Tue, 12 Feb 2019 15:04:02 -0800 Message-Id: <20190212230402.26851-4-sean.j.christopherson@intel.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20190212230402.26851-1-sean.j.christopherson@intel.com> References: <20190212230402.26851-1-sean.j.christopherson@intel.com> MIME-Version: 1.0 Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The hardware exception injection test toggles unrestricted guest so that it can test the case where an event is injected into real mode with and without an error code (exception error codes don't exist in real mode). Unrestricted guest has its own requirements, specifically that EPT is also enabled (since IA32 paging could be disabled). Unfortunately, the enable_unrestricted_guest() helper fails to ensure EPT is enabled, which causes all subsequent VMLAUNCH instructions to fail with "invalid control field". Use the new added enable_ept() to configure unrestricted guest. In addition, assert that unrestricted guest is disabled at the beginning of the relevant section as things will likely go sideways if unrestricted guest is already enabled, e.g. odds are good it was enabled in order to muck with CR0. This allows for the removal of disable_unrestricted_guest() entirely. And finally, clean up the control fields after finishing the unrestricted guest section (instead of invoking the defunct disable_unrestricted_guest()). Note that it's not the unrestricted guest tests that fail, since there is no "vmlaunch succeeds" variant, rather its the following tests that expect success that end up failing (because the shoddy enabling of URG isn't undone). Fixes: 8d2cdb3 ("x86: Add test for nested VM entry prereqs") Cc: Marc Orr Signed-off-by: Sean Christopherson Reviewed-by: Marc Orr --- x86/vmx.h | 18 ------------------ x86/vmx_tests.c | 32 +++++++++++++++++++++++++++++--- 2 files changed, 29 insertions(+), 21 deletions(-) diff --git a/x86/vmx.h b/x86/vmx.h index 8a00f73..bcfaa79 100644 --- a/x86/vmx.h +++ b/x86/vmx.h @@ -779,24 +779,6 @@ static inline bool invvpid(unsigned long type, u64 vpid, u64 gla) return ret; } -static inline int enable_unrestricted_guest(void) -{ - if (!(ctrl_cpu_rev[0].clr & CPU_SECONDARY)) - return -1; - - if (!(ctrl_cpu_rev[1].clr & CPU_URG)) - return -1; - - vmcs_write(CPU_EXEC_CTRL0, vmcs_read(CPU_EXEC_CTRL0) | CPU_SECONDARY); - vmcs_write(CPU_EXEC_CTRL1, vmcs_read(CPU_EXEC_CTRL1) | CPU_URG); - return 0; -} - -static inline void disable_unrestricted_guest(void) -{ - vmcs_write(CPU_EXEC_CTRL1, vmcs_read(CPU_EXEC_CTRL1) & ~CPU_URG); -} - const char *exit_reason_description(u64 reason); void print_vmexit_info(void); void print_vmentry_failure_info(struct vmentry_failure *failure); diff --git a/x86/vmx_tests.c b/x86/vmx_tests.c index 4cfb55f..ff51185 100644 --- a/x86/vmx_tests.c +++ b/x86/vmx_tests.c @@ -1067,6 +1067,21 @@ static int enable_ept(void) return setup_eptp(0, false); } +static int enable_unrestricted_guest(void) +{ + if (!(ctrl_cpu_rev[0].clr & CPU_SECONDARY) || + !(ctrl_cpu_rev[1].clr & CPU_URG)) + return 1; + + if (enable_ept()) + return 1; + + vmcs_write(CPU_EXEC_CTRL0, vmcs_read(CPU_EXEC_CTRL0) | CPU_SECONDARY); + vmcs_write(CPU_EXEC_CTRL1, vmcs_read(CPU_EXEC_CTRL1) | CPU_URG); + + return 0; +} + static void ept_enable_ad_bits(void) { eptp |= EPTP_AD_FLAG; @@ -4081,12 +4096,16 @@ static void test_invalid_event_injection(void) * (a) the "unrestricted guest" VM-execution control is 0 * (b) CR0.PE is set. */ + + /* Assert that unrestricted guest is disabled or unsupported */ + assert(!(ctrl_cpu_rev[0].clr & CPU_SECONDARY) || + !(secondary_save & CPU_URG)); + ent_intr_info = ent_intr_info_base | INTR_TYPE_HARD_EXCEPTION | GP_VECTOR; report_prefix_pushf("%s, VM-entry intr info=0x%x", "error code <-> (!URG || prot_mode) [-]", ent_intr_info); - disable_unrestricted_guest(); vmcs_write(GUEST_CR0, guest_cr0_save & ~X86_CR0_PE & ~X86_CR0_PG); vmcs_write(ENT_INTR_INFO, ent_intr_info); test_vmx_controls(false, false); @@ -4097,18 +4116,19 @@ static void test_invalid_event_injection(void) report_prefix_pushf("%s, VM-entry intr info=0x%x", "error code <-> (!URG || prot_mode) [+]", ent_intr_info); - disable_unrestricted_guest(); vmcs_write(GUEST_CR0, guest_cr0_save & ~X86_CR0_PE & ~X86_CR0_PG); vmcs_write(ENT_INTR_INFO, ent_intr_info); test_vmx_controls(true, false); report_prefix_pop(); + if (enable_unrestricted_guest()) + goto skip_unrestricted_guest; + ent_intr_info = ent_intr_info_base | INTR_INFO_DELIVER_CODE_MASK | INTR_TYPE_HARD_EXCEPTION | GP_VECTOR; report_prefix_pushf("%s, VM-entry intr info=0x%x", "error code <-> (!URG || prot_mode) [-]", ent_intr_info); - enable_unrestricted_guest(); vmcs_write(GUEST_CR0, guest_cr0_save & ~X86_CR0_PE & ~X86_CR0_PG); vmcs_write(ENT_INTR_INFO, ent_intr_info); test_vmx_controls(false, false); @@ -4124,6 +4144,12 @@ static void test_invalid_event_injection(void) test_vmx_controls(false, false); report_prefix_pop(); + vmcs_write(CPU_EXEC_CTRL1, secondary_save); + vmcs_write(CPU_EXEC_CTRL0, primary_save); + +skip_unrestricted_guest: + vmcs_write(GUEST_CR0, guest_cr0_save); + /* deliver-error-code is 1 iff the interruption type is HW exception */ report_prefix_push("error code <-> HW exception"); for (cnt = 0; cnt < 8; cnt++) {