From 1f3e69af5f938ff331bf5d6bf379a877e4b69315 Mon Sep 17 00:00:00 2001 From: Rick Edgecombe Date: Fri, 10 Apr 2026 16:26:54 -0700 Subject: [PATCH 1/2] KVM: TDX: Fix x2APIC MSR handling in tdx_has_emulated_msr() Rework tdx_has_emulated_msr() to explicitly enumerate the x2APIC MSRs that KVM can emulate, instead of trying to enumerate the MSRs that KVM cannot emulate. Drop the inner switch and list the emulatable x2APIC registers directly in the outer switch's "return true" block. The old code had multiple bugs in the x2APIC range handling. X2APIC_MSR(APIC_ISR + APIC_ISR_NR) was incorrect because APIC_ISR_NR is 0x8, not 0x80, so the X2APIC_MSR() shift lost the lower bits, collapsing each range to a single MSR. IA32_X2APIC_SELF_IPI was also missing from the non-emulatable list. Note, these bugs are relatively benign, as they only affect a guest that is requesting "bogus" emulation. KVM has no visibility into whether or not a guest has enabled #VE reduction, which changes which MSRs the TDX-Module handles itself versus triggering a #VE for the guest to make a TDVMCALL. So maintaining a list of non-emulatable MSRs is fragile. Listing only the MSRs KVM can always emulate sidesteps the problem. Suggested-by: Sean Christopherson Reported-by: Dmytro Maluka Closes: https://lore.kernel.org/all/20260318190111.1041924-1-dmaluka@chromium.org Fixes: dd50294f3e3c ("KVM: TDX: Implement callbacks for MSR operations") Assisted-by: Claude:claude-opus-4-6 [based on a diff from Sean, but added missed LVTCMCI case, log] Signed-off-by: Rick Edgecombe Reviewed-by: Binbin Wu Link: https://patch.msgid.link/20260410232654.3864196-1-rick.p.edgecombe@intel.com [sean: call out the bugs are relatively benign, expand comment] Signed-off-by: Sean Christopherson --- arch/x86/kvm/vmx/tdx.c | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c index b8c3d3d8bbfe..e58a64400186 100644 --- a/arch/x86/kvm/vmx/tdx.c +++ b/arch/x86/kvm/vmx/tdx.c @@ -2116,23 +2116,29 @@ bool tdx_has_emulated_msr(u32 index) case MSR_IA32_MC0_CTL2 ... MSR_IA32_MCx_CTL2(KVM_MAX_MCE_BANKS) - 1: /* MSR_IA32_MCx_{CTL, STATUS, ADDR, MISC, CTL2} */ case MSR_KVM_POLL_CONTROL: + /* + * Except for x2APIC registers that are virtualized by the CPU, which + * KVM can't emulate as KVM doesn't have access to the virtual APIC + * page, KVM emulates the same set of x2APIC registers for TDX versus + * non-TDX guests. + */ + case X2APIC_MSR(APIC_ID): + case X2APIC_MSR(APIC_LVR): + case X2APIC_MSR(APIC_LDR): + case X2APIC_MSR(APIC_SPIV): + case X2APIC_MSR(APIC_ESR): + case X2APIC_MSR(APIC_LVTCMCI): + case X2APIC_MSR(APIC_ICR): + case X2APIC_MSR(APIC_LVTT): + case X2APIC_MSR(APIC_LVTTHMR): + case X2APIC_MSR(APIC_LVTPC): + case X2APIC_MSR(APIC_LVT0): + case X2APIC_MSR(APIC_LVT1): + case X2APIC_MSR(APIC_LVTERR): + case X2APIC_MSR(APIC_TMICT): + case X2APIC_MSR(APIC_TMCCT): + case X2APIC_MSR(APIC_TDCR): return true; - case APIC_BASE_MSR ... APIC_BASE_MSR + 0xff: - /* - * x2APIC registers that are virtualized by the CPU can't be - * emulated, KVM doesn't have access to the virtual APIC page. - */ - switch (index) { - case X2APIC_MSR(APIC_TASKPRI): - case X2APIC_MSR(APIC_PROCPRI): - case X2APIC_MSR(APIC_EOI): - case X2APIC_MSR(APIC_ISR) ... X2APIC_MSR(APIC_ISR + APIC_ISR_NR): - case X2APIC_MSR(APIC_TMR) ... X2APIC_MSR(APIC_TMR + APIC_ISR_NR): - case X2APIC_MSR(APIC_IRR) ... X2APIC_MSR(APIC_IRR + APIC_ISR_NR): - return false; - default: - return true; - } default: return false; } From ca674df13b195eb6d124ab059799d4e03fa40624 Mon Sep 17 00:00:00 2001 From: Xuanqing Shi <1356292400@qq.com> Date: Tue, 26 May 2026 19:26:17 -0700 Subject: [PATCH 2/2] KVM: VMX: Handle bad values on proxied writes to LBR MSRs Use the "safe" WRMSR API when writing LBRs on behalf of the guest (or host userspace), and propagate any errors back to the instigator, as the value being written is untrusted. E.g. if the guest (or host userspace) attempts to set reserved bits in LBR_SELECT, then KVM needs to return an error, and not WARN on the bad value. Continue using the "unsafe" version of RDMSR, as it should be impossible to reach the helper with a completely bogus MSR, i.e. WARNing on RDMSR failure is very desirable, e.g. to make KVM bugs more visible. unchecked MSR access error: WRMSR to 0x1c8 (tried to write 0x0000000000004000) Call Trace: intel_pmu_set_msr+0x4e0/0x7f0 [kvm_intel] kvm_pmu_set_msr+0x17e/0x1c0 [kvm] kvm_set_msr_common+0xc76/0x1440 [kvm] vmx_set_msr+0x5e6/0x1570 [kvm_intel] kvm_emulate_wrmsr+0x54/0x1d0 [kvm] vmx_handle_exit+0x7fc/0x970 [kvm_intel] Fixes: 1b5ac3226a1a ("KVM: vmx/pmu: Pass-through LBR msrs when the guest LBR event is ACTIVE") Cc: stable@vger.kernel.org Signed-off-by: Xuanqing Shi <1356292400@qq.com> [sean: rework changelog, only modify WRMSR path, tag for stable@] Link: https://patch.msgid.link/20260527022617.3973884-1-seanjc@google.com Signed-off-by: Sean Christopherson --- arch/x86/kvm/vmx/pmu_intel.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/vmx/pmu_intel.c b/arch/x86/kvm/vmx/pmu_intel.c index 27eb76e6b6a0..22138c487216 100644 --- a/arch/x86/kvm/vmx/pmu_intel.c +++ b/arch/x86/kvm/vmx/pmu_intel.c @@ -308,13 +308,15 @@ static bool intel_pmu_handle_lbr_msrs_access(struct kvm_vcpu *vcpu, */ local_irq_disable(); if (lbr_desc->event->state == PERF_EVENT_STATE_ACTIVE) { + int err = 0; + if (read) rdmsrq(index, msr_info->data); else - wrmsrq(index, msr_info->data); + err = wrmsrq_safe(index, msr_info->data); __set_bit(INTEL_PMC_IDX_FIXED_VLBR, vcpu_to_pmu(vcpu)->pmc_in_use); local_irq_enable(); - return true; + return !err; } clear_bit(INTEL_PMC_IDX_FIXED_VLBR, vcpu_to_pmu(vcpu)->pmc_in_use); local_irq_enable();