From patchwork Fri Jan 11 00:11:59 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Jim Mattson X-Patchwork-Id: 10757077 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 BF1661390 for ; Fri, 11 Jan 2019 00:12:13 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id AA26229D6B for ; Fri, 11 Jan 2019 00:12:13 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 9C7C129D74; Fri, 11 Jan 2019 00:12:13 +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 0D04129D6B for ; Fri, 11 Jan 2019 00:12:12 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730754AbfAKAML (ORCPT ); Thu, 10 Jan 2019 19:12:11 -0500 Received: from mail-pg1-f201.google.com ([209.85.215.201]:47564 "EHLO mail-pg1-f201.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728974AbfAKAML (ORCPT ); Thu, 10 Jan 2019 19:12:11 -0500 Received: by mail-pg1-f201.google.com with SMTP id o17so7349316pgi.14 for ; Thu, 10 Jan 2019 16:12:10 -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 :content-transfer-encoding; bh=fTKPCr28DhUEo+7tmCapushgSwG+fkieRVHZ32E6cuk=; b=XreKNqR4u02kUV5LuItPo0A3OeLDOvDgr7DaKohYTO1uiK/o36HV3jFgKw70m+srX6 Up7GMzwwbBXCa2vcnvqn2AULZ/ILdY4BjzxLvj0LQr0KcIU99r8rvvhiz0z5RctDJOA9 Knv1k+3v8leqyfcL1m9MiNpuwgPfjv0FSMKz8/Sbr/o/cNPoDMaizphn6J0Vo5pGpTZj OpSuNPw3VuEI1GdPMTOUEALkmZ9aTTVOmw+1BV8PJ9tNR/uOjMFrz0tk65OAb8nC1yyE XdAAQQEDeEQUH2UnrWVXUTJp8BKuhMbq3sAGD0zkhOyox6DBRog7dPWf2ittkOXWcB4z Ra9w== 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 :content-transfer-encoding; bh=fTKPCr28DhUEo+7tmCapushgSwG+fkieRVHZ32E6cuk=; b=Va26mWEasWEcnUo1MWFJR6/VdGtwfJAIc/CKsQGfaZx+Py8+3yR/3qVt5nHYhVUzti 7ZeW05TK9WyAI3rfR2v8ois1GI3xrUta7kPpvy9dI854EObVCIMY9j9Q+6K5B/dvHSps aEmuA5xbxa8KbYzExwnyQZGryeaEwh6UzFdiRnehFFXW64x341qJqGdFSB2e7L0A4rsm zrSCtMNAuxjy3hTStxBsDfgnrR5ySD7U/TMzzhe76F6f6xrbi3lPaN6TPokJTVuV4Qag eZKDCUIrdogBNRKTLvDTWRSqPwFrFY2/ifLnCAi3fFpwpfPH9dpVuiipiSN4n9z+ECGt ah/w== X-Gm-Message-State: AJcUukf4W7sCn44nJg9MAspOCezbdIlEHRp/4F+513gHXwTLBKIViekw X+WsrhEC1ISEuQ2POBwgWUSZ+HHUomvzhLA89nmkCRVWr3NkpiFKDvfEasK+duWa/6yrcBAbJkv mkIC2CC89Uq24sZvrucVtcuDO50R46jo8BKTm4aN/Wn2TJMzVLWy4hL2ve8EKEJ8= X-Google-Smtp-Source: ALg8bN715slA3gzef6xmmtj1OyBl6e7ib3xdLHGrc73rH5g6Hx6c2LH+MDbJCFx0LYouZPmUKG0gclYODxzzeg== X-Received: by 2002:a17:902:1023:: with SMTP id b32mr2872417pla.121.1547165530014; Thu, 10 Jan 2019 16:12:10 -0800 (PST) Date: Thu, 10 Jan 2019 16:11:59 -0800 Message-Id: <20190111001159.106695-1-jmattson@google.com> Mime-Version: 1.0 X-Mailer: git-send-email 2.20.1.97.g81188d93c3-goog Subject: [kvm-unit-tests PATCH] Add VMX INS/OUTS test From: Jim Mattson To: kvm@vger.kernel.org Cc: Jim Mattson , Marc Orr Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Test that all of the appropriate exit information is provided to L1 for INS and OUTS instructions intercepted in L2. Signed-off-by: Jim Mattson Reviewed-by: Marc Orr --- lib/x86/msr.h | 3 ++ x86/unittests.cfg | 6 +++ x86/vmx.h | 17 ++++++++ x86/vmx_tests.c | 98 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 124 insertions(+) diff --git a/lib/x86/msr.h b/lib/x86/msr.h index abf0d93bc58d..d0f3e79b2d37 100644 --- a/lib/x86/msr.h +++ b/lib/x86/msr.h @@ -405,6 +405,9 @@ #define MSR_IA32_VMX_TRUE_EXIT 0x0000048f #define MSR_IA32_VMX_TRUE_ENTRY 0x00000490 +/* MSR_IA32_VMX_BASIC bits */ +#define MSR_IA32_VMX_BASIC_INOUT (1ULL << 54) + /* MSR_IA32_VMX_MISC bits */ #define MSR_IA32_VMX_MISC_VMWRITE_SHADOW_RO_FIELDS (1ULL << 29) diff --git a/x86/unittests.cfg b/x86/unittests.cfg index c744a6d8b163..d7270a542751 100644 --- a/x86/unittests.cfg +++ b/x86/unittests.cfg @@ -536,6 +536,12 @@ extra_params = -cpu host,+vmx -m 2560 -append invvpid_test_v2 arch = x86_64 groups = vmx +[vmx_ins_outs_test] +file = vmx.flat +extra_params = -cpu host,+vmx -m 2560 -append vmx_ins_outs_test +arch = x86_64 +groups = vmx + [vmx_controls] file = vmx.flat extra_params = -cpu host,+vmx -m 2560 -append vmx_controls_test diff --git a/x86/vmx.h b/x86/vmx.h index ba47455e1593..4bd8827a28df 100644 --- a/x86/vmx.h +++ b/x86/vmx.h @@ -7,6 +7,15 @@ #include "asm/page.h" #include "asm/io.h" +enum vmx_segment { + VMX_SEG_ES = 0, + VMX_SEG_CS = 1, + VMX_SEG_SS = 2, + VMX_SEG_DS = 3, + VMX_SEG_FS = 4, + VMX_SEG_GS = 5 +}; + struct vmcs_hdr { u32 revision_id:31; u32 shadow_vmcs:1; @@ -539,6 +548,14 @@ enum vm_instruction_error_number { #define VMX_IO_PORT_MASK 0xFFFF0000 #define VMX_IO_PORT_SHIFT 16 +#define VMX_IO_ADDR_SIZE_MASK 0x380 +#define VMX_IO_ADDR_SIZE_SHIFT 7 +#define _VMX_IO_ADDR_16 0 +#define _VMX_IO_ADDR_32 1 +#define _VMX_IO_ADDR_64 2 +#define VMX_IO_SEGMENT_MASK 0x38000 +#define VMX_IO_SEGMENT_SHIFT 15 + #define VMX_TEST_START 0 #define VMX_TEST_VMEXIT 1 #define VMX_TEST_EXIT 2 diff --git a/x86/vmx_tests.c b/x86/vmx_tests.c index 7a8d6ce5f169..f96fcc4246bf 100644 --- a/x86/vmx_tests.c +++ b/x86/vmx_tests.c @@ -3922,6 +3922,103 @@ static void test_apic_ctls(void) test_posted_intr(); } +static void ins_outs_test_guest(void) +{ + asm ("rep;insb" : : "d" (1)); + asm ("rep;outsb" : : "d" (2)); + asm ("insw" : : "d" (3)); + asm ("fs outsw" : : "d" (4)); + asm ("addr32 insl" : : "d" (5)); + asm ("addr32 gs outsl" : : "d" (6)); +} + +static void check_io_exit(unsigned size, unsigned in, unsigned string, + unsigned rep, unsigned imm, u16 port, + unsigned addr_size, enum vmx_segment segment) +{ + u32 reason = vmcs_read(EXI_REASON); + u64 exit_qual = vmcs_read(EXI_QUALIFICATION); + u32 inst_info = vmcs_read(EXI_INST_INFO); + + report("Exit reason (%u) is I/O instruction", reason == VMX_IO, + reason); + report("Size (%lu) is %u", (exit_qual & VMX_IO_SIZE_MASK) == size, + (exit_qual & VMX_IO_SIZE_MASK), size); + report("In (%lu) is %u", (exit_qual & VMX_IO_DIRECTION_MASK) == in, + (exit_qual & VMX_IO_DIRECTION_MASK), in); + report("String (%lu) is %u", (exit_qual & VMX_IO_STRING) == string, + (exit_qual & VMX_IO_STRING), string); + report("Rep (%lu) is %u", (exit_qual & VMX_IO_REP) == rep, + (exit_qual & VMX_IO_REP), rep); + report("Immediate (%lu) is %u", + (exit_qual & VMX_IO_OPRAND_IMM) == imm, + (exit_qual & VMX_IO_OPRAND_IMM), imm); + report("Port (%lu) is %u", + ((exit_qual & VMX_IO_PORT_MASK) >> VMX_IO_PORT_SHIFT) == port, + ((exit_qual & VMX_IO_PORT_MASK) >> VMX_IO_PORT_SHIFT), port); + + if (!(exit_qual & VMX_IO_STRING)) + return; + + if (!(rdmsr(MSR_IA32_VMX_BASIC) & MSR_IA32_VMX_BASIC_INOUT)) { + report_skip("VM-exit instruction-information field not defined for INS & OUTS"); + return; + } + + report("Address size (%u) is %u", + ((inst_info & VMX_IO_ADDR_SIZE_MASK) >> + VMX_IO_ADDR_SIZE_SHIFT) == addr_size, + ((inst_info & VMX_IO_ADDR_SIZE_MASK) >> + VMX_IO_ADDR_SIZE_SHIFT), addr_size); + + if ((exit_qual & VMX_IO_DIRECTION_MASK) == VMX_IO_IN) + return; + + report("Segment (%u) is %u", + ((inst_info & VMX_IO_SEGMENT_MASK) >> + VMX_IO_SEGMENT_SHIFT) == segment, + ((inst_info & VMX_IO_SEGMENT_MASK) >> + VMX_IO_SEGMENT_SHIFT), segment); +} + +static void vmx_ins_outs_test(void) +{ + test_set_guest(ins_outs_test_guest); + vmcs_set_bits(CPU_EXEC_CTRL0, CPU_IO); + + enter_guest(); + check_io_exit(_VMX_IO_BYTE, VMX_IO_IN, VMX_IO_STRING, VMX_IO_REP, + 0, 1, _VMX_IO_ADDR_64, -1); + skip_exit_insn(); + + enter_guest(); + check_io_exit(_VMX_IO_BYTE, VMX_IO_OUT, VMX_IO_STRING, VMX_IO_REP, + 0, 2, _VMX_IO_ADDR_64, VMX_SEG_DS); + skip_exit_insn(); + + enter_guest(); + check_io_exit(_VMX_IO_WORD, VMX_IO_IN, VMX_IO_STRING, 0, + 0, 3, _VMX_IO_ADDR_64, -1); + skip_exit_insn(); + + enter_guest(); + check_io_exit(_VMX_IO_WORD, VMX_IO_OUT, VMX_IO_STRING, 0, + 0, 4, _VMX_IO_ADDR_64, VMX_SEG_FS); + skip_exit_insn(); + + enter_guest(); + check_io_exit(_VMX_IO_LONG, VMX_IO_IN, VMX_IO_STRING, 0, + 0, 5, _VMX_IO_ADDR_32, -1); + skip_exit_insn(); + + enter_guest(); + check_io_exit(_VMX_IO_LONG, VMX_IO_OUT, VMX_IO_STRING, 0, + 0, 6, _VMX_IO_ADDR_32, VMX_SEG_GS); + skip_exit_insn(); + + enter_guest(); +} + /* * If the “enable VPID†VM-execution control is 1, the value of the * of the VPID VM-execution control field must not be 0000H. @@ -5896,6 +5993,7 @@ struct vmx_test vmx_tests[] = { TEST(fixture_test_case2), /* Opcode tests. */ TEST(invvpid_test_v2), + TEST(vmx_ins_outs_test), /* VM-entry tests */ TEST(vmx_controls_test), TEST(vmentry_movss_shadow_test),