Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/x86/kernel/cpu/vmware.c
10699 views
1
/*
2
* VMware Detection code.
3
*
4
* Copyright (C) 2008, VMware, Inc.
5
* Author : Alok N Kataria <[email protected]>
6
*
7
* This program is free software; you can redistribute it and/or modify
8
* it under the terms of the GNU General Public License as published by
9
* the Free Software Foundation; either version 2 of the License, or
10
* (at your option) any later version.
11
*
12
* This program is distributed in the hope that it will be useful, but
13
* WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
15
* NON INFRINGEMENT. See the GNU General Public License for more
16
* details.
17
*
18
* You should have received a copy of the GNU General Public License
19
* along with this program; if not, write to the Free Software
20
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21
*
22
*/
23
24
#include <linux/dmi.h>
25
#include <linux/module.h>
26
#include <asm/div64.h>
27
#include <asm/x86_init.h>
28
#include <asm/hypervisor.h>
29
30
#define CPUID_VMWARE_INFO_LEAF 0x40000000
31
#define VMWARE_HYPERVISOR_MAGIC 0x564D5868
32
#define VMWARE_HYPERVISOR_PORT 0x5658
33
34
#define VMWARE_PORT_CMD_GETVERSION 10
35
#define VMWARE_PORT_CMD_GETHZ 45
36
37
#define VMWARE_PORT(cmd, eax, ebx, ecx, edx) \
38
__asm__("inl (%%dx)" : \
39
"=a"(eax), "=c"(ecx), "=d"(edx), "=b"(ebx) : \
40
"0"(VMWARE_HYPERVISOR_MAGIC), \
41
"1"(VMWARE_PORT_CMD_##cmd), \
42
"2"(VMWARE_HYPERVISOR_PORT), "3"(UINT_MAX) : \
43
"memory");
44
45
static inline int __vmware_platform(void)
46
{
47
uint32_t eax, ebx, ecx, edx;
48
VMWARE_PORT(GETVERSION, eax, ebx, ecx, edx);
49
return eax != (uint32_t)-1 && ebx == VMWARE_HYPERVISOR_MAGIC;
50
}
51
52
static unsigned long vmware_get_tsc_khz(void)
53
{
54
uint64_t tsc_hz, lpj;
55
uint32_t eax, ebx, ecx, edx;
56
57
VMWARE_PORT(GETHZ, eax, ebx, ecx, edx);
58
59
tsc_hz = eax | (((uint64_t)ebx) << 32);
60
do_div(tsc_hz, 1000);
61
BUG_ON(tsc_hz >> 32);
62
printk(KERN_INFO "TSC freq read from hypervisor : %lu.%03lu MHz\n",
63
(unsigned long) tsc_hz / 1000,
64
(unsigned long) tsc_hz % 1000);
65
66
if (!preset_lpj) {
67
lpj = ((u64)tsc_hz * 1000);
68
do_div(lpj, HZ);
69
preset_lpj = lpj;
70
}
71
72
return tsc_hz;
73
}
74
75
static void __init vmware_platform_setup(void)
76
{
77
uint32_t eax, ebx, ecx, edx;
78
79
VMWARE_PORT(GETHZ, eax, ebx, ecx, edx);
80
81
if (ebx != UINT_MAX)
82
x86_platform.calibrate_tsc = vmware_get_tsc_khz;
83
else
84
printk(KERN_WARNING
85
"Failed to get TSC freq from the hypervisor\n");
86
}
87
88
/*
89
* While checking the dmi string information, just checking the product
90
* serial key should be enough, as this will always have a VMware
91
* specific string when running under VMware hypervisor.
92
*/
93
static bool __init vmware_platform(void)
94
{
95
if (cpu_has_hypervisor) {
96
unsigned int eax;
97
unsigned int hyper_vendor_id[3];
98
99
cpuid(CPUID_VMWARE_INFO_LEAF, &eax, &hyper_vendor_id[0],
100
&hyper_vendor_id[1], &hyper_vendor_id[2]);
101
if (!memcmp(hyper_vendor_id, "VMwareVMware", 12))
102
return true;
103
} else if (dmi_available && dmi_name_in_serial("VMware") &&
104
__vmware_platform())
105
return true;
106
107
return false;
108
}
109
110
/*
111
* VMware hypervisor takes care of exporting a reliable TSC to the guest.
112
* Still, due to timing difference when running on virtual cpus, the TSC can
113
* be marked as unstable in some cases. For example, the TSC sync check at
114
* bootup can fail due to a marginal offset between vcpus' TSCs (though the
115
* TSCs do not drift from each other). Also, the ACPI PM timer clocksource
116
* is not suitable as a watchdog when running on a hypervisor because the
117
* kernel may miss a wrap of the counter if the vcpu is descheduled for a
118
* long time. To skip these checks at runtime we set these capability bits,
119
* so that the kernel could just trust the hypervisor with providing a
120
* reliable virtual TSC that is suitable for timekeeping.
121
*/
122
static void __cpuinit vmware_set_cpu_features(struct cpuinfo_x86 *c)
123
{
124
set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC);
125
set_cpu_cap(c, X86_FEATURE_TSC_RELIABLE);
126
}
127
128
const __refconst struct hypervisor_x86 x86_hyper_vmware = {
129
.name = "VMware",
130
.detect = vmware_platform,
131
.set_cpu_features = vmware_set_cpu_features,
132
.init_platform = vmware_platform_setup,
133
};
134
EXPORT_SYMBOL(x86_hyper_vmware);
135
136