When the guest and host use different TSC frequencies - specifically when "tsc-frequency" is configured - the guest TSC becomes unsynchronized after additional vCPUs are added. Suppose the host TSC frequency is 2596.102 MHz. Here are steps to reproduce: Create the QEMU instance with a different TSC frequency 2596.100 MHz. -cpu host,tsc-frequency=2596100000 \ -smp 2,maxcpus=8 \ After the guest VM has booted, add two additional vCPUs. (qemu) device_add host-x86_64-cpu,id=core2,socket-id=0,core-id=2,thread-id=0 (qemu) device_add host-x86_64-cpu,id=core3,socket-id=0,core-id=3,thread-id=0 The guest TSC becomes unsynchronized. The vCPUs end up with different TSC offsets. host# cat /sys/kernel/debug/kvm/167789-11/vcpu0/tsc-offset -345550695701016 host# cat /sys/kernel/debug/kvm/167789-11/vcpu1/tsc-offset -345550695701016 host# cat /sys/kernel/debug/kvm/167789-11/vcpu2/tsc-offset -345700146347894 host# cat /sys/kernel/debug/kvm/167789-11/vcpu3/tsc-offset -345700945993728 This issue occurs because KVM synchronizes the guest TSC twice for each newly added vCPU. In other words, kvm_synchronize_tsc() is invoked twice per vCPU by KVM. During the first synchronization, kvm->arch.default_tsc_khz is used. During the second synchronization, the TSC frequency configured by QEMU is used. Because different TSC frequencies are used during these two synchronization steps, the guest TSC becomes unsynchronized in KVM. Linux kernel commit ffbb61d09fc5 ("KVM: x86: Accept KVM_[GS]ET_TSC_KHZ as a VM ioctl.") introduced support in KVM to help mitigate this issue. QEMU should add corresponding support to address the problem on its side. Always issue the VM ioctl KVM_SET_TSC_KHZ before creating any vCPUs, so that the default TSC frequency is set correctly for all subsequently created vCPUs. Signed-off-by: Dongli Zhang --- This is based on the latest QEMU commit, along with the patchset below, which has already been queued by Paolo. https://lore.kernel.org/qemu-devel/20260207134620.638214-1-pbonzini@redhat.com target/i386/kvm/kvm.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c index 9f1a4d4cbb..56bba9460d 100644 --- a/target/i386/kvm/kvm.c +++ b/target/i386/kvm/kvm.c @@ -2065,6 +2065,9 @@ int kvm_arch_pre_create_vcpu(CPUState *cpu, Error **errp) int ret; if (first) { + X86CPU *x86cpu = X86_CPU(cpu); + CPUX86State *env = &x86cpu->env; + first = false; /* @@ -2086,6 +2089,17 @@ int kvm_arch_pre_create_vcpu(CPUState *cpu, Error **errp) return ret; } } + + if (!is_tdx_vm() && env->tsc_khz && + kvm_check_extension(kvm_state, KVM_CAP_VM_TSC_CONTROL)) { + ret = kvm_vm_ioctl(kvm_state, KVM_SET_TSC_KHZ, env->tsc_khz); + if (ret < 0) { + error_setg_errno(errp, -ret, + "Unable to set TSC frequency to %"PRId64" kHz", + env->tsc_khz); + return ret; + } + } } if (is_tdx_vm()) { -- 2.39.3