diff options
Diffstat (limited to 'target-i386/kvm.c')
-rw-r--r-- | target-i386/kvm.c | 87 |
1 files changed, 58 insertions, 29 deletions
diff --git a/target-i386/kvm.c b/target-i386/kvm.c index 4389959f6..097fe1188 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -30,9 +30,13 @@ #include "qemu/config-file.h" #include "hw/i386/pc.h" #include "hw/i386/apic.h" +#include "hw/i386/apic_internal.h" +#include "hw/i386/apic-msidef.h" #include "exec/ioport.h" #include <asm/hyperv.h> #include "hw/pci/pci.h" +#include "migration/migration.h" +#include "qapi/qmp/qerror.h" //#define DEBUG_KVM @@ -130,14 +134,13 @@ static const struct kvm_para_features { { KVM_CAP_NOP_IO_DELAY, KVM_FEATURE_NOP_IO_DELAY }, { KVM_CAP_PV_MMU, KVM_FEATURE_MMU_OP }, { KVM_CAP_ASYNC_PF, KVM_FEATURE_ASYNC_PF }, - { -1, -1 } }; static int get_para_features(KVMState *s) { int i, features = 0; - for (i = 0; i < ARRAY_SIZE(para_features) - 1; i++) { + for (i = 0; i < ARRAY_SIZE(para_features); i++) { if (kvm_check_extension(s, para_features[i].cap)) { features |= (1 << para_features[i].feature); } @@ -447,6 +450,8 @@ static bool hyperv_enabled(X86CPU *cpu) cpu->hyperv_relaxed_timing); } +static Error *invtsc_mig_blocker; + #define KVM_MAX_CPUID_ENTRIES 100 int kvm_arch_init_vcpu(CPUState *cs) @@ -527,23 +532,25 @@ int kvm_arch_init_vcpu(CPUState *cs) has_msr_hv_hypercall = true; } - memcpy(signature, "KVMKVMKVM\0\0\0", 12); - c = &cpuid_data.entries[cpuid_i++]; - c->function = KVM_CPUID_SIGNATURE | kvm_base; - c->eax = 0; - c->ebx = signature[0]; - c->ecx = signature[1]; - c->edx = signature[2]; + if (cpu->expose_kvm) { + memcpy(signature, "KVMKVMKVM\0\0\0", 12); + c = &cpuid_data.entries[cpuid_i++]; + c->function = KVM_CPUID_SIGNATURE | kvm_base; + c->eax = KVM_CPUID_FEATURES | kvm_base; + c->ebx = signature[0]; + c->ecx = signature[1]; + c->edx = signature[2]; - c = &cpuid_data.entries[cpuid_i++]; - c->function = KVM_CPUID_FEATURES | kvm_base; - c->eax = env->features[FEAT_KVM]; + c = &cpuid_data.entries[cpuid_i++]; + c->function = KVM_CPUID_FEATURES | kvm_base; + c->eax = env->features[FEAT_KVM]; - has_msr_async_pf_en = c->eax & (1 << KVM_FEATURE_ASYNC_PF); + has_msr_async_pf_en = c->eax & (1 << KVM_FEATURE_ASYNC_PF); - has_msr_pv_eoi_en = c->eax & (1 << KVM_FEATURE_PV_EOI); + has_msr_pv_eoi_en = c->eax & (1 << KVM_FEATURE_PV_EOI); - has_msr_kvm_steal_time = c->eax & (1 << KVM_FEATURE_STEAL_TIME); + has_msr_kvm_steal_time = c->eax & (1 << KVM_FEATURE_STEAL_TIME); + } cpu_x86_cpuid(env, 0, 0, &limit, &unused, &unused, &unused); @@ -702,6 +709,17 @@ int kvm_arch_init_vcpu(CPUState *cs) !!(c->ecx & CPUID_EXT_SMX); } + c = cpuid_find_entry(&cpuid_data.cpuid, 0x80000007, 0); + if (c && (c->edx & 1<<8) && invtsc_mig_blocker == NULL) { + /* for migration */ + error_setg(&invtsc_mig_blocker, + "State blocked by non-migratable CPU device" + " (invtsc flag)"); + migrate_add_blocker(invtsc_mig_blocker); + /* for savevm */ + vmstate_x86_cpu.unmigratable = 1; + } + cpuid_data.cpuid.padding = 0; r = kvm_vcpu_ioctl(cs, KVM_SET_CPUID2, &cpuid_data); if (r) { @@ -724,9 +742,8 @@ int kvm_arch_init_vcpu(CPUState *cs) return 0; } -void kvm_arch_reset_vcpu(CPUState *cs) +void kvm_arch_reset_vcpu(X86CPU *cpu) { - X86CPU *cpu = X86_CPU(cs); CPUX86State *env = &cpu->env; env->exception_injected = -1; @@ -740,6 +757,16 @@ void kvm_arch_reset_vcpu(CPUState *cs) } } +void kvm_arch_do_init_vcpu(X86CPU *cpu) +{ + CPUX86State *env = &cpu->env; + + /* APs get directly into wait-for-SIPI state. */ + if (env->mp_state == KVM_MP_STATE_UNINITIALIZED) { + env->mp_state = KVM_MP_STATE_INIT_RECEIVED; + } +} + static int kvm_get_supported_msrs(KVMState *s) { static int kvm_supported_msrs; @@ -1420,7 +1447,7 @@ static int kvm_get_sregs(X86CPU *cpu) HF_OSFXSR_MASK | HF_LMA_MASK | HF_CS32_MASK | \ HF_SS32_MASK | HF_CS64_MASK | HF_ADDSEG_MASK) - hflags = (env->segs[R_CS].flags >> DESC_DPL_SHIFT) & HF_CPL_MASK; + hflags = (env->segs[R_SS].flags >> DESC_DPL_SHIFT) & HF_CPL_MASK; hflags |= (env->cr[0] & CR0_PE_MASK) << (HF_PE_SHIFT - CR0_PE_SHIFT); hflags |= (env->cr[0] << (HF_MP_SHIFT - CR0_MP_SHIFT)) & (HF_MP_MASK | HF_EM_MASK | HF_TS_MASK); @@ -2005,14 +2032,15 @@ void kvm_arch_pre_run(CPUState *cpu, struct kvm_run *run) } } - if (!kvm_irqchip_in_kernel()) { - /* Force the VCPU out of its inner loop to process any INIT requests - * or pending TPR access reports. */ - if (cpu->interrupt_request & - (CPU_INTERRUPT_INIT | CPU_INTERRUPT_TPR)) { - cpu->exit_request = 1; - } + /* Force the VCPU out of its inner loop to process any INIT requests + * or (for userspace APIC, but it is cheap to combine the checks here) + * pending TPR access reports. + */ + if (cpu->interrupt_request & (CPU_INTERRUPT_INIT | CPU_INTERRUPT_TPR)) { + cpu->exit_request = 1; + } + if (!kvm_irqchip_in_kernel()) { /* Try to inject an interrupt if the guest can accept it */ if (run->ready_for_interrupt_injection && (cpu->interrupt_request & CPU_INTERRUPT_HARD) && @@ -2092,6 +2120,11 @@ int kvm_arch_process_async_events(CPUState *cs) } } + if (cs->interrupt_request & CPU_INTERRUPT_INIT) { + kvm_cpu_synchronize_state(cs); + do_cpu_init(cpu); + } + if (kvm_irqchip_in_kernel()) { return 0; } @@ -2105,10 +2138,6 @@ int kvm_arch_process_async_events(CPUState *cs) (cs->interrupt_request & CPU_INTERRUPT_NMI)) { cs->halted = 0; } - if (cs->interrupt_request & CPU_INTERRUPT_INIT) { - kvm_cpu_synchronize_state(cs); - do_cpu_init(cpu); - } if (cs->interrupt_request & CPU_INTERRUPT_SIPI) { kvm_cpu_synchronize_state(cs); do_cpu_sipi(cpu); |