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 index 01a84bea2d..33fbe13a3e 160000 --- a/roms/seabios +++ b/roms/seabios @@ -1 +1 @@ -Subproject commit 01a84bea2d28a19d2405c1ecac4bdef17683cc0c +Subproject commit 33fbe13a3e2a01e0ba1087a8feed801a0451db21 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 } };