From patchwork Fri Sep 13 06:35:18 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arthur Chunqi Li X-Patchwork-Id: 2881821 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 8794D9F1E3 for ; Fri, 13 Sep 2013 06:35:44 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 7D9972029B for ; Fri, 13 Sep 2013 06:35:43 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 6810B203F1 for ; Fri, 13 Sep 2013 06:35:42 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755500Ab3IMGfj (ORCPT ); Fri, 13 Sep 2013 02:35:39 -0400 Received: from mail-pb0-f53.google.com ([209.85.160.53]:61591 "EHLO mail-pb0-f53.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752462Ab3IMGfe (ORCPT ); Fri, 13 Sep 2013 02:35:34 -0400 Received: by mail-pb0-f53.google.com with SMTP id up15so823309pbc.26 for ; Thu, 12 Sep 2013 23:35:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=23u89wjHyMCnO4q3tqNyvL5wIhCKBdikCd1JJ1eikR0=; b=NFQftLRvpXRYRiJyxjo5ZGyGX0o2WwW2lzuLzu3PGVkV0KGipjA1gFF0SITOX4qGUC 06nEZiOWvKjQgNKOGoHxw3hAE5Q9o2QeAeLCdTyqzaqexHwxJCcF9E2jwHu2l++bm2n3 rFlB1ugyqWm+DIL7zPRSl5x/+fvimFCq6WgjPcROql9o6des44HCY9Pt/ccDY+h81HvS Awb5n19AD/DXk+iScL8p4Iyc5e9eZVOqewMsCfI59JlN5SZE3Q9umTwLlH05ckP4nZRd TrpmSdOIU1fAUgz+Upvit7bgrz5RxPHOWM0PpCYPmy1ul8f3D9B1nTywOHYF0lhEZDRq iqmQ== X-Received: by 10.66.179.143 with SMTP id dg15mr13673067pac.52.1379054134015; Thu, 12 Sep 2013 23:35:34 -0700 (PDT) Received: from Blade1-01.Blade1-01 ([162.105.146.101]) by mx.google.com with ESMTPSA id qa9sm9492946pbc.7.1969.12.31.16.00.00 (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Thu, 12 Sep 2013 23:35:32 -0700 (PDT) From: Arthur Chunqi Li To: kvm@vger.kernel.org Cc: jan.kiszka@web.de, gleb@redhat.com, pbonzini@redhat.com, Arthur Chunqi Li Subject: [RFC PATCH 1/2] kvm-unit-tests: VMX: Add vmentry failed handler to framework Date: Fri, 13 Sep 2013 14:35:18 +0800 Message-Id: <1379054119-13336-2-git-send-email-yzt356@gmail.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1379054119-13336-1-git-send-email-yzt356@gmail.com> References: <1379054119-13336-1-git-send-email-yzt356@gmail.com> Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Spam-Status: No, score=-7.7 required=5.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, FREEMAIL_FROM, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, T_DKIM_INVALID, UNPARSEABLE_RELAY autolearn=ham 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 Add vmentry failed handler to vmx framework to catch direct fail of vmentry. When vmlaunch/vmresume directly fail to the next instruction, a entry failed handler is used to handle this failure. Resume failure from entry failed handler will cause entry double fail and directly exit to L1. Signed-off-by: Arthur Chunqi Li --- lib/x86/vm.h | 3 +++ x86/vmx.c | 34 ++++++++++++++++++++-------------- x86/vmx.h | 15 +++++++++++++-- x86/vmx_tests.c | 31 +++++++++++++++++++++---------- 4 files changed, 57 insertions(+), 26 deletions(-) diff --git a/lib/x86/vm.h b/lib/x86/vm.h index 6e0ce2b..c8565b5 100644 --- a/lib/x86/vm.h +++ b/lib/x86/vm.h @@ -19,7 +19,10 @@ #define X86_CR0_PE 0x00000001 #define X86_CR0_MP 0x00000002 #define X86_CR0_TS 0x00000008 +#define X86_CR0_ET 0x00000010 #define X86_CR0_WP 0x00010000 +#define X86_CR0_NW 0x20000000 +#define X86_CR0_CD 0x40000000 #define X86_CR0_PG 0x80000000 #define X86_CR4_VMXE 0x00000001 #define X86_CR4_TSD 0x00000004 diff --git a/x86/vmx.c b/x86/vmx.c index 9db4ef4..6a2bf44 100644 --- a/x86/vmx.c +++ b/x86/vmx.c @@ -44,14 +44,6 @@ void report(const char *name, int result) } } -static int make_vmcs_current(struct vmcs *vmcs) -{ - bool ret; - - asm volatile ("vmptrld %1; setbe %0" : "=q" (ret) : "m" (vmcs) : "cc"); - return ret; -} - /* entry_sysenter */ asm( ".align 4, 0x90\n\t" @@ -631,6 +623,7 @@ static int exit_handler() static int vmx_run() { u32 ret = 0, fail = 0; + bool entry_double_fail = false; while (1) { asm volatile ( @@ -657,28 +650,41 @@ static int vmx_run() ); if (fail) - ret = launched ? VMX_TEST_RESUME_ERR : - VMX_TEST_LAUNCH_ERR; + if (entry_double_fail) + ret = launched ? VMX_TEST_RESUME_ERR : + VMX_TEST_LAUNCH_ERR; + else { + ret = current->entry_failed_handler(launched); + if (ret == VMX_TEST_RESUME) { + entry_double_fail = true; + host_rflags &= ~(X86_EFLAGS_ZF | + X86_EFLAGS_CF); + } + } else { launched = 1; + entry_double_fail = false; ret = exit_handler(); } if (ret != VMX_TEST_RESUME) break; + ret = fail = 0; } launched = 0; switch (ret) { case VMX_TEST_VMEXIT: return 0; case VMX_TEST_LAUNCH_ERR: - printf("%s : vmlaunch failed.\n", __func__); + printf("%s : vmlaunch failed, entry_double_fail=%d.\n", + __func__, entry_double_fail); if ((!(host_rflags & X86_EFLAGS_CF) && !(host_rflags & X86_EFLAGS_ZF)) || ((host_rflags & X86_EFLAGS_CF) && (host_rflags & X86_EFLAGS_ZF))) printf("\tvmlaunch set wrong flags\n"); report("test vmlaunch", 0); break; case VMX_TEST_RESUME_ERR: - printf("%s : vmresume failed.\n", __func__); + printf("%s : vmresume failed, entry_double_fail=%d.\n", + __func__, entry_double_fail); if ((!(host_rflags & X86_EFLAGS_CF) && !(host_rflags & X86_EFLAGS_ZF)) || ((host_rflags & X86_EFLAGS_CF) && (host_rflags & X86_EFLAGS_ZF))) printf("\tvmresume set wrong flags\n"); @@ -700,12 +706,12 @@ static int test_run(struct vmx_test *test) return 1; } init_vmcs(&(test->vmcs)); + current = test; /* Directly call test->init is ok here, init_vmcs has done vmcs init, vmclear and vmptrld*/ if (test->init) - test->init(test->vmcs); + test->init(); test->exits = 0; - current = test; regs = test->guest_regs; vmcs_write(GUEST_RFLAGS, regs.rflags | 0x2); launched = 0; diff --git a/x86/vmx.h b/x86/vmx.h index dc1ebdf..469b4dc 100644 --- a/x86/vmx.h +++ b/x86/vmx.h @@ -4,7 +4,8 @@ #include "libcflat.h" struct vmcs { - u32 revision_id; /* vmcs revision identifier */ + u32 revision_id:31, /* vmcs revision identifier */ + shadow:1; /* shadow-VMCS indicator */ u32 abort; /* VMX-abort indicator */ /* VMCS data */ char data[0]; @@ -32,10 +33,11 @@ struct regs { struct vmx_test { const char *name; - void (*init)(struct vmcs *vmcs); + void (*init)(); void (*guest_main)(); int (*exit_handler)(); void (*syscall_handler)(u64 syscall_no); + int (*entry_failed_handler)(); struct regs guest_regs; struct vmcs *vmcs; int exits; @@ -378,6 +380,7 @@ enum Ctrl1 { CPU_URG = 1ul << 7, CPU_WBINVD = 1ul << 6, CPU_RDRAND = 1ul << 11, + CPU_SHADOW = 1ul << 14, }; #define SAVE_GPR \ @@ -512,6 +515,14 @@ extern union vmx_ctrl_exit ctrl_exit_rev; extern union vmx_ctrl_ent ctrl_enter_rev; extern union vmx_ept_vpid ept_vpid; +static int make_vmcs_current(struct vmcs *vmcs) +{ + bool ret; + + asm volatile ("vmptrld %1; setbe %0" : "=q" (ret) : "m" (vmcs) : "cc"); + return ret; +} + static inline int vmcs_clear(struct vmcs *vmcs) { bool ret; diff --git a/x86/vmx_tests.c b/x86/vmx_tests.c index 0759e10..e95e6b8 100644 --- a/x86/vmx_tests.c +++ b/x86/vmx_tests.c @@ -73,6 +73,12 @@ void basic_syscall_handler(u64 syscall_no) { } +int basic_entry_failed_handler() +{ + return launched ? VMX_TEST_RESUME_ERR : + VMX_TEST_LAUNCH_ERR; +} + void vmenter_main() { u64 rax; @@ -1111,22 +1117,27 @@ static int ept_exit_handler() basic_* just implement some basic functions */ struct vmx_test vmx_tests[] = { { "null", basic_init, basic_guest_main, basic_exit_handler, - basic_syscall_handler, {0} }, + basic_syscall_handler, basic_entry_failed_handler, {0} }, { "vmenter", basic_init, vmenter_main, vmenter_exit_handler, - basic_syscall_handler, {0} }, + basic_syscall_handler, basic_entry_failed_handler, {0} }, { "preemption timer", preemption_timer_init, preemption_timer_main, - preemption_timer_exit_handler, basic_syscall_handler, {0} }, + preemption_timer_exit_handler, basic_syscall_handler, + basic_entry_failed_handler, {0} }, { "control field PAT", test_ctrl_pat_init, test_ctrl_pat_main, - test_ctrl_pat_exit_handler, basic_syscall_handler, {0} }, + test_ctrl_pat_exit_handler, basic_syscall_handler, + basic_entry_failed_handler, {0} }, { "control field EFER", test_ctrl_efer_init, test_ctrl_efer_main, - test_ctrl_efer_exit_handler, basic_syscall_handler, {0} }, + test_ctrl_efer_exit_handler, basic_syscall_handler, + basic_entry_failed_handler, {0} }, { "CR shadowing", basic_init, cr_shadowing_main, - cr_shadowing_exit_handler, basic_syscall_handler, {0} }, + cr_shadowing_exit_handler, basic_syscall_handler, + basic_entry_failed_handler, {0} }, { "I/O bitmap", iobmp_init, iobmp_main, iobmp_exit_handler, - basic_syscall_handler, {0} }, + basic_syscall_handler, basic_entry_failed_handler, {0} }, { "instruction intercept", insn_intercept_init, insn_intercept_main, - insn_intercept_exit_handler, basic_syscall_handler, {0} }, + insn_intercept_exit_handler, basic_syscall_handler, + basic_entry_failed_handler, {0} }, { "EPT framework", ept_init, ept_main, ept_exit_handler, - basic_syscall_handler, {0} }, - { NULL, NULL, NULL, NULL, NULL, {0} }, + basic_syscall_handler, basic_entry_failed_handler, {0} }, + { NULL, NULL, NULL, NULL, NULL, NULL, {0} }, };