Received: by 2002:a6b:fb09:0:0:0:0:0 with SMTP id h9csp5660286iog; Thu, 23 Jun 2022 02:48:07 -0700 (PDT) X-Google-Smtp-Source: AGRyM1u/yV9tTWMAFf3NT/gAaAUhPg/aT+DlpsqJmp1FClWD/7lmSWNV4to7KEjadatManl20zzq X-Received: by 2002:a17:907:1c87:b0:6f0:29ea:cc01 with SMTP id nb7-20020a1709071c8700b006f029eacc01mr7352365ejc.671.1655977686872; Thu, 23 Jun 2022 02:48:06 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1655977686; cv=none; d=google.com; s=arc-20160816; b=sQca9Ovq3kRDrE6GWslctCQypHaFBPzIixmfRi1jWietV/d94iRrAyj02/E1Y2wRtB afRQ3XQL2fTEYTXFJvyaxqS/aLUQTD2kC0IgyrdoVKSdk5+sGfHYEZ1xvFkj+exdSMnf A6KUmpPlpnp6GL7SvWQasMR+Rwt7YvQ1hj84fSMSjuCuLGaE4iT4bgVk+M5z03EIUNha xH+klF1vAlA/NAEqr1xAbCfUogg0XjOrPlp7Q7gypvmF4zQeltXhxwSMVnGNzfF/yBin ypkoJ9Te8tAtIILYwwdJrFe+uPTDlNBiHSI94ev3Rkp3vpe/xqWUqfhFzcldjGA7dBV1 iq/w== 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 :user-agent:references:in-reply-to:date:cc:to:from:subject :message-id:dkim-signature; bh=5Z+ZDJJgpbgIXOZdFi38EUFLQ9DT89Je0CI9wqZBuNk=; b=ZJIC6/PERC1oeKNln5XospHo9hXrVayaDu2Kz4Bs3dwhrDr6abloFTY8ES4nEGE0h7 aSyDzyZDU9KSbmSDO/SqD9oxut0Lsx3hs/xw9zT7gXy7DLXvD7jU5WQaz/EkojlRBT8I Idf20y6GR9LhMpw961xQT08mKrAzwUkNmf5mjFldGdlmmzAaSZzCtunerRRvhbwXd6Jb 2P+ucJSZw7PCrL4Zy/y8CecmwDWKavMXba72ugNhbPUGkBHNvxTMEQXdRtkv2ytkivnV VCi8jygBgmymRbw+1MRXgUDNMWwDez/NsmRNszMmmNoDH2F30bTI2pUsNBBymt6pESkM zrxQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@redhat.com header.s=mimecast20190719 header.b=WsK7lRIq; 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 i9-20020a1709067a4900b0070897236380si21245581ejo.19.2022.06.23.02.47.41; Thu, 23 Jun 2022 02:48:06 -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=WsK7lRIq; 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 S230316AbiFWJod (ORCPT + 99 others); Thu, 23 Jun 2022 05:44:33 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46926 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229720AbiFWJob (ORCPT ); Thu, 23 Jun 2022 05:44:31 -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 A4F5149279 for ; Thu, 23 Jun 2022 02:44:30 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1655977469; 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=5Z+ZDJJgpbgIXOZdFi38EUFLQ9DT89Je0CI9wqZBuNk=; b=WsK7lRIqe8O26GxhDScwQm/bUutjhuKUXXph/u1vHjZT5VZRWSb0M51xqfeUhGecQWXV7j MXSowZesw4fbYX0mGb7CzypgSSCHBJsd3CeJqe+ImCtf5L449obS5h705mW4jbEC59a27J j3TwELUP+p21POee6UcCy8iodS4frJI= 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-163-smz41-0vPfiHxCFPUHlplg-1; Thu, 23 Jun 2022 05:44:26 -0400 X-MC-Unique: smz41-0vPfiHxCFPUHlplg-1 Received: from smtp.corp.redhat.com (int-mx09.intmail.prod.int.rdu2.redhat.com [10.11.54.9]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 623D4185A7B2; Thu, 23 Jun 2022 09:44:25 +0000 (UTC) Received: from starship (unknown [10.40.194.180]) by smtp.corp.redhat.com (Postfix) with ESMTP id 3462E492CA5; Thu, 23 Jun 2022 09:44:19 +0000 (UTC) Message-ID: Subject: Re: [RFC PATCH v3 02/19] KVM: x86: inhibit APICv/AVIC when the guest and/or host changes apic id/base from the defaults. From: Maxim Levitsky To: Sean Christopherson Cc: kvm@vger.kernel.org, Wanpeng Li , Vitaly Kuznetsov , Jani Nikula , Paolo Bonzini , Tvrtko Ursulin , Rodrigo Vivi , Zhenyu Wang , Joonas Lahtinen , Tom Lendacky , Ingo Molnar , David Airlie , Thomas Gleixner , Dave Hansen , x86@kernel.org, intel-gfx@lists.freedesktop.org, Daniel Vetter , Borislav Petkov , Joerg Roedel , linux-kernel@vger.kernel.org, Jim Mattson , Zhi Wang , Brijesh Singh , "H. Peter Anvin" , intel-gvt-dev@lists.freedesktop.org, dri-devel@lists.freedesktop.org Date: Thu, 23 Jun 2022 12:44:18 +0300 In-Reply-To: References: <20220427200314.276673-1-mlevitsk@redhat.com> <20220427200314.276673-3-mlevitsk@redhat.com> Content-Type: text/plain; charset="UTF-8" User-Agent: Evolution 3.36.5 (3.36.5-2.fc32) MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Scanned-By: MIMEDefang 2.85 on 10.11.54.9 X-Spam-Status: No, score=-3.4 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_LOW, 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 On Thu, 2022-05-19 at 16:06 +0000, Sean Christopherson wrote: > On Wed, Apr 27, 2022, Maxim Levitsky wrote: > > Neither of these settings should be changed by the guest and it is > > a burden to support it in the acceleration code, so just inhibit > > it instead. > > > > Also add a boolean 'apic_id_changed' to indicate if apic id ever changed. > > > > Signed-off-by: Maxim Levitsky > > --- > > arch/x86/include/asm/kvm_host.h | 3 +++ > > arch/x86/kvm/lapic.c | 25 ++++++++++++++++++++++--- > > arch/x86/kvm/lapic.h | 8 ++++++++ > > 3 files changed, 33 insertions(+), 3 deletions(-) > > > > diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h > > index 63eae00625bda..636df87542555 100644 > > --- a/arch/x86/include/asm/kvm_host.h > > +++ b/arch/x86/include/asm/kvm_host.h > > @@ -1070,6 +1070,8 @@ enum kvm_apicv_inhibit { > > APICV_INHIBIT_REASON_ABSENT, > > /* AVIC is disabled because SEV doesn't support it */ > > APICV_INHIBIT_REASON_SEV, > > + /* APIC ID and/or APIC base was changed by the guest */ > > I don't see any reason to inhibit APICv if the APIC base is changed. KVM has > never supported that, and disabling APICv won't "fix" anything. > > Ignoring that is a minor simplification, but also allows for a more intuitive > name, e.g. > > APICV_INHIBIT_REASON_APIC_ID_MODIFIED, > > The inhibit also needs to be added avic_check_apicv_inhibit_reasons() and > vmx_check_apicv_inhibit_reasons(). > > > + APICV_INHIBIT_REASON_RO_SETTINGS, > > }; > > > > struct kvm_arch { > > @@ -1258,6 +1260,7 @@ struct kvm_arch { > > hpa_t hv_root_tdp; > > spinlock_t hv_root_tdp_lock; > > #endif > > + bool apic_id_changed; > > }; > > > > struct kvm_vm_stat { > > diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c > > index 66b0eb0bda94e..8996675b3ef4c 100644 > > --- a/arch/x86/kvm/lapic.c > > +++ b/arch/x86/kvm/lapic.c > > @@ -2038,6 +2038,19 @@ static void apic_manage_nmi_watchdog(struct kvm_lapic *apic, u32 lvt0_val) > > } > > } > > > > +static void kvm_lapic_check_initial_apic_id(struct kvm_lapic *apic) > > The "check" part is misleading/confusing. "check" helpers usually query and return > state. I assume you avoided "changed" because the ID may or may not actually be > changing. Maybe kvm_apic_id_updated()? Ah, better idea. What about > kvm_lapic_xapic_id_updated()? See below for reasoning. > > > +{ > > + if (kvm_apic_has_initial_apic_id(apic)) > > Rather than add a single-use helper, invoke the helper from kvm_apic_state_fixup() > in the !x2APIC path, then this can KVM_BUG_ON() x2APIC to help document that KVM > should never allow the ID to change for x2APIC. > > > + return; > > + > > + pr_warn_once("APIC ID change is unsupported by KVM"); > > It's supported (modulo x2APIC shenanigans), otherwise KVM wouldn't need to disable > APICv. > > > + kvm_set_apicv_inhibit(apic->vcpu->kvm, > > + APICV_INHIBIT_REASON_RO_SETTINGS); > > + > > + apic->vcpu->kvm->arch.apic_id_changed = true; > > +} > > + > > static int kvm_lapic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val) > > { > > int ret = 0; > > @@ -2046,9 +2059,11 @@ static int kvm_lapic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val) > > > > switch (reg) { > > case APIC_ID: /* Local APIC ID */ > > - if (!apic_x2apic_mode(apic)) > > + if (!apic_x2apic_mode(apic)) { > > + > > Spurious newline. > > > kvm_apic_set_xapic_id(apic, val >> 24); > > - else > > + kvm_lapic_check_initial_apic_id(apic); > > + } else > > Needs curly braces for both paths. > > > ret = 1; > > break; > > > > E.g. > > --- > arch/x86/include/asm/kvm_host.h | 1 + > arch/x86/kvm/lapic.c | 21 +++++++++++++++++++-- > arch/x86/kvm/svm/avic.c | 3 ++- > arch/x86/kvm/vmx/vmx.c | 3 ++- > 4 files changed, 24 insertions(+), 4 deletions(-) > > diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h > index d895d25c5b2f..d888fa1bae77 100644 > --- a/arch/x86/include/asm/kvm_host.h > +++ b/arch/x86/include/asm/kvm_host.h > @@ -1071,6 +1071,7 @@ enum kvm_apicv_inhibit { > APICV_INHIBIT_REASON_BLOCKIRQ, > APICV_INHIBIT_REASON_ABSENT, > APICV_INHIBIT_REASON_SEV, > + APICV_INHIBIT_REASON_APIC_ID_MODIFIED, > }; > > struct kvm_arch { > diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c > index 5fd678c90288..6fe8f20f03d8 100644 > --- a/arch/x86/kvm/lapic.c > +++ b/arch/x86/kvm/lapic.c > @@ -2039,6 +2039,19 @@ static void apic_manage_nmi_watchdog(struct kvm_lapic *apic, u32 lvt0_val) > } > } > > +static void kvm_lapic_xapic_id_updated(struct kvm_lapic *apic) > +{ > + struct kvm *kvm = apic->vcpu->kvm; > + > + if (KVM_BUG_ON(apic_x2apic_mode(apic), kvm)) > + return; > + > + if (kvm_xapic_id(apic) == apic->vcpu->vcpu_id) > + return; > + > + kvm_set_apicv_inhibit(kvm, APICV_INHIBIT_REASON_APIC_ID_MODIFIED); > +} > + > static int kvm_lapic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val) > { > int ret = 0; > @@ -2047,10 +2060,12 @@ static int kvm_lapic_reg_write(struct kvm_lapic *apic, u32 reg, u32 val) > > switch (reg) { > case APIC_ID: /* Local APIC ID */ > - if (!apic_x2apic_mode(apic)) > + if (!apic_x2apic_mode(apic)) { > kvm_apic_set_xapic_id(apic, val >> 24); > - else > + kvm_lapic_xapic_id_updated(apic); > + } else { > ret = 1; > + } > break; > > case APIC_TASKPRI: > @@ -2665,6 +2680,8 @@ static int kvm_apic_state_fixup(struct kvm_vcpu *vcpu, > icr = __kvm_lapic_get_reg64(s->regs, APIC_ICR); > __kvm_lapic_set_reg(s->regs, APIC_ICR2, icr >> 32); > } > + } else { > + kvm_lapic_xapic_id_updated(vcpu->arch.apic); > } > > return 0; > diff --git a/arch/x86/kvm/svm/avic.c b/arch/x86/kvm/svm/avic.c > index 54fe03714f8a..239c3e8b1f3f 100644 > --- a/arch/x86/kvm/svm/avic.c > +++ b/arch/x86/kvm/svm/avic.c > @@ -910,7 +910,8 @@ bool avic_check_apicv_inhibit_reasons(enum kvm_apicv_inhibit reason) > BIT(APICV_INHIBIT_REASON_PIT_REINJ) | > BIT(APICV_INHIBIT_REASON_X2APIC) | > BIT(APICV_INHIBIT_REASON_BLOCKIRQ) | > - BIT(APICV_INHIBIT_REASON_SEV); > + BIT(APICV_INHIBIT_REASON_SEV) | > + BIT(APICV_INHIBIT_REASON_APIC_ID_MODIFIED); > > return supported & BIT(reason); > } > diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c > index b06eafa5884d..941adade21ea 100644 > --- a/arch/x86/kvm/vmx/vmx.c > +++ b/arch/x86/kvm/vmx/vmx.c > @@ -7818,7 +7818,8 @@ static bool vmx_check_apicv_inhibit_reasons(enum kvm_apicv_inhibit reason) > ulong supported = BIT(APICV_INHIBIT_REASON_DISABLE) | > BIT(APICV_INHIBIT_REASON_ABSENT) | > BIT(APICV_INHIBIT_REASON_HYPERV) | > - BIT(APICV_INHIBIT_REASON_BLOCKIRQ); > + BIT(APICV_INHIBIT_REASON_BLOCKIRQ) | > + BIT(APICV_INHIBIT_REASON_APIC_ID_MODIFIED); > > return supported & BIT(reason); > } > > base-commit: 6ab6e3842d18e4529fa524fb6c668ae8a8bf54f4 > -- > Hi Sean! So, I decided to stop beeing lazy and to understand how KVM actually treats the whole thing: - kvm_apic_set_xapic_id - called when apic id changes either by guest write, cpu reset or x2apic beeing disabled due to write to apic base msr. apic register is updated, and apic map is recalculated - kvm_apic_set_x2apic_id - called only when apic base write (guest or userspace), enables x2apic. caller uses vcpu->vcpu_id explicity - kvm_apic_state_fixup - when apic state is uploaded by userspace, has check that check for x2apic api. Also triggers apic map update - kvm_recalculate_apic_map this updates the apic map that we use in IPI emulation. - xapic id (aka APIC_ID >> 24) is only used for APICs which are not in xapic mode. - x2apic ids (aka vcpu->vcpu_id) are used for all APICs which are in x2apic mode, and also (as a hack, when an apic has vcpu_id > 255, even if not in x2apic mode, its x2apic id is still put in the map) Conclusions: - Practically speaking, when an apic is in x2apic mode, even if userspace uploaded non standard APIC_ID, it is ignored, and just read back (garbage in - garbage out) - Non standard APIC ID is lost when switching to x2apic mode. Best regards, Maxim Levitsky PS: sending this so this info is not lost. Thankfully my APICv inhibit patch got accepted upstream, so one issue less to deal with.