Detect VMware guest and set the TSC frequency as reported by the hypervisor.
VMware products virtualize TSC and it run at fixed frequency in so-called "apparent time". Although virtualized i8254 also runs in apparent time, TSC calibration always gives slightly off frequency because of the complicated timer emulation and lost-tick correction mechanism.
This commit is contained in:
parent
12fa2ffdff
commit
3b56923bc2
@ -32,6 +32,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/param.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/cpu.h>
|
||||
#include <sys/limits.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/sysctl.h>
|
||||
@ -90,6 +91,87 @@ static struct timecounter tsc_timecounter = {
|
||||
800, /* quality (adjusted in code) */
|
||||
};
|
||||
|
||||
#define VMW_HVMAGIC 0x564d5868
|
||||
#define VMW_HVPORT 0x5658
|
||||
#define VMW_HVCMD_GETVERSION 10
|
||||
#define VMW_HVCMD_GETHZ 45
|
||||
|
||||
static __inline void
|
||||
vmware_hvcall(u_int cmd, u_int *p)
|
||||
{
|
||||
|
||||
__asm __volatile("inl (%%dx)"
|
||||
: "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3])
|
||||
: "0" (VMW_HVMAGIC), "1" (UINT_MAX), "2" (cmd), "3" (VMW_HVPORT)
|
||||
: "memory");
|
||||
}
|
||||
|
||||
static int
|
||||
tsc_freq_vmware(void)
|
||||
{
|
||||
char hv_sig[13];
|
||||
u_int regs[4];
|
||||
char *p;
|
||||
u_int hv_high;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* [RFC] CPUID usage for interaction between Hypervisors and Linux.
|
||||
* http://lkml.org/lkml/2008/10/1/246
|
||||
*
|
||||
* KB1009458: Mechanisms to determine if software is running in
|
||||
* a VMware virtual machine
|
||||
* http://kb.vmware.com/kb/1009458
|
||||
*/
|
||||
hv_high = 0;
|
||||
if ((cpu_feature2 & CPUID2_HV) != 0) {
|
||||
do_cpuid(0x40000000, regs);
|
||||
hv_high = regs[0];
|
||||
for (i = 1, p = hv_sig; i < 4; i++, p += sizeof(regs) / 4)
|
||||
memcpy(p, ®s[i], sizeof(regs[i]));
|
||||
*p = '\0';
|
||||
if (bootverbose) {
|
||||
/*
|
||||
* HV vendor ID string
|
||||
* ------------+--------------
|
||||
* KVM "KVMKVMKVM"
|
||||
* Microsoft "Microsoft Hv"
|
||||
* VMware "VMwareVMware"
|
||||
* Xen "XenVMMXenVMM"
|
||||
*/
|
||||
printf("Hypervisor: Origin = \"%s\"\n", hv_sig);
|
||||
}
|
||||
if (strncmp(hv_sig, "VMwareVMware", 12) != 0)
|
||||
return (0);
|
||||
} else {
|
||||
p = getenv("smbios.system.serial");
|
||||
if (p == NULL)
|
||||
return (0);
|
||||
if (strncmp(p, "VMware-", 7) != 0 &&
|
||||
strncmp(p, "VMW", 3) != 0) {
|
||||
freeenv(p);
|
||||
return (0);
|
||||
}
|
||||
freeenv(p);
|
||||
vmware_hvcall(VMW_HVCMD_GETVERSION, regs);
|
||||
if (regs[1] != VMW_HVMAGIC)
|
||||
return (0);
|
||||
}
|
||||
if (hv_high >= 0x40000010) {
|
||||
do_cpuid(0x40000010, regs);
|
||||
tsc_freq = regs[0] * 1000;
|
||||
} else {
|
||||
vmware_hvcall(VMW_HVCMD_GETHZ, regs);
|
||||
if (regs[1] != UINT_MAX)
|
||||
tsc_freq = regs[0] | ((uint64_t)regs[1] << 32);
|
||||
}
|
||||
tsc_is_invariant = 1;
|
||||
#ifdef SMP
|
||||
smp_tsc = 1; /* XXX */
|
||||
#endif
|
||||
return (1);
|
||||
}
|
||||
|
||||
static void
|
||||
tsc_freq_intel(void)
|
||||
{
|
||||
@ -102,7 +184,6 @@ tsc_freq_intel(void)
|
||||
/*
|
||||
* Intel Processor Identification and the CPUID Instruction
|
||||
* Application Note 485.
|
||||
*
|
||||
* http://www.intel.com/assets/pdf/appnote/241618.pdf
|
||||
*/
|
||||
if (cpu_exthigh >= 0x80000004) {
|
||||
@ -156,6 +237,25 @@ probe_tsc_freq(void)
|
||||
u_int regs[4];
|
||||
uint64_t tsc1, tsc2;
|
||||
|
||||
if (cpu_high >= 6) {
|
||||
do_cpuid(6, regs);
|
||||
if ((regs[2] & CPUID_PERF_STAT) != 0) {
|
||||
/*
|
||||
* XXX Some emulators expose host CPUID without actual
|
||||
* support for these MSRs. We must test whether they
|
||||
* really work.
|
||||
*/
|
||||
wrmsr(MSR_MPERF, 0);
|
||||
wrmsr(MSR_APERF, 0);
|
||||
DELAY(10);
|
||||
if (rdmsr(MSR_MPERF) > 0 && rdmsr(MSR_APERF) > 0)
|
||||
tsc_perf_stat = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (tsc_freq_vmware())
|
||||
return;
|
||||
|
||||
switch (cpu_vendor_id) {
|
||||
case CPU_VENDOR_AMD:
|
||||
if ((amd_pminfo & AMDPM_TSC_INVARIANT) != 0 ||
|
||||
@ -181,22 +281,6 @@ probe_tsc_freq(void)
|
||||
break;
|
||||
}
|
||||
|
||||
if (cpu_high >= 6) {
|
||||
do_cpuid(6, regs);
|
||||
if ((regs[2] & CPUID_PERF_STAT) != 0) {
|
||||
/*
|
||||
* XXX Some emulators expose host CPUID without actual
|
||||
* support for these MSRs. We must test whether they
|
||||
* really work.
|
||||
*/
|
||||
wrmsr(MSR_MPERF, 0);
|
||||
wrmsr(MSR_APERF, 0);
|
||||
DELAY(10);
|
||||
if (rdmsr(MSR_MPERF) > 0 && rdmsr(MSR_APERF) > 0)
|
||||
tsc_perf_stat = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (tsc_skip_calibration) {
|
||||
if (cpu_vendor_id == CPU_VENDOR_INTEL)
|
||||
tsc_freq_intel();
|
||||
|
Loading…
x
Reference in New Issue
Block a user