From patchwork Thu Jul 6 23:14:16 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bandan Das X-Patchwork-Id: 9829215 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 9395B602BD for ; Thu, 6 Jul 2017 23:14:21 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 82F6D283DA for ; Thu, 6 Jul 2017 23:14:21 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 773992852A; Thu, 6 Jul 2017 23:14:21 +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,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 E4C662851A for ; Thu, 6 Jul 2017 23:14:20 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752963AbdGFXOS (ORCPT ); Thu, 6 Jul 2017 19:14:18 -0400 Received: from mx1.redhat.com ([209.132.183.28]:48742 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752658AbdGFXOR (ORCPT ); Thu, 6 Jul 2017 19:14:17 -0400 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 548B883F3E for ; Thu, 6 Jul 2017 23:14:17 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 548B883F3E Authentication-Results: ext-mx03.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx03.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=bsd@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com 548B883F3E Received: from gigantic.usersys.redhat.com (dhcp-17-169.bos.redhat.com [10.18.17.169]) by smtp.corp.redhat.com (Postfix) with ESMTPS id DDC9F600C2; Thu, 6 Jul 2017 23:14:16 +0000 (UTC) From: Bandan Das To: kvm@vger.kernel.org Cc: Paolo Bonzini Subject: [kvm-unit-tests PATCH] vmx_tests: Add vmfunc tests Date: Thu, 06 Jul 2017 19:14:16 -0400 Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/25.2 (gnu/linux) MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.27]); Thu, 06 Jul 2017 23:14:17 +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 Besides for the obvious vmfunc call in L2 for eptp switching, other tests are to check for valid error paths when L2 calls vmfunc when L1 hasn't enabled it in the secondary controls, L2 calls vmfunc with an invalid function number or calls it with an invalid field from the eptp list Signed-off-by: Bandan Das Reviewed-by: Paolo Bonzini --- lib/x86/msr.h | 1 + x86/vmx.h | 8 +++- x86/vmx_tests.c | 146 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 154 insertions(+), 1 deletion(-) diff --git a/lib/x86/msr.h b/lib/x86/msr.h index 2c0598c..41f75d9 100644 --- a/lib/x86/msr.h +++ b/lib/x86/msr.h @@ -400,6 +400,7 @@ #define MSR_IA32_VMX_TRUE_PROC 0x0000048e #define MSR_IA32_VMX_TRUE_EXIT 0x0000048f #define MSR_IA32_VMX_TRUE_ENTRY 0x00000490 +#define MSR_IA32_VMX_VMFUNC 0x00000491 #define MSR_IA32_TSCDEADLINE 0x000006e0 diff --git a/x86/vmx.h b/x86/vmx.h index d12b9de..b424674 100644 --- a/x86/vmx.h +++ b/x86/vmx.h @@ -138,11 +138,14 @@ enum Encoding { TSC_OFFSET_HI = 0x2011ul, APIC_VIRT_ADDR = 0x2012ul, APIC_ACCS_ADDR = 0x2014ul, + VMFUNC_CTRL = 0x2018ul, + VMFUNC_CTRL_HI = 0x2019ul, EPTP = 0x201aul, EPTP_HI = 0x201bul, PMLADDR = 0x200eul, PMLADDR_HI = 0x200ful, - + EPTP_LIST_ADDR = 0x2024ul, + EPTP_LIST_ADDR_HI = 0x2025ul, /* 64-Bit Readonly Data Field */ INFO_PHYS_ADDR = 0x2400ul, @@ -394,6 +397,7 @@ enum Ctrl1 { CPU_URG = 1ul << 7, CPU_WBINVD = 1ul << 6, CPU_RDRAND = 1ul << 11, + CPU_VMFUNC = 1ul << 13, CPU_PML = 1ul << 17, }; @@ -405,6 +409,8 @@ enum Intr_type { VMX_INTR_TYPE_SOFT_EXCEPTION = 6, }; +#define EPTP_SWITCHING 0x1 + /* * Interruption-information format */ diff --git a/x86/vmx_tests.c b/x86/vmx_tests.c index 2522d3a..01c58cc 100644 --- a/x86/vmx_tests.c +++ b/x86/vmx_tests.c @@ -29,6 +29,9 @@ void *data_page1, *data_page2; void *pml_log; #define PML_INDEX 512 +void *vpage, *hpage1, *hpage2; +void *eptp_list; + static inline unsigned ffs(unsigned x) { int pos = -1; @@ -1332,6 +1335,148 @@ static int eptad_init() return r; } +static int vmfunc_init() +{ + eptp_list = alloc_page(); + u64 *buf = eptp_list; + + vpage = alloc_page(); + hpage1 = alloc_page(); + hpage2 = alloc_page(); + + *((u32 *)vpage) = 0x1; + *((u32 *)hpage1) = 0x2; + *((u32 *)hpage2) = 0x3; + + ept_init_common(false); + buf[0] = (u64)pml4; + install_ept(pml4, (unsigned long)hpage1, (unsigned long)vpage, + EPT_RA | EPT_WA | EPT_EA); + + ept_init_common(false); + buf[1] = (u64)pml4; + install_ept(pml4, (unsigned long)hpage2, (unsigned long)vpage, + EPT_RA | EPT_WA | EPT_EA); + + if (!(ctrl_cpu_rev[1].clr & CPU_VMFUNC)) { + printf("\tVMFUNC is not supported"); + return VMX_TEST_EXIT; + } + + return VMX_TEST_START; +} + +static void vmfunc_ud_handler(struct ex_regs *regs) +{ + switch(vmx_get_test_stage()) { + case 0: + case 3: + regs->rip += 3; + vmx_inc_test_stage(); + vmx_inc_test_stage(); + break; + default: + printf("Unexpected #UD hit!\n"); + print_vmexit_info(); + exit(0); + } +} + +static void vmfunc_main() +{ + int nr = 0, ept = 0; + + handle_exception(UD_VECTOR, vmfunc_ud_handler); + vmx_set_test_stage(0); + + /* Call vmfunc when L1 hasn't enabled it' */ + asm volatile("vmfunc" + : + : "a"(nr), "c"(ept) + : "memory"); + + report("VMFUNC - Disabled VMFUNC in sec controls causes #UD", + vmx_get_test_stage() == 2); + + vmcall(); + /* function > 64 causes #UD */ + nr = 64; + asm volatile("vmfunc" + : + : "a"(nr), "c"(ept) + : "memory"); + report("VMFUNC - guest call with EAX > 63 causes #UD", + vmx_get_test_stage() == 5); + + /* invalid vm function causes vmexit */ + nr = 1; + asm volatile("vmfunc" + : + : "a"(nr), "c"(ept) + : "memory"); + report("VMFUNC - guest call with non-existant function", + vmx_get_test_stage() == 6); + + /* invalid entry from the eptp list causes vmexit */ + nr = 0; + ept = 512; + asm volatile("vmfunc" + : + : "a"(nr), "c"(ept) + : "memory"); + report("VMFUNC - guest call with invalid entry in eptp list", + vmx_get_test_stage() == 7); + + /* + * vpage points to hpage2 with value 0x3 + * vmfunc with ecx = 0 should make vpage + * point to 0x2 + */ + if (*((u32 *)vpage) != 0x3) { + printf("Guest address points to unexpected page\n"); + exit(0); + } + ept = 0; + asm volatile("vmfunc" + : + : "a"(nr), "c"(ept) + : "memory"); + report("VMFUNC - call to switch ept pointer without an exit", + (vmx_get_test_stage() == 7) && (*((u32 *)vpage) == 0x2)); +} + +static int vmfunc_exit_handler(void) +{ + ulong reason = vmcs_read(EXI_REASON) & 0xff; + u64 guest_rip = vmcs_read(GUEST_RIP); + u32 insn_len = vmcs_read(EXI_INST_LEN); + u32 ctrl_cpu; + u64 controls; + + switch (reason) { + case VMX_VMCALL: + ctrl_cpu = vmcs_read(CPU_EXEC_CTRL1) | CPU_VMFUNC; + vmcs_write(CPU_EXEC_CTRL1, ctrl_cpu); + + controls = rdmsr(MSR_IA32_VMX_VMFUNC) & 1; + if (!(controls & EPTP_SWITCHING)) { + printf("\tEPTP switching is not supported"); + return VMX_TEST_EXIT; + } + + vmcs_write(EPTP_LIST_ADDR, (u64)eptp_list); + vmcs_write(VMFUNC_CTRL, controls); + case VMX_VMFUNC: + vmx_inc_test_stage(); + vmcs_write(GUEST_RIP, guest_rip + insn_len); + return VMX_TEST_RESUME; + default: + report("Unknown exit reason, %ld", false, reason); + print_vmexit_info(); + } + return VMX_TEST_VMEXIT; +} + static int pml_init() { u32 ctrl_cpu; @@ -3173,6 +3318,7 @@ struct vmx_test vmx_tests[] = { disable_rdtscp_exit_handler, NULL, {0} }, { "int3", int3_init, int3_guest_main, int3_exit_handler, NULL, {0} }, { "into", into_init, into_guest_main, into_exit_handler, NULL, {0} }, + { "vmfunc", vmfunc_init, vmfunc_main, vmfunc_exit_handler, NULL, {0} }, { "exit_monitor_from_l2_test", NULL, exit_monitor_from_l2_main, exit_monitor_from_l2_handler, NULL, {0} }, /* Basic V2 tests. */