From patchwork Mon Dec 16 09:57:27 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Kiszka X-Patchwork-Id: 3352761 Return-Path: X-Original-To: patchwork-kvm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 98E95C0D4A for ; Mon, 16 Dec 2013 09:58:05 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 743F020303 for ; Mon, 16 Dec 2013 09:58:04 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id A9A1320375 for ; Mon, 16 Dec 2013 09:57:59 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753239Ab3LPJ5x (ORCPT ); Mon, 16 Dec 2013 04:57:53 -0500 Received: from goliath.siemens.de ([192.35.17.28]:34530 "EHLO goliath.siemens.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753223Ab3LPJ5o (ORCPT ); Mon, 16 Dec 2013 04:57:44 -0500 Received: from mail1.siemens.de (localhost [127.0.0.1]) by goliath.siemens.de (8.13.6/8.13.6) with ESMTP id rBG9vbq7003014; Mon, 16 Dec 2013 10:57:37 +0100 Received: from mchn199C.mchp.siemens.de.com ([146.254.78.38]) by mail1.siemens.de (8.14.3/8.14.3) with SMTP id rBG9vTCG007502; Mon, 16 Dec 2013 10:57:36 +0100 From: Jan Kiszka To: Gleb Natapov , Paolo Bonzini Cc: kvm , Arthur Chunqi Li Subject: [PATCH 14/15] VMX: Add test cases around interrupt injection and halting Date: Mon, 16 Dec 2013 10:57:27 +0100 Message-Id: <54431d044d70d2ce06a9dfb964e0181e4c078d76.1387187847.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.4 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 This checks for interrupt delivery to L2, unintercepted hlt in L2 and explicit L2 suspension via the activity state HLT. Signed-off-by: Jan Kiszka --- x86/vmx.c | 3 +- x86/vmx.h | 3 ++ x86/vmx_tests.c | 125 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 129 insertions(+), 2 deletions(-) diff --git a/x86/vmx.c b/x86/vmx.c index fe950e6..a475aec 100644 --- a/x86/vmx.c +++ b/x86/vmx.c @@ -457,7 +457,7 @@ static void init_vmcs_guest(void) vmcs_write(GUEST_RFLAGS, 0x2); /* 26.3.1.5 */ - vmcs_write(GUEST_ACTV_STATE, 0); + vmcs_write(GUEST_ACTV_STATE, ACTV_ACTIVE); vmcs_write(GUEST_INTR_STATE, 0); } @@ -482,7 +482,6 @@ static int init_vmcs(struct vmcs **vmcs) ctrl_pin |= PIN_EXTINT | PIN_NMI | PIN_VIRT_NMI; ctrl_exit = EXI_LOAD_EFER | EXI_HOST_64; ctrl_enter = (ENT_LOAD_EFER | ENT_GUEST_64); - ctrl_cpu[0] |= CPU_HLT; /* DIsable IO instruction VMEXIT now */ ctrl_cpu[0] &= (~(CPU_IO | CPU_IO_BITMAP)); ctrl_cpu[1] = 0; diff --git a/x86/vmx.h b/x86/vmx.h index bc8c86f..3867793 100644 --- a/x86/vmx.h +++ b/x86/vmx.h @@ -500,6 +500,9 @@ enum Ctrl1 { #define INVEPT_SINGLE 1 #define INVEPT_GLOBAL 2 +#define ACTV_ACTIVE 0 +#define ACTV_HLT 1 + extern struct regs regs; extern union vmx_basic basic; diff --git a/x86/vmx_tests.c b/x86/vmx_tests.c index 36c56b4..27ab032 100644 --- a/x86/vmx_tests.c +++ b/x86/vmx_tests.c @@ -9,6 +9,8 @@ #include "vm.h" #include "io.h" #include "fwcfg.h" +#include "isr.h" +#include "apic.h" u64 ia32_pat; u64 ia32_efer; @@ -1103,6 +1105,127 @@ static int ept_exit_handler() return VMX_TEST_VMEXIT; } +#define TIMER_VECTOR 222 + +static volatile bool timer_fired; + +static void timer_isr(isr_regs_t *regs) +{ + timer_fired = true; + apic_write(APIC_EOI, 0); +} + +static int interrupt_init(struct vmcs *vmcs) +{ + msr_bmp_init(); + vmcs_write(PIN_CONTROLS, vmcs_read(PIN_CONTROLS) & ~PIN_EXTINT); + handle_irq(TIMER_VECTOR, timer_isr); + return VMX_TEST_START; +} + +static void interrupt_main(void) +{ + long long start; + + set_stage(0); + + apic_write(APIC_LVTT, TIMER_VECTOR); + irq_enable(); + + apic_write(APIC_TMICT, 1); + asm volatile ("nop"); + report("direct interrupt without delay", timer_fired); + + timer_fired = false; + irq_disable(); + start = rdtsc(); + apic_write(APIC_TMICT, 1000000); + + asm volatile ("sti; hlt"); + + report("direct interrupt + hlt", + (rdtsc() - start > 1000000 && timer_fired)); + + vmcall(); + apic_write(APIC_TMICT, 0); + irq_disable(); + timer_fired = false; + start = rdtsc(); + apic_write(APIC_TMICT, 1000000); + + asm volatile ("sti; hlt"); + + report("intercepted interrupt + hlt", + (rdtsc() - start > 10000 && timer_fired)); + + apic_write(APIC_TMICT, 0); + irq_disable(); + timer_fired = false; + start = rdtsc(); + apic_write(APIC_TMICT, 1000000); + + irq_enable(); + asm volatile ("nop"); + vmcall(); + + report("direct interrupt + activity state hlt", + (rdtsc() - start > 10000 && timer_fired && get_stage() == 2)); + + vmcall(); + apic_write(APIC_TMICT, 0); + irq_disable(); + timer_fired = false; + start = rdtsc(); + apic_write(APIC_TMICT, 1000000); + + irq_enable(); + asm volatile ("nop"); + vmcall(); + + report("intercepted interrupt + activity state hlt", + (rdtsc() - start > 10000 && timer_fired && get_stage() == 4)); +} + +static int interrupt_exit_handler(void) +{ + u64 guest_rip = vmcs_read(GUEST_RIP); + ulong reason = vmcs_read(EXI_REASON) & 0xff; + u32 insn_len = vmcs_read(EXI_INST_LEN); + + switch (reason) { + case VMX_VMCALL: + switch (get_stage()) { + case 0: + case 2: + set_stage(get_stage() + 1); + vmcs_write(PIN_CONTROLS, + vmcs_read(PIN_CONTROLS) | PIN_EXTINT); + break; + case 1: + case 3: + vmcs_write(GUEST_ACTV_STATE, ACTV_HLT); + set_stage(get_stage() + 1); + break; + } + vmcs_write(GUEST_RIP, guest_rip + insn_len); + return VMX_TEST_RESUME; + case VMX_EXTINT: + irq_enable(); + asm volatile ("nop"); + irq_disable(); + vmcs_write(PIN_CONTROLS, + vmcs_read(PIN_CONTROLS) & ~PIN_EXTINT); + vmcs_write(GUEST_ACTV_STATE, ACTV_ACTIVE); + vmcs_write(GUEST_RIP, guest_rip + insn_len); + return VMX_TEST_RESUME; + default: + printf("Unknown exit reason, %d\n", reason); + print_vmexit_info(); + } + + return VMX_TEST_VMEXIT; +} + /* name/init/guest_main/exit_handler/syscall_handler/guest_regs */ struct vmx_test vmx_tests[] = { { "null", NULL, basic_guest_main, basic_exit_handler, NULL, {0} }, @@ -1120,5 +1243,7 @@ struct vmx_test vmx_tests[] = { { "instruction intercept", insn_intercept_init, insn_intercept_main, insn_intercept_exit_handler, NULL, {0} }, { "EPT framework", ept_init, ept_main, ept_exit_handler, NULL, {0} }, + { "interrupt", interrupt_init, interrupt_main, + interrupt_exit_handler, NULL, {0} }, { NULL, NULL, NULL, NULL, NULL, {0} }, };