aboutsummaryrefslogtreecommitdiff
path: root/target/i386/cpu.c
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2022-03-24 09:21:41 +0100
committerPaolo Bonzini <pbonzini@redhat.com>2022-03-24 18:30:46 +0100
commit5286c3662294119dc2dd1e9296757337211451f6 (patch)
tree287d45628f5b747073ff304c301821331e220c55 /target/i386/cpu.c
parentde65b39a517c9977769c612af716dc418ce2ea0b (diff)
downloadqemu-5286c3662294119dc2dd1e9296757337211451f6.zip
qemu-5286c3662294119dc2dd1e9296757337211451f6.tar.gz
qemu-5286c3662294119dc2dd1e9296757337211451f6.tar.bz2
target/i386: properly reset TSC on reset
Some versions of Windows hang on reboot if their TSC value is greater than 2^54. The calibration of the Hyper-V reference time overflows and fails; as a result the processors' clock sources are out of sync. The issue is that the TSC _should_ be reset to 0 on CPU reset and QEMU tries to do that. However, KVM special cases writing 0 to the TSC and thinks that QEMU is trying to hot-plug a CPU, which is correct the first time through but not later. Thwart this valiant effort and reset the TSC to 1 instead, but only if the CPU has been run once. For this to work, env->tsc has to be moved to the part of CPUArchState that is not zeroed at the beginning of x86_cpu_reset. Reported-by: Vadim Rozenfeld <vrozenfe@redhat.com> Supersedes: <20220324082346.72180-1-pbonzini@redhat.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'target/i386/cpu.c')
-rw-r--r--target/i386/cpu.c13
1 files changed, 13 insertions, 0 deletions
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
index ec3b50b..cb6b546 100644
--- a/target/i386/cpu.c
+++ b/target/i386/cpu.c
@@ -5931,6 +5931,19 @@ static void x86_cpu_reset(DeviceState *dev)
env->xstate_bv = 0;
env->pat = 0x0007040600070406ULL;
+
+ if (kvm_enabled()) {
+ /*
+ * KVM handles TSC = 0 specially and thinks we are hot-plugging
+ * a new CPU, use 1 instead to force a reset.
+ */
+ if (env->tsc != 0) {
+ env->tsc = 1;
+ }
+ } else {
+ env->tsc = 0;
+ }
+
env->msr_ia32_misc_enable = MSR_IA32_MISC_ENABLE_DEFAULT;
if (env->features[FEAT_1_ECX] & CPUID_EXT_MONITOR) {
env->msr_ia32_misc_enable |= MSR_IA32_MISC_ENABLE_MWAIT;