From: Sean Christopherson <seanjc@google.com>
To: Jim Mattson <jmattson@google.com>
Cc: pbonzini@redhat.com, chao.gao@intel.com, kvm@vger.kernel.org
Subject: Re: [PATCH v5 2/2] KVM: VMX: Cap VMX preemption timer to work around Intel erratum
Date: Tue, 28 Jul 2026 08:03:31 -0700 [thread overview]
Message-ID: <amjEw9QcQN7owHKF@google.com> (raw)
In-Reply-To: <20260724234914.987987-3-jmattson@google.com>
On Fri, Jul 24, 2026, Jim Mattson wrote:
Sorry for the late review, I didn't actually look at the code in the previous
versions.
> diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
> index a07faa066ef0..ebe83a641473 100644
> --- a/arch/x86/kvm/vmx/vmx.c
> +++ b/arch/x86/kvm/vmx/vmx.c
> @@ -153,6 +153,7 @@ module_param(dump_invalid_vmcs, bool, 0644);
> #ifdef CONFIG_X86_64
> static int __read_mostly cpu_preemption_timer_multi;
> static bool __read_mostly enable_preemption_timer = 1;
> +static u64 __ro_after_init preemption_timer_limit;
> module_param_named(preemption_timer, enable_preemption_timer, bool, S_IRUGO);
> #else
> #define enable_preemption_timer false
> @@ -8306,6 +8307,26 @@ static inline int u64_shl_div_u64(u64 a, unsigned int shift,
> return 0;
> }
>
> +/*
> + * Workaround for a widespread Intel erratum (e.g. EMR158) where the
> + * VMX-preemption timer may expire earlier than expected when programmed
> + * with large values. The workaround is to cap the timer value to strictly
> + * less than 2^25 * CPUID.15H:EBX / CPUID.15H:EAX.
> + */
> +static __init u64 calc_preemption_timer_limit(void)
> +{
> + u32 eax, ebx, ecx, edx;
> +
> + if (cpuid_eax(0) < 0x15)
> + return 1ULL << 32;
Tracking an exclusive limit is cumbersome because all of KVM's usage deals with
the max value, i.e. it forces all usage to effectively do "- 1". I also think
we should go with "max_value" instead of "limit" so that there's less chance for
confusion around whether the limit is exclusive or inclusive.
And we should provide a local "const u64" for maximum architectural value. The
other option would be to initialize the global to the max architectural value,
and then do early returns here, but I like explicitly setting the global before
checking it against use_timer_freq.
> +
> + cpuid(0x15, &eax, &ebx, &ecx, &edx);
> + if (!eax || !ebx)
> + return 1ULL << 32;
> +
> + return min_t(u64, 1ULL << 32, ((u64)ebx << 25) / eax);
While I appreciate Sashiko's paranoia about "((u64)ebx << 25) / eax)" yielding
zero, I think we should treat that as a WARNable offence. And to avoid a false
positive due to running as a VM of a misconfigured hypervisor, I think we should
only apply the erratum workaround on bare metal, i.e. use the maximum value if
KVM detects X86_FEATURE_HYPERVISOR.
So this as fixup? If this looks good to you, I'm happy to post v6 since I've
already got it locally and tested on CLX, ICX, and EMR.
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index ebe83a641473..dae41842a9ce 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -153,7 +153,7 @@ module_param(dump_invalid_vmcs, bool, 0644);
#ifdef CONFIG_X86_64
static int __read_mostly cpu_preemption_timer_multi;
static bool __read_mostly enable_preemption_timer = 1;
-static u64 __ro_after_init preemption_timer_limit;
+static u64 __ro_after_init preemption_timer_max_value;
module_param_named(preemption_timer, enable_preemption_timer, bool, S_IRUGO);
#else
#define enable_preemption_timer false
@@ -8313,18 +8313,25 @@ static inline int u64_shl_div_u64(u64 a, unsigned int shift,
* with large values. The workaround is to cap the timer value to strictly
* less than 2^25 * CPUID.15H:EBX / CPUID.15H:EAX.
*/
-static __init u64 calc_preemption_timer_limit(void)
+static __init u64 calc_preemption_timer_max_value(void)
{
+ const u64 ARCHITECTURAL_MAX_VALUE = UINT_MAX;
u32 eax, ebx, ecx, edx;
+ if (cpu_feature_enabled(X86_FEATURE_HYPERVISOR))
+ return ARCHITECTURAL_MAX_VALUE;
+
if (cpuid_eax(0) < 0x15)
- return 1ULL << 32;
+ return ARCHITECTURAL_MAX_VALUE;
cpuid(0x15, &eax, &ebx, &ecx, &edx);
if (!eax || !ebx)
- return 1ULL << 32;
+ return ARCHITECTURAL_MAX_VALUE;
- return min_t(u64, 1ULL << 32, ((u64)ebx << 25) / eax);
+ if (WARN_ON_ONCE(!(((u64)ebx << 25) / eax)))
+ return ARCHITECTURAL_MAX_VALUE;
+
+ return (((u64)ebx << 25) / eax) - 1;
}
static __init void vmx_setup_preemption_timer(void)
@@ -8338,7 +8345,7 @@ static __init void vmx_setup_preemption_timer(void)
cpu_preemption_timer_multi =
vmx_misc_preemption_timer_rate(vmcs_config.misc);
- preemption_timer_limit = calc_preemption_timer_limit();
+ preemption_timer_max_value = calc_preemption_timer_max_value();
if (tsc_khz)
use_timer_freq = (u64)tsc_khz * 1000;
@@ -8349,8 +8356,7 @@ static __init void vmx_setup_preemption_timer(void)
* value. Don't use the timer if it might cause spurious exits
* at a rate faster than 0.1 Hz (of uninterrupted guest time).
*/
- if (!preemption_timer_limit ||
- use_timer_freq > (preemption_timer_limit - 1) / 10)
+ if (use_timer_freq > preemption_timer_max_value / 10)
enable_preemption_timer = false;
}
@@ -8392,7 +8398,7 @@ int vmx_set_hv_timer(struct kvm_vcpu *vcpu, u64 guest_deadline_tsc,
* It's possible that it fits on later vmentries, but checking
* on every vmentry is costly so we just use an hrtimer.
*/
- if ((delta_tsc >> cpu_preemption_timer_multi) >= preemption_timer_limit)
+ if ((delta_tsc >> cpu_preemption_timer_multi) > preemption_timer_max_value)
return -ERANGE;
vmx->hv_deadline_tsc = tscl + delta_tsc;
@@ -8426,7 +8432,7 @@ static void vmx_update_hv_timer(struct kvm_vcpu *vcpu, bool force_immediate_exit
vmcs_write32(VMX_PREEMPTION_TIMER_VALUE, delta_tsc);
vmx->loaded_vmcs->hv_timer_soft_disabled = false;
} else if (!vmx->loaded_vmcs->hv_timer_soft_disabled) {
- vmcs_write32(VMX_PREEMPTION_TIMER_VALUE, preemption_timer_limit - 1);
+ vmcs_write32(VMX_PREEMPTION_TIMER_VALUE, preemption_timer_max_value);
vmx->loaded_vmcs->hv_timer_soft_disabled = true;
}
}
next prev parent reply other threads:[~2026-07-28 15:03 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-24 23:49 [PATCH v5 0/2] Compute safe bound for VMX preemption timer Jim Mattson
2026-07-24 23:49 ` [PATCH v5 1/2] KVM: VMX: Bury all of the VMX preemption timer code under CONFIG_X86_64=y Jim Mattson
2026-07-28 5:16 ` Chao Gao
2026-07-28 7:13 ` Binbin Wu
2026-07-24 23:49 ` [PATCH v5 2/2] KVM: VMX: Cap VMX preemption timer to work around Intel erratum Jim Mattson
2026-07-28 7:22 ` Binbin Wu
2026-07-28 15:03 ` Sean Christopherson [this message]
2026-07-28 15:28 ` Jim Mattson
2026-07-28 15:40 ` 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=amjEw9QcQN7owHKF@google.com \
--to=seanjc@google.com \
--cc=chao.gao@intel.com \
--cc=jmattson@google.com \
--cc=kvm@vger.kernel.org \
--cc=pbonzini@redhat.com \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.