From: Sean Christopherson <seanjc@google.com>
To: stable@vger.kernel.org,
Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
Sasha Levin <sashal@kernel.org>
Cc: kvm@vger.kernel.org, linux-kernel@vger.kernel.org,
Paolo Bonzini <pbonzini@redhat.com>
Subject: [PATCH 6.1.y 02/21] KVM: x86: Re-split x2APIC ICR into ICR+ICR2 for AMD (x2AVIC)
Date: Thu, 14 Aug 2025 17:11:46 -0700 [thread overview]
Message-ID: <20250815001205.2370711-3-seanjc@google.com> (raw)
In-Reply-To: <20250815001205.2370711-1-seanjc@google.com>
[ 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 <mlevitsk@redhat.com>
Cc: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
Link: https://lore.kernel.org/r/20240719235107.3023592-4-seanjc@google.com
Signed-off-by: Sean Christopherson <seanjc@google.com>
[sean: resolve minor syntatic conflicts]
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
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_host.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, u64 data)
data &= ~APIC_ICR_BUSY;
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;
}
+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, u32 offset)
* maybe-unecessary write, and both are in the noise anyways.
*/
if (apic_x2apic_mode(apic) && offset == APIC_ICR)
- WARN_ON_ONCE(kvm_x2apic_icr_write(apic, kvm_lapic_get_reg64(apic, APIC_ICR)));
+ 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 *vcpu,
/*
* 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 = kvm_apic_calc_x2apic_ldr(*id);
- icr = __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 = __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 = __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 = __kvm_lapic_get_reg64(s->regs, APIC_ICR);
+ __kvm_lapic_set_reg(s->regs, APIC_ICR2, icr >> 32);
+ }
}
}
@@ -2971,7 +2989,7 @@ static int kvm_lapic_msr_read(struct kvm_lapic *apic, u32 reg, u64 *data)
u32 low;
if (reg == APIC_ICR) {
- *data = kvm_lapic_get_reg64(apic, APIC_ICR);
+ *data = kvm_x2apic_icr_read(apic);
return 0;
}
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 = {
.enable_nmi_window = svm_enable_nmi_window,
.enable_irq_window = svm_enable_irq_window,
.update_cr8_intercept = svm_update_cr8_intercept,
+
+ .x2apic_icr_is_split = true,
.set_virtual_apic_mode = avic_refresh_virtual_apic_mode,
.refresh_apicv_exec_ctrl = avic_refresh_apicv_exec_ctrl,
.check_apicv_inhibit_reasons = 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 = {
.enable_nmi_window = vmx_enable_nmi_window,
.enable_irq_window = vmx_enable_irq_window,
.update_cr8_intercept = vmx_update_cr8_intercept,
+
+ .x2apic_icr_is_split = false,
.set_virtual_apic_mode = vmx_set_virtual_apic_mode,
.set_apic_access_page_addr = vmx_set_apic_access_page_addr,
.refresh_apicv_exec_ctrl = vmx_refresh_apicv_exec_ctrl,
--
2.51.0.rc1.163.g2494970778-goog
next prev parent reply other threads:[~2025-08-15 0:12 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-08-15 0:11 [PATCH 6.1.y 00/21] KVM: x86: Backports for 6.1.y Sean Christopherson
2025-08-15 0:11 ` [PATCH 6.1.y 01/21] KVM: SVM: Set RFLAGS.IF=1 in C code, to get VMRUN out of the STI shadow Sean Christopherson
2025-08-15 0:11 ` Sean Christopherson [this message]
2025-08-15 0:11 ` [PATCH 6.1.y 03/21] KVM: x86: Plumb in the vCPU to kvm_x86_ops.hwapic_isr_update() Sean Christopherson
2025-08-15 0:11 ` [PATCH 6.1.y 04/21] KVM: nVMX: Defer SVI update to vmcs01 on EOI when L2 is active w/o VID Sean Christopherson
2025-08-15 0:11 ` [PATCH 6.1.y 05/21] KVM: x86: Take irqfds.lock when adding/deleting IRQ bypass producer Sean Christopherson
2025-08-15 0:11 ` [PATCH 6.1.y 06/21] KVM: x86: Snapshot the host's DEBUGCTL in common x86 Sean Christopherson
2025-08-15 0:11 ` [PATCH 6.1.y 07/21] KVM: x86: Snapshot the host's DEBUGCTL after disabling IRQs Sean Christopherson
2025-08-15 0:11 ` [PATCH 6.1.y 08/21] KVM: x86/pmu: Gate all "unimplemented MSR" prints on report_ignored_msrs Sean Christopherson
2025-08-15 0:11 ` [PATCH 6.1.y 09/21] KVM: x86: Plumb "force_immediate_exit" into kvm_entry() tracepoint Sean Christopherson
2025-08-15 0:11 ` [PATCH 6.1.y 10/21] KVM: VMX: Re-enter guest in fastpath for "spurious" preemption timer exits Sean Christopherson
2025-08-15 0:11 ` [PATCH 6.1.y 11/21] KVM: VMX: Handle forced exit due to preemption timer in fastpath Sean Christopherson
2025-08-15 0:11 ` [PATCH 6.1.y 12/21] KVM: x86: Move handling of is_guest_mode() into fastpath exit handlers Sean Christopherson
2025-08-15 0:11 ` [PATCH 6.1.y 13/21] KVM: VMX: Handle KVM-induced preemption timer exits in fastpath for L2 Sean Christopherson
2025-08-15 0:11 ` [PATCH 6.1.y 14/21] KVM: x86: Fully defer to vendor code to decide how to force immediate exit Sean Christopherson
2025-08-15 0:11 ` [PATCH 6.1.y 15/21] KVM: x86: Convert vcpu_run()'s immediate exit param into a generic bitmap Sean Christopherson
2025-08-15 0:12 ` [PATCH 6.1.y 16/21] KVM: x86: Drop kvm_x86_ops.set_dr6() in favor of a new KVM_RUN flag Sean Christopherson
2025-08-15 0:12 ` [PATCH 6.1.y 17/21] KVM: VMX: Allow guest to set DEBUGCTL.RTM_DEBUG if RTM is supported Sean Christopherson
2025-08-15 0:12 ` [PATCH 6.1.y 18/21] KVM: VMX: Extract checking of guest's DEBUGCTL into helper Sean Christopherson
2025-08-15 0:12 ` [PATCH 6.1.y 19/21] KVM: nVMX: Check vmcs12->guest_ia32_debugctl on nested VM-Enter Sean Christopherson
2025-08-15 0:12 ` [PATCH 6.1.y 20/21] KVM: VMX: Wrap all accesses to IA32_DEBUGCTL with getter/setter APIs Sean Christopherson
2025-08-15 0:12 ` [PATCH 6.1.y 21/21] KVM: VMX: Preserve host's DEBUGCTLMSR_FREEZE_IN_SMM while running the guest Sean Christopherson
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250815001205.2370711-3-seanjc@google.com \
--to=seanjc@google.com \
--cc=gregkh@linuxfoundation.org \
--cc=kvm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=pbonzini@redhat.com \
--cc=sashal@kernel.org \
--cc=stable@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).