From 78653b235acb47220ecbc4278fc1fdbed5ab9549 Mon Sep 17 00:00:00 2001 From: Marcelo Tosatti Date: Wed, 25 Jun 2014 15:57:11 +0200 Subject: [PATCH 26/26] target-i386: block migration and savevm if invariant tsc is exposed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RH-Author: Marcelo Tosatti Message-id: <20140625155755.084745180@amt.cnet> Patchwork-id: 59376 O-Subject: [patch 2/2] target-i386: block migration and savevm if invariant tsc is exposed Bugzilla: 996771 RH-Acked-by: Eduardo Habkost RH-Acked-by: Juan Quintela RH-Acked-by: Andrew Jones v2: drop migration blocker as its not necessary (savevm and migration check for the vmstate register blocker) v3: - drop savevm blocker as its not necessary (migration and savevm check for migration blocker) - match upstream error message (Eduardo) ------ Invariant TSC documentation mentions that "invariant TSC will run at a constant rate in all ACPI P-, C-. and T-states". This is not the case if migration to a host with different TSC frequency is allowed, or if savevm is performed. So block migration/savevm. Signed-off-by: Marcelo Tosatti Reviewed-by: Eduardo Habkost Signed-off-by: Eduardo Habkost Reviewed-by: Juan Quintela [AF: Updated error message] Signed-off-by: Andreas Färber BZ: 996771 upstream commit 68bfd0ad4a1dcc4c328d5db85dc746b49c1ec07e --- qemu-kvm-x86.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ target-i386/kvm.c | 1 + 2 files changed, 46 insertions(+) Signed-off-by: Miroslav Rezanina --- qemu-kvm-x86.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ target-i386/kvm.c | 1 + 2 files changed, 46 insertions(+), 0 deletions(-) diff --git a/qemu-kvm-x86.c b/qemu-kvm-x86.c index 03a75eb..78e58a7 100644 --- a/qemu-kvm-x86.c +++ b/qemu-kvm-x86.c @@ -1435,9 +1435,43 @@ unsigned long kvm_arch_vcpu_id(CPUArchState *env) return env->cpuid_apic_id; } +/* + * Find matching entry for function/index on kvm_cpuid2 struct + */ +static struct kvm_cpuid_entry2 *cpuid_find_entry(struct kvm_cpuid_entry2 *entries, + int nent, + uint32_t function, + uint32_t index) +{ + int i; + for (i = 0; i < nent; ++i) { + if (entries[i].function == function && + entries[i].index == index) { + return &entries[i]; + } + } + /* not found: */ + return NULL; +} + +static Error *invtsc_mig_blocker; + +static const VMStateDescription vmstate_cpu_invtsc = { + .name = "cpu_invtsc", + .version_id = 1, + .minimum_version_id = 1, + .minimum_version_id_old = 1, + .unmigratable = 1, + .fields = (VMStateField []) { + VMSTATE_UINT32(halted, CPUState), /* dummy */ + VMSTATE_END_OF_LIST() + } +}; + int kvm_arch_init_vcpu(CPUState *cenv) { struct kvm_cpuid_entry2 cpuid_ent[100]; + struct kvm_cpuid_entry2 *c; #ifdef KVM_CPUID_SIGNATURE struct kvm_cpuid_entry2 *pv_ent; uint32_t signature[3]; @@ -1534,6 +1568,17 @@ int kvm_arch_init_vcpu(CPUState *cenv) for (i = 0x80000000; i <= limit; ++i) do_cpuid_ent(&cpuid_ent[cpuid_nent++], i, 0, ©); + c = cpuid_find_entry(cpuid_ent, cpuid_nent, 0x80000007, 0); + if (c && (c->edx & 1<<8) && invtsc_mig_blocker == NULL) { + /* migration */ + error_setg(&invtsc_mig_blocker, + "State blocked by non-migratable CPU device" + " (invtsc flag)"); + migrate_add_blocker(invtsc_mig_blocker); + /* savevm */ + vmstate_register(NULL, 1, &vmstate_cpu_invtsc, cenv); + } + kvm_setup_cpuid2(cenv, cpuid_nent, cpuid_ent); #ifdef KVM_CAP_MCE diff --git a/target-i386/kvm.c b/target-i386/kvm.c index 3d22663..c863a4b 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -24,6 +24,7 @@ #include "cpu.h" #include "gdbstub.h" #include "host-utils.h" +#include "migration.h" static void kvm_clear_vapic(CPUState *env) { -- 1.7.1