From nobody Mon Jun 15 10:47:20 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id BD0A3C433EF for ; Wed, 8 Jun 2022 22:45:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235926AbiFHWps (ORCPT ); Wed, 8 Jun 2022 18:45:48 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:32832 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236959AbiFHWpW (ORCPT ); Wed, 8 Jun 2022 18:45:22 -0400 Received: from mail-yw1-x1149.google.com (mail-yw1-x1149.google.com [IPv6:2607:f8b0:4864:20::1149]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C620A2506CB for ; Wed, 8 Jun 2022 15:45:21 -0700 (PDT) Received: by mail-yw1-x1149.google.com with SMTP id 00721157ae682-31382419c22so15075587b3.18 for ; Wed, 08 Jun 2022 15:45:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=reply-to:date:in-reply-to:message-id:mime-version:references :subject:from:to:cc; bh=Aj47vH7bOM7CIvT8Dyt2GzqDM34J/7dBeBUz69774ew=; b=FvUPMqERCr+vn5DAlXucDMK8JQYwnBC6iD8ztZR5A8TbC0iMs2oNwezvO8LZsbk2Bd JAnaOUZlOiKhfVjCBJhHExnscF2eISgVrvFq+nbT+JmZ7aqhE2tG9XNQZLeCqXw8yDHQ FHC3PRf0jU40rP479ZovjS3+Cu/81X9UX9pbb3DjmdXZGlRx1JB2Wep4jVFaj5DVxZrO 25RiEmgEBl0NQ1gGT7yrntGFbguPrYyNx2VpcH7B6YueRUaLHp5ioeHiaIX5zViGdvaj dvqZ3w7+J+wTbq734pXBBu9nywfJaXrQvl4ybyZbRWZFvkS4gMVHZbQUF+Nph9rz2J4b HAqg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:reply-to:date:in-reply-to:message-id :mime-version:references:subject:from:to:cc; bh=Aj47vH7bOM7CIvT8Dyt2GzqDM34J/7dBeBUz69774ew=; b=leOAqoBy+1f6zZ19C+OHycLPRT7qCs9e0a4N4fEJvzgGZu2UzmGuFSkm700sH/GIkJ 3EqmCphU/iVwa1DFxv4OJTphGEdztn0relmnCa7a6Y0i0uIV3MWBEJmNxzDi2wD+RYSb QiX3qXND/dow+Kwu9555mM7rnQoOR4FYKNiwMnwWmNeQPXL4ngt+RXV1v6zkn5z6LF8l Uf0VWDerserqUPjTvxOdcCPIdibZxRWR/wpZZCd8SIVNK+H4e4W1LBFzbZPbtn/c13IQ JJiuF95gyHm6v0aTAmIdgo8DVcUNKxl59wpv5naorMoByn28Njs1L/Q18RGNpbqYoA9V VpjA== X-Gm-Message-State: AOAM5321CMMQ8XOY4KoYj83UTgrDMpopS0jcGpSyv+qf3A9AkLjAh9G/ zroY1rKC+O+Zy3/rKVF0o2B9vntps20= X-Google-Smtp-Source: ABdhPJwitxoDkwVjT8ngUL3WN+GVfi9ZRSFxFHUCta7tvzet9Zy5A3/DRpzqmKRGgeqbz97ywWxxDaO5gjo= X-Received: from seanjc.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:3e5]) (user=seanjc job=sendgmr) by 2002:a0d:d843:0:b0:30e:c210:87a4 with SMTP id a64-20020a0dd843000000b0030ec21087a4mr39532146ywe.313.1654728321051; Wed, 08 Jun 2022 15:45:21 -0700 (PDT) Reply-To: Sean Christopherson Date: Wed, 8 Jun 2022 22:45:12 +0000 In-Reply-To: <20220608224516.3788274-1-seanjc@google.com> Message-Id: <20220608224516.3788274-2-seanjc@google.com> Mime-Version: 1.0 References: <20220608224516.3788274-1-seanjc@google.com> X-Mailer: git-send-email 2.36.1.255.ge46751e96f-goog Subject: [PATCH 1/5] KVM: x86: Add a quirk for KVM's "MONITOR/MWAIT are NOPs!" behavior From: Sean Christopherson To: Paolo Bonzini Cc: Sean Christopherson , Vitaly Kuznetsov , Wanpeng Li , Jim Mattson , Joerg Roedel , kvm@vger.kernel.org, linux-kernel@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add a quirk for KVM's behavior of emulating intercepted MONITOR/MWAIT instructions a NOPs regardless of whether or not they are supported in guest CPUID. KVM's current behavior was likely motiviated by a certain fruity operating system that expects MONITOR/MWAIT to be supported unconditionally and blindly executes MONITOR/MWAIT without first checking CPUID. And because KVM does NOT advertise MONITOR/MWAIT to userspace, that's effectively the default setup for any VMM that regurgitates KVM_GET_SUPPORTED_CPUID to KVM_SET_CPUID2. Note, this quirk interacts with KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT. The behavior is actually desirable, as userspace VMMs that want to unconditionally hide MONITOR/MWAIT from the guest can leave the MISC_ENABLE quirk enabled. Signed-off-by: Sean Christopherson --- Documentation/virt/kvm/api.rst | 13 +++++++++++++ arch/x86/include/asm/kvm_host.h | 3 ++- arch/x86/include/uapi/asm/kvm.h | 1 + arch/x86/kvm/x86.c | 26 +++++++++++++++++--------- 4 files changed, 33 insertions(+), 10 deletions(-) diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index 42a1984fafc8..5c6cd8f7975f 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -7374,6 +7374,19 @@ The valid bits in cap.args[0] are: hypercall instructions. Executing the incorrect hypercall instruction will generate a #UD within the guest. + +KVM_X86_QUIRK_MWAIT_NEVER_FAULTS By default, KVM emulates MONITOR/MWAIT= (if + they are intercepted) as NOPs regardle= ss of + whether or not MONITOR/MWAIT are suppo= rted + according to guest CPUID. When this q= uirk + is disabled and KVM_X86_DISABLE_EXITS_= MWAIT + is not set (MONITOR/MWAIT are intercep= ted), + KVM will inject a #UD on MONITOR/MWAIT= if + they're unsupported per guest CPUID. = Note, + KVM will modify MONITOR/MWAIT support = in + guest CPUID on writes to MISC_ENABLE if + KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT is + disabled. =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D =20 7.32 KVM_CAP_MAX_VCPU_ID diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_hos= t.h index 6cf5d77d7896..bc3e85a81f41 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -2011,6 +2011,7 @@ int memslot_rmap_alloc(struct kvm_memory_slot *slot, = unsigned long npages); KVM_X86_QUIRK_LAPIC_MMIO_HOLE | \ KVM_X86_QUIRK_OUT_7E_INC_RIP | \ KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT | \ - KVM_X86_QUIRK_FIX_HYPERCALL_INSN) + KVM_X86_QUIRK_FIX_HYPERCALL_INSN | \ + KVM_X86_QUIRK_MWAIT_NEVER_FAULTS) =20 #endif /* _ASM_X86_KVM_HOST_H */ diff --git a/arch/x86/include/uapi/asm/kvm.h b/arch/x86/include/uapi/asm/kv= m.h index 24c807c8d5f7..b7c92844550b 100644 --- a/arch/x86/include/uapi/asm/kvm.h +++ b/arch/x86/include/uapi/asm/kvm.h @@ -438,6 +438,7 @@ struct kvm_sync_regs { #define KVM_X86_QUIRK_OUT_7E_INC_RIP (1 << 3) #define KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT (1 << 4) #define KVM_X86_QUIRK_FIX_HYPERCALL_INSN (1 << 5) +#define KVM_X86_QUIRK_MWAIT_NEVER_FAULTS (1 << 6) =20 #define KVM_STATE_NESTED_FORMAT_VMX 0 #define KVM_STATE_NESTED_FORMAT_SVM 1 diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 2db6f0373fa3..14abcd5c2714 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2034,13 +2034,6 @@ int kvm_emulate_invd(struct kvm_vcpu *vcpu) } EXPORT_SYMBOL_GPL(kvm_emulate_invd); =20 -int kvm_emulate_mwait(struct kvm_vcpu *vcpu) -{ - pr_warn_once("kvm: MWAIT instruction emulated as NOP!\n"); - return kvm_emulate_as_nop(vcpu); -} -EXPORT_SYMBOL_GPL(kvm_emulate_mwait); - int kvm_handle_invalid_op(struct kvm_vcpu *vcpu) { kvm_queue_exception(vcpu, UD_VECTOR); @@ -2048,10 +2041,25 @@ int kvm_handle_invalid_op(struct kvm_vcpu *vcpu) } EXPORT_SYMBOL_GPL(kvm_handle_invalid_op); =20 + +static int kvm_emulate_monitor_mwait(struct kvm_vcpu *vcpu, const char *in= sn) +{ + if (!kvm_check_has_quirk(vcpu->kvm, KVM_X86_QUIRK_MWAIT_NEVER_FAULTS) && + !guest_cpuid_has(vcpu, X86_FEATURE_MWAIT)) + return kvm_handle_invalid_op(vcpu); + + pr_warn_once("kvm: %s instruction emulated as NOP!\n", insn); + return kvm_emulate_as_nop(vcpu); +} +int kvm_emulate_mwait(struct kvm_vcpu *vcpu) +{ + return kvm_emulate_monitor_mwait(vcpu, "MWAIT"); +} +EXPORT_SYMBOL_GPL(kvm_emulate_mwait); + int kvm_emulate_monitor(struct kvm_vcpu *vcpu) { - pr_warn_once("kvm: MONITOR instruction emulated as NOP!\n"); - return kvm_emulate_as_nop(vcpu); + return kvm_emulate_monitor_mwait(vcpu, "MONITOR"); } EXPORT_SYMBOL_GPL(kvm_emulate_monitor); =20 --=20 2.36.1.255.ge46751e96f-goog From nobody Mon Jun 15 10:47:20 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id B2746C43334 for ; Wed, 8 Jun 2022 22:45:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236548AbiFHWpm (ORCPT ); Wed, 8 Jun 2022 18:45:42 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:32906 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230322AbiFHWpY (ORCPT ); Wed, 8 Jun 2022 18:45:24 -0400 Received: from mail-pg1-x549.google.com (mail-pg1-x549.google.com [IPv6:2607:f8b0:4864:20::549]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 170112509DE for ; Wed, 8 Jun 2022 15:45:23 -0700 (PDT) Received: by mail-pg1-x549.google.com with SMTP id e189-20020a6369c6000000b003fd31d5990fso7428429pgc.20 for ; Wed, 08 Jun 2022 15:45:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=reply-to:date:in-reply-to:message-id:mime-version:references :subject:from:to:cc; bh=bMeLzNqhuJTdm9rwRjOvyOW1NIK0cUo/UeP8lk5uQQk=; b=RTci0xO1Vz2BmgyGPbxy8QXpFkdH+ggaqzqeLo4Jix+zXRb8DSVHAG43bnDq8z+FjZ bFtvXGvgyTmMJqGChfSf9JkiBxoWo52u2B4fyD46Hf3h2Kv8F2ZqO3b2p9F/Fz+JbLEi DcIyW7+KfXcZ2YsECuT7Hnpwk46+HBI9Vb0J51B7pvaOLcfOP28Bt8FXxWzwXvZlybCQ 2HMeoUC/bQmTMKV8gRc5xK1QWfRNwiql78g//a4YiSbgKmLIQrdOwjXXMel1JUrTYixs qY1RYUKbttjV9CpnXX67owvnSRxwvouR2wp9oVazITMEj7gqt7ZUBvC/dwZ73ZPTf5E4 v2rA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:reply-to:date:in-reply-to:message-id :mime-version:references:subject:from:to:cc; bh=bMeLzNqhuJTdm9rwRjOvyOW1NIK0cUo/UeP8lk5uQQk=; b=U477N3ywEEH7tAwJCldsNO6hHP9q/NXrYhIflj5y8YJ3idjgF56mcbf90qHiRAYz9a QFeildqmg7MbuAgo/JW9/79ydlVKd1xhHM6MGiKLsvS5e3b1k7+YtFJ/4wPrgKVpyTfx iGcTK4u7Gxi0qEdkkLoW8F4Qcb+mMNHVtqGDG9W/wEP1gsZpeQxtNw7mTWDPkT+g/p0y axyIMm/AEd298LWdq3rT9Nn2wu5d17mZUH8TgYhZDJpCrdErp2UYIS9W0EiJYGgcwBuK dsQIvvV9wdG0eVRgvwN6AwmVZK5XYRCOvw6GXpYotYw4xveWZruG6Qz31GZQe9/PeWTt FbhQ== X-Gm-Message-State: AOAM530YLA0vYP7B8ES3Vtn6eH0vt66WoTw0NqZU3eti3BuS/+hTf2fr kSsedIRIFTgNNHoticT2ruUiuFE/y64= X-Google-Smtp-Source: ABdhPJxAB+hWrNgX9ONVVmSW2qP7kFPqjUnpslfLFOoCOsg6wzg7WB0oSO0Faqf1QF6xWquQUnOPTmoaVoE= X-Received: from seanjc.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:3e5]) (user=seanjc job=sendgmr) by 2002:a05:6a00:1946:b0:4fe:309f:d612 with SMTP id s6-20020a056a00194600b004fe309fd612mr104701730pfk.10.1654728322537; Wed, 08 Jun 2022 15:45:22 -0700 (PDT) Reply-To: Sean Christopherson Date: Wed, 8 Jun 2022 22:45:13 +0000 In-Reply-To: <20220608224516.3788274-1-seanjc@google.com> Message-Id: <20220608224516.3788274-3-seanjc@google.com> Mime-Version: 1.0 References: <20220608224516.3788274-1-seanjc@google.com> X-Mailer: git-send-email 2.36.1.255.ge46751e96f-goog Subject: [PATCH 2/5] KVM: selftests: Add x86-64 support for exception fixup From: Sean Christopherson To: Paolo Bonzini Cc: Sean Christopherson , Vitaly Kuznetsov , Wanpeng Li , Jim Mattson , Joerg Roedel , kvm@vger.kernel.org, linux-kernel@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add x86-64 support for exception fixup on single instructions, without forcing tests to install their own fault handlers. Use registers r9-r11 to flag the instruction as "safe" and pass fixup/vector information, i.e. introduce yet another flavor of fixup (versus the kernel's in-memory tables and KUT's per-CPU area) to take advantage of KVM sefltests being 64-bit only. Using only registers avoids the need to allocate fixup tables, ensure FS or GS base is valid for the guest, ensure memory is mapped into the guest, etc..., and also reduces the potential for recursive faults due to accessing memory. Providing exception fixup trivializes tests that just want to verify that an instruction faults, e.g. no need to track start/end using global labels, no need to install a dedicated handler, etc... Deliberately do not support #DE in exception fixup so that the fixup glue doesn't need to account for a fault with vector =3D=3D 0, i.e. the vector c= an also indicate that a fault occurred. KVM injects #DE only for esoteric emulation scenarios, i.e. there's very, very little value in testing #DE. Force any test that wants to generate #DEs to install its own handler(s). Use kvm_pv_test as a guinea pig for the new fixup, as it has a very straightforward use case of wanting to verify that RDMSR and WRMSR fault. Signed-off-by: Sean Christopherson --- .../selftests/kvm/include/x86_64/processor.h | 74 +++++++++++++++++ .../selftests/kvm/lib/x86_64/processor.c | 17 ++++ .../selftests/kvm/x86_64/kvm_pv_test.c | 82 ++++--------------- 3 files changed, 109 insertions(+), 64 deletions(-) diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools= /testing/selftests/kvm/include/x86_64/processor.h index 3fd3d58148c2..15aa076765a5 100644 --- a/tools/testing/selftests/kvm/include/x86_64/processor.h +++ b/tools/testing/selftests/kvm/include/x86_64/processor.h @@ -15,6 +15,8 @@ #include #include =20 +#include + #include "../kvm_util.h" =20 #define NMI_VECTOR 0x02 @@ -750,6 +752,78 @@ void vcpu_init_descriptor_tables(struct kvm_vcpu *vcpu= ); void vm_install_exception_handler(struct kvm_vm *vm, int vector, void (*handler)(struct ex_regs *)); =20 +/* If a toddler were to say "abracadabra". */ +#define KVM_EXCEPTION_MAGIC 0xabacadabaull + +/* + * KVM selftest exception fixup uses registers to coordinate with the exce= ption + * handler, versus the kernel's in-memory tables and KVM-Unit-Tests's in-m= emory + * per-CPU data. Using only registers avoids having to map memory into the + * guest, doesn't require a valid, stable GS.base, and reduces the risk of + * for recursive faults when accessing memory in the handler. The downsid= e to + * using registers is that it restricts what registers can be used by the = actual + * instruction. But, selftests are 64-bit only, making register* pressure= a + * minor concern. Use r9-r11 as they are volatile, i.e. don't need* to be= saved + * by the callee, and except for r11 are not implicit parameters to any + * instructions. Ideally, fixup would use r8-r10 and thus avoid implicit + * parameters entirely, but Hyper-V's hypercall ABI uses r8 and testing Hy= per-V + * is higher priority than testing non-faulting SYSCALL/SYSRET. + * + * Note, the fixup handler deliberately does not handle #DE, i.e. the vect= or + * is guaranteed to be non-zero on fault. + * + * REGISTER INPUTS: + * r9 =3D MAGIC + * r10 =3D RIP + * r11 =3D new RIP on fault + * + * REGISTER OUTPUTS: + * r9 =3D exception vector (non-zero) + */ +#define KVM_ASM_SAFE(insn) \ + "mov $" __stringify(KVM_EXCEPTION_MAGIC) ", %%r9\n\t" \ + "lea 1f(%%rip), %%r10\n\t" \ + "lea 2f(%%rip), %%r11\n\t" \ + "1: " insn "\n\t" \ + "mov $0, %[vector]\n\t" \ + "jmp 3f\n\t" \ + "2:\n\t" \ + "mov %%r9b, %[vector]\n\t" \ + "3:\n\t" + +#define KVM_ASM_SAFE_OUTPUTS(v) [vector] "=3Dqm"(v) +#define KVM_ASM_SAFE_CLOBBERS "r9", "r10", "r11" + +#define kvm_asm_safe(insn, inputs...) \ +({ \ + uint8_t vector; \ + \ + asm volatile(KVM_ASM_SAFE(insn) \ + : KVM_ASM_SAFE_OUTPUTS(vector) \ + : inputs \ + : KVM_ASM_SAFE_CLOBBERS); \ + vector; \ +}) + +static inline uint8_t rdmsr_safe(uint32_t msr, uint64_t *val) +{ + uint8_t vector; + uint32_t a, d; + + asm volatile(KVM_ASM_SAFE("rdmsr") + : "=3Da"(a), "=3Dd"(d), KVM_ASM_SAFE_OUTPUTS(vector) + : "c"(msr) + : KVM_ASM_SAFE_CLOBBERS); + + *val =3D (uint64_t)a | ((uint64_t)d << 32); + return vector; +} + +static inline uint8_t wrmsr_safe(uint32_t msr, uint64_t val) +{ + return kvm_asm_safe("wrmsr", "A"(val), "c"(msr)); +} + uint64_t vm_get_page_table_entry(struct kvm_vm *vm, struct kvm_vcpu *vcpu, uint64_t vaddr); void vm_set_page_table_entry(struct kvm_vm *vm, struct kvm_vcpu *vcpu, diff --git a/tools/testing/selftests/kvm/lib/x86_64/processor.c b/tools/tes= ting/selftests/kvm/lib/x86_64/processor.c index 5cb73b2f9978..95db8eebcc1d 100644 --- a/tools/testing/selftests/kvm/lib/x86_64/processor.c +++ b/tools/testing/selftests/kvm/lib/x86_64/processor.c @@ -1079,6 +1079,20 @@ static void set_idt_entry(struct kvm_vm *vm, int vec= tor, unsigned long addr, e->offset2 =3D addr >> 32; } =20 + +static bool kvm_fixup_exception(struct ex_regs *regs) +{ + if (regs->r9 !=3D KVM_EXCEPTION_MAGIC || regs->rip !=3D regs->r10) + return false; + + if (regs->vector =3D=3D DE_VECTOR) + return false; + + regs->rip =3D regs->r11; + regs->r9 =3D regs->vector; + return true; +} + void kvm_exit_unexpected_vector(uint32_t value) { ucall(UCALL_UNHANDLED, 1, value); @@ -1094,6 +1108,9 @@ void route_exception(struct ex_regs *regs) return; } =20 + if (kvm_fixup_exception(regs)) + return; + kvm_exit_unexpected_vector(regs->vector); } =20 diff --git a/tools/testing/selftests/kvm/x86_64/kvm_pv_test.c b/tools/testi= ng/selftests/kvm/x86_64/kvm_pv_test.c index 7ab61f3f2a20..37875e864030 100644 --- a/tools/testing/selftests/kvm/x86_64/kvm_pv_test.c +++ b/tools/testing/selftests/kvm/x86_64/kvm_pv_test.c @@ -12,55 +12,6 @@ #include "kvm_util.h" #include "processor.h" =20 -extern unsigned char rdmsr_start; -extern unsigned char rdmsr_end; - -static u64 do_rdmsr(u32 idx) -{ - u32 lo, hi; - - asm volatile("rdmsr_start: rdmsr;" - "rdmsr_end:" - : "=3Da"(lo), "=3Dc"(hi) - : "c"(idx)); - - return (((u64) hi) << 32) | lo; -} - -extern unsigned char wrmsr_start; -extern unsigned char wrmsr_end; - -static void do_wrmsr(u32 idx, u64 val) -{ - u32 lo, hi; - - lo =3D val; - hi =3D val >> 32; - - asm volatile("wrmsr_start: wrmsr;" - "wrmsr_end:" - : : "a"(lo), "c"(idx), "d"(hi)); -} - -static int nr_gp; - -static void guest_gp_handler(struct ex_regs *regs) -{ - unsigned char *rip =3D (unsigned char *)regs->rip; - bool r, w; - - r =3D rip =3D=3D &rdmsr_start; - w =3D rip =3D=3D &wrmsr_start; - GUEST_ASSERT(r || w); - - nr_gp++; - - if (r) - regs->rip =3D (uint64_t)&rdmsr_end; - else - regs->rip =3D (uint64_t)&wrmsr_end; -} - struct msr_data { uint32_t idx; const char *name; @@ -89,14 +40,16 @@ static struct msr_data msrs_to_test[] =3D { =20 static void test_msr(struct msr_data *msr) { + uint64_t ignored; + uint8_t vector; + PR_MSR(msr); - do_rdmsr(msr->idx); - GUEST_ASSERT(READ_ONCE(nr_gp) =3D=3D 1); =20 - nr_gp =3D 0; - do_wrmsr(msr->idx, 0); - GUEST_ASSERT(READ_ONCE(nr_gp) =3D=3D 1); - nr_gp =3D 0; + vector =3D rdmsr_safe(msr->idx, &ignored); + GUEST_ASSERT_1(vector =3D=3D GP_VECTOR, vector); + + vector =3D wrmsr_safe(msr->idx, 0); + GUEST_ASSERT_1(vector =3D=3D GP_VECTOR, vector); } =20 struct hcall_data { @@ -156,12 +109,6 @@ static void pr_hcall(struct ucall *uc) pr_info("testing hcall: %s (%lu)\n", hc->name, hc->nr); } =20 -static void handle_abort(struct ucall *uc) -{ - TEST_FAIL("%s at %s:%ld", (const char *)uc->args[0], - __FILE__, uc->args[1]); -} - static void enter_guest(struct kvm_vcpu *vcpu) { struct kvm_run *run =3D vcpu->run; @@ -181,7 +128,9 @@ static void enter_guest(struct kvm_vcpu *vcpu) pr_hcall(&uc); break; case UCALL_ABORT: - handle_abort(&uc); + TEST_FAIL("%s at %s:%ld, vector =3D %lu", + (const char *)uc.args[0], __FILE__, + uc.args[1], uc.args[2]); return; case UCALL_DONE: return; @@ -191,6 +140,7 @@ static void enter_guest(struct kvm_vcpu *vcpu) =20 int main(void) { + struct kvm_cpuid_entry2 *entry; struct kvm_vcpu *vcpu; struct kvm_vm *vm; =20 @@ -200,11 +150,15 @@ int main(void) =20 vcpu_enable_cap(vcpu, KVM_CAP_ENFORCE_PV_FEATURE_CPUID, 1); =20 - vcpu_clear_cpuid_entry(vcpu, KVM_CPUID_FEATURES); + entry =3D vcpu_get_cpuid_entry(vcpu, KVM_CPUID_FEATURES); + entry->eax =3D 0; + entry->ebx =3D 0; + entry->ecx =3D 0; + entry->edx =3D 0; + vcpu_set_cpuid(vcpu); =20 vm_init_descriptor_tables(vm); vcpu_init_descriptor_tables(vcpu); - vm_install_exception_handler(vm, GP_VECTOR, guest_gp_handler); =20 enter_guest(vcpu); kvm_vm_free(vm); --=20 2.36.1.255.ge46751e96f-goog From nobody Mon Jun 15 10:47:20 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id CF5E1C43334 for ; Wed, 8 Jun 2022 22:45:40 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236760AbiFHWpi (ORCPT ); Wed, 8 Jun 2022 18:45:38 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:32836 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235167AbiFHWp0 (ORCPT ); Wed, 8 Jun 2022 18:45:26 -0400 Received: from mail-pf1-x44a.google.com (mail-pf1-x44a.google.com [IPv6:2607:f8b0:4864:20::44a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C210D2509FD for ; Wed, 8 Jun 2022 15:45:24 -0700 (PDT) Received: by mail-pf1-x44a.google.com with SMTP id q12-20020a056a0002ac00b0051bb2e66c91so11327999pfs.4 for ; Wed, 08 Jun 2022 15:45:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=reply-to:date:in-reply-to:message-id:mime-version:references :subject:from:to:cc; bh=07WAXpZ8zYpETI7/zyyHdKHPCaSNMRWniZB3LhzmunI=; b=n4NpljONrmuO8XHC+yhagdRPrE5285G0RXSdHOSmWK2IHXg+uKRc1NX6IIL/9Q1e0/ eTT6gu0GDKeYFly+9WUIonxDDVnEks+0WK1ZiP1Xe5FKWYEQL0a+QiUwko0jFEN+FUqi RxXYrO+ek5Xy5E1Acdas5hE3AVgFWNpyQdkiR0iYTpN+WsakKEpLe5hGm7M3tD29encC M2TiOsC//mdu1Zu+Yz73MTylWILBWz/pFxNFdU2uztePhtcVYS8YUveNPsjJhkZWlZei ue+KYpaS98++kLbDqfV2Bb1R503KAe1cBuIifnEsXRxG/4LQZn/IqC1hSoggxEhgKHYi UmlQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:reply-to:date:in-reply-to:message-id :mime-version:references:subject:from:to:cc; bh=07WAXpZ8zYpETI7/zyyHdKHPCaSNMRWniZB3LhzmunI=; b=xnWiLRjk+1Y3XFkS+1WFZCje2AqAZ65VhrPJ4hBxa0AycNM3YaSiXddvZV3hWqVuR1 sA9VK4n6rXYv8YVf0BG/ezmiyhuifewYDaGDdXUWPuYcJK0d7+OcLMaGd+zzSDG6hqCi EsYoAUMm6j/8m0ecscCur8z0GGEzJKqyfRj0b2mgSPsZvFz2xzC7gsuDXQ9L++17wilh PMwslpzUf9u6Z5/ol3Bb+zdp01NjlEa7Npu7+LiKkTix2SnVthju0ELvw5B0lbjNRhQq f9ezUJLZ76ADuBh4/JLOwpg7ZMx/2jf7iv/QGFvEwVkQ94Zc4neMYFmvP4crZuTRzj/n VEiA== X-Gm-Message-State: AOAM532cC9S4gkgJ67vInAF8kH/SSZlj7V0j61/rVM6xmcZ6/VANy2PM 5iv5Z9dJLNP/gOg2Mx078fhOX8FwduA= X-Google-Smtp-Source: ABdhPJzZ220X3EGihTs7WYUjhmHEiiWcHk7yzkTbOsrf6kQXHP5XoP3qtOADSq73ynOjcLGTWIuOgNfwIKc= X-Received: from seanjc.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:3e5]) (user=seanjc job=sendgmr) by 2002:a05:6a00:8ce:b0:510:9298:ea26 with SMTP id s14-20020a056a0008ce00b005109298ea26mr36502407pfu.55.1654728324255; Wed, 08 Jun 2022 15:45:24 -0700 (PDT) Reply-To: Sean Christopherson Date: Wed, 8 Jun 2022 22:45:14 +0000 In-Reply-To: <20220608224516.3788274-1-seanjc@google.com> Message-Id: <20220608224516.3788274-4-seanjc@google.com> Mime-Version: 1.0 References: <20220608224516.3788274-1-seanjc@google.com> X-Mailer: git-send-email 2.36.1.255.ge46751e96f-goog Subject: [PATCH 3/5] KVM: selftests: Mostly fix comically broken Hyper-V Features test From: Sean Christopherson To: Paolo Bonzini Cc: Sean Christopherson , Vitaly Kuznetsov , Wanpeng Li , Jim Mattson , Joerg Roedel , kvm@vger.kernel.org, linux-kernel@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Explicitly do all setup at every stage of the Hyper-V Features test, e.g. set the MSR/hypercall, enable capabilities, etc... Now that the VM is recreated for every stage, values that are written into the VM's address space, i.e. shared with the guest, are reset between sub-tests, as are any capabilities, etc... Fix the hypercall params as well, which were broken in the same rework. The "hcall" struct/pointer needs to point at the hcall_params object, not the set of hypercall pages. The goofs were hidden by the test's dubious behavior of using '0' to signal "done", i.e. the MSR test ran exactly one sub-test, and the hypercall test was a gigantic nop. Fixes: 6c1186430a80 ("KVM: selftests: Avoid KVM_SET_CPUID2 after KVM_RUN in= hyperv_features test") Signed-off-by: Sean Christopherson --- .../selftests/kvm/x86_64/hyperv_features.c | 146 ++++++++++-------- 1 file changed, 83 insertions(+), 63 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/hyperv_features.c b/tools/t= esting/selftests/kvm/x86_64/hyperv_features.c index 3d0df079496b..5ec40422d72a 100644 --- a/tools/testing/selftests/kvm/x86_64/hyperv_features.c +++ b/tools/testing/selftests/kvm/x86_64/hyperv_features.c @@ -101,52 +101,44 @@ struct hcall_data { =20 static void guest_msr(struct msr_data *msr) { - int i =3D 0; - - while (msr->idx) { - WRITE_ONCE(nr_gp, 0); - if (!msr->write) - do_rdmsr(msr->idx); - else - do_wrmsr(msr->idx, msr->write_val); - - if (msr->available) - GUEST_ASSERT(READ_ONCE(nr_gp) =3D=3D 0); - else - GUEST_ASSERT(READ_ONCE(nr_gp) =3D=3D 1); - - GUEST_SYNC(i++); - } - + GUEST_ASSERT(msr->idx); + + WRITE_ONCE(nr_gp, 0); + if (!msr->write) + do_rdmsr(msr->idx); + else + do_wrmsr(msr->idx, msr->write_val); + + if (msr->available) + GUEST_ASSERT(READ_ONCE(nr_gp) =3D=3D 0); + else + GUEST_ASSERT(READ_ONCE(nr_gp) =3D=3D 1); GUEST_DONE(); } =20 static void guest_hcall(vm_vaddr_t pgs_gpa, struct hcall_data *hcall) { - int i =3D 0; u64 res, input, output; =20 + GUEST_ASSERT(hcall->control); + wrmsr(HV_X64_MSR_GUEST_OS_ID, LINUX_OS_ID); wrmsr(HV_X64_MSR_HYPERCALL, pgs_gpa); =20 - while (hcall->control) { - nr_ud =3D 0; - if (!(hcall->control & HV_HYPERCALL_FAST_BIT)) { - input =3D pgs_gpa; - output =3D pgs_gpa + 4096; - } else { - input =3D output =3D 0; - } - - res =3D hypercall(hcall->control, input, output); - if (hcall->ud_expected) - GUEST_ASSERT(nr_ud =3D=3D 1); - else - GUEST_ASSERT(res =3D=3D hcall->expect); - - GUEST_SYNC(i++); + nr_ud =3D 0; + if (!(hcall->control & HV_HYPERCALL_FAST_BIT)) { + input =3D pgs_gpa; + output =3D pgs_gpa + 4096; + } else { + input =3D output =3D 0; } =20 + res =3D hypercall(hcall->control, input, output); + if (hcall->ud_expected) + GUEST_ASSERT(nr_ud =3D=3D 1); + else + GUEST_ASSERT(res =3D=3D hcall->expect); + GUEST_DONE(); } =20 @@ -202,6 +194,10 @@ static void guest_test_msrs_access(void) =20 run =3D vcpu->run; =20 + /* TODO: Make this entire test easier to maintain. */ + if (stage >=3D 21) + vcpu_enable_cap(vcpu, KVM_CAP_HYPERV_SYNIC2, 0); + switch (stage) { case 0: /* @@ -245,11 +241,13 @@ static void guest_test_msrs_access(void) break; case 6: feat->eax |=3D HV_MSR_VP_RUNTIME_AVAILABLE; + msr->idx =3D HV_X64_MSR_VP_RUNTIME; msr->write =3D 0; msr->available =3D 1; break; case 7: /* Read only */ + msr->idx =3D HV_X64_MSR_VP_RUNTIME; msr->write =3D 1; msr->write_val =3D 1; msr->available =3D 0; @@ -262,11 +260,13 @@ static void guest_test_msrs_access(void) break; case 9: feat->eax |=3D HV_MSR_TIME_REF_COUNT_AVAILABLE; + msr->idx =3D HV_X64_MSR_TIME_REF_COUNT; msr->write =3D 0; msr->available =3D 1; break; case 10: /* Read only */ + msr->idx =3D HV_X64_MSR_TIME_REF_COUNT; msr->write =3D 1; msr->write_val =3D 1; msr->available =3D 0; @@ -279,11 +279,13 @@ static void guest_test_msrs_access(void) break; case 12: feat->eax |=3D HV_MSR_VP_INDEX_AVAILABLE; + msr->idx =3D HV_X64_MSR_VP_INDEX; msr->write =3D 0; msr->available =3D 1; break; case 13: /* Read only */ + msr->idx =3D HV_X64_MSR_VP_INDEX; msr->write =3D 1; msr->write_val =3D 1; msr->available =3D 0; @@ -296,10 +298,12 @@ static void guest_test_msrs_access(void) break; case 15: feat->eax |=3D HV_MSR_RESET_AVAILABLE; + msr->idx =3D HV_X64_MSR_RESET; msr->write =3D 0; msr->available =3D 1; break; case 16: + msr->idx =3D HV_X64_MSR_RESET; msr->write =3D 1; msr->write_val =3D 0; msr->available =3D 1; @@ -312,10 +316,12 @@ static void guest_test_msrs_access(void) break; case 18: feat->eax |=3D HV_MSR_REFERENCE_TSC_AVAILABLE; + msr->idx =3D HV_X64_MSR_REFERENCE_TSC; msr->write =3D 0; msr->available =3D 1; break; case 19: + msr->idx =3D HV_X64_MSR_REFERENCE_TSC; msr->write =3D 1; msr->write_val =3D 0; msr->available =3D 1; @@ -331,14 +337,18 @@ static void guest_test_msrs_access(void) * Remains unavailable even with KVM_CAP_HYPERV_SYNIC2 * capability enabled and guest visible CPUID bit unset. */ - vcpu_enable_cap(vcpu, KVM_CAP_HYPERV_SYNIC2, 0); + msr->idx =3D HV_X64_MSR_EOM; + msr->write =3D 0; + msr->available =3D 0; break; case 22: feat->eax |=3D HV_MSR_SYNIC_AVAILABLE; + msr->idx =3D HV_X64_MSR_EOM; msr->write =3D 0; msr->available =3D 1; break; case 23: + msr->idx =3D HV_X64_MSR_EOM; msr->write =3D 1; msr->write_val =3D 0; msr->available =3D 1; @@ -351,22 +361,28 @@ static void guest_test_msrs_access(void) break; case 25: feat->eax |=3D HV_MSR_SYNTIMER_AVAILABLE; + msr->idx =3D HV_X64_MSR_STIMER0_CONFIG; msr->write =3D 0; msr->available =3D 1; break; case 26: + msr->idx =3D HV_X64_MSR_STIMER0_CONFIG; msr->write =3D 1; msr->write_val =3D 0; msr->available =3D 1; break; case 27: /* Direct mode test */ + msr->idx =3D HV_X64_MSR_STIMER0_CONFIG; msr->write =3D 1; msr->write_val =3D 1 << 12; msr->available =3D 0; break; case 28: feat->edx |=3D HV_STIMER_DIRECT_MODE_AVAILABLE; + msr->idx =3D HV_X64_MSR_STIMER0_CONFIG; + msr->write =3D 1; + msr->write_val =3D 1 << 12; msr->available =3D 1; break; =20 @@ -377,6 +393,7 @@ static void guest_test_msrs_access(void) break; case 30: feat->eax |=3D HV_MSR_APIC_ACCESS_AVAILABLE; + msr->idx =3D HV_X64_MSR_EOI; msr->write =3D 1; msr->write_val =3D 1; msr->available =3D 1; @@ -389,11 +406,13 @@ static void guest_test_msrs_access(void) break; case 32: feat->eax |=3D HV_ACCESS_FREQUENCY_MSRS; + msr->idx =3D HV_X64_MSR_TSC_FREQUENCY; msr->write =3D 0; msr->available =3D 1; break; case 33: /* Read only */ + msr->idx =3D HV_X64_MSR_TSC_FREQUENCY; msr->write =3D 1; msr->write_val =3D 1; msr->available =3D 0; @@ -406,10 +425,12 @@ static void guest_test_msrs_access(void) break; case 35: feat->eax |=3D HV_ACCESS_REENLIGHTENMENT; + msr->idx =3D HV_X64_MSR_REENLIGHTENMENT_CONTROL; msr->write =3D 0; msr->available =3D 1; break; case 36: + msr->idx =3D HV_X64_MSR_REENLIGHTENMENT_CONTROL; msr->write =3D 1; msr->write_val =3D 1; msr->available =3D 1; @@ -429,10 +450,12 @@ static void guest_test_msrs_access(void) break; case 39: feat->edx |=3D HV_FEATURE_GUEST_CRASH_MSR_AVAILABLE; + msr->idx =3D HV_X64_MSR_CRASH_P0; msr->write =3D 0; msr->available =3D 1; break; case 40: + msr->idx =3D HV_X64_MSR_CRASH_P0; msr->write =3D 1; msr->write_val =3D 1; msr->available =3D 1; @@ -446,30 +469,28 @@ static void guest_test_msrs_access(void) case 42: feat->edx |=3D HV_FEATURE_DEBUG_MSRS_AVAILABLE; dbg->eax |=3D HV_X64_SYNDBG_CAP_ALLOW_KERNEL_DEBUGGING; + msr->idx =3D HV_X64_MSR_SYNDBG_STATUS; msr->write =3D 0; msr->available =3D 1; break; case 43: + msr->idx =3D HV_X64_MSR_SYNDBG_STATUS; msr->write =3D 1; msr->write_val =3D 0; msr->available =3D 1; break; =20 case 44: - /* END */ - msr->idx =3D 0; - break; + kvm_vm_free(vm); + return; } =20 vcpu_set_cpuid(vcpu); =20 memcpy(prev_cpuid, vcpu->cpuid, kvm_cpuid2_size(vcpu->cpuid->nent)); =20 - if (msr->idx) - pr_debug("Stage %d: testing msr: 0x%x for %s\n", stage, - msr->idx, msr->write ? "write" : "read"); - else - pr_debug("Stage %d: finish\n", stage); + pr_debug("Stage %d: testing msr: 0x%x for %s\n", stage, + msr->idx, msr->write ? "write" : "read"); =20 vcpu_run(vcpu); TEST_ASSERT(run->exit_reason =3D=3D KVM_EXIT_IO, @@ -477,16 +498,14 @@ static void guest_test_msrs_access(void) run->exit_reason, exit_reason_str(run->exit_reason)); =20 switch (get_ucall(vcpu, &uc)) { - case UCALL_SYNC: - TEST_ASSERT(uc.args[1] =3D=3D 0, - "Unexpected stage: %ld (0 expected)\n", - uc.args[1]); - break; case UCALL_ABORT: TEST_FAIL("%s at %s:%ld", (const char *)uc.args[0], __FILE__, uc.args[1]); return; case UCALL_DONE: + break; + default: + TEST_FAIL("Unhandled ucall: %ld", uc.cmd); return; } =20 @@ -516,11 +535,11 @@ static void guest_test_hcalls_access(void) =20 /* Hypercall input/output */ hcall_page =3D vm_vaddr_alloc_pages(vm, 2); - hcall =3D addr_gva2hva(vm, hcall_page); memset(addr_gva2hva(vm, hcall_page), 0x0, 2 * getpagesize()); =20 hcall_params =3D vm_vaddr_alloc_page(vm); memset(addr_gva2hva(vm, hcall_params), 0x0, getpagesize()); + hcall =3D addr_gva2hva(vm, hcall_params); =20 vcpu_args_set(vcpu, 2, addr_gva2gpa(vm, hcall_page), hcall_params); vcpu_enable_cap(vcpu, KVM_CAP_HYPERV_ENFORCE_CPUID, 1); @@ -552,6 +571,7 @@ static void guest_test_hcalls_access(void) break; case 2: feat->ebx |=3D HV_POST_MESSAGES; + hcall->control =3D HVCALL_POST_MESSAGE; hcall->expect =3D HV_STATUS_INVALID_HYPERCALL_INPUT; break; =20 @@ -561,6 +581,7 @@ static void guest_test_hcalls_access(void) break; case 4: feat->ebx |=3D HV_SIGNAL_EVENTS; + hcall->control =3D HVCALL_SIGNAL_EVENT; hcall->expect =3D HV_STATUS_INVALID_HYPERCALL_INPUT; break; =20 @@ -570,10 +591,12 @@ static void guest_test_hcalls_access(void) break; case 6: dbg->eax |=3D HV_X64_SYNDBG_CAP_ALLOW_KERNEL_DEBUGGING; + hcall->control =3D HVCALL_RESET_DEBUG_SESSION; hcall->expect =3D HV_STATUS_ACCESS_DENIED; break; case 7: feat->ebx |=3D HV_DEBUGGING; + hcall->control =3D HVCALL_RESET_DEBUG_SESSION; hcall->expect =3D HV_STATUS_OPERATION_DENIED; break; =20 @@ -583,6 +606,7 @@ static void guest_test_hcalls_access(void) break; case 9: recomm->eax |=3D HV_X64_REMOTE_TLB_FLUSH_RECOMMENDED; + hcall->control =3D HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE; hcall->expect =3D HV_STATUS_SUCCESS; break; case 10: @@ -591,6 +615,7 @@ static void guest_test_hcalls_access(void) break; case 11: recomm->eax |=3D HV_X64_EX_PROCESSOR_MASKS_RECOMMENDED; + hcall->control =3D HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE_EX; hcall->expect =3D HV_STATUS_SUCCESS; break; =20 @@ -600,6 +625,7 @@ static void guest_test_hcalls_access(void) break; case 13: recomm->eax |=3D HV_X64_CLUSTER_IPI_RECOMMENDED; + hcall->control =3D HVCALL_SEND_IPI; hcall->expect =3D HV_STATUS_INVALID_HYPERCALL_INPUT; break; case 14: @@ -613,6 +639,7 @@ static void guest_test_hcalls_access(void) hcall->expect =3D HV_STATUS_ACCESS_DENIED; break; case 16: + hcall->control =3D HVCALL_NOTIFY_LONG_SPIN_WAIT; recomm->ebx =3D 0xfff; hcall->expect =3D HV_STATUS_SUCCESS; break; @@ -622,26 +649,21 @@ static void guest_test_hcalls_access(void) hcall->ud_expected =3D true; break; case 18: + hcall->control =3D HVCALL_FLUSH_VIRTUAL_ADDRESS_SPACE | HV_HYPERCALL_FA= ST_BIT; feat->edx |=3D HV_X64_HYPERCALL_XMM_INPUT_AVAILABLE; hcall->ud_expected =3D false; hcall->expect =3D HV_STATUS_SUCCESS; break; - case 19: - /* END */ - hcall->control =3D 0; - break; + kvm_vm_free(vm); + return; } =20 vcpu_set_cpuid(vcpu); =20 memcpy(prev_cpuid, vcpu->cpuid, kvm_cpuid2_size(vcpu->cpuid->nent)); =20 - if (hcall->control) - pr_debug("Stage %d: testing hcall: 0x%lx\n", stage, - hcall->control); - else - pr_debug("Stage %d: finish\n", stage); + pr_debug("Stage %d: testing hcall: 0x%lx\n", stage, hcall->control); =20 vcpu_run(vcpu); TEST_ASSERT(run->exit_reason =3D=3D KVM_EXIT_IO, @@ -649,16 +671,14 @@ static void guest_test_hcalls_access(void) run->exit_reason, exit_reason_str(run->exit_reason)); =20 switch (get_ucall(vcpu, &uc)) { - case UCALL_SYNC: - TEST_ASSERT(uc.args[1] =3D=3D 0, - "Unexpected stage: %ld (0 expected)\n", - uc.args[1]); - break; case UCALL_ABORT: TEST_FAIL("%s at %s:%ld", (const char *)uc.args[0], __FILE__, uc.args[1]); return; case UCALL_DONE: + break; + default: + TEST_FAIL("Unhandled ucall: %ld", uc.cmd); return; } =20 --=20 2.36.1.255.ge46751e96f-goog From nobody Mon Jun 15 10:47:20 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id AD77FC43334 for ; Wed, 8 Jun 2022 22:45:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236910AbiFHWpd (ORCPT ); Wed, 8 Jun 2022 18:45:33 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60458 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236535AbiFHWp1 (ORCPT ); Wed, 8 Jun 2022 18:45:27 -0400 Received: from mail-pf1-x449.google.com (mail-pf1-x449.google.com [IPv6:2607:f8b0:4864:20::449]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3F7CB250E59 for ; Wed, 8 Jun 2022 15:45:26 -0700 (PDT) Received: by mail-pf1-x449.google.com with SMTP id 206-20020a6218d7000000b0051893ee2888so9595908pfy.16 for ; Wed, 08 Jun 2022 15:45:26 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=reply-to:date:in-reply-to:message-id:mime-version:references :subject:from:to:cc; bh=odWASXlloDi60XXoBrlzFlyWsT1m7IgRF4ZHI9ifXSg=; b=SUBOFoIgf90Txf8Nz+beruQQ7cYKBDZ5tsjoZOqGJh1/Q0jvMXGaS4vpnsOIZz8VxJ gT9pu9+SO4R/r0xtsSmlALrI7SKB3YIKrPA/PT49ihp/SB8mXiw4pCO92iJronG3x2FU qljTMX9E1Jalg3CUVPFGkprKD5TqpksWSKRWBGet0tVbkz5tqrleQ+KXrAxwmKIiCzrr MiVGCGdQxQk60JH9TNj6SvKUJVdhGDW1S5puZEPmpp3LyRFfmkwOHd5pRVlnbT9GR3+D fRyzFzZaFM935hzwsARKC/2VdWqPSK2DjuXovvDDsuGgcUulyEa5Y7qXFpAw2QZCpJ/Q Y4Og== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:reply-to:date:in-reply-to:message-id :mime-version:references:subject:from:to:cc; bh=odWASXlloDi60XXoBrlzFlyWsT1m7IgRF4ZHI9ifXSg=; b=uOyTmKzVXNoxYv4VXuo3XyuONFNJCLvoX9J98733sFIbEL7PGh58eEIw3nwMT4H0DZ QzctbNBMh3fK3JixborYUnVlRUWSRt8Rnxm/2iykquzboEtWyRu0OlODzn8pKBgC0hmd Zpogto10cB5zyyyWtCUz1Mm/TxQYDexVQAOWTPbHgkVkX80X6zUL2WgHbpFaSs+STgT8 3uggU4S1o1t0xn1NeX3UrqAoAPugrDrR5AWA68jV+Z895+NTzRNWp88KzSOh+JGIla3U xOp0wewTG0SkQUhK3Hto9hmVAqn3MDz+tR7AuZNKTMuGA3hGnhAp89gaPXUCw4w/rsp4 hHKw== X-Gm-Message-State: AOAM5334I26LoB9X6C2BO9/befmQXr2sBMm5lKW0QxYMI/Wt9k3whwfo 7Jvca6n3N/O+UQpnXEXsb3nAwejnOWM= X-Google-Smtp-Source: ABdhPJzQaZNHK6o2xZ0ojhjwS0+2ugBghUe638w9x98DctunKZduCh6I6F4eCzJI9Q7xdgEtohDcq89DJSw= X-Received: from seanjc.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:3e5]) (user=seanjc job=sendgmr) by 2002:a63:594c:0:b0:3fd:9b8b:863d with SMTP id j12-20020a63594c000000b003fd9b8b863dmr18078697pgm.250.1654728325763; Wed, 08 Jun 2022 15:45:25 -0700 (PDT) Reply-To: Sean Christopherson Date: Wed, 8 Jun 2022 22:45:15 +0000 In-Reply-To: <20220608224516.3788274-1-seanjc@google.com> Message-Id: <20220608224516.3788274-5-seanjc@google.com> Mime-Version: 1.0 References: <20220608224516.3788274-1-seanjc@google.com> X-Mailer: git-send-email 2.36.1.255.ge46751e96f-goog Subject: [PATCH 4/5] KVM: selftests: Use exception fixup for #UD/#GP Hyper-V MSR/hcall tests From: Sean Christopherson To: Paolo Bonzini Cc: Sean Christopherson , Vitaly Kuznetsov , Wanpeng Li , Jim Mattson , Joerg Roedel , kvm@vger.kernel.org, linux-kernel@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Use exception fixup to verify VMCALL/RDMSR/WRMSR fault as expected in the Hyper-V Features test. No functional change intended. Signed-off-by: Sean Christopherson --- .../selftests/kvm/x86_64/hyperv_features.c | 117 +++++------------- 1 file changed, 33 insertions(+), 84 deletions(-) diff --git a/tools/testing/selftests/kvm/x86_64/hyperv_features.c b/tools/t= esting/selftests/kvm/x86_64/hyperv_features.c index 5ec40422d72a..0de13ab38e8b 100644 --- a/tools/testing/selftests/kvm/x86_64/hyperv_features.c +++ b/tools/testing/selftests/kvm/x86_64/hyperv_features.c @@ -15,75 +15,20 @@ =20 #define LINUX_OS_ID ((u64)0x8100 << 48) =20 -extern unsigned char rdmsr_start; -extern unsigned char rdmsr_end; - -static u64 do_rdmsr(u32 idx) -{ - u32 lo, hi; - - asm volatile("rdmsr_start: rdmsr;" - "rdmsr_end:" - : "=3Da"(lo), "=3Dc"(hi) - : "c"(idx)); - - return (((u64) hi) << 32) | lo; -} - -extern unsigned char wrmsr_start; -extern unsigned char wrmsr_end; - -static void do_wrmsr(u32 idx, u64 val) -{ - u32 lo, hi; - - lo =3D val; - hi =3D val >> 32; - - asm volatile("wrmsr_start: wrmsr;" - "wrmsr_end:" - : : "a"(lo), "c"(idx), "d"(hi)); -} - -static int nr_gp; -static int nr_ud; - -static inline u64 hypercall(u64 control, vm_vaddr_t input_address, - vm_vaddr_t output_address) -{ - u64 hv_status; - - asm volatile("mov %3, %%r8\n" - "vmcall" - : "=3Da" (hv_status), - "+c" (control), "+d" (input_address) - : "r" (output_address) - : "cc", "memory", "r8", "r9", "r10", "r11"); - - return hv_status; -} - -static void guest_gp_handler(struct ex_regs *regs) -{ - unsigned char *rip =3D (unsigned char *)regs->rip; - bool r, w; - - r =3D rip =3D=3D &rdmsr_start; - w =3D rip =3D=3D &wrmsr_start; - GUEST_ASSERT(r || w); - - nr_gp++; - - if (r) - regs->rip =3D (uint64_t)&rdmsr_end; - else - regs->rip =3D (uint64_t)&wrmsr_end; -} - -static void guest_ud_handler(struct ex_regs *regs) -{ - nr_ud++; - regs->rip +=3D 3; +static inline uint8_t hypercall(u64 control, vm_vaddr_t input_address, + vm_vaddr_t output_address, uint64_t *hv_status) +{ + uint8_t vector; + + /* Note both the hypercall and the "asm safe" clobber r9-r11. */ + asm volatile("mov %[output_address], %%r8\n\t" + KVM_ASM_SAFE("vmcall") + : "=3Da" (*hv_status), + "+c" (control), "+d" (input_address), + KVM_ASM_SAFE_OUTPUTS(vector) + : [output_address] "r"(output_address) + : "cc", "memory", "r8", KVM_ASM_SAFE_CLOBBERS); + return vector; } =20 struct msr_data { @@ -101,31 +46,33 @@ struct hcall_data { =20 static void guest_msr(struct msr_data *msr) { + uint64_t ignored; + uint8_t vector; + GUEST_ASSERT(msr->idx); =20 - WRITE_ONCE(nr_gp, 0); if (!msr->write) - do_rdmsr(msr->idx); + vector =3D rdmsr_safe(msr->idx, &ignored); else - do_wrmsr(msr->idx, msr->write_val); + vector =3D wrmsr_safe(msr->idx, msr->write_val); =20 if (msr->available) - GUEST_ASSERT(READ_ONCE(nr_gp) =3D=3D 0); + GUEST_ASSERT_2(!vector, msr->idx, vector); else - GUEST_ASSERT(READ_ONCE(nr_gp) =3D=3D 1); + GUEST_ASSERT_2(vector =3D=3D GP_VECTOR, msr->idx, vector); GUEST_DONE(); } =20 static void guest_hcall(vm_vaddr_t pgs_gpa, struct hcall_data *hcall) { u64 res, input, output; + uint8_t vector; =20 GUEST_ASSERT(hcall->control); =20 wrmsr(HV_X64_MSR_GUEST_OS_ID, LINUX_OS_ID); wrmsr(HV_X64_MSR_HYPERCALL, pgs_gpa); =20 - nr_ud =3D 0; if (!(hcall->control & HV_HYPERCALL_FAST_BIT)) { input =3D pgs_gpa; output =3D pgs_gpa + 4096; @@ -133,12 +80,14 @@ static void guest_hcall(vm_vaddr_t pgs_gpa, struct hca= ll_data *hcall) input =3D output =3D 0; } =20 - res =3D hypercall(hcall->control, input, output); + vector =3D hypercall(hcall->control, input, output, &res); if (hcall->ud_expected) - GUEST_ASSERT(nr_ud =3D=3D 1); + GUEST_ASSERT_2(vector =3D=3D UD_VECTOR, hcall->control, vector); else - GUEST_ASSERT(res =3D=3D hcall->expect); + GUEST_ASSERT_2(!vector, hcall->control, vector); =20 + GUEST_ASSERT_2(!hcall->ud_expected || res =3D=3D hcall->expect, + hcall->expect, res); GUEST_DONE(); } =20 @@ -190,7 +139,6 @@ static void guest_test_msrs_access(void) =20 vm_init_descriptor_tables(vm); vcpu_init_descriptor_tables(vcpu); - vm_install_exception_handler(vm, GP_VECTOR, guest_gp_handler); =20 run =3D vcpu->run; =20 @@ -499,8 +447,9 @@ static void guest_test_msrs_access(void) =20 switch (get_ucall(vcpu, &uc)) { case UCALL_ABORT: - TEST_FAIL("%s at %s:%ld", (const char *)uc.args[0], - __FILE__, uc.args[1]); + TEST_FAIL("%s at %s:%ld, MSR =3D %lx, vector =3D %lx", + (const char *)uc.args[0], __FILE__, + uc.args[1], uc.args[2], uc.args[3]); return; case UCALL_DONE: break; @@ -531,7 +480,6 @@ static void guest_test_hcalls_access(void) =20 vm_init_descriptor_tables(vm); vcpu_init_descriptor_tables(vcpu); - vm_install_exception_handler(vm, UD_VECTOR, guest_ud_handler); =20 /* Hypercall input/output */ hcall_page =3D vm_vaddr_alloc_pages(vm, 2); @@ -672,8 +620,9 @@ static void guest_test_hcalls_access(void) =20 switch (get_ucall(vcpu, &uc)) { case UCALL_ABORT: - TEST_FAIL("%s at %s:%ld", (const char *)uc.args[0], - __FILE__, uc.args[1]); + TEST_FAIL("%s at %s:%ld, arg1 =3D %lx, arg2 =3D %lx", + (const char *)uc.args[0], __FILE__, + uc.args[1], uc.args[2], uc.args[3]); return; case UCALL_DONE: break; --=20 2.36.1.255.ge46751e96f-goog From nobody Mon Jun 15 10:47:20 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id D7934C43334 for ; Wed, 8 Jun 2022 22:45:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229539AbiFHWpp (ORCPT ); Wed, 8 Jun 2022 18:45:45 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33666 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236800AbiFHWp3 (ORCPT ); Wed, 8 Jun 2022 18:45:29 -0400 Received: from mail-pf1-x44a.google.com (mail-pf1-x44a.google.com [IPv6:2607:f8b0:4864:20::44a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 030D72504CB for ; Wed, 8 Jun 2022 15:45:27 -0700 (PDT) Received: by mail-pf1-x44a.google.com with SMTP id q12-20020a056a0002ac00b0051bb2e66c91so11327999pfs.4 for ; Wed, 08 Jun 2022 15:45:27 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=reply-to:date:in-reply-to:message-id:mime-version:references :subject:from:to:cc; bh=L6CG/ucwyzRbxPhEP+xskpq5cumPIfOGi6WfytIM0VI=; b=EVrWDujSzZhYWScj6uvyk/wsH9irmGTL6WNySzq7huYNhDGk2RcPTI6RmAp+SHuBd9 tUjiNPGzPKbB+WvXlCxogt0M9Mbw8kwAjdR95DKE6qPdhzNa57z58+zWAHhnOziOHbn+ Zwqth5TBzimqdtVbE+W+DNFJBcTLFJwYtJL9p9msqFQXjrg3eZpLkpoTUjqIPhJ7VNGq DFg32qozGkUujV/IdgRsor4H2O5y+mDXrza/czdxLHnhX8QYnZAzv4xOtaVLGnzjbKVj XPpl+91Ds74ar752Cg7+9B0m+II28CnWOtVSf2z2RonRixRyR5jeyNV9/TI2siqPjny+ cSIA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:reply-to:date:in-reply-to:message-id :mime-version:references:subject:from:to:cc; bh=L6CG/ucwyzRbxPhEP+xskpq5cumPIfOGi6WfytIM0VI=; b=BIXpw5S0+qb7WeIiNCPZ1Tsjb1SLALY8+ibiXmtKdQCRvqaEQAialAaYsx95ieSLAt nbUJOrt8fY6M3LPlJb5ZG+iAaHuGjm0vwcP5yTHcSYLfAGfUwZmpwP8TmWnIXJqSIQpu SDBAgYLy43YWqFleg4CKUHdd5G/AYVEyCKGKbIsc6vCLfgvAATtAZq8YMweU+RJC0dYt TwTvJdiysNFbg6YYmEnjJ0Erh/JKGnn6/QHuFUuZUA3XUsBuSPVbGx6hsrOmWOIw5xNx 9yiN5DAukB2wKOy3bmgvtbK9w7J2o3FQJSP00pO2HqRHrwmAmteoEJ13FwW5Kw5gaAnM ATVg== X-Gm-Message-State: AOAM532yfux4Tsa/KcHTdAkDt9FPmOSop5m3FmRm+TVusi7KEL0RN67R dBgmptg0cC4dr5fBJAWFHLrLPULYbBA= X-Google-Smtp-Source: ABdhPJx9WF++0c78k3640NdFplCX1fFdbExMr6dWv7IOPQRs+W4YuRh0MTHB9N/9ITqnrqr6Dd0MjFHwpsI= X-Received: from seanjc.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:3e5]) (user=seanjc job=sendgmr) by 2002:a17:90a:5a48:b0:1e3:4180:a218 with SMTP id m8-20020a17090a5a4800b001e34180a218mr262148pji.182.1654728327551; Wed, 08 Jun 2022 15:45:27 -0700 (PDT) Reply-To: Sean Christopherson Date: Wed, 8 Jun 2022 22:45:16 +0000 In-Reply-To: <20220608224516.3788274-1-seanjc@google.com> Message-Id: <20220608224516.3788274-6-seanjc@google.com> Mime-Version: 1.0 References: <20220608224516.3788274-1-seanjc@google.com> X-Mailer: git-send-email 2.36.1.255.ge46751e96f-goog Subject: [PATCH 5/5] KVM: selftests: Add MONITOR/MWAIT quirk test From: Sean Christopherson To: Paolo Bonzini Cc: Sean Christopherson , Vitaly Kuznetsov , Wanpeng Li , Jim Mattson , Joerg Roedel , kvm@vger.kernel.org, linux-kernel@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add a test to verify the "MONITOR/MWAIT never fault" quirk, and as a bonus, also verify the related "MISC_ENABLES ignores ENABLE_MWAIT" quirk. If the "never fault" quirk is enabled, MONITOR/MWAIT should always be emulated as NOPs, even if they're reported as disabled in guest CPUID. Use the MISC_ENABLES quirk to coerce KVM into toggling the MWAIT CPUID enable, as KVM now disallows manually toggling CPUID bits after running the vCPU. Signed-off-by: Sean Christopherson --- tools/testing/selftests/kvm/.gitignore | 1 + tools/testing/selftests/kvm/Makefile | 1 + .../selftests/kvm/x86_64/monitor_mwait_test.c | 127 ++++++++++++++++++ 3 files changed, 129 insertions(+) create mode 100644 tools/testing/selftests/kvm/x86_64/monitor_mwait_test.c diff --git a/tools/testing/selftests/kvm/.gitignore b/tools/testing/selftes= ts/kvm/.gitignore index 0ab0e255d292..1a56522f009c 100644 --- a/tools/testing/selftests/kvm/.gitignore +++ b/tools/testing/selftests/kvm/.gitignore @@ -27,6 +27,7 @@ /x86_64/hyperv_svm_test /x86_64/max_vcpuid_cap_test /x86_64/mmio_warning_test +/x86_64/monitor_mwait_test /x86_64/platform_info_test /x86_64/pmu_event_filter_test /x86_64/set_boot_cpu_id diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests= /kvm/Makefile index 9a256c1f1bdf..bbbfdeb7ee9b 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -56,6 +56,7 @@ TEST_GEN_PROGS_x86_64 +=3D x86_64/hyperv_svm_test TEST_GEN_PROGS_x86_64 +=3D x86_64/kvm_clock_test TEST_GEN_PROGS_x86_64 +=3D x86_64/kvm_pv_test TEST_GEN_PROGS_x86_64 +=3D x86_64/mmio_warning_test +TEST_GEN_PROGS_x86_64 +=3D x86_64/monitor_mwait_test TEST_GEN_PROGS_x86_64 +=3D x86_64/platform_info_test TEST_GEN_PROGS_x86_64 +=3D x86_64/pmu_event_filter_test TEST_GEN_PROGS_x86_64 +=3D x86_64/set_boot_cpu_id diff --git a/tools/testing/selftests/kvm/x86_64/monitor_mwait_test.c b/tool= s/testing/selftests/kvm/x86_64/monitor_mwait_test.c new file mode 100644 index 000000000000..b9af8e29721e --- /dev/null +++ b/tools/testing/selftests/kvm/x86_64/monitor_mwait_test.c @@ -0,0 +1,127 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include +#include + +#include "kvm_util.h" +#include "processor.h" + +enum monitor_mwait_testcases { + MWAIT_QUIRK_DISABLED =3D BIT(0), + MISC_ENABLES_QUIRK_DISABLED =3D BIT(1), + MWAIT_DISABLED =3D BIT(2), +}; + +static void guest_monitor_wait(int testcase) +{ + /* + * If both MWAIT and its quirk are disabled, MONITOR/MWAIT should #UD, + * in all other scenarios KVM should emulate them as nops. + */ + bool fault_wanted =3D (testcase & MWAIT_QUIRK_DISABLED) && + (testcase & MWAIT_DISABLED); + u8 vector; + + GUEST_SYNC(testcase); + + vector =3D kvm_asm_safe("monitor"); + if (fault_wanted) + GUEST_ASSERT_2(vector =3D=3D UD_VECTOR, testcase, vector); + else + GUEST_ASSERT_2(!vector, testcase, vector); + + vector =3D kvm_asm_safe("monitor"); + if (fault_wanted) + GUEST_ASSERT_2(vector =3D=3D UD_VECTOR, testcase, vector); + else + GUEST_ASSERT_2(!vector, testcase, vector); +} + +static void guest_code(void) +{ + guest_monitor_wait(MWAIT_DISABLED); + + guest_monitor_wait(MWAIT_QUIRK_DISABLED | MWAIT_DISABLED); + + guest_monitor_wait(MISC_ENABLES_QUIRK_DISABLED | MWAIT_DISABLED); + guest_monitor_wait(MISC_ENABLES_QUIRK_DISABLED); + + guest_monitor_wait(MISC_ENABLES_QUIRK_DISABLED | MWAIT_QUIRK_DISABLED | M= WAIT_DISABLED); + guest_monitor_wait(MISC_ENABLES_QUIRK_DISABLED | MWAIT_QUIRK_DISABLED); + + GUEST_DONE(); +} + +int main(int argc, char *argv[]) +{ + uint64_t disabled_quirks; + struct kvm_vcpu *vcpu; + struct kvm_run *run; + struct kvm_vm *vm; + struct ucall uc; + int testcase; + + TEST_REQUIRE(kvm_has_cap(KVM_CAP_DISABLE_QUIRKS2)); + + vm =3D vm_create_with_one_vcpu(&vcpu, guest_code); + vcpu_clear_cpuid_feature(vcpu, X86_FEATURE_MWAIT); + + run =3D vcpu->run; + + vm_init_descriptor_tables(vm); + vcpu_init_descriptor_tables(vcpu); + + while (1) { + vcpu_run(vcpu); + + TEST_ASSERT(run->exit_reason =3D=3D KVM_EXIT_IO, + "Unexpected exit reason: %u (%s),\n", + run->exit_reason, + exit_reason_str(run->exit_reason)); + + switch (get_ucall(vcpu, &uc)) { + case UCALL_SYNC: + testcase =3D uc.args[1]; + break; + case UCALL_ABORT: + TEST_FAIL("%s at %s:%ld, testcase =3D %lx, vector =3D %ld", + (const char *)uc.args[0], __FILE__, + uc.args[1], uc.args[2], uc.args[3]); + goto done; + case UCALL_DONE: + goto done; + default: + TEST_FAIL("Unknown ucall %lu", uc.cmd); + goto done; + } + + disabled_quirks =3D 0; + if (testcase & MWAIT_QUIRK_DISABLED) + disabled_quirks |=3D KVM_X86_QUIRK_MWAIT_NEVER_FAULTS; + if (testcase & MISC_ENABLES_QUIRK_DISABLED) + disabled_quirks |=3D KVM_X86_QUIRK_MISC_ENABLE_NO_MWAIT; + vm_enable_cap(vm, KVM_CAP_DISABLE_QUIRKS2, disabled_quirks); + + /* + * If the MISC_ENABLES quirk (KVM neglects to update CPUID to + * enable/disable MWAIT) is disabled, toggle the ENABLE_MWAIT + * bit in MISC_ENABLES accordingly. If the quirk is enabled, + * the only valid configuration is MWAIT disabled, as CPUID + * can't be manually changed after running the vCPU. + */ + if (!(testcase & MISC_ENABLES_QUIRK_DISABLED)) { + TEST_ASSERT(testcase & MWAIT_DISABLED, + "Can't toggle CPUID features after running vCPU"); + continue; + } + + vcpu_set_msr(vcpu, MSR_IA32_MISC_ENABLE, + (testcase & MWAIT_DISABLED) ? 0 : MSR_IA32_MISC_ENABLE_MWAIT); + } + +done: + kvm_vm_free(vm); + return 0; +} --=20 2.36.1.255.ge46751e96f-goog