From nobody Sat Oct 4 16:15:04 2025 Received: from mail-pf1-f202.google.com (mail-pf1-f202.google.com [209.85.210.202]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 78B481DA21 for ; Fri, 15 Aug 2025 00:12:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755216738; cv=none; b=KwIRDcHBXA9ZN752mB1wTpg4R0+rQHX8AjRJmkP6Ygb63Nh4ppxwUfo7dku52BSc8zrhTJ61RyUtk5yEV+HJ7ZRj5/3R4kp/SxD/hnsmS21xWr1FoQ7zgq7djURbIuDTTE/T2oj1YbgtEbjtRJmwP6B0LRGQaIyZ2DV3wo++Uck= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1755216738; c=relaxed/simple; bh=/BkaJeh+u+w0PxculFeU+YAag3AmTz4Ma5Y3HwSoFSs=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=CWeW0pglCiRYdhwbVg5pG23ZOxFq9hH3LATYS2tJrGDB1xZautndTqpy5koyxGK8Czq9we5awTCWxPUAkQLgyQAF1bjV6ovqjLzeIGHOnasnZhWe8uAuS1ZbzTwrb0tiOdmKVRu7Q8OJq0I7iwin5nWlw296QAuPNzWPTNoVcA4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--seanjc.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=fjxpROve; arc=none smtp.client-ip=209.85.210.202 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--seanjc.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="fjxpROve" Received: by mail-pf1-f202.google.com with SMTP id d2e1a72fcca58-76e2ead3b51so2439206b3a.2 for ; Thu, 14 Aug 2025 17:12:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1755216736; x=1755821536; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:reply-to:from:to:cc:subject:date:message-id:reply-to; bh=14QM1z+dm5GkgFjlzKHbTF7lRU9gP89BnvFIFOimBio=; b=fjxpROveZrLbbe9N4INHzKkHMIVPiymU4b25zskqhOQ2r17Bqa5kno+lqqVbFrCgQV XfhEOZhuXieVIcCHJCtUw7Jv3UA+8bfVxfJPtMd0P/6KtU/wyvOqZ3dxRFK++J4Nq3LD c++H/cVEOVaF1yox2vc0tDFGGSIv5kE7nl/ImF/uWjy7kZ9UOpYgnwEUfdWKq79EZhXP VHb2bxk9oHdKXwdupzv/2X/dJDVCaxk50qxJWfIkaeyYO5BqeltBlMfSFs+gb89tPgsh NyeDSiN2gUP1N26lIgRCChMzRpYtsEMMiXVM4aqFv556A56CSq2dEI5vLHvzzbHAKEfE exFA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1755216736; x=1755821536; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:reply-to:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=14QM1z+dm5GkgFjlzKHbTF7lRU9gP89BnvFIFOimBio=; b=c9grhCnEsWjkY91M1Qc8sBaJO5fD6azPKASmnWHXd7bt60nULSisPTlWy7JKeFFY3B 4KcHsFiJTYxVVY+qGmkNshNV7z1qpfy0zGl0Do7QSuVmXz/xfmP40idqWIElGhgSaQN5 rBfNGOGjv3+hy3WVsXbw9pCmJj2eQ/fdb3IyORlPusKuF4Nw2RXWFZxb+SnUKNQxhbeJ zJIhS9WLp28Yxak33LY6x2b6gOtZVOqIn0Hh/EUDJvVUXzDF9n1InwwrWnoM2NjKwBsG zBz1VtQnFXZ4sodx0WueQdciwg2kMqt1IIXA0O11o5qEZMnynH50FBNYOOGJRQiI/kb+ v07w== X-Forwarded-Encrypted: i=1; AJvYcCXOXWJTpP4fYy9sapC/1SRyG/qLkyhtHdii2YuV/VYTwbPMG/cq8kYQt+88fo42mUozT8it1ID9G9mZT+E=@vger.kernel.org X-Gm-Message-State: AOJu0YzO0XjHyIqhUX3IxKFxmTXTXvYnuhQob10S2u18nO8z1VaRQFda RIvfUrMxWD9fNAfu4oBBnTmQfUOlXwZi8Z6fu1uN2tryaCgEeqG0sXKQeJMABQ5rcSwPl2tLaYz hYl+UYQ== X-Google-Smtp-Source: AGHT+IFeo9E+l/DagxMz1Ec9Bybnt5sRn/yXPRsbfvMN+GXHL3ok4MUTGXxfotByzxbvgqgO+WCoCPEZr8U= X-Received: from pfmy19.prod.google.com ([2002:aa7:8053:0:b0:76b:cac2:6d23]) (user=seanjc job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6a21:32a8:b0:232:6630:bca4 with SMTP id adf61e73a8af0-240d2e5bad4mr311881637.15.1755216735769; Thu, 14 Aug 2025 17:12:15 -0700 (PDT) Reply-To: Sean Christopherson Date: Thu, 14 Aug 2025 17:11:46 -0700 In-Reply-To: <20250815001205.2370711-1-seanjc@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250815001205.2370711-1-seanjc@google.com> X-Mailer: git-send-email 2.51.0.rc1.163.g2494970778-goog Message-ID: <20250815001205.2370711-3-seanjc@google.com> Subject: [PATCH 6.1.y 02/21] KVM: x86: Re-split x2APIC ICR into ICR+ICR2 for AMD (x2AVIC) From: Sean Christopherson To: stable@vger.kernel.org, Greg Kroah-Hartman , Sasha Levin Cc: kvm@vger.kernel.org, linux-kernel@vger.kernel.org, Paolo Bonzini Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" [ Upstream commit 73b42dc69be8564d4951a14d00f827929fe5ef79 ] Re-introduce the "split" x2APIC ICR storage that KVM used prior to Intel's IPI virtualization support, but only for AMD. While not stated anywhere in the APM, despite stating the ICR is a single 64-bit register, AMD CPUs store the 64-bit ICR as two separate 32-bit values in ICR and ICR2. When IPI virtualization (IPIv on Intel, all AVIC flavors on AMD) is enabled, KVM needs to match CPU behavior as some ICR ICR writes will be handled by the CPU, not by KVM. Add a kvm_x86_ops knob to control the underlying format used by the CPU to store the x2APIC ICR, and tune it to AMD vs. Intel regardless of whether or not x2AVIC is enabled. If KVM is handling all ICR writes, the storage format for x2APIC mode doesn't matter, and having the behavior follow AMD versus Intel will provide better test coverage and ease debugging. Fixes: 4d1d7942e36a ("KVM: SVM: Introduce logic to (de)activate x2AVIC mode= ") Cc: stable@vger.kernel.org Cc: Maxim Levitsky Cc: Suravee Suthikulpanit Link: https://lore.kernel.org/r/20240719235107.3023592-4-seanjc@google.com Signed-off-by: Sean Christopherson [sean: resolve minor syntatic conflicts] Signed-off-by: Sean Christopherson --- arch/x86/include/asm/kvm_host.h | 2 ++ arch/x86/kvm/lapic.c | 42 +++++++++++++++++++++++---------- arch/x86/kvm/svm/svm.c | 2 ++ arch/x86/kvm/vmx/vmx.c | 2 ++ 4 files changed, 36 insertions(+), 12 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_hos= t.h index eb06c2f68314..17b4e61a52b9 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1547,6 +1547,8 @@ struct kvm_x86_ops { void (*enable_nmi_window)(struct kvm_vcpu *vcpu); void (*enable_irq_window)(struct kvm_vcpu *vcpu); void (*update_cr8_intercept)(struct kvm_vcpu *vcpu, int tpr, int irr); + + const bool x2apic_icr_is_split; bool (*check_apicv_inhibit_reasons)(enum kvm_apicv_inhibit reason); void (*refresh_apicv_exec_ctrl)(struct kvm_vcpu *vcpu); void (*hwapic_irr_update)(struct kvm_vcpu *vcpu, int max_irr); diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 7f57dce5c828..42eec987ac3d 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -2315,11 +2315,25 @@ int kvm_x2apic_icr_write(struct kvm_lapic *apic, u6= 4 data) data &=3D ~APIC_ICR_BUSY; =20 kvm_apic_send_ipi(apic, (u32)data, (u32)(data >> 32)); - kvm_lapic_set_reg64(apic, APIC_ICR, data); + if (kvm_x86_ops.x2apic_icr_is_split) { + kvm_lapic_set_reg(apic, APIC_ICR, data); + kvm_lapic_set_reg(apic, APIC_ICR2, data >> 32); + } else { + kvm_lapic_set_reg64(apic, APIC_ICR, data); + } trace_kvm_apic_write(APIC_ICR, data); return 0; } =20 +static u64 kvm_x2apic_icr_read(struct kvm_lapic *apic) +{ + if (kvm_x86_ops.x2apic_icr_is_split) + return (u64)kvm_lapic_get_reg(apic, APIC_ICR) | + (u64)kvm_lapic_get_reg(apic, APIC_ICR2) << 32; + + return kvm_lapic_get_reg64(apic, APIC_ICR); +} + /* emulate APIC access in a trap manner */ void kvm_apic_write_nodecode(struct kvm_vcpu *vcpu, u32 offset) { @@ -2337,7 +2351,7 @@ void kvm_apic_write_nodecode(struct kvm_vcpu *vcpu, u= 32 offset) * maybe-unecessary write, and both are in the noise anyways. */ if (apic_x2apic_mode(apic) && offset =3D=3D APIC_ICR) - WARN_ON_ONCE(kvm_x2apic_icr_write(apic, kvm_lapic_get_reg64(apic, APIC_I= CR))); + WARN_ON_ONCE(kvm_x2apic_icr_write(apic, kvm_x2apic_icr_read(apic))); else kvm_lapic_reg_write(apic, offset, kvm_lapic_get_reg(apic, offset)); } @@ -2760,18 +2774,22 @@ static int kvm_apic_state_fixup(struct kvm_vcpu *vc= pu, =20 /* * In x2APIC mode, the LDR is fixed and based on the id. And - * ICR is internally a single 64-bit register, but needs to be - * split to ICR+ICR2 in userspace for backwards compatibility. + * if the ICR is _not_ split, ICR is internally a single 64-bit + * register, but needs to be split to ICR+ICR2 in userspace for + * backwards compatibility. */ - if (set) { + if (set) *ldr =3D kvm_apic_calc_x2apic_ldr(*id); =20 - icr =3D __kvm_lapic_get_reg(s->regs, APIC_ICR) | - (u64)__kvm_lapic_get_reg(s->regs, APIC_ICR2) << 32; - __kvm_lapic_set_reg64(s->regs, APIC_ICR, icr); - } else { - icr =3D __kvm_lapic_get_reg64(s->regs, APIC_ICR); - __kvm_lapic_set_reg(s->regs, APIC_ICR2, icr >> 32); + if (!kvm_x86_ops.x2apic_icr_is_split) { + if (set) { + icr =3D __kvm_lapic_get_reg(s->regs, APIC_ICR) | + (u64)__kvm_lapic_get_reg(s->regs, APIC_ICR2) << 32; + __kvm_lapic_set_reg64(s->regs, APIC_ICR, icr); + } else { + icr =3D __kvm_lapic_get_reg64(s->regs, APIC_ICR); + __kvm_lapic_set_reg(s->regs, APIC_ICR2, icr >> 32); + } } } =20 @@ -2971,7 +2989,7 @@ static int kvm_lapic_msr_read(struct kvm_lapic *apic,= u32 reg, u64 *data) u32 low; =20 if (reg =3D=3D APIC_ICR) { - *data =3D kvm_lapic_get_reg64(apic, APIC_ICR); + *data =3D kvm_x2apic_icr_read(apic); return 0; } =20 diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c index c95a84afc35f..b922f31d1415 100644 --- a/arch/x86/kvm/svm/svm.c +++ b/arch/x86/kvm/svm/svm.c @@ -4851,6 +4851,8 @@ static struct kvm_x86_ops svm_x86_ops __initdata =3D { .enable_nmi_window =3D svm_enable_nmi_window, .enable_irq_window =3D svm_enable_irq_window, .update_cr8_intercept =3D svm_update_cr8_intercept, + + .x2apic_icr_is_split =3D true, .set_virtual_apic_mode =3D avic_refresh_virtual_apic_mode, .refresh_apicv_exec_ctrl =3D avic_refresh_apicv_exec_ctrl, .check_apicv_inhibit_reasons =3D avic_check_apicv_inhibit_reasons, diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c index fbe26b88f731..9a5cb896229f 100644 --- a/arch/x86/kvm/vmx/vmx.c +++ b/arch/x86/kvm/vmx/vmx.c @@ -8202,6 +8202,8 @@ static struct kvm_x86_ops vmx_x86_ops __initdata =3D { .enable_nmi_window =3D vmx_enable_nmi_window, .enable_irq_window =3D vmx_enable_irq_window, .update_cr8_intercept =3D vmx_update_cr8_intercept, + + .x2apic_icr_is_split =3D false, .set_virtual_apic_mode =3D vmx_set_virtual_apic_mode, .set_apic_access_page_addr =3D vmx_set_apic_access_page_addr, .refresh_apicv_exec_ctrl =3D vmx_refresh_apicv_exec_ctrl, --=20 2.51.0.rc1.163.g2494970778-goog