From patchwork Thu Jun 29 17:26:46 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?b?UmFkaW0gS3LEjW3DocWZ?= X-Patchwork-Id: 9817489 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 11DC660365 for ; Thu, 29 Jun 2017 17:27:07 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id F108128886 for ; Thu, 29 Jun 2017 17:27:06 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id E581228897; Thu, 29 Jun 2017 17:27:06 +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=-6.9 required=2.0 tests=BAYES_00,HK_RANDOM_FROM, 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 5414528886 for ; Thu, 29 Jun 2017 17:27:06 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752981AbdF2R1F (ORCPT ); Thu, 29 Jun 2017 13:27:05 -0400 Received: from mx1.redhat.com ([209.132.183.28]:47241 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752370AbdF2R1C (ORCPT ); Thu, 29 Jun 2017 13:27:02 -0400 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 4FED331E7DA; Thu, 29 Jun 2017 17:27:01 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 4FED331E7DA Authentication-Results: ext-mx05.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx05.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=rkrcmar@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com 4FED331E7DA Received: from potion (unknown [10.43.2.65]) by smtp.corp.redhat.com (Postfix) with SMTP id 3392D17D9B; Thu, 29 Jun 2017 17:26:58 +0000 (UTC) Received: by potion (sSMTP sendmail emulation); Thu, 29 Jun 2017 19:26:57 +0200 From: =?UTF-8?q?Radim=20Kr=C4=8Dm=C3=A1=C5=99?= To: kvm@vger.kernel.org Cc: Paolo Bonzini , David Matlack , Peter Feiner Subject: [kvm-unit-tests PATCH 2/3] x86/vmx: fix detection of unmapped PTE Date: Thu, 29 Jun 2017 19:26:46 +0200 Message-Id: <20170629172647.22188-3-rkrcmar@redhat.com> In-Reply-To: <20170629172647.22188-1-rkrcmar@redhat.com> References: <20170629172647.22188-1-rkrcmar@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.14 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.29]); Thu, 29 Jun 2017 17:27:01 +0000 (UTC) Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP check_ept_ad() was testing get_ept_pte() for 0, which meant that the PTE lookup failed. dff740c00197 ("x86: ept assertions") changed the return value in that case to -1, which broke the test. Returning 0 and -1 is ambiguous, so let's return false instead and get the PTE through a pointer argument. This skips a test that was failing before, because it was looking at invalid type (the meta -1) instead of the pte. Signed-off-by: Radim Krčmář Reviewed-by: Peter Feiner --- I'm not sure if the case was supposed to be tested more, rather than called as "ok". --- x86/vmx.c | 33 +++++++++++++++++++-------------- x86/vmx.h | 4 ++-- x86/vmx_tests.c | 20 ++++++++++---------- 3 files changed, 31 insertions(+), 26 deletions(-) diff --git a/x86/vmx.c b/x86/vmx.c index 9189a66759ec..5e3832727f05 100644 --- a/x86/vmx.c +++ b/x86/vmx.c @@ -809,29 +809,30 @@ void setup_ept_range(unsigned long *pml4, unsigned long start, /* get_ept_pte : Get the PTE of a given level in EPT, @level == 1 means get the latest level*/ -unsigned long get_ept_pte(unsigned long *pml4, - unsigned long guest_addr, int level) +bool get_ept_pte(unsigned long *pml4, unsigned long guest_addr, int level, + unsigned long *pte) { int l; - unsigned long *pt = pml4, pte; + unsigned long *pt = pml4, iter_pte; unsigned offset; assert(level >= 1 && level <= 4); for (l = EPT_PAGE_LEVEL; ; --l) { offset = (guest_addr >> EPT_LEVEL_SHIFT(l)) & EPT_PGDIR_MASK; - pte = pt[offset]; - if (!(pte & (EPT_PRESENT))) - return -1; + iter_pte = pt[offset]; + if (!(iter_pte & (EPT_PRESENT))) + return false; if (l == level) break; - if (l < 4 && (pte & EPT_LARGE_PAGE)) - return -1; - pt = (unsigned long *)(pte & EPT_ADDR_MASK); + if (l < 4 && (iter_pte & EPT_LARGE_PAGE)) + return false; + pt = (unsigned long *)(iter_pte & EPT_ADDR_MASK); } offset = (guest_addr >> EPT_LEVEL_SHIFT(l)) & EPT_PGDIR_MASK; - pte = pt[offset]; - return pte; + if (pte) + *pte = pt[offset]; + return true; } static void clear_ept_ad_pte(unsigned long *pml4, unsigned long guest_addr) @@ -894,9 +895,10 @@ void check_ept_ad(unsigned long *pml4, u64 guest_cr3, for (l = EPT_PAGE_LEVEL; ; --l) { offset = (guest_addr >> EPT_LEVEL_SHIFT(l)) & EPT_PGDIR_MASK; - ept_pte = get_ept_pte(pml4, (u64) &pt[offset], 1); - if (ept_pte == 0) + if (!get_ept_pte(pml4, (u64) &pt[offset], 1, &ept_pte)) { + printf("EPT - guest level %d page table is not mapped.\n", l); return; + } if (!bad_pt_ad) { bad_pt_ad |= (ept_pte & (EPT_ACCESS_FLAG|EPT_DIRTY_FLAG)) != expected_pt_ad; @@ -925,7 +927,10 @@ void check_ept_ad(unsigned long *pml4, u64 guest_cr3, offset_in_page = guest_addr & ((1 << EPT_LEVEL_SHIFT(l)) - 1); gpa = (pt[offset] & PT_ADDR_MASK) | (guest_addr & offset_in_page); - ept_pte = get_ept_pte(pml4, gpa, 1); + if (!get_ept_pte(pml4, gpa, 1, &ept_pte)) { + report("EPT - guest physical address is not mapped", false); + return; + } report("EPT - guest physical address A=%d/D=%d", (ept_pte & (EPT_ACCESS_FLAG|EPT_DIRTY_FLAG)) == expected_gpa_ad, !!(expected_gpa_ad & EPT_ACCESS_FLAG), diff --git a/x86/vmx.h b/x86/vmx.h index 787466653f8b..efbb320f44c7 100644 --- a/x86/vmx.h +++ b/x86/vmx.h @@ -697,8 +697,8 @@ void install_ept(unsigned long *pml4, unsigned long phys, unsigned long guest_addr, u64 perm); void setup_ept_range(unsigned long *pml4, unsigned long start, unsigned long len, int map_1g, int map_2m, u64 perm); -unsigned long get_ept_pte(unsigned long *pml4, - unsigned long guest_addr, int level); +bool get_ept_pte(unsigned long *pml4, unsigned long guest_addr, int level, + unsigned long *pte); void set_ept_pte(unsigned long *pml4, unsigned long guest_addr, int level, u64 pte_val); void check_ept_ad(unsigned long *pml4, u64 guest_cr3, diff --git a/x86/vmx_tests.c b/x86/vmx_tests.c index 7be016ce4fbc..181c3c73cb60 100644 --- a/x86/vmx_tests.c +++ b/x86/vmx_tests.c @@ -1212,17 +1212,18 @@ static int ept_exit_handler_common(bool have_ad) break; case 3: clear_ept_ad(pml4, guest_cr3, (unsigned long)data_page1); - data_page1_pte = get_ept_pte(pml4, - (unsigned long)data_page1, 1); + TEST_ASSERT(get_ept_pte(pml4, (unsigned long)data_page1, + 1, &data_page1_pte)); set_ept_pte(pml4, (unsigned long)data_page1, 1, data_page1_pte & ~EPT_PRESENT); ept_sync(INVEPT_SINGLE, eptp); break; case 4: - data_page1_pte = get_ept_pte(pml4, - (unsigned long)data_page1, 2); + TEST_ASSERT(get_ept_pte(pml4, (unsigned long)data_page1, + 2, &data_page1_pte)); data_page1_pte &= PAGE_MASK; - data_page1_pte_pte = get_ept_pte(pml4, data_page1_pte, 2); + TEST_ASSERT(get_ept_pte(pml4, data_page1_pte, + 2, &data_page1_pte_pte)); set_ept_pte(pml4, data_page1_pte, 2, data_page1_pte_pte & ~EPT_PRESENT); ept_sync(INVEPT_SINGLE, eptp); @@ -1267,7 +1268,7 @@ static int ept_exit_handler_common(bool have_ad) if (exit_qual == (EPT_VLT_WR | EPT_VLT_LADDR_VLD | EPT_VLT_PADDR)) vmx_inc_test_stage(); - set_ept_pte(pml4, (unsigned long)data_page1, + set_ept_pte(pml4, (unsigned long)data_page1, 1, data_page1_pte | (EPT_PRESENT)); ept_sync(INVEPT_SINGLE, eptp); break; @@ -2175,8 +2176,7 @@ static unsigned long ept_twiddle(unsigned long gpa, bool mkhuge, int level, unsigned long pte; /* Screw with the mapping at the requested level. */ - orig_pte = get_ept_pte(pml4, gpa, level); - TEST_ASSERT(orig_pte != -1); + TEST_ASSERT(get_ept_pte(pml4, gpa, level, &orig_pte)); pte = orig_pte; if (mkhuge) pte = (orig_pte & ~EPT_ADDR_MASK) | data->hpa | EPT_LARGE_PAGE; @@ -2603,8 +2603,8 @@ static void ept_access_test_setup(void) * Make sure nothing's mapped here so the tests that screw with the * pml4 entry don't inadvertently break something. */ - TEST_ASSERT_EQ(get_ept_pte(pml4, data->gpa, 4), -1); - TEST_ASSERT_EQ(get_ept_pte(pml4, data->gpa + size - 1, 4), -1); + TEST_ASSERT(!get_ept_pte(pml4, data->gpa, 4, NULL)); + TEST_ASSERT(!get_ept_pte(pml4, data->gpa + size - 1, 4, NULL)); install_ept(pml4, data->hpa, data->gpa, EPT_PRESENT); data->hva[0] = MAGIC_VAL_1;