From patchwork Sat Jan 4 17:59:07 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Kiszka X-Patchwork-Id: 3434181 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 E8691C02DC for ; Sat, 4 Jan 2014 17:59:37 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id D34572015F for ; Sat, 4 Jan 2014 17:59:36 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id C57382014A for ; Sat, 4 Jan 2014 17:59:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754384AbaADR7c (ORCPT ); Sat, 4 Jan 2014 12:59:32 -0500 Received: from mout.web.de ([212.227.17.11]:54084 "EHLO mout.web.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754069AbaADR72 (ORCPT ); Sat, 4 Jan 2014 12:59:28 -0500 Received: from mchn199C.home ([95.157.58.223]) by smtp.web.de (mrweb004) with ESMTPSA (Nemesis) id 0M37rD-1VAhjc0XY7-00suU7 for ; Sat, 04 Jan 2014 18:59:27 +0100 From: Jan Kiszka To: Gleb Natapov , Paolo Bonzini , Marcelo Tosatti Cc: kvm Subject: [PATCH 01/13] VMX: Add test cases around interrupt injection and halting Date: Sat, 4 Jan 2014 18:59:07 +0100 Message-Id: X-Mailer: git-send-email 1.8.1.1.298.ge7eed54 In-Reply-To: References: In-Reply-To: References: X-Provags-ID: V03:K0:0p32iQLAIBk5disXj5GPpexTzWv6j4j/cMyGRsPFq9/0AL4seL4 X4bG/o7SjCMVVCvoNVu7e5ERxQNcuNtq0K82P7yCL1q+uXQlmqe6AXbC0j/Ofz3lPpyNuJC fObDi97CLj+qUARN+ezCpJAgMiARD4GBgR5edje9eYniw9ZVo6dOsi7Bf7z8ddRp2qAPVec 1gNkEzt/MRzHnp7IFeDDg== Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Spam-Status: No, score=-7.3 required=5.0 tests=BAYES_00,FREEMAIL_FROM, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, 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 From: Jan Kiszka This checks for interrupt delivery to L2, unintercepted hlt in L2 and explicit L2 suspension via the activity state HLT. All tests are performed both with direct interrupt injection and external interrupt interception. Signed-off-by: Jan Kiszka --- x86/vmx.c | 3 +- x86/vmx.h | 3 ++ x86/vmx_tests.c | 144 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 148 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 bec34c4..70efb50 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; @@ -1117,6 +1119,146 @@ 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, loops; + + set_stage(0); + + apic_write(APIC_LVTT, TIMER_VECTOR); + irq_enable(); + + apic_write(APIC_TMICT, 1); + for (loops = 0; loops < 10000000 && !timer_fired; loops++) + asm volatile ("nop"); + report("direct interrupt while running guest", timer_fired); + + apic_write(APIC_TMICT, 0); + irq_disable(); + vmcall(); + timer_fired = false; + apic_write(APIC_TMICT, 1); + for (loops = 0; loops < 10000000 && !timer_fired; loops++) + asm volatile ("nop"); + report("intercepted interrupt while running guest", timer_fired); + + irq_enable(); + apic_write(APIC_TMICT, 0); + irq_disable(); + vmcall(); + timer_fired = false; + start = rdtsc(); + apic_write(APIC_TMICT, 1000000); + + asm volatile ("sti; hlt"); + + report("direct interrupt + hlt", + rdtsc() - start > 1000000 && timer_fired); + + apic_write(APIC_TMICT, 0); + irq_disable(); + vmcall(); + 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(); + vmcall(); + 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); + + apic_write(APIC_TMICT, 0); + irq_disable(); + vmcall(); + 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); +} + +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: + case 5: + vmcs_write(PIN_CONTROLS, + vmcs_read(PIN_CONTROLS) | PIN_EXTINT); + break; + case 1: + case 3: + vmcs_write(PIN_CONTROLS, + vmcs_read(PIN_CONTROLS) & ~PIN_EXTINT); + break; + case 4: + case 6: + vmcs_write(GUEST_ACTV_STATE, ACTV_HLT); + break; + } + set_stage(get_stage() + 1); + vmcs_write(GUEST_RIP, guest_rip + insn_len); + return VMX_TEST_RESUME; + case VMX_EXTINT: + irq_enable(); + asm volatile ("nop"); + irq_disable(); + if (get_stage() >= 2) { + 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} }, @@ -1134,5 +1276,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} }, };