From patchwork Tue Jun 17 07:04:40 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Kiszka X-Patchwork-Id: 4364381 Return-Path: X-Original-To: patchwork-kvm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 2D19B9F26E for ; Tue, 17 Jun 2014 07:05:36 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 6CE15202AE for ; Tue, 17 Jun 2014 07:05:34 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 58541202BE for ; Tue, 17 Jun 2014 07:05:33 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752618AbaFQHEu (ORCPT ); Tue, 17 Jun 2014 03:04:50 -0400 Received: from david.siemens.de ([192.35.17.14]:48314 "EHLO david.siemens.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751690AbaFQHEu (ORCPT ); Tue, 17 Jun 2014 03:04:50 -0400 Received: from mail1.siemens.de (localhost [127.0.0.1]) by david.siemens.de (8.14.3/8.14.3) with ESMTP id s5H74khq031083; Tue, 17 Jun 2014 09:04:46 +0200 Received: from mchn199C.mchp.siemens.de.com ([146.254.78.6]) by mail1.siemens.de (8.14.3/8.14.3) with SMTP id s5H74iXp009397; Tue, 17 Jun 2014 09:04:45 +0200 From: Jan Kiszka To: Paolo Bonzini Cc: kvm , Bandan Das Subject: [PATCH v2 3/6] VMX: Test both interception and execution of instructions Date: Tue, 17 Jun 2014 09:04:40 +0200 Message-Id: <66014a9f281dcf41ee19b9e5e0038a2f204daae9.1402988683.git.jan.kiszka@siemens.com> X-Mailer: git-send-email 1.8.1.1.298.ge7eed54 In-Reply-To: References: In-Reply-To: References: Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Spam-Status: No, score=-7.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Extend the instruction interception test to also check for interception-free execution. Signed-off-by: Jan Kiszka --- x86/vmx_tests.c | 121 +++++++++++++++++++++++++++++++++----------------------- 1 file changed, 72 insertions(+), 49 deletions(-) diff --git a/x86/vmx_tests.c b/x86/vmx_tests.c index 5485e4c..f02de3d 100644 --- a/x86/vmx_tests.c +++ b/x86/vmx_tests.c @@ -807,7 +807,6 @@ static int iobmp_exit_handler() #define INSN_CPU0 0 #define INSN_CPU1 1 #define INSN_ALWAYS_TRAP 2 -#define INSN_NEVER_TRAP 3 #define FIELD_EXIT_QUAL (1 << 1) #define FIELD_INSN_INFO (1 << 2) @@ -818,7 +817,7 @@ asm( "insn_mwait: mwait;ret\n\t" "insn_rdpmc: rdpmc;ret\n\t" "insn_rdtsc: rdtsc;ret\n\t" - "insn_cr3_load: mov %rax,%cr3;ret\n\t" + "insn_cr3_load: mov cr3,%rax; mov %rax,%cr3;ret\n\t" "insn_cr3_store: mov %cr3,%rax;ret\n\t" #ifdef __x86_64__ "insn_cr8_load: mov %rax,%cr8;ret\n\t" @@ -848,6 +847,7 @@ extern void insn_cpuid(); extern void insn_invd(); u32 cur_insn; +u64 cr3; struct insn_table { const char *name; @@ -901,55 +901,56 @@ static struct insn_table insn_table[] = { static int insn_intercept_init() { - u32 ctrl_cpu[2]; + u32 ctrl_cpu; - ctrl_cpu[0] = vmcs_read(CPU_EXEC_CTRL0); - ctrl_cpu[0] |= CPU_HLT | CPU_INVLPG | CPU_MWAIT | CPU_RDPMC | CPU_RDTSC | - CPU_CR3_LOAD | CPU_CR3_STORE | -#ifdef __x86_64__ - CPU_CR8_LOAD | CPU_CR8_STORE | -#endif - CPU_MONITOR | CPU_PAUSE | CPU_SECONDARY; - ctrl_cpu[0] &= ctrl_cpu_rev[0].clr; - vmcs_write(CPU_EXEC_CTRL0, ctrl_cpu[0]); - ctrl_cpu[1] = vmcs_read(CPU_EXEC_CTRL1); - ctrl_cpu[1] |= CPU_WBINVD | CPU_RDRAND; - ctrl_cpu[1] &= ctrl_cpu_rev[1].clr; - vmcs_write(CPU_EXEC_CTRL1, ctrl_cpu[1]); + ctrl_cpu = ctrl_cpu_rev[0].set | CPU_SECONDARY; + ctrl_cpu &= ctrl_cpu_rev[0].clr; + vmcs_write(CPU_EXEC_CTRL0, ctrl_cpu); + vmcs_write(CPU_EXEC_CTRL1, ctrl_cpu_rev[1].set); + cr3 = read_cr3(); return VMX_TEST_START; } static void insn_intercept_main() { - cur_insn = 0; - while(insn_table[cur_insn].name != NULL) { - vmx_set_test_stage(cur_insn); - if ((insn_table[cur_insn].type == INSN_CPU0 - && !(ctrl_cpu_rev[0].clr & insn_table[cur_insn].flag)) - || (insn_table[cur_insn].type == INSN_CPU1 - && !(ctrl_cpu_rev[1].clr & insn_table[cur_insn].flag))) { - printf("\tCPU_CTRL1.CPU_%s is not supported.\n", - insn_table[cur_insn].name); + char msg[80]; + + for (cur_insn = 0; insn_table[cur_insn].name != NULL; cur_insn++) { + vmx_set_test_stage(cur_insn * 2); + if ((insn_table[cur_insn].type == INSN_CPU0 && + !(ctrl_cpu_rev[0].clr & insn_table[cur_insn].flag)) || + (insn_table[cur_insn].type == INSN_CPU1 && + !(ctrl_cpu_rev[1].clr & insn_table[cur_insn].flag))) { + printf("\tCPU_CTRL%d.CPU_%s is not supported.\n", + insn_table[cur_insn].type - INSN_CPU0, + insn_table[cur_insn].name); continue; } + + if ((insn_table[cur_insn].type == INSN_CPU0 && + !(ctrl_cpu_rev[0].set & insn_table[cur_insn].flag)) || + (insn_table[cur_insn].type == INSN_CPU1 && + !(ctrl_cpu_rev[1].set & insn_table[cur_insn].flag))) { + /* skip hlt, it stalls the guest and is tested below */ + if (insn_table[cur_insn].insn_func != insn_hlt) + insn_table[cur_insn].insn_func(); + snprintf(msg, sizeof(msg), "execute %s", + insn_table[cur_insn].name); + report(msg, vmx_get_test_stage() == cur_insn * 2); + } else if (insn_table[cur_insn].type != INSN_ALWAYS_TRAP) + printf("\tCPU_CTRL%d.CPU_%s always traps.\n", + insn_table[cur_insn].type - INSN_CPU0, + insn_table[cur_insn].name); + + vmcall(); + insn_table[cur_insn].insn_func(); - switch (insn_table[cur_insn].type) { - case INSN_CPU0: - case INSN_CPU1: - case INSN_ALWAYS_TRAP: - if (vmx_get_test_stage() != cur_insn + 1) - report(insn_table[cur_insn].name, 0); - else - report(insn_table[cur_insn].name, 1); - break; - case INSN_NEVER_TRAP: - if (vmx_get_test_stage() == cur_insn + 1) - report(insn_table[cur_insn].name, 0); - else - report(insn_table[cur_insn].name, 1); - break; - } - cur_insn ++; + snprintf(msg, sizeof(msg), "intercept %s", + insn_table[cur_insn].name); + report(msg, vmx_get_test_stage() == cur_insn * 2 + 1); + + vmx_set_test_stage(cur_insn * 2 + 1); + vmcall(); } } @@ -967,14 +968,36 @@ static int insn_intercept_exit_handler() exit_qual = vmcs_read(EXI_QUALIFICATION); insn_len = vmcs_read(EXI_INST_LEN); insn_info = vmcs_read(EXI_INST_INFO); - pass = (cur_insn == vmx_get_test_stage()) && + + if (reason == VMX_VMCALL) { + u32 val = 0; + + if (insn_table[cur_insn].type == INSN_CPU0) + val = vmcs_read(CPU_EXEC_CTRL0); + else if (insn_table[cur_insn].type == INSN_CPU1) + val = vmcs_read(CPU_EXEC_CTRL1); + + if (vmx_get_test_stage() & 1) + val &= ~insn_table[cur_insn].flag; + else + val |= insn_table[cur_insn].flag; + + if (insn_table[cur_insn].type == INSN_CPU0) + vmcs_write(CPU_EXEC_CTRL0, val | ctrl_cpu_rev[0].set); + else if (insn_table[cur_insn].type == INSN_CPU1) + vmcs_write(CPU_EXEC_CTRL1, val | ctrl_cpu_rev[1].set); + } else { + pass = (cur_insn * 2 == vmx_get_test_stage()) && insn_table[cur_insn].reason == reason; - if (insn_table[cur_insn].test_field & FIELD_EXIT_QUAL) - pass = pass && insn_table[cur_insn].exit_qual == exit_qual; - if (insn_table[cur_insn].test_field & FIELD_INSN_INFO) - pass = pass && insn_table[cur_insn].insn_info == insn_info; - if (pass) - vmx_inc_test_stage(); + if (insn_table[cur_insn].test_field & FIELD_EXIT_QUAL && + insn_table[cur_insn].exit_qual != exit_qual) + pass = false; + if (insn_table[cur_insn].test_field & FIELD_INSN_INFO && + insn_table[cur_insn].insn_info != insn_info) + pass = false; + if (pass) + vmx_inc_test_stage(); + } vmcs_write(GUEST_RIP, guest_rip + insn_len); return VMX_TEST_RESUME; }