summaryrefslogtreecommitdiffstats
path: root/target/i386/kvm.c
diff options
context:
space:
mode:
authorPhil Dennis-Jordan2017-01-20 15:11:34 +0100
committerPaolo Bonzini2017-01-27 18:07:57 +0100
commit9954a1582e18b03ddb66f6c892dccf2c3508f4b2 (patch)
tree2df459a4a6da4995d624ec004a691d1d2db13c1b /target/i386/kvm.c
parentblock: get max_transfer limit for char (scsi-generic) devices (diff)
downloadqemu-9954a1582e18b03ddb66f6c892dccf2c3508f4b2.tar.gz
qemu-9954a1582e18b03ddb66f6c892dccf2c3508f4b2.tar.xz
qemu-9954a1582e18b03ddb66f6c892dccf2c3508f4b2.zip
x86-KVM: Supply TSC and APIC clock rates to guest like VMWare
This fixes timekeeping of x86-64 Darwin/OS X/macOS guests when using KVM. Darwin/OS X/macOS for x86-64 uses the TSC for timekeeping; it normally calibrates this by querying various clock frequency scaling MSRs. Details depend on the exact CPU model detected. The local APIC timer frequency is extracted from (EFI) firmware. This is problematic in the presence of virtualisation, as the MSRs in question are typically not handled by the hypervisor. VMWare (Fusion) advertises TSC and APIC frequency via a custom 0x40000010 CPUID leaf, in the eax and ebx registers respectively. This is documented at https://lwn.net/Articles/301888/ among other places. Darwin/OS X/macOS looks for the generic 0x40000000 hypervisor leaf, and if this indicates via eax that leaf 0x40000010 might be available, that is in turn queried for the two frequencies. This adds a CPU option "vmware-cpuid-freq" to enable the same behaviour when running Qemu with KVM acceleration, if the KVM TSC frequency can be determined, and it is stable. (invtsc or user-specified) The virtualised APIC bus cycle is hardcoded to 1GHz in KVM, so ebx of the CPUID leaf is also hardcoded to this value. Signed-off-by: Phil Dennis-Jordan <phil@philjordan.eu> Message-Id: <1484921496-11257-2-git-send-email-phil@philjordan.eu> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'target/i386/kvm.c')
-rw-r--r--target/i386/kvm.c36
1 files changed, 30 insertions, 6 deletions
diff --git a/target/i386/kvm.c b/target/i386/kvm.c
index 8e130ccf9c..27fd0505df 100644
--- a/target/i386/kvm.c
+++ b/target/i386/kvm.c
@@ -982,12 +982,6 @@ int kvm_arch_init_vcpu(CPUState *cs)
}
}
- cpuid_data.cpuid.padding = 0;
- r = kvm_vcpu_ioctl(cs, KVM_SET_CPUID2, &cpuid_data);
- if (r) {
- goto fail;
- }
-
r = kvm_arch_set_tsc_khz(cs);
if (r < 0) {
goto fail;
@@ -1007,6 +1001,36 @@ int kvm_arch_init_vcpu(CPUState *cs)
}
}
+ if (cpu->vmware_cpuid_freq
+ /* Guests depend on 0x40000000 to detect this feature, so only expose
+ * it if KVM exposes leaf 0x40000000. (Conflicts with Hyper-V) */
+ && cpu->expose_kvm
+ && kvm_base == KVM_CPUID_SIGNATURE
+ /* TSC clock must be stable and known for this feature. */
+ && ((env->features[FEAT_8000_0007_EDX] & CPUID_APM_INVTSC)
+ || env->user_tsc_khz != 0)
+ && env->tsc_khz != 0) {
+
+ c = &cpuid_data.entries[cpuid_i++];
+ c->function = KVM_CPUID_SIGNATURE | 0x10;
+ c->eax = env->tsc_khz;
+ /* LAPIC resolution of 1ns (freq: 1GHz) is hardcoded in KVM's
+ * APIC_BUS_CYCLE_NS */
+ c->ebx = 1000000;
+ c->ecx = c->edx = 0;
+
+ c = cpuid_find_entry(&cpuid_data.cpuid, kvm_base, 0);
+ c->eax = MAX(c->eax, KVM_CPUID_SIGNATURE | 0x10);
+ }
+
+ cpuid_data.cpuid.nent = cpuid_i;
+
+ cpuid_data.cpuid.padding = 0;
+ r = kvm_vcpu_ioctl(cs, KVM_SET_CPUID2, &cpuid_data);
+ if (r) {
+ goto fail;
+ }
+
if (has_xsave) {
env->kvm_xsave_buf = qemu_memalign(4096, sizeof(struct kvm_xsave));
}