Received: by 2002:a05:6a10:2726:0:0:0:0 with SMTP id ib38csp2975433pxb; Mon, 4 Apr 2022 04:46:21 -0700 (PDT) X-Google-Smtp-Source: ABdhPJzKqaKfYK03WDbUBq1YoWnjvgvPJa74+bvSnMbDXAekdlEZfN0CYhSi0+mJPrEV5vCQODTX X-Received: by 2002:a17:907:1624:b0:6db:8caa:d71 with SMTP id hb36-20020a170907162400b006db8caa0d71mr10673697ejc.723.1649072781284; Mon, 04 Apr 2022 04:46:21 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1649072781; cv=none; d=google.com; s=arc-20160816; b=mBMz1Q8QhObaNI1dVOwc3ERF9W6yCNVKoczLX/XNBVD0oplCEPyXOveRqNsdyGGi1D t72b9G+GC3QD39A7n2MvO8a823TVc6SRG8dShn4/J49PYPYHJxF54K/wkb9mzhiUQSIw gx73kN7h7Ak4tdGbKd/pnJj8Hymspa7qJyfbiBw6vABLAWxbg6CH8/HaSByafRnqkaSS x8dp9wa19u4khkc3pkCjBd33G2ivhHUqdC9MxNhXI+I2JoYSTGbwLIMw7umcT1YP52h1 mqvlhHDOi5MMCfsMdWmleBLLWTrvPltJgGitADlgpvlsK3Bo3LzkIAqr3dQegg1x365k jL3A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:references:mime-version :message-id:in-reply-to:date:reply-to:dkim-signature; bh=OExX1Igb+SEI7PdUVeKXKi/G1aHbfTSQe6uvI8ZE66s=; b=jA4fCk5SiOcealq9EICNJ1VWyOKPMP1U8DifYoOLdxcjBawFwh7Bx4Q5KTpYG9Klsm xjFogbBK+Kh2H6c9wrLFT5bUjyAODvoT4B0vvFIgGdETszrDCHpCYKISHDG+rNl6gHu5 KNrE6KPkIvDZdz2JOaKWST2uE0+JdLUE/6dNNj6zXjglwlYBsHzArBW0t0gBpyiMWGWZ bzzcIld+j51W52upkG/M2KdODNG+wfQAOiav98BJ9VT3EkT5otkjJtPU+kfvkwvJIuAf MFX5QulAHAhaMfh30746GJC66cWiWx/BVOyE3l044L8pzoUAps91UxZqiizkxihYqSM3 kbXQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=QoWYxsIz; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Return-Path: Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id q9-20020a1709066b0900b006df76385da5si6182443ejr.581.2022.04.04.04.45.55; Mon, 04 Apr 2022 04:46:21 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=QoWYxsIz; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S238617AbiDBBLf (ORCPT + 99 others); Fri, 1 Apr 2022 21:11:35 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44330 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1353675AbiDBBLO (ORCPT ); Fri, 1 Apr 2022 21:11:14 -0400 Received: from mail-pl1-x64a.google.com (mail-pl1-x64a.google.com [IPv6:2607:f8b0:4864:20::64a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5F3E0A145D for ; Fri, 1 Apr 2022 18:09:19 -0700 (PDT) Received: by mail-pl1-x64a.google.com with SMTP id z8-20020a170903018800b001566875e0f5so1668480plg.21 for ; Fri, 01 Apr 2022 18:09:19 -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=OExX1Igb+SEI7PdUVeKXKi/G1aHbfTSQe6uvI8ZE66s=; b=QoWYxsIze+C3Ee47cmi+k5goTPGx2Io4H2IyLGbi5BL+YuSOtk8JZB9VbBiKfn+5KE tyrkF6Zyy4naj8XbTkWvhkg/sFU+thgF+DR7zGxHaU0Zufu1ol74uxq4AXOtb0GAHX2+ RCwbWhRxvZMYnWlv5Pel0agogKAldZa+yRq1pBY6qslSIaYI1EsqNARyskD1VinUqj37 0o4B7ukkXknlytvlvFrKfIN3Log0v9sa7s+sDwVihw3X5My32CK4QQgkdwX9QMxI0OCg rolELI0I7ldjj+6WJTt4XTF7oYy1R+nt/GzVXksOb23zb7L7SLrRPoB+qBeferqjl3zT i/Qg== 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=OExX1Igb+SEI7PdUVeKXKi/G1aHbfTSQe6uvI8ZE66s=; b=pNtPBwdUOHqGAUkj/ukfOwn/c14196ZqQD26UxgS5MIbGZvWAz5D00qtYxakYDSMro gEiE4kW1fo2+hUPUkbe/w9BdbztSjOvWDh7YFUSZdktv0A2TTjhspV0vCA5Gwvg3EWsQ reNhrNFl1UJEVI2ckBrPDvc7+Eruak7bFJbkMK0hQ/1dum8xEp6TAa7V8l7zBO1nw1Ic C/AeLDriILP486aD5EWT2Hq9WfAJIGJCcRMc7z/xFdW/0a//Wz8WlT3M/BzN1W0Ze96G PR4rwdmekiw/kI1IM8DQ37rFHq9Bk+LcKGz54xJ9zoJcQ6KrrXnk4suThUHtQJ4E7KxN v2aQ== X-Gm-Message-State: AOAM533zN8NkGR4f7eEUz2xw/+A3/ceCiT/MHiT7Y4cXmDXgl4MDWH3D rb4rHUz7g99mB39FzIjjXsqYmNzkLpY= X-Received: from seanjc.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:3e5]) (user=seanjc job=sendgmr) by 2002:a63:6d4c:0:b0:398:7c40:c160 with SMTP id i73-20020a636d4c000000b003987c40c160mr17309928pgc.109.1648861758524; Fri, 01 Apr 2022 18:09:18 -0700 (PDT) Reply-To: Sean Christopherson Date: Sat, 2 Apr 2022 01:09:03 +0000 In-Reply-To: <20220402010903.727604-1-seanjc@google.com> Message-Id: <20220402010903.727604-9-seanjc@google.com> Mime-Version: 1.0 References: <20220402010903.727604-1-seanjc@google.com> X-Mailer: git-send-email 2.35.1.1094.g7c7d902a7c-goog Subject: [PATCH 8/8] KVM: selftests: nSVM: Add svm_nested_soft_inject_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, "Maciej S . Szmigiero" Content-Type: text/plain; charset="UTF-8" X-Spam-Status: No, score=-9.6 required=5.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE,USER_IN_DEF_DKIM_WL autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Maciej S. Szmigiero Add a KVM self-test that checks whether a nSVM L1 is able to successfully inject a software interrupt and a soft exception into its L2 guest. In practice, this tests both the next_rip field consistency and L1-injected event with intervening L0 VMEXIT during its delivery: the first nested VMRUN (that's also trying to inject a software interrupt) will immediately trigger a L0 NPF. This L0 NPF will have zero in its CPU-returned next_rip field, which if incorrectly reused by KVM will trigger a #PF when trying to return to such address 0 from the interrupt handler. Signed-off-by: Maciej S. Szmigiero Signed-off-by: Sean Christopherson --- tools/testing/selftests/kvm/.gitignore | 1 + tools/testing/selftests/kvm/Makefile | 1 + .../selftests/kvm/include/x86_64/svm_util.h | 2 + .../kvm/x86_64/svm_nested_soft_inject_test.c | 147 ++++++++++++++++++ 4 files changed, 151 insertions(+) create mode 100644 tools/testing/selftests/kvm/x86_64/svm_nested_soft_inject_test.c diff --git a/tools/testing/selftests/kvm/.gitignore b/tools/testing/selftests/kvm/.gitignore index 1f1b6c978bf7..1354d3f4a362 100644 --- a/tools/testing/selftests/kvm/.gitignore +++ b/tools/testing/selftests/kvm/.gitignore @@ -33,6 +33,7 @@ /x86_64/state_test /x86_64/svm_vmcall_test /x86_64/svm_int_ctl_test +/x86_64/svm_nested_soft_inject_test /x86_64/sync_regs_test /x86_64/tsc_msrs_test /x86_64/userspace_io_test diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile index c9cdbd248727..cef6d583044b 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -66,6 +66,7 @@ TEST_GEN_PROGS_x86_64 += x86_64/state_test TEST_GEN_PROGS_x86_64 += x86_64/vmx_preemption_timer_test TEST_GEN_PROGS_x86_64 += x86_64/svm_vmcall_test TEST_GEN_PROGS_x86_64 += x86_64/svm_int_ctl_test +TEST_GEN_PROGS_x86_64 += x86_64/svm_nested_soft_inject_test TEST_GEN_PROGS_x86_64 += x86_64/tsc_scaling_sync TEST_GEN_PROGS_x86_64 += x86_64/sync_regs_test TEST_GEN_PROGS_x86_64 += x86_64/userspace_io_test diff --git a/tools/testing/selftests/kvm/include/x86_64/svm_util.h b/tools/testing/selftests/kvm/include/x86_64/svm_util.h index a25aabd8f5e7..d49f7c9b4564 100644 --- a/tools/testing/selftests/kvm/include/x86_64/svm_util.h +++ b/tools/testing/selftests/kvm/include/x86_64/svm_util.h @@ -16,6 +16,8 @@ #define CPUID_SVM_BIT 2 #define CPUID_SVM BIT_ULL(CPUID_SVM_BIT) +#define SVM_EXIT_EXCP_BASE 0x040 +#define SVM_EXIT_HLT 0x078 #define SVM_EXIT_MSR 0x07c #define SVM_EXIT_VMMCALL 0x081 diff --git a/tools/testing/selftests/kvm/x86_64/svm_nested_soft_inject_test.c b/tools/testing/selftests/kvm/x86_64/svm_nested_soft_inject_test.c new file mode 100644 index 000000000000..d39be5d885c1 --- /dev/null +++ b/tools/testing/selftests/kvm/x86_64/svm_nested_soft_inject_test.c @@ -0,0 +1,147 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * Based on: + * svm_int_ctl_test + * + * Copyright (C) 2021, Red Hat, Inc. + * + */ + +#include "test_util.h" +#include "kvm_util.h" +#include "processor.h" +#include "svm_util.h" + +#define VCPU_ID 0 +#define INT_NR 0x20 +#define X86_FEATURE_NRIPS BIT(3) + +#define vmcall() \ + __asm__ __volatile__( \ + "vmmcall\n" \ + ) + +#define ud2() \ + __asm__ __volatile__( \ + "ud2\n" \ + ) + +#define hlt() \ + __asm__ __volatile__( \ + "hlt\n" \ + ) + +static unsigned int bp_fired; +static void guest_bp_handler(struct ex_regs *regs) +{ + bp_fired++; +} + +static unsigned int int_fired; +static void guest_int_handler(struct ex_regs *regs) +{ + int_fired++; +} + +static void l2_guest_code(void) +{ + GUEST_ASSERT(int_fired == 1); + vmcall(); + ud2(); + + GUEST_ASSERT(bp_fired == 1); + hlt(); +} + +static void l1_guest_code(struct svm_test_data *svm) +{ + #define L2_GUEST_STACK_SIZE 64 + unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE]; + struct vmcb *vmcb = svm->vmcb; + + /* Prepare for L2 execution. */ + generic_svm_setup(svm, l2_guest_code, + &l2_guest_stack[L2_GUEST_STACK_SIZE]); + + vmcb->control.intercept_exceptions |= BIT(PF_VECTOR) | BIT(UD_VECTOR); + vmcb->control.intercept |= BIT(INTERCEPT_HLT); + + vmcb->control.event_inj = INT_NR | SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_SOFT; + /* The return address pushed on stack */ + vmcb->control.next_rip = vmcb->save.rip; + + run_guest(vmcb, svm->vmcb_gpa); + GUEST_ASSERT_3(vmcb->control.exit_code == SVM_EXIT_VMMCALL, + vmcb->control.exit_code, + vmcb->control.exit_info_1, vmcb->control.exit_info_2); + + /* Skip over VMCALL */ + vmcb->save.rip += 3; + + vmcb->control.event_inj = BP_VECTOR | SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_EXEPT; + /* The return address pushed on stack, skip over UD2 */ + vmcb->control.next_rip = vmcb->save.rip + 2; + + run_guest(vmcb, svm->vmcb_gpa); + GUEST_ASSERT_3(vmcb->control.exit_code == SVM_EXIT_HLT, + vmcb->control.exit_code, + vmcb->control.exit_info_1, vmcb->control.exit_info_2); + + GUEST_DONE(); +} + +int main(int argc, char *argv[]) +{ + struct kvm_cpuid_entry2 *cpuid; + struct kvm_vm *vm; + vm_vaddr_t svm_gva; + struct kvm_guest_debug debug; + + nested_svm_check_supported(); + + cpuid = kvm_get_supported_cpuid_entry(0x8000000a); + if (!(cpuid->edx & X86_FEATURE_NRIPS)) { + print_skip("nRIP Save unavailable"); + exit(KSFT_SKIP); + } + + vm = vm_create_default(VCPU_ID, 0, (void *) l1_guest_code); + + vm_init_descriptor_tables(vm); + vcpu_init_descriptor_tables(vm, VCPU_ID); + + vm_install_exception_handler(vm, BP_VECTOR, guest_bp_handler); + vm_install_exception_handler(vm, INT_NR, guest_int_handler); + + vcpu_alloc_svm(vm, &svm_gva); + vcpu_args_set(vm, VCPU_ID, 1, svm_gva); + + memset(&debug, 0, sizeof(debug)); + vcpu_set_guest_debug(vm, VCPU_ID, &debug); + + struct kvm_run *run = vcpu_state(vm, VCPU_ID); + struct ucall uc; + + vcpu_run(vm, VCPU_ID); + TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, + "Got exit_reason other than KVM_EXIT_IO: %u (%s)\n", + run->exit_reason, + exit_reason_str(run->exit_reason)); + + switch (get_ucall(vm, VCPU_ID, &uc)) { + case UCALL_ABORT: + TEST_FAIL("%s at %s:%ld, vals = 0x%lx 0x%lx 0x%lx", (const char *)uc.args[0], + __FILE__, uc.args[1], uc.args[2], uc.args[3], uc.args[4]); + break; + /* NOT REACHED */ + case UCALL_DONE: + goto done; + default: + TEST_FAIL("Unknown ucall 0x%lx.", uc.cmd); + } +done: + kvm_vm_free(vm); + return 0; +} -- 2.35.1.1094.g7c7d902a7c-goog