Received: by 2002:ac0:da4c:0:0:0:0:0 with SMTP id a12csp1125316imi; Fri, 22 Jul 2022 18:12:23 -0700 (PDT) X-Google-Smtp-Source: AGRyM1uChvR6FaUKgbLCMF+ekPKERhroozXwpj+abTMXpzBhWQh5hjrB5DRBnQ+zk0/HWUjrxtpx X-Received: by 2002:a63:6945:0:b0:41a:5127:a477 with SMTP id e66-20020a636945000000b0041a5127a477mr2056446pgc.15.1658538743579; Fri, 22 Jul 2022 18:12:23 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1658538743; cv=none; d=google.com; s=arc-20160816; b=ng417jCzaScX59y4VSADwYp5D1nzO4r9ZqWbN3QqVx46/nudnSOClnpr257L23HH/q 8GZMf8Is3s/C46gVj4uLOZSDZx9wYOE33qr8SDB3pSEGk4iGUBzIqOmB60E2i8SG8P7l sVsUjFJsnI7YtjTPCJiK+JCEOHuSK1f9TM1NnH1cXfWVMuucKH2eh+Nox1hoFGHn1ukS ufk9uDr09jmzfMwZoXLQPLadpI71n9wwM6Zx/5KT/+kLywUzicAd1i9/5UKMFBCyBm6O 36Ak7MdOeYTh2/xICfj+k2aXF3j4pkC+5JHQVM1VgKcIxS5100DNx5k4W3QvGhWWuMmT qHZw== 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=8QUcqYdas0eqDSvXYo4Sqhu3pNlKhGcIVM8bC4z4X4E=; b=HmSmbxZvPvgIypbgarDGkBfrVnH0h6Wyzwhd/Vccdify6e/uYdLshYkoOdj8W5e66D s0Zfb5h+QK5PjccGUVTK+X7bl40m3Evhx0wsMA+45Tx7+BpBO2pKo2H4KTsfH5S6e4l9 DcKEIib1DNltQlGOXrczDEdemJaN02uvtFynq2vVYbQDpAw6G7MVdRS5OeHmDPYqySKz ApRf4Po+zvvbJIrhehw+hITLLOGFsorxa8cEzIdSlHMoCalkKUk0s4ozXgqLO/0dbDks IayJupF69nBmUqeZVmfVGzmBfRimxG7bF2jDnBMG3Bdb8oOLM9wgGJ+hVLz6KxMGp2O9 VxOQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20210112 header.b=sjhztSts; 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 192-20020a6302c9000000b00412a01e9b07si7515149pgc.847.2022.07.22.18.12.08; Fri, 22 Jul 2022 18:12:23 -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=sjhztSts; 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 S236993AbiGWAyS (ORCPT + 99 others); Fri, 22 Jul 2022 20:54:18 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58188 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236870AbiGWAxT (ORCPT ); Fri, 22 Jul 2022 20:53:19 -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 9A9EAC1DDF for ; Fri, 22 Jul 2022 17:52:29 -0700 (PDT) Received: by mail-pl1-x64a.google.com with SMTP id b17-20020a170903229100b0016d3e892112so1961010plh.6 for ; Fri, 22 Jul 2022 17:52:29 -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=8QUcqYdas0eqDSvXYo4Sqhu3pNlKhGcIVM8bC4z4X4E=; b=sjhztStshfGUZjDU7uyDWl8wKUBQr+RDpjo1ZpkTve75pKSWyt00NUhxwC4ubI3hwv m0VPkRoleUb5rZXcYoQHOjO0RV6QpchamAIQ9PYcsNmzHtsy5H7oMOvDkwFcGyCmWCKS XJoDgXEHuS1V57Toaoc6+lOOPHFdnvMUV/0IFaw8rGfvzRlO2p19Wb0mL7MAUmy5TwgJ OkD7RaEqGX8O1AtHLTvxVZ6qRQXzjlRazM+gQZBGH7s/pg0IfIFkEDSXKsW3VLuVrf5b 26akg/dEbbCI2Iiv26BFVp5C5mWhPWTk6KzOuJOxL9bpiFADJKaNGvAXC6OFjBE0/l7r /fJA== 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=8QUcqYdas0eqDSvXYo4Sqhu3pNlKhGcIVM8bC4z4X4E=; b=N7XwFLvWBjOIPiWGQusj5fEa+SxhM9DRzRrDYl/QFPCOdAIn1B4fIcvqSlcJAzbMHb LLDjOnC7cwipm/tUEFQFJnt0VMdQCAokiEDfwTp5U5yE8+kwnx1be7j9HfLvVNVzsbWX u2AoD6IDlbvogQXRjhEtrkaFn4iTijsotVh0wFO+2s/QtR5mnCJceCpSiU/LvxRurGCB XNj5wkRPLSSUEr7082nM4bbKpd+IhPHu4ie9Cl4ItRR9GlOKXeMvWp+ASkSPt256olWU dxoL5WWskpSegcrZ8L7vYMYw2TnryTaoyWAYAh8+1LDD1H+tBwZ3AYctlfylWXP03Jbg /V7Q== X-Gm-Message-State: AJIora+ElGHZ4oFCkuYXiA9Xj2Tcqjz+N+Z27AYkEerbZ49y9wlr49c6 FauslZXWki/CCK1Dg8Lm1wnYE8S2ufY= X-Received: from zagreus.c.googlers.com ([fda3:e722:ac3:cc00:7f:e700:c0a8:5c37]) (user=seanjc job=sendgmr) by 2002:a17:902:8602:b0:16c:dfae:9afb with SMTP id f2-20020a170902860200b0016cdfae9afbmr2430916plo.35.1658537536913; Fri, 22 Jul 2022 17:52:16 -0700 (PDT) Reply-To: Sean Christopherson Date: Sat, 23 Jul 2022 00:51:35 +0000 In-Reply-To: <20220723005137.1649592-1-seanjc@google.com> Message-Id: <20220723005137.1649592-23-seanjc@google.com> Mime-Version: 1.0 References: <20220723005137.1649592-1-seanjc@google.com> X-Mailer: git-send-email 2.37.1.359.gd136c6c3e2-goog Subject: [PATCH v4 22/24] KVM: x86: Rename inject_pending_events() to kvm_check_and_inject_events() From: Sean Christopherson To: Sean Christopherson , Paolo Bonzini Cc: kvm@vger.kernel.org, linux-kernel@vger.kernel.org, Jim Mattson , Maxim Levitsky , Oliver Upton , Peter Shier 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,USER_IN_DEF_DKIM_WL autolearn=unavailable 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 Rename inject_pending_events() to kvm_check_and_inject_events() in order to capture the fact that it handles more than just pending events, and to (mostly) align with kvm_check_nested_events(), which omits the "inject" for brevity. Add a comment above kvm_check_and_inject_events() to provide a high-level synopsis, and to document a virtualization hole (KVM erratum if you will) that exists due to KVM not strictly tracking instruction boundaries with respect to coincident instruction restarts and asynchronous events. No functional change inteded. Signed-off-by: Sean Christopherson Reviewed-by: Maxim Levitsky --- arch/x86/kvm/svm/nested.c | 2 +- arch/x86/kvm/svm/svm.c | 2 +- arch/x86/kvm/x86.c | 46 ++++++++++++++++++++++++++++++++++++--- 3 files changed, 45 insertions(+), 5 deletions(-) diff --git a/arch/x86/kvm/svm/nested.c b/arch/x86/kvm/svm/nested.c index 405075286965..6b3b18404533 100644 --- a/arch/x86/kvm/svm/nested.c +++ b/arch/x86/kvm/svm/nested.c @@ -1312,7 +1312,7 @@ static void nested_svm_inject_exception_vmexit(struct kvm_vcpu *vcpu) else vmcb->control.exit_info_2 = vcpu->arch.cr2; } else if (ex->vector == DB_VECTOR) { - /* See inject_pending_event. */ + /* See kvm_check_and_inject_events(). */ kvm_deliver_exception_payload(vcpu, ex); if (vcpu->arch.dr7 & DR7_GD) { diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index 74cbe177e0d1..12e66e2114d1 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -3520,7 +3520,7 @@ void svm_complete_interrupt_delivery(struct kvm_vcpu *vcpu, int delivery_mode, /* Note, this is called iff the local APIC is in-kernel. */ if (!READ_ONCE(vcpu->arch.apic->apicv_active)) { - /* Process the interrupt via inject_pending_event */ + /* Process the interrupt via kvm_check_and_inject_events(). */ kvm_make_request(KVM_REQ_EVENT, vcpu); kvm_vcpu_kick(vcpu); return; diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index d714f335749c..4ed4811a7137 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -9704,7 +9704,47 @@ static void kvm_inject_exception(struct kvm_vcpu *vcpu) static_call(kvm_x86_inject_exception)(vcpu); } -static int inject_pending_event(struct kvm_vcpu *vcpu, bool *req_immediate_exit) +/* + * Check for any event (interrupt or exception) that is ready to be injected, + * and if there is at least one event, inject the event with the highest + * priority. This handles both "pending" events, i.e. events that have never + * been injected into the guest, and "injected" events, i.e. events that were + * injected as part of a previous VM-Enter, but weren't successfully delivered + * and need to be re-injected. + * + * Note, this is not guaranteed to be invoked on a guest instruction boundary, + * i.e. doesn't guarantee that there's an event window in the guest. KVM must + * be able to inject exceptions in the "middle" of an instruction, and so must + * also be able to re-inject NMIs and IRQs in the middle of an instruction. + * I.e. for exceptions and re-injected events, NOT invoking this on instruction + * boundaries is necessary and correct. + * + * For simplicity, KVM uses a single path to inject all events (except events + * that are injected directly from L1 to L2) and doesn't explicitly track + * instruction boundaries for asynchronous events. However, because VM-Exits + * that can occur during instruction execution typically result in KVM skipping + * the instruction or injecting an exception, e.g. instruction and exception + * intercepts, and because pending exceptions have higher priority than pending + * interrupts, KVM still honors instruction boundaries in most scenarios. + * + * But, if a VM-Exit occurs during instruction execution, and KVM does NOT skip + * the instruction or inject an exception, then KVM can incorrecty inject a new + * asynchrounous event if the event became pending after the CPU fetched the + * instruction (in the guest). E.g. if a page fault (#PF, #NPF, EPT violation) + * occurs and is resolved by KVM, a coincident NMI, SMI, IRQ, etc... can be + * injected on the restarted instruction instead of being deferred until the + * instruction completes. + * + * In practice, this virtualization hole is unlikely to be observed by the + * guest, and even less likely to cause functional problems. To detect the + * hole, the guest would have to trigger an event on a side effect of an early + * phase of instruction execution, e.g. on the instruction fetch from memory. + * And for it to be a functional problem, the guest would need to depend on the + * ordering between that side effect, the instruction completing, _and_ the + * delivery of the asynchronous event. + */ +static int kvm_check_and_inject_events(struct kvm_vcpu *vcpu, + bool *req_immediate_exit) { bool can_inject; int r; @@ -10183,7 +10223,7 @@ void kvm_vcpu_update_apicv(struct kvm_vcpu *vcpu) * When APICv gets disabled, we may still have injected interrupts * pending. At the same time, KVM_REQ_EVENT may not be set as APICv was * still active when the interrupt got accepted. Make sure - * inject_pending_event() is called to check for that. + * kvm_check_and_inject_events() is called to check for that. */ if (!apic->apicv_active) kvm_make_request(KVM_REQ_EVENT, vcpu); @@ -10480,7 +10520,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) goto out; } - r = inject_pending_event(vcpu, &req_immediate_exit); + r = kvm_check_and_inject_events(vcpu, &req_immediate_exit); if (r < 0) { r = 0; goto out; -- 2.37.1.359.gd136c6c3e2-goog