aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hw/i386/pc.c1
-rw-r--r--hw/i386/pc_piix.c2
-rw-r--r--hw/i386/pc_q35.c2
-rw-r--r--include/hw/i386/pc.h3
m---------roms/seabios0
-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
9 files changed, 49 insertions, 1 deletions
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 9e37186776..293e22a7e1 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -1963,6 +1963,7 @@ static void pc_machine_class_init(ObjectClass *oc, void *data)
/* BIOS ACPI tables: 128K. Other BIOS datastructures: less than 4K reported
* to be used at the moment, 32K should be enough for a while. */
pcmc->acpi_data_size = 0x20000 + 0x8000;
+ pcmc->save_tsc_khz = true;
mc->get_hotplug_handler = pc_get_hotpug_handler;
mc->cpu_index_to_socket_id = pc_cpu_index_to_socket_id;
mc->default_boot_order = "cad";
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index df2b824385..97219129ac 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -432,9 +432,11 @@ DEFINE_I440FX_MACHINE(v2_6, "pc-i440fx-2.6", NULL,
static void pc_i440fx_2_5_machine_options(MachineClass *m)
{
+ PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
pc_i440fx_2_6_machine_options(m);
m->alias = NULL;
m->is_default = 0;
+ pcmc->save_tsc_khz = false;
SET_MACHINE_COMPAT(m, PC_COMPAT_2_5);
}
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index 412b3cd375..8b76d5c94b 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -360,8 +360,10 @@ DEFINE_Q35_MACHINE(v2_6, "pc-q35-2.6", NULL,
static void pc_q35_2_5_machine_options(MachineClass *m)
{
+ PCMachineClass *pcmc = PC_MACHINE_CLASS(m);
pc_q35_2_6_machine_options(m);
m->alias = NULL;
+ pcmc->save_tsc_khz = false;
SET_MACHINE_COMPAT(m, PC_COMPAT_2_5);
}
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index 588a33cfa3..5bac03d975 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -120,6 +120,9 @@ struct PCMachineClass {
bool has_reserved_memory;
bool enforce_aligned_dimm;
bool broken_reserved_end;
+
+ /* TSC rate migration: */
+ bool save_tsc_khz;
};
#define TYPE_PC_MACHINE "generic-pc-machine"
diff --git a/roms/seabios b/roms/seabios
-Subproject 01a84bea2d28a19d2405c1ecac4bdef17683cc0
+Subproject 33fbe13a3e2a01e0ba1087a8feed801a0451db2
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
}
};