From patchwork Fri Sep 21 18:55:53 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jim Mattson X-Patchwork-Id: 10610865 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 38879161F for ; Fri, 21 Sep 2018 18:56:11 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 2792C2E72F for ; Fri, 21 Sep 2018 18:56:11 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 1BEC22E731; Fri, 21 Sep 2018 18:56:11 +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 77E902E72F for ; Fri, 21 Sep 2018 18:56:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2391156AbeIVAqU (ORCPT ); Fri, 21 Sep 2018 20:46:20 -0400 Received: from mail-io1-f74.google.com ([209.85.166.74]:44108 "EHLO mail-io1-f74.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S2390726AbeIVAqT (ORCPT ); Fri, 21 Sep 2018 20:46:19 -0400 Received: by mail-io1-f74.google.com with SMTP id s15-v6so23976158iob.11 for ; Fri, 21 Sep 2018 11:56:08 -0700 (PDT) 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=DhVzHG9tHqiZZAiXHd3wFJR1+jgM4KmDsB4nyh7l6oE=; b=CHS/BYEV2OSzIhUWx/MbEMLkWFUuRL3/Nr9paeHAlFoRkAdE2foXSK9medGUPOM/sE U1cmaTwZ6OmLw1seJRaxD6q3OeXAbuIYv4ayMH0ELEpwqO9XhNgBd7lZHYJjxp1Z9MpC zx4b8dfJeBBxFoCF0heV4lpLVOzNlRnNVy/34un1by+JZOs40sh+9P5gA3JuABYxuFhj M+Syj4qquWYFuiNdmEo2d0ZsevYCUsyj2vOJk47CFlrz9oSqqMhd/g+3nfkwD0yP1qPc GhjnCx+8B3XLS10T+U5x/3FA6xviyGf5J6p9Pr3clRoInW7vTltqmIgTTA3U9b9mUWZs 64bw== 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=DhVzHG9tHqiZZAiXHd3wFJR1+jgM4KmDsB4nyh7l6oE=; b=UVHSn3WmEACncLQXJ2gmP2vnWbjWgjy/9dAlOcNcCfVtDzgFv8peWVJkCfNLENHX77 HwsShq+5MtG43szx4abIlFeYXlgUqeP1ryw46hwn1wjX+ToaQTpmMw8emHih2NxFZljg 3vLgewmOiVhEhXMjAktGhF+5dmwxzZfzmMnaJV/uC4YVkEEqxeqH5xfiVQux3DrOt66Z 3VPEgoWWNntVw5eb5eLt1+mEqsCJGKsleJnMk9FweKwvrHhnruR3fzyEvAKtUfbLf5eV 4U0t4rJIJ12nKL+dJhzog3LwriXxhBKtuJTWgfjQ5IO8E4zueIwCn2PjU01+5arsoVKE azBw== X-Gm-Message-State: APzg51BaJpjw4xrTCJ5E+eEb8gX7GWK8zI/YAKgSa2p/zcpNnNgmt3vc sNqVHUqVUZ7zBLa1jIgV11a3FFCtQWyLQ3L7Abs0WrE9EX1XeMh/xDZQHYWUHOC6Y5nDf+xlIfx RfZGJHGrBvBB5xSJ8y16ZsYD/N40A4hYg6dNUQrM9idrJri3Wl0Xtx3KTbUIv40Q= X-Google-Smtp-Source: ANB0VdZonPfn4TNLclzSZS5L/HdydnRvoP03u9zD9CA0H+PQ/TIg8RKr23lJDEyeGjTFCdY2HNvxwd0bkRhNkw== X-Received: by 2002:a24:4c89:: with SMTP id a131-v6mr5658089itb.5.1537556167627; Fri, 21 Sep 2018 11:56:07 -0700 (PDT) Date: Fri, 21 Sep 2018 11:55:53 -0700 Message-Id: <20180921185553.167882-1-jmattson@google.com> Mime-Version: 1.0 X-Mailer: git-send-email 2.19.0.444.g18242da7ef-goog Subject: [kvm-unit-tests PATCH] x86: nVMX: Basic test of #DB intercept in L1 From: Jim Mattson To: kvm@vger.kernel.org, Paolo Bonzini , Sean Christopherson Cc: Jim Mattson Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Test a single-step trap delivered by hardware to set expectations, and then test a single-step trap synthesized by L0 to see if those expectations are met. As a bonus, test a single-step trap in a transactional region to set expectations for that unusual case as well. Signed-off-by: Jim Mattson Reviewed-by: Peter Shier --- x86/unittests.cfg | 6 ++ x86/vmx_tests.c | 157 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 163 insertions(+) diff --git a/x86/unittests.cfg b/x86/unittests.cfg index 2d04806..e455d96 100644 --- a/x86/unittests.cfg +++ b/x86/unittests.cfg @@ -566,6 +566,12 @@ extra_params = -cpu host,+vmx -m 2560 -append vmx_nm_test arch = x86_64 groups = vmx +[vmx_db_test] +file = vmx.flat +extra_params = -cpu host,+vmx -m 2560 -append vmx_db_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 1574970..524b82d 100644 --- a/x86/vmx_tests.c +++ b/x86/vmx_tests.c @@ -3,6 +3,9 @@ * * Author : Arthur Chunqi Li */ + +#include + #include "vmx.h" #include "msr.h" #include "processor.h" @@ -4684,6 +4687,159 @@ static void vmx_nm_test(void) enter_guest(); } +static void vmx_db_test_guest(void) +{ + /* + * For a hardware generated single-step #DB. + */ + asm volatile("vmcall;" + "nop;" + ".Lpost_nop:"); + /* + * For an L0 synthesized single-step #DB. (L0 intercepts WBINVD and + * emulates it in software.) + */ + asm volatile("vmcall;" + "wbinvd;" + ".Lpost_wbinvd:"); + /* + * For a hardware generated single-step #DB in a transactional region. + */ + asm volatile("vmcall;" + ".Lxbegin: xbegin .Lpost_xbegin;" + ".Lpost_xbegin:"); +} + +/* + * Clear the pending debug exceptions and RFLAGS.TF and re-enter + * L2. No #DB is delivered and L2 continues to the next point of + * interest. + */ +static void dismiss_db(void) +{ + vmcs_write(GUEST_PENDING_DEBUG, 0); + vmcs_write(GUEST_RFLAGS, X86_EFLAGS_FIXED); + enter_guest(); +} + +/* + * Check a variety of VMCS fields relevant to an intercepted #DB exception. + * Then throw away the #DB exception and resume L2. + */ +static void check_db_exit(bool xfail, void *expected_rip, + u64 expected_exit_qual, u64 expected_dr6) +{ + u32 reason = vmcs_read(EXI_REASON); + u32 intr_info = vmcs_read(EXI_INTR_INFO); + u64 exit_qual = vmcs_read(EXI_QUALIFICATION); + u64 guest_rip = vmcs_read(GUEST_RIP); + u64 guest_pending_dbg = vmcs_read(GUEST_PENDING_DEBUG); + u64 dr6 = read_dr6(); + const u32 expected_intr_info = INTR_INFO_VALID_MASK | + INTR_TYPE_HARD_EXCEPTION | DB_VECTOR; + + report("Expected #DB VM-exit", + reason == VMX_EXC_NMI && intr_info == expected_intr_info); + report("Expected RIP %p (actual %lx)", (u64)expected_rip == guest_rip, + expected_rip, guest_rip); + report("Expected pending debug exceptions 0 (actual %lx)", + 0 == guest_pending_dbg, guest_pending_dbg); + report_xfail("Expected exit qualification %lx (actual %lx)", xfail, + expected_exit_qual == exit_qual, + expected_exit_qual, exit_qual); + report_xfail("Expected DR6 %lx (actual %lx)", xfail, + expected_dr6 == dr6, expected_dr6, dr6); + dismiss_db(); +} + +/* + * Assuming the guest has just exited on a VMCALL instruction, skip + * over the vmcall, set the guest's RFLAGS.TF in the VMCS, and resume + * L2. + */ +static void single_step_guest(u64 starting_dr6) +{ + skip_exit_vmcall(); + write_dr6(starting_dr6); + vmcs_write(GUEST_RFLAGS, X86_EFLAGS_FIXED | X86_EFLAGS_TF); + enter_guest(); +} + +/* + * If L1 intercepts #DB, verify that a single-step trap clears pending + * debug exceptions, populates the exit qualification field properly, + * and that DR6 is not prematurely clobbered. + */ +static void vmx_db_test(void) +{ + /* + * We are going to set a few arbitrary bits in DR6 to verify that + * (a) DR6 is not modified by an intercepted #DB, and + * (b) stale bits in DR6 don't leak into the exit qualification + * field for a subsequent #DB exception. + */ + const u64 starting_dr6 = DR6_RESERVED | DR_SWITCH | 0xa; + extern char post_nop asm(".Lpost_nop"); + extern char post_wbinvd asm(".Lpost_wbinvd"); + extern char xbegin asm(".Lxbegin"); + extern char post_xbegin asm(".Lpost_xbegin"); + + /* + * L1 wants to intercept #DB exceptions encountered in L2. + */ + vmcs_write(EXC_BITMAP, BIT(DB_VECTOR)); + + /* + * Start L2 and run it up to the first point of interest. + */ + test_set_guest(vmx_db_test_guest); + enter_guest(); + + /* + * Hardware-delivered #DB trap for single-step sets the standard. + */ + single_step_guest(starting_dr6); + printf("\nHardware delivered single-step\n"); + check_db_exit(false, &post_nop, DR_STEP, starting_dr6); + + /* + * L0 synthesized #DB trap for single-step is buggy, because + * kvm (a) clobbers DR6 too early, and (b) tries its best to + * reconstitute the exit qualification from the prematurely + * modified DR6, but fails miserably. + */ + single_step_guest(starting_dr6); + printf("\nSoftware synthesized single-step\n"); + check_db_exit(true, &post_wbinvd, DR_STEP, starting_dr6); + + /* + * Optional RTM test for hardware that supports RTM, to + * demonstrate that the current volume 3 of the SDM + * (325384-067US), table 27-1 is incorrect. Bit 16 of the exit + * qualification for debug exceptions is not reserved. It is + * set to 1 if a debug exception (#DB) or a breakpoint + * exception (#BP) occurs inside an RTM region while advanced + * debugging of RTM transactional regions is enabled. + */ + if (cpuid(7).b & BIT(11)) { + vmcs_write(ENT_CONTROLS, + vmcs_read(ENT_CONTROLS) | ENT_LOAD_DBGCTLS); + /* + * Set DR7.RTM[bit 11] and IA32_DEBUGCTL.RTM[bit 15] + * in the guest to enable advanced debugging of RTM + * transactional regions. + */ + vmcs_write(GUEST_DR7, BIT(11)); + vmcs_write(GUEST_DEBUGCTL, BIT(15)); + single_step_guest(starting_dr6); + printf("\nHardware delivered single-step in transactional region\n"); + check_db_exit(false, &xbegin, BIT(16), starting_dr6); + } else { + vmcs_write(GUEST_RIP, (u64)&post_xbegin); + enter_guest(); + } +} + static bool cpu_has_apicv(void) { return ((ctrl_cpu_rev[1].clr & CPU_APIC_REG_VIRT) && @@ -5245,6 +5401,7 @@ struct vmx_test vmx_tests[] = { /* Regression tests */ TEST(vmx_cr_load_test), TEST(vmx_nm_test), + TEST(vmx_db_test), /* EPT access tests. */ TEST(ept_access_test_not_present), TEST(ept_access_test_read_only),