Received: by 2002:a5d:9c59:0:0:0:0:0 with SMTP id 25csp780966iof; Mon, 6 Jun 2022 12:21:12 -0700 (PDT) X-Google-Smtp-Source: ABdhPJyh9WpA/2MG/9r1XpIPQ6NzcvcLfkY8P+nWGIws7viueDi4e573P3tHil2/PbNtOrc3o4kP X-Received: by 2002:a17:902:e0c2:b0:167:6128:e63d with SMTP id e2-20020a170902e0c200b001676128e63dmr13898065pla.16.1654543271847; Mon, 06 Jun 2022 12:21:11 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1654543271; cv=none; d=google.com; s=arc-20160816; b=OK+l7kW1eWQq39B1kEYdX/BPCu6SnHmWR+1rywInQoDZylDY9GeZRPHKLRVKQz8wS6 vcwBPAvvxQdTecaeyE3eRiJdCl/T0lvT4dteGWg4lsxvuUlz2dvkp/s000lhQChsYIsE mDKiULYthcrgRgK4LGYXWLlAWMes9jSb/WVcE4yHIXEHef4YbTGFwVB5iR7iG2IwF46+ q0QHyXLLpsBEHc5vLFswiwinazi5/mOtEDOmWns7mycIeEWU+TYbvGmIpsg4GcYF55yj 7hxyu+/plyz0CPr11m8ibDFs1GfqBZat/cvxs4t96Y3MyLdhoQsJbqg6LCGnPz7u1Cvi 7MTA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=5ouDcIYJZnuwxcggSN3JWhIbWktPsI+ueJ4oKyyKY60=; b=Cb1uWZdKUkhLR4Ujy+iIIkfnfzIfbU9HO+0alMUy7n8TO3UmrtwzUHzrdRBXySYUyw xt7ATGQGP9N0CyPvocUBVrAvZZf1EdK8JqjCmcZTlIf1DN3cWIoEJ4O7Vgcp4lZxLeji f3r6m2nZOsWCugcc2gejjSdNCgdAiFd90sfmqJ2kDrR4lpHVKFjbX+OEE+cJq7CvhhMJ x8+9G/sfu6SHV+vJ4cfYT++EYZy8vJBysdQLaBJKkbKHVUhwcG8kDvVhhgdCVbXthWT1 iVm4TdtNHCYCUFFMkeUQ5JwXHRlsIRPT84HdwLOlFy4qLzauUqW1T3ItvfCfJq9goLw1 1S4g== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=d+neJr2F; 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=NONE sp=NONE dis=NONE) header.from=redhat.com Return-Path: Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id h184-20020a6383c1000000b003fca9a6092asi1690151pge.778.2022.06.06.12.20.59; Mon, 06 Jun 2022 12:21:11 -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=@redhat.com header.s=mimecast20190719 header.b=d+neJr2F; 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=NONE sp=NONE dis=NONE) header.from=redhat.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231314AbiFFSJL (ORCPT + 99 others); Mon, 6 Jun 2022 14:09:11 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:44888 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231298AbiFFSI7 (ORCPT ); Mon, 6 Jun 2022 14:08:59 -0400 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id DFB642FE71 for ; Mon, 6 Jun 2022 11:08:55 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1654538935; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=5ouDcIYJZnuwxcggSN3JWhIbWktPsI+ueJ4oKyyKY60=; b=d+neJr2FP3uoKAsDWF0lGAPsrzHm99VahBg54sX01RG3gBrxytVRISC+a0ZOIrTVHPFs4L eN0rCzcugPIMW29iWdR9HUzJh8CbLUzcsKxc0PehrtTEG5YDjfq2LnY7rl72VJZLeWpKwS PtgmLohZMN/s7UM6HWZTNY/T0SB1tw8= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-433-295CEvSJM7-w7nt7JRQBvg-1; Mon, 06 Jun 2022 14:08:50 -0400 X-MC-Unique: 295CEvSJM7-w7nt7JRQBvg-1 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id E56C81010368; Mon, 6 Jun 2022 18:08:49 +0000 (UTC) Received: from localhost.localdomain (unknown [10.40.194.180]) by smtp.corp.redhat.com (Postfix) with ESMTP id 4BDEA1121314; Mon, 6 Jun 2022 18:08:46 +0000 (UTC) From: Maxim Levitsky To: kvm@vger.kernel.org Cc: Wanpeng Li , Vitaly Kuznetsov , Sean Christopherson , Jim Mattson , "H. Peter Anvin" , Joerg Roedel , Dave Hansen , Ingo Molnar , Suravee Suthikulpanit , linux-kernel@vger.kernel.org, Maxim Levitsky , Thomas Gleixner , x86@kernel.org, Borislav Petkov , Paolo Bonzini , stable@vger.kernel.org Subject: [PATCH 4/7] KVM: x86: SVM: fix avic_kick_target_vcpus_fast Date: Mon, 6 Jun 2022 21:08:26 +0300 Message-Id: <20220606180829.102503-5-mlevitsk@redhat.com> In-Reply-To: <20220606180829.102503-1-mlevitsk@redhat.com> References: <20220606180829.102503-1-mlevitsk@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 X-Spam-Status: No, score=-3.3 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_NONE,T_SCC_BODY_TEXT_LINE 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 There are two issues in avic_kick_target_vcpus_fast 1. It is legal to issue an IPI request with APIC_DEST_NOSHORT and a physical destination of 0xFF (or 0xFFFFFFFF in case of x2apic), which must be treated as a broadcast destination. Fix this by explicitly checking for it. Also don’t use ‘index’ in this case as it gives no new information. 2. It is legal to issue a logical IPI request to more than one target. Index field only provides index in physical id table of first such target and therefore can't be used before we are sure that only a single target was addressed. Instead, parse the ICRL/ICRH, double check that a unicast interrupt was requested, and use that info to figure out the physical id of the target vCPU. At that point there is no need to use the index field as well. In addition to fixing the above issues, also skip the call to kvm_apic_match_dest. It is possible to do this now, because now as long as AVIC is not inhibited, it is guaranteed that none of the vCPUs changed their apic id from its default value. This fixes boot of windows guest with AVIC enabled because it uses IPI with 0xFF destination and no destination shorthand. Fixes: 7223fd2d5338 ("KVM: SVM: Use target APIC ID to complete AVIC IRQs when possible") Cc: stable@vger.kernel.org Signed-off-by: Maxim Levitsky --- arch/x86/kvm/svm/avic.c | 105 ++++++++++++++++++++++++++-------------- 1 file changed, 69 insertions(+), 36 deletions(-) diff --git a/arch/x86/kvm/svm/avic.c b/arch/x86/kvm/svm/avic.c index 072e2c8cc66aa..5d98ac575dedc 100644 --- a/arch/x86/kvm/svm/avic.c +++ b/arch/x86/kvm/svm/avic.c @@ -291,58 +291,91 @@ void avic_ring_doorbell(struct kvm_vcpu *vcpu) static int avic_kick_target_vcpus_fast(struct kvm *kvm, struct kvm_lapic *source, u32 icrl, u32 icrh, u32 index) { - u32 dest, apic_id; - struct kvm_vcpu *vcpu; + u32 l1_physical_id, dest; + struct kvm_vcpu *target_vcpu; int dest_mode = icrl & APIC_DEST_MASK; int shorthand = icrl & APIC_SHORT_MASK; struct kvm_svm *kvm_svm = to_kvm_svm(kvm); - u32 *avic_logical_id_table = page_address(kvm_svm->avic_logical_id_table_page); if (shorthand != APIC_DEST_NOSHORT) return -EINVAL; - /* - * The AVIC incomplete IPI #vmexit info provides index into - * the physical APIC ID table, which can be used to derive - * guest physical APIC ID. - */ + if (apic_x2apic_mode(source)) + dest = icrh; + else + dest = GET_APIC_DEST_FIELD(icrh); + if (dest_mode == APIC_DEST_PHYSICAL) { - apic_id = index; + /* broadcast destination, use slow path */ + if (apic_x2apic_mode(source) && dest == X2APIC_BROADCAST) + return -EINVAL; + if (!apic_x2apic_mode(source) && dest == APIC_BROADCAST) + return -EINVAL; + + l1_physical_id = dest; + + if (WARN_ON_ONCE(l1_physical_id != index)) + return -EINVAL; + } else { - if (!apic_x2apic_mode(source)) { - /* For xAPIC logical mode, the index is for logical APIC table. */ - apic_id = avic_logical_id_table[index] & 0x1ff; + u32 bitmap, cluster; + int logid_index; + + if (apic_x2apic_mode(source)) { + /* 16 bit dest mask, 16 bit cluster id */ + bitmap = dest & 0xFFFF0000; + cluster = (dest >> 16) << 4; + } else if (kvm_lapic_get_reg(source, APIC_DFR) == APIC_DFR_FLAT) { + /* 8 bit dest mask*/ + bitmap = dest; + cluster = 0; } else { - return -EINVAL; + /* 4 bit desk mask, 4 bit cluster id */ + bitmap = dest & 0xF; + cluster = (dest >> 4) << 2; } - } - /* - * Assuming vcpu ID is the same as physical apic ID, - * and use it to retrieve the target vCPU. - */ - vcpu = kvm_get_vcpu_by_id(kvm, apic_id); - if (!vcpu) - return -EINVAL; + if (unlikely(!bitmap)) + /* guest bug: nobody to send the logical interrupt to */ + return 0; - if (apic_x2apic_mode(vcpu->arch.apic)) - dest = icrh; - else - dest = GET_APIC_DEST_FIELD(icrh); + if (!is_power_of_2(bitmap)) + /* multiple logical destinations, use slow path */ + return -EINVAL; - /* - * Try matching the destination APIC ID with the vCPU. - */ - if (kvm_apic_match_dest(vcpu, source, shorthand, dest, dest_mode)) { - vcpu->arch.apic->irr_pending = true; - svm_complete_interrupt_delivery(vcpu, - icrl & APIC_MODE_MASK, - icrl & APIC_INT_LEVELTRIG, - icrl & APIC_VECTOR_MASK); - return 0; + logid_index = cluster + __ffs(bitmap); + + if (apic_x2apic_mode(source)) { + l1_physical_id = logid_index; + } else { + u32 *avic_logical_id_table = + page_address(kvm_svm->avic_logical_id_table_page); + + u32 logid_entry = avic_logical_id_table[logid_index]; + + if (WARN_ON_ONCE(index != logid_index)) + return -EINVAL; + + /* guest bug: non existing/reserved logical destination */ + if (unlikely(!(logid_entry & AVIC_LOGICAL_ID_ENTRY_VALID_MASK))) + return 0; + + l1_physical_id = logid_entry & + AVIC_LOGICAL_ID_ENTRY_GUEST_PHYSICAL_ID_MASK; + } } - return -EINVAL; + target_vcpu = kvm_get_vcpu_by_id(kvm, l1_physical_id); + if (unlikely(!target_vcpu)) + /* guest bug: non existing vCPU is a target of this IPI*/ + return 0; + + target_vcpu->arch.apic->irr_pending = true; + svm_complete_interrupt_delivery(target_vcpu, + icrl & APIC_MODE_MASK, + icrl & APIC_INT_LEVELTRIG, + icrl & APIC_VECTOR_MASK); + return 0; } static void avic_kick_target_vcpus(struct kvm *kvm, struct kvm_lapic *source, -- 2.26.3