aboutsummaryrefslogtreecommitdiff
path: root/target-i386
diff options
context:
space:
mode:
Diffstat (limited to 'target-i386')
-rw-r--r--target-i386/cpu.c2
-rw-r--r--target-i386/cpu.h1
-rw-r--r--target-i386/kvm.c9
-rw-r--r--target-i386/machine.c30
4 files changed, 41 insertions, 1 deletions
diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index 69880b79fa..d3f8a4e4ea 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -1728,7 +1728,7 @@ static void x86_cpuid_set_tsc_freq(Object *obj, Visitor *v, void *opaque,
return;
}
- cpu->env.tsc_khz = value / 1000;
+ cpu->env.tsc_khz = cpu->env.user_tsc_khz = value / 1000;
}
static void x86_cpuid_get_apic_id(Object *obj, Visitor *v, void *opaque,
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index 77e62b2506..28cbaf5030 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -978,6 +978,7 @@ typedef struct CPUX86State {
uint32_t sipi_vector;
bool tsc_valid;
int64_t tsc_khz;
+ int64_t user_tsc_khz; /* for sanity check only */
void *kvm_xsave_buf;
uint64_t mcg_cap;
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index 23d6b869a3..419bb18bb3 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -2507,6 +2507,15 @@ int kvm_arch_put_registers(CPUState *cpu, int level)
}
}
+ if (level == KVM_PUT_FULL_STATE) {
+ /* We don't check for kvm_arch_set_tsc_khz() errors here,
+ * because TSC frequency mismatch shouldn't abort migration,
+ * unless the user explicitly asked for a more strict TSC
+ * setting (e.g. using an explicit "tsc-freq" option).
+ */
+ kvm_arch_set_tsc_khz(cpu);
+ }
+
ret = kvm_getput_regs(x86_cpu, 1);
if (ret < 0) {
return ret;
diff --git a/target-i386/machine.c b/target-i386/machine.c
index 4d802882f5..0d381ac0c0 100644
--- a/target-i386/machine.c
+++ b/target-i386/machine.c
@@ -6,6 +6,8 @@
#include "cpu.h"
#include "sysemu/kvm.h"
+#include "qemu/error-report.h"
+
static const VMStateDescription vmstate_segment = {
.name = "segment",
.version_id = 1,
@@ -331,6 +333,13 @@ static int cpu_post_load(void *opaque, int version_id)
CPUX86State *env = &cpu->env;
int i;
+ if (env->tsc_khz && env->user_tsc_khz &&
+ env->tsc_khz != env->user_tsc_khz) {
+ error_report("Mismatch between user-specified TSC frequency and "
+ "migrated TSC frequency");
+ return -EINVAL;
+ }
+
/*
* Real mode guest segments register DPL should be zero.
* Older KVM version were setting it wrongly.
@@ -839,6 +848,26 @@ static const VMStateDescription vmstate_xss = {
}
};
+static bool tsc_khz_needed(void *opaque)
+{
+ X86CPU *cpu = opaque;
+ CPUX86State *env = &cpu->env;
+ MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine());
+ PCMachineClass *pcmc = PC_MACHINE_CLASS(mc);
+ return env->tsc_khz && pcmc->save_tsc_khz;
+}
+
+static const VMStateDescription vmstate_tsc_khz = {
+ .name = "cpu/tsc_khz",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = tsc_khz_needed,
+ .fields = (VMStateField[]) {
+ VMSTATE_INT64(env.tsc_khz, X86CPU),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
VMStateDescription vmstate_x86_cpu = {
.name = "cpu",
.version_id = 12,
@@ -961,6 +990,7 @@ VMStateDescription vmstate_x86_cpu = {
&vmstate_msr_hyperv_stimer,
&vmstate_avx512,
&vmstate_xss,
+ &vmstate_tsc_khz,
NULL
}
};