From patchwork Wed Nov 21 00:26:19 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jim Mattson X-Patchwork-Id: 10691477 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 946DF13BF for ; Wed, 21 Nov 2018 00:26:35 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 80BAA2AED1 for ; Wed, 21 Nov 2018 00:26:35 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 751CA2AEE1; Wed, 21 Nov 2018 00:26:35 +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=-15.5 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI, USER_IN_DEF_DKIM_WL 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 D22B22AED8 for ; Wed, 21 Nov 2018 00:26:34 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726047AbeKUK61 (ORCPT ); Wed, 21 Nov 2018 05:58:27 -0500 Received: from mail-ot1-f74.google.com ([209.85.210.74]:55856 "EHLO mail-ot1-f74.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725913AbeKUK61 (ORCPT ); Wed, 21 Nov 2018 05:58:27 -0500 Received: by mail-ot1-f74.google.com with SMTP id e3so2123805otd.22 for ; Tue, 20 Nov 2018 16:26:32 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:message-id:mime-version:subject:from:to:cc; bh=3YkHIkVL969En66710y+6hTqPkXNV13niBCTCROHWPc=; b=tJ/b4SJ7c78pEe7U6QLhqnTvzJReAsJl+X8vP58vuAKiZs+IEFHzKdnGanl7Ffl+qG QVvtbpVpzBemfsZwa8CIf2Jg8TZ+WRYx6frQ3rUJxCobm5tAqlfJ0DLymDnvzTnqdqn7 C84+rlY0OUXelH4s4qMsEmr+13HahgtCuF66OhEzyRjWkN1rb+ckQs9qEt+x82cCB8qd DtwWVK/fzJ12wF228nzcQ6hTdF2DRFURie+XxvLNxwPme4m9EV8ckrZmPeb9Lr9AVMqe AvfJ+tFsGAgx0tOHSDIvjI8fl1bQm482GJhZhTq0MFTqMb/Rc9IzMdTRqGQOJG/qL4/Z 1u7w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:message-id:mime-version:subject:from:to:cc; bh=3YkHIkVL969En66710y+6hTqPkXNV13niBCTCROHWPc=; b=DQcNA7MyC3tZXq7mPOJ43T5KX8e8L8nCGAtPTJMyVZTY4Pno9D1FwRkcN3loVt7K4b UnTZDApShioma3A+4FhuYJzSWEJr8TyB9JubOnZp/jyZKwpmx15A7orRdP+PeAxvUMZQ ZaztHZqz9J7tHkUqgQT8VRziEuCTVE6jWBDu1SROEgh/GFafgPTOH39V6RRUItg3eJtP 5f/MdhLPnCP0Q+L3FoDSh36ZSsI/eagKQOXT1rpFuWskpuxl57W5verBqaGOoE+thr6o fmaJUdEEnM2hgw5ESj+yHllJMifH7SdLeAU8/3X0OOmN/iSsOO/qyFgElFic431Q/DRO 3GaA== X-Gm-Message-State: AA+aEWZEQSYcOvMbN6pPeNqcADeYIp58h+Ax2HCwxe5RE4UVdq0uTM+I VOq1KiP+M5BkloqLJs48u1BXmRSBy8G1OtRQnXIUTKh32/wx7FpTPZx7lfdxXjgoqvVP/+hTQJG AkH7zZEHA/VREHPsOMLzCB2YFHbCY1tw3E7Ne8C6LXguMg/eSzY3ODctOcu9D2KQ= X-Google-Smtp-Source: AFSGD/Wp0KilNndBS8uvX8xHx8Y3QSPyEvxjC8AguKQfoAsTddXyqEZUv7jzOG4hTFAgtqRqfM/ezw2PDVE7Iw== X-Received: by 2002:a9d:2961:: with SMTP id d88mr2826694otb.44.1542759992401; Tue, 20 Nov 2018 16:26:32 -0800 (PST) Date: Tue, 20 Nov 2018 16:26:19 -0800 Message-Id: <20181121002620.240795-1-jmattson@google.com> Mime-Version: 1.0 X-Mailer: git-send-email 2.19.1.1215.g8438c0b245-goog Subject: [kvm-unit-tests PATCH 1/2] x86: nVMX: Basic test of NMI-window exiting From: Jim Mattson To: kvm@vger.kernel.org Cc: Jim Mattson , Peter Shier Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Test various NMI-window exiting scenarios. In the active activity state, test without any blocking, with blocking by MOV-SS, no blocking with event injection, and with blocking by NMI. In the halted activity state, test without any blocking, with and without event injection. Signed-off-by: Jim Mattson Reviewed-by: Peter Shier --- lib/x86/desc.h | 9 +++ x86/unittests.cfg | 6 ++ x86/vmx_tests.c | 137 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 152 insertions(+) diff --git a/lib/x86/desc.h b/lib/x86/desc.h index 977a233..7a7358a 100644 --- a/lib/x86/desc.h +++ b/lib/x86/desc.h @@ -224,4 +224,13 @@ void __set_exception_jmpbuf(jmp_buf *addr); #define set_exception_jmpbuf(jmpbuf) \ (setjmp(jmpbuf) ? : (__set_exception_jmpbuf(&(jmpbuf)), 0)) +static inline void *get_idt_addr(idt_entry_t *entry) +{ + uintptr_t addr = entry->offset0 | ((u32)entry->offset1 << 16); +#ifdef __x86_64__ + addr |= (u64)entry->offset2 << 32; +#endif + return (void *)addr; +} + #endif diff --git a/x86/unittests.cfg b/x86/unittests.cfg index 3b21a85..04faa6e 100644 --- a/x86/unittests.cfg +++ b/x86/unittests.cfg @@ -578,6 +578,12 @@ extra_params = -cpu host,+vmx -m 2560 -append vmx_db_test arch = x86_64 groups = vmx +[vmx_nmi_window_test] +file = vmx.flat +extra_params = -cpu host,+vmx -m 2560 -append vmx_nmi_window_test +arch = x86_64 +groups = vmx + [vmx_eoi_bitmap_ioapic_scan] file = vmx.flat smp = 2 diff --git a/x86/vmx_tests.c b/x86/vmx_tests.c index b105b23..ec4f051 100644 --- a/x86/vmx_tests.c +++ b/x86/vmx_tests.c @@ -5031,6 +5031,142 @@ static void vmx_pending_event_hlt_test(void) vmx_pending_event_test_core(true); } +static int vmx_window_test_ud_count; + +static void vmx_window_test_ud_handler(struct ex_regs *regs) +{ + vmx_window_test_ud_count++; +} + +static void vmx_nmi_window_test_guest(void) +{ + handle_exception(UD_VECTOR, vmx_window_test_ud_handler); + + asm volatile("vmcall\n\t" + "nop\n\t"); + + handle_exception(UD_VECTOR, NULL); +} + +static void verify_nmi_window_exit(u64 rip) +{ + u32 exit_reason = vmcs_read(EXI_REASON); + + report("Exit reason (%d) is 'NMI window'", + exit_reason == VMX_NMI_WINDOW, exit_reason); + report("RIP (%#lx) is %#lx", vmcs_read(GUEST_RIP) == rip, + vmcs_read(GUEST_RIP), rip); + report("Activity state (%ld) is 'ACTIVE'", + vmcs_read(GUEST_ACTV_STATE) == ACTV_ACTIVE, + vmcs_read(GUEST_ACTV_STATE)); +} + +static void vmx_nmi_window_test(void) +{ + u64 nop_addr; + void *ud_fault_addr = get_idt_addr(&boot_idt[UD_VECTOR]); + + if (!(ctrl_pin_rev.clr & PIN_VIRT_NMI)) { + report_skip("CPU does not support the \"Virtual NMIs\" VM-execution control."); + return; + } + + if (!(ctrl_cpu_rev[0].clr & CPU_NMI_WINDOW)) { + report_skip("CPU does not support the \"NMI-window exiting\" VM-execution control."); + return; + } + + vmx_window_test_ud_count = 0; + + report_prefix_push("NMI-window"); + test_set_guest(vmx_nmi_window_test_guest); + vmcs_set_bits(PIN_CONTROLS, PIN_VIRT_NMI); + enter_guest(); + skip_exit_vmcall(); + nop_addr = vmcs_read(GUEST_RIP); + + /* + * Ask for "NMI-window exiting," and expect an immediate VM-exit. + * RIP will not advance. + */ + report_prefix_push("active, no blocking"); + vmcs_set_bits(CPU_EXEC_CTRL0, CPU_NMI_WINDOW); + enter_guest(); + verify_nmi_window_exit(nop_addr); + report_prefix_pop(); + + /* + * Ask for "NMI-window exiting" in a MOV-SS shadow, and expect + * a VM-exit on the next instruction after the nop. (The nop + * is one byte.) + */ + report_prefix_push("active, blocking by MOV-SS"); + vmcs_write(GUEST_INTR_STATE, GUEST_INTR_STATE_MOVSS); + enter_guest(); + verify_nmi_window_exit(nop_addr + 1); + report_prefix_pop(); + + /* + * Ask for "NMI-window exiting" (with event injection), and + * expect a VM-exit after the event is injected. (RIP should + * be at the address specified in the IDT entry for #UD.) + */ + report_prefix_push("active, no blocking, injecting #UD"); + vmcs_write(ENT_INTR_INFO, + INTR_INFO_VALID_MASK | INTR_TYPE_HARD_EXCEPTION | UD_VECTOR); + enter_guest(); + verify_nmi_window_exit((u64)ud_fault_addr); + report_prefix_pop(); + + /* + * Ask for "NMI-window exiting" with NMI blocking, and expect + * a VM-exit after the next IRET (i.e. after the #UD handler + * returns). So, RIP should be back at one byte past the nop. + */ + report_prefix_push("active, blocking by NMI"); + vmcs_write(GUEST_INTR_STATE, GUEST_INTR_STATE_NMI); + enter_guest(); + verify_nmi_window_exit(nop_addr + 1); + report("#UD handler executed once (actual %d times)", + vmx_window_test_ud_count == 1, + vmx_window_test_ud_count); + report_prefix_pop(); + + if (!(rdmsr(MSR_IA32_VMX_MISC) & (1 << 6))) { + report_skip("CPU does not support activity state HLT."); + } else { + /* + * Ask for "NMI-window exiting" when entering activity + * state HLT, and expect an immediate VM-exit. RIP is + * still one byte past the nop. + */ + report_prefix_push("halted, no blocking"); + vmcs_write(GUEST_ACTV_STATE, ACTV_HLT); + enter_guest(); + verify_nmi_window_exit(nop_addr + 1); + report_prefix_pop(); + + /* + * Ask for "NMI-window exiting" when entering activity + * state HLT (with event injection), and expect a + * VM-exit after the event is injected. (RIP should be + * at the address specified in the IDT entry for #UD.) + */ + report_prefix_push("halted, no blocking, injecting #UD"); + vmcs_write(GUEST_ACTV_STATE, ACTV_HLT); + vmcs_write(ENT_INTR_INFO, + INTR_INFO_VALID_MASK | INTR_TYPE_HARD_EXCEPTION | + UD_VECTOR); + enter_guest(); + verify_nmi_window_exit((u64)ud_fault_addr); + report_prefix_pop(); + } + + vmcs_clear_bits(CPU_EXEC_CTRL0, CPU_NMI_WINDOW); + enter_guest(); + report_prefix_pop(); +} + static void vmx_db_test_guest(void) { /* @@ -5833,6 +5969,7 @@ struct vmx_test vmx_tests[] = { TEST(vmx_cr_load_test), TEST(vmx_nm_test), TEST(vmx_db_test), + TEST(vmx_nmi_window_test), TEST(vmx_pending_event_test), TEST(vmx_pending_event_hlt_test), /* EPT access tests. */ From patchwork Wed Nov 21 00:26:20 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jim Mattson X-Patchwork-Id: 10691479 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 1534B13AD for ; Wed, 21 Nov 2018 00:26:46 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id F1AC62AEE1 for ; Wed, 21 Nov 2018 00:26:45 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id E2B8A2AEF1; Wed, 21 Nov 2018 00:26:45 +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=-15.5 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI,RCVD_IN_DNSWL_HI, USER_IN_DEF_DKIM_WL 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 BD9112AEE1 for ; Wed, 21 Nov 2018 00:26:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726144AbeKUK6h (ORCPT ); Wed, 21 Nov 2018 05:58:37 -0500 Received: from mail-yb1-f201.google.com ([209.85.219.201]:53221 "EHLO mail-yb1-f201.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725903AbeKUK6h (ORCPT ); Wed, 21 Nov 2018 05:58:37 -0500 Received: by mail-yb1-f201.google.com with SMTP id 7-v6so2081646ybi.19 for ; Tue, 20 Nov 2018 16:26:42 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=d4CBiBZM4oY20fmpCqSQt7WbN4kQNp6W5MMLCwoMtGI=; b=TzaH6/v8Oa0o62OqG2ePdVOiSR7VdzoZ5qObKVU0QaxxL235rnUSdrleaWXKwjNX84 xzeOrU9z1mlVFlsDHSKDOWnO+VDSn1gSBACHPpQ/CVkuo+RImDr3gelhi0gY46b7XbOY IYO6QCQyWEGCjClXPxLYOZuxActtL6oYzE8UdnrMfbi96j4K5Mpo0lVQ4Akf4PFMiuHL O3+wbET08Jjwxs1Xb37Cck/7Vv1Wv9hY/TqGFNOxhSLCmUejYsSc6mzs0qndYaEZwlTT q7PDyrrwqaYFO9vhIEPzbzQoZFKH8Y6EP5HE2DyKn13jUAa7VxoV5JO2iiNAeRKK8LHh jFLg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=d4CBiBZM4oY20fmpCqSQt7WbN4kQNp6W5MMLCwoMtGI=; b=PSKn8u8U2v3oc6d0spUwxB4vKFdsXhDjSeRSJY6bmHLWt3vszv6svDMwOS7g9uSeRk B5C8PXLhQqlIq9bV+j2idypZP84u8ayviaBBW9+xbTbFKMJslzVzLMtnBrMl+UX2Iw00 7fUeviAgXb9tm3EEXqDRMQ59ymgpx+E3Chs2uYBSuC7LeysWqaQavTy9uKXxi4D7zId7 uTDU7XshSkEFp21xUjz1n9YFhCHLJJP7DMRK9yBLOEsAt69V+6RBPAdlydQObRP92wTj SH3lGMxR0Ub3Z+rRGXKQFFdwEAmVJ27aJ1FQhKKs+1wP/R/lr7N56QxKRJH/VFVxs4wL 1tGw== X-Gm-Message-State: AGRZ1gJ6NM8QT7PHbrx5ggNKsgMw6pv+xJNmdnqll0dNgm95bED2Rhda f8Zjh303ZX8SkfRxdR/ESvaENNQrPcoFXpt16s7tb3uSviC8fuXPivRaYN1t5vEn/HbwEslc/z1 d+APCayTft7SX65XQsbuwEPwyEgMugrdtUwiHomVC/HQQuc7Js/BEj21KEoxQICA= X-Google-Smtp-Source: AJdET5frDh+EmF38zcY94o0iYGmhvm+1VlFvuFFXsvg3Ew64FA7v+/t1uBVSjfxEOSf08sZc9HmfolYUnyGWQg== X-Received: by 2002:a81:6288:: with SMTP id w130-v6mr1959183ywb.21.1542760002320; Tue, 20 Nov 2018 16:26:42 -0800 (PST) Date: Tue, 20 Nov 2018 16:26:20 -0800 In-Reply-To: <20181121002620.240795-1-jmattson@google.com> Message-Id: <20181121002620.240795-2-jmattson@google.com> Mime-Version: 1.0 References: <20181121002620.240795-1-jmattson@google.com> X-Mailer: git-send-email 2.19.1.1215.g8438c0b245-goog Subject: [kvm-unit-tests PATCH 2/2] x86: nVMX: Basic test of interrupt-window exiting From: Jim Mattson To: kvm@vger.kernel.org Cc: Jim Mattson , Peter Shier Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Test various interrupt-window exiting scenarios. In the active activity state, test without any blocking (with and without event injection), with blocking by MOV-SS, with blocking by STI, and with RFLAGS.IF clear. In the halted activity state, test without any blocking (with and without event injection). Signed-off-by: Jim Mattson Reviewed-by: Peter Shier --- x86/unittests.cfg | 6 ++ x86/vmx_tests.c | 171 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 177 insertions(+) diff --git a/x86/unittests.cfg b/x86/unittests.cfg index 04faa6e..366322c 100644 --- a/x86/unittests.cfg +++ b/x86/unittests.cfg @@ -584,6 +584,12 @@ extra_params = -cpu host,+vmx -m 2560 -append vmx_nmi_window_test arch = x86_64 groups = vmx +[vmx_intr_window_test] +file = vmx.flat +extra_params = -cpu host,+vmx -m 2560 -append vmx_intr_window_test +arch = x86_64 +groups = vmx + [vmx_eoi_bitmap_ioapic_scan] file = vmx.flat smp = 2 diff --git a/x86/vmx_tests.c b/x86/vmx_tests.c index ec4f051..edba028 100644 --- a/x86/vmx_tests.c +++ b/x86/vmx_tests.c @@ -5167,6 +5167,176 @@ static void vmx_nmi_window_test(void) report_prefix_pop(); } +static void vmx_intr_window_test_guest(void) +{ + handle_exception(UD_VECTOR, vmx_window_test_ud_handler); + + /* + * The two consecutive STIs are to ensure that only the first + * one has a shadow. Note that NOP and STI are one byte + * instructions. + */ + asm volatile("vmcall\n\t" + "nop\n\t" + "sti\n\t" + "sti\n\t"); + + handle_exception(UD_VECTOR, NULL); +} + +static void verify_intr_window_exit(u64 rip) +{ + u32 exit_reason = vmcs_read(EXI_REASON); + + report("Exit reason (%d) is 'interrupt window'", + exit_reason == VMX_INTR_WINDOW, exit_reason); + report("RIP (%#lx) is %#lx", vmcs_read(GUEST_RIP) == rip, + vmcs_read(GUEST_RIP), rip); + report("Activity state (%ld) is 'ACTIVE'", + vmcs_read(GUEST_ACTV_STATE) == ACTV_ACTIVE, + vmcs_read(GUEST_ACTV_STATE)); +} + +static void vmx_intr_window_test(void) +{ + u64 vmcall_addr; + u64 nop_addr; + unsigned int orig_ud_gate_type; + void *ud_fault_addr = get_idt_addr(&boot_idt[UD_VECTOR]); + + if (!(ctrl_cpu_rev[0].clr & CPU_INTR_WINDOW)) { + report_skip("CPU does not support the \"interrupt-window exiting\" VM-execution control."); + return; + } + + /* + * Change the IDT entry for #UD from interrupt gate to trap gate, + * so that it won't clear RFLAGS.IF. We don't want interrupts to + * be disabled after vectoring a #UD. + */ + orig_ud_gate_type = boot_idt[UD_VECTOR].type; + boot_idt[UD_VECTOR].type = 15; + + report_prefix_push("interrupt-window"); + test_set_guest(vmx_intr_window_test_guest); + enter_guest(); + assert_exit_reason(VMX_VMCALL); + vmcall_addr = vmcs_read(GUEST_RIP); + + /* + * Ask for "interrupt-window exiting" with RFLAGS.IF set and + * no blocking; expect an immediate VM-exit. Note that we have + * not advanced past the vmcall instruction yet, so RIP should + * point to the vmcall instruction. + */ + report_prefix_push("active, no blocking, RFLAGS.IF=1"); + vmcs_set_bits(CPU_EXEC_CTRL0, CPU_INTR_WINDOW); + vmcs_write(GUEST_RFLAGS, X86_EFLAGS_FIXED | X86_EFLAGS_IF); + enter_guest(); + verify_intr_window_exit(vmcall_addr); + report_prefix_pop(); + + /* + * Ask for "interrupt-window exiting" (with event injection) + * with RFLAGS.IF set and no blocking; expect a VM-exit after + * the event is injected. That is, RIP should should be at the + * address specified in the IDT entry for #UD. + */ + report_prefix_push("active, no blocking, RFLAGS.IF=1, injecting #UD"); + vmcs_write(ENT_INTR_INFO, + INTR_INFO_VALID_MASK | INTR_TYPE_HARD_EXCEPTION | UD_VECTOR); + vmcall_addr = vmcs_read(GUEST_RIP); + enter_guest(); + verify_intr_window_exit((u64)ud_fault_addr); + report_prefix_pop(); + + /* + * Let the L2 guest run through the IRET, back to the VMCALL. + * We have to clear the "interrupt-window exiting" + * VM-execution control, or it would just keep causing + * VM-exits. Then, advance past the VMCALL and set the + * "interrupt-window exiting" VM-execution control again. + */ + vmcs_clear_bits(CPU_EXEC_CTRL0, CPU_INTR_WINDOW); + enter_guest(); + skip_exit_vmcall(); + nop_addr = vmcs_read(GUEST_RIP); + vmcs_set_bits(CPU_EXEC_CTRL0, CPU_INTR_WINDOW); + + /* + * Ask for "interrupt-window exiting" in a MOV-SS shadow with + * RFLAGS.IF set, and expect a VM-exit on the next + * instruction. (NOP is one byte.) + */ + report_prefix_push("active, blocking by MOV-SS, RFLAGS.IF=1"); + vmcs_write(GUEST_INTR_STATE, GUEST_INTR_STATE_MOVSS); + enter_guest(); + verify_intr_window_exit(nop_addr + 1); + report_prefix_pop(); + + /* + * Back up to the NOP and ask for "interrupt-window exiting" + * in an STI shadow with RFLAGS.IF set, and expect a VM-exit + * on the next instruction. (NOP is one byte.) + */ + report_prefix_push("active, blocking by STI, RFLAGS.IF=1"); + vmcs_write(GUEST_RIP, nop_addr); + vmcs_write(GUEST_INTR_STATE, GUEST_INTR_STATE_STI); + enter_guest(); + verify_intr_window_exit(nop_addr + 1); + report_prefix_pop(); + + /* + * Ask for "interrupt-window exiting" with RFLAGS.IF clear, + * and expect a VM-exit on the instruction following the STI + * shadow. Only the first STI (which is one byte past the NOP) + * should have a shadow. The second STI (which is two bytes + * past the NOP) has no shadow. Therefore, the interrupt + * window opens at three bytes past the NOP. + */ + report_prefix_push("active, RFLAGS.IF = 0"); + vmcs_write(GUEST_RFLAGS, X86_EFLAGS_FIXED); + enter_guest(); + verify_intr_window_exit(nop_addr + 3); + report_prefix_pop(); + + if (!(rdmsr(MSR_IA32_VMX_MISC) & (1 << 6))) { + report_skip("CPU does not support activity state HLT."); + } else { + /* + * Ask for "interrupt-window exiting" when entering + * activity state HLT, and expect an immediate + * VM-exit. RIP is still three bytes past the nop. + */ + report_prefix_push("halted, no blocking"); + vmcs_write(GUEST_ACTV_STATE, ACTV_HLT); + enter_guest(); + verify_intr_window_exit(nop_addr + 3); + report_prefix_pop(); + + /* + * Ask for "interrupt-window exiting" when entering + * activity state HLT (with event injection), and + * expect a VM-exit after the event is injected. That + * is, RIP should should be at the address specified + * in the IDT entry for #UD. + */ + report_prefix_push("halted, no blocking, injecting #UD"); + vmcs_write(GUEST_ACTV_STATE, ACTV_HLT); + vmcs_write(ENT_INTR_INFO, + INTR_INFO_VALID_MASK | INTR_TYPE_HARD_EXCEPTION | + UD_VECTOR); + enter_guest(); + verify_intr_window_exit((u64)ud_fault_addr); + report_prefix_pop(); + } + + boot_idt[UD_VECTOR].type = orig_ud_gate_type; + vmcs_clear_bits(CPU_EXEC_CTRL0, CPU_INTR_WINDOW); + enter_guest(); + report_prefix_pop(); +} + static void vmx_db_test_guest(void) { /* @@ -5970,6 +6140,7 @@ struct vmx_test vmx_tests[] = { TEST(vmx_nm_test), TEST(vmx_db_test), TEST(vmx_nmi_window_test), + TEST(vmx_intr_window_test), TEST(vmx_pending_event_test), TEST(vmx_pending_event_hlt_test), /* EPT access tests. */