1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24#include <linux/dmi.h>
25#include <linux/module.h>
26#include <linux/init.h>
27#include <linux/export.h>
28#include <linux/clocksource.h>
29#include <asm/div64.h>
30#include <asm/x86_init.h>
31#include <asm/hypervisor.h>
32#include <asm/timer.h>
33#include <asm/apic.h>
34
35#undef pr_fmt
36#define pr_fmt(fmt) "vmware: " fmt
37
38#define CPUID_VMWARE_INFO_LEAF 0x40000000
39#define VMWARE_HYPERVISOR_MAGIC 0x564D5868
40#define VMWARE_HYPERVISOR_PORT 0x5658
41
42#define VMWARE_PORT_CMD_GETVERSION 10
43#define VMWARE_PORT_CMD_GETHZ 45
44#define VMWARE_PORT_CMD_GETVCPU_INFO 68
45#define VMWARE_PORT_CMD_LEGACY_X2APIC 3
46#define VMWARE_PORT_CMD_VCPU_RESERVED 31
47
48#define VMWARE_PORT(cmd, eax, ebx, ecx, edx) \
49 __asm__("inl (%%dx)" : \
50 "=a"(eax), "=c"(ecx), "=d"(edx), "=b"(ebx) : \
51 "0"(VMWARE_HYPERVISOR_MAGIC), \
52 "1"(VMWARE_PORT_CMD_##cmd), \
53 "2"(VMWARE_HYPERVISOR_PORT), "3"(UINT_MAX) : \
54 "memory");
55
56static unsigned long vmware_tsc_khz;
57
58static inline int __vmware_platform(void)
59{
60 uint32_t eax, ebx, ecx, edx;
61 VMWARE_PORT(GETVERSION, eax, ebx, ecx, edx);
62 return eax != (uint32_t)-1 && ebx == VMWARE_HYPERVISOR_MAGIC;
63}
64
65static unsigned long vmware_get_tsc_khz(void)
66{
67 return vmware_tsc_khz;
68}
69
70#ifdef CONFIG_PARAVIRT
71static struct cyc2ns_data vmware_cyc2ns;
72static int vmw_sched_clock __initdata = 1;
73
74static __init int setup_vmw_sched_clock(char *s)
75{
76 vmw_sched_clock = 0;
77 return 0;
78}
79early_param("no-vmw-sched-clock", setup_vmw_sched_clock);
80
81static unsigned long long notrace vmware_sched_clock(void)
82{
83 unsigned long long ns;
84
85 ns = mul_u64_u32_shr(rdtsc(), vmware_cyc2ns.cyc2ns_mul,
86 vmware_cyc2ns.cyc2ns_shift);
87 ns -= vmware_cyc2ns.cyc2ns_offset;
88 return ns;
89}
90
91static void __init vmware_sched_clock_setup(void)
92{
93 struct cyc2ns_data *d = &vmware_cyc2ns;
94 unsigned long long tsc_now = rdtsc();
95
96 clocks_calc_mult_shift(&d->cyc2ns_mul, &d->cyc2ns_shift,
97 vmware_tsc_khz, NSEC_PER_MSEC, 0);
98 d->cyc2ns_offset = mul_u64_u32_shr(tsc_now, d->cyc2ns_mul,
99 d->cyc2ns_shift);
100
101 pv_time_ops.sched_clock = vmware_sched_clock;
102 pr_info("using sched offset of %llu ns\n", d->cyc2ns_offset);
103}
104
105static void __init vmware_paravirt_ops_setup(void)
106{
107 pv_info.name = "VMware hypervisor";
108 pv_cpu_ops.io_delay = paravirt_nop;
109
110 if (vmware_tsc_khz && vmw_sched_clock)
111 vmware_sched_clock_setup();
112}
113#else
114#define vmware_paravirt_ops_setup() do {} while (0)
115#endif
116
117
118
119
120
121
122
123
124
125
126
127
128
129static void __init vmware_set_capabilities(void)
130{
131 setup_force_cpu_cap(X86_FEATURE_CONSTANT_TSC);
132 setup_force_cpu_cap(X86_FEATURE_TSC_RELIABLE);
133}
134
135static void __init vmware_platform_setup(void)
136{
137 uint32_t eax, ebx, ecx, edx;
138 uint64_t lpj, tsc_khz;
139
140 VMWARE_PORT(GETHZ, eax, ebx, ecx, edx);
141
142 if (ebx != UINT_MAX) {
143 lpj = tsc_khz = eax | (((uint64_t)ebx) << 32);
144 do_div(tsc_khz, 1000);
145 WARN_ON(tsc_khz >> 32);
146 pr_info("TSC freq read from hypervisor : %lu.%03lu MHz\n",
147 (unsigned long) tsc_khz / 1000,
148 (unsigned long) tsc_khz % 1000);
149
150 if (!preset_lpj) {
151 do_div(lpj, HZ);
152 preset_lpj = lpj;
153 }
154
155 vmware_tsc_khz = tsc_khz;
156 x86_platform.calibrate_tsc = vmware_get_tsc_khz;
157 x86_platform.calibrate_cpu = vmware_get_tsc_khz;
158
159#ifdef CONFIG_X86_LOCAL_APIC
160
161 lapic_timer_frequency = ecx / HZ;
162 pr_info("Host bus clock speed read from hypervisor : %u Hz\n",
163 ecx);
164#endif
165 } else {
166 printk(KERN_WARNING
167 "Failed to get TSC freq from the hypervisor\n");
168 }
169
170 vmware_paravirt_ops_setup();
171
172#ifdef CONFIG_X86_IO_APIC
173 no_timer_check = 1;
174#endif
175
176 vmware_set_capabilities();
177}
178
179
180
181
182
183
184static uint32_t __init vmware_platform(void)
185{
186 if (cpu_has_hypervisor) {
187 unsigned int eax;
188 unsigned int hyper_vendor_id[3];
189
190 cpuid(CPUID_VMWARE_INFO_LEAF, &eax, &hyper_vendor_id[0],
191 &hyper_vendor_id[1], &hyper_vendor_id[2]);
192 if (!memcmp(hyper_vendor_id, "VMwareVMware", 12))
193 return CPUID_VMWARE_INFO_LEAF;
194 } else if (dmi_available && dmi_name_in_serial("VMware") &&
195 __vmware_platform())
196 return 1;
197
198 return 0;
199}
200
201
202static bool __init vmware_legacy_x2apic_available(void)
203{
204 uint32_t eax, ebx, ecx, edx;
205 VMWARE_PORT(GETVCPU_INFO, eax, ebx, ecx, edx);
206 return (eax & (1 << VMWARE_PORT_CMD_VCPU_RESERVED)) == 0 &&
207 (eax & (1 << VMWARE_PORT_CMD_LEGACY_X2APIC)) != 0;
208}
209
210const __refconst struct hypervisor_x86 x86_hyper_vmware = {
211 .name = "VMware",
212 .detect = vmware_platform,
213 .init_platform = vmware_platform_setup,
214 .x2apic_available = vmware_legacy_x2apic_available,
215};
216EXPORT_SYMBOL(x86_hyper_vmware);
217