30
30
#include <asm/hypervisor.h>
31
31
#include <asm/timer.h>
32
32
#include <asm/apic.h>
33
+ #include <asm/vmware.h>
33
34
34
35
#undef pr_fmt
35
36
#define pr_fmt (fmt ) "vmware: " fmt
36
37
37
- #define CPUID_VMWARE_INFO_LEAF 0x40000000
38
+ #define CPUID_VMWARE_INFO_LEAF 0x40000000
39
+ #define CPUID_VMWARE_FEATURES_LEAF 0x40000010
40
+ #define CPUID_VMWARE_FEATURES_ECX_VMMCALL BIT(0)
41
+ #define CPUID_VMWARE_FEATURES_ECX_VMCALL BIT(1)
42
+
38
43
#define VMWARE_HYPERVISOR_MAGIC 0x564D5868
39
- #define VMWARE_HYPERVISOR_PORT 0x5658
40
44
41
- #define VMWARE_PORT_CMD_GETVERSION 10
42
- #define VMWARE_PORT_CMD_GETHZ 45
43
- #define VMWARE_PORT_CMD_GETVCPU_INFO 68
44
- #define VMWARE_PORT_CMD_LEGACY_X2APIC 3
45
- #define VMWARE_PORT_CMD_VCPU_RESERVED 31
45
+ #define VMWARE_CMD_GETVERSION 10
46
+ #define VMWARE_CMD_GETHZ 45
47
+ #define VMWARE_CMD_GETVCPU_INFO 68
48
+ #define VMWARE_CMD_LEGACY_X2APIC 3
49
+ #define VMWARE_CMD_VCPU_RESERVED 31
46
50
47
51
#define VMWARE_PORT (cmd , eax , ebx , ecx , edx ) \
48
52
__asm__("inl (%%dx)" : \
49
- "=a"(eax), "=c"(ecx), "=d"(edx), "=b"(ebx) : \
50
- "0"(VMWARE_HYPERVISOR_MAGIC), \
51
- "1"(VMWARE_PORT_CMD_##cmd), \
52
- "2"(VMWARE_HYPERVISOR_PORT), "3"(UINT_MAX) : \
53
- "memory");
53
+ "=a"(eax), "=c"(ecx), "=d"(edx), "=b"(ebx) : \
54
+ "a"(VMWARE_HYPERVISOR_MAGIC), \
55
+ "c"(VMWARE_CMD_##cmd), \
56
+ "d"(VMWARE_HYPERVISOR_PORT), "b"(UINT_MAX) : \
57
+ "memory")
58
+
59
+ #define VMWARE_VMCALL (cmd , eax , ebx , ecx , edx ) \
60
+ __asm__("vmcall" : \
61
+ "=a"(eax), "=c"(ecx), "=d"(edx), "=b"(ebx) : \
62
+ "a"(VMWARE_HYPERVISOR_MAGIC), \
63
+ "c"(VMWARE_CMD_##cmd), \
64
+ "d"(0), "b"(UINT_MAX) : \
65
+ "memory")
66
+
67
+ #define VMWARE_VMMCALL (cmd , eax , ebx , ecx , edx ) \
68
+ __asm__("vmmcall" : \
69
+ "=a"(eax), "=c"(ecx), "=d"(edx), "=b"(ebx) : \
70
+ "a"(VMWARE_HYPERVISOR_MAGIC), \
71
+ "c"(VMWARE_CMD_##cmd), \
72
+ "d"(0), "b"(UINT_MAX) : \
73
+ "memory")
74
+
75
+ #define VMWARE_CMD (cmd , eax , ebx , ecx , edx ) do { \
76
+ switch (vmware_hypercall_mode) { \
77
+ case CPUID_VMWARE_FEATURES_ECX_VMCALL: \
78
+ VMWARE_VMCALL(cmd, eax, ebx, ecx, edx); \
79
+ break; \
80
+ case CPUID_VMWARE_FEATURES_ECX_VMMCALL: \
81
+ VMWARE_VMMCALL(cmd, eax, ebx, ecx, edx); \
82
+ break; \
83
+ default: \
84
+ VMWARE_PORT(cmd, eax, ebx, ecx, edx); \
85
+ break; \
86
+ } \
87
+ } while (0)
54
88
55
89
static unsigned long vmware_tsc_khz __ro_after_init ;
90
+ static u8 vmware_hypercall_mode __ro_after_init ;
56
91
57
92
static inline int __vmware_platform (void )
58
93
{
59
94
uint32_t eax , ebx , ecx , edx ;
60
- VMWARE_PORT (GETVERSION , eax , ebx , ecx , edx );
95
+ VMWARE_CMD (GETVERSION , eax , ebx , ecx , edx );
61
96
return eax != (uint32_t )-1 && ebx == VMWARE_HYPERVISOR_MAGIC ;
62
97
}
63
98
@@ -129,14 +164,18 @@ static void __init vmware_set_capabilities(void)
129
164
{
130
165
setup_force_cpu_cap (X86_FEATURE_CONSTANT_TSC );
131
166
setup_force_cpu_cap (X86_FEATURE_TSC_RELIABLE );
167
+ if (vmware_hypercall_mode == CPUID_VMWARE_FEATURES_ECX_VMCALL )
168
+ setup_force_cpu_cap (X86_FEATURE_VMCALL );
169
+ else if (vmware_hypercall_mode == CPUID_VMWARE_FEATURES_ECX_VMMCALL )
170
+ setup_force_cpu_cap (X86_FEATURE_VMW_VMMCALL );
132
171
}
133
172
134
173
static void __init vmware_platform_setup (void )
135
174
{
136
175
uint32_t eax , ebx , ecx , edx ;
137
176
uint64_t lpj , tsc_khz ;
138
177
139
- VMWARE_PORT (GETHZ , eax , ebx , ecx , edx );
178
+ VMWARE_CMD (GETHZ , eax , ebx , ecx , edx );
140
179
141
180
if (ebx != UINT_MAX ) {
142
181
lpj = tsc_khz = eax | (((uint64_t )ebx ) << 32 );
@@ -174,10 +213,21 @@ static void __init vmware_platform_setup(void)
174
213
vmware_set_capabilities ();
175
214
}
176
215
216
+ static u8 vmware_select_hypercall (void )
217
+ {
218
+ int eax , ebx , ecx , edx ;
219
+
220
+ cpuid (CPUID_VMWARE_FEATURES_LEAF , & eax , & ebx , & ecx , & edx );
221
+ return (ecx & (CPUID_VMWARE_FEATURES_ECX_VMMCALL |
222
+ CPUID_VMWARE_FEATURES_ECX_VMCALL ));
223
+ }
224
+
177
225
/*
178
226
* While checking the dmi string information, just checking the product
179
227
* serial key should be enough, as this will always have a VMware
180
228
* specific string when running under VMware hypervisor.
229
+ * If !boot_cpu_has(X86_FEATURE_HYPERVISOR), vmware_hypercall_mode
230
+ * intentionally defaults to 0.
181
231
*/
182
232
static uint32_t __init vmware_platform (void )
183
233
{
@@ -187,8 +237,16 @@ static uint32_t __init vmware_platform(void)
187
237
188
238
cpuid (CPUID_VMWARE_INFO_LEAF , & eax , & hyper_vendor_id [0 ],
189
239
& hyper_vendor_id [1 ], & hyper_vendor_id [2 ]);
190
- if (!memcmp (hyper_vendor_id , "VMwareVMware" , 12 ))
240
+ if (!memcmp (hyper_vendor_id , "VMwareVMware" , 12 )) {
241
+ if (eax >= CPUID_VMWARE_FEATURES_LEAF )
242
+ vmware_hypercall_mode =
243
+ vmware_select_hypercall ();
244
+
245
+ pr_info ("hypercall mode: 0x%02x\n" ,
246
+ (unsigned int ) vmware_hypercall_mode );
247
+
191
248
return CPUID_VMWARE_INFO_LEAF ;
249
+ }
192
250
} else if (dmi_available && dmi_name_in_serial ("VMware" ) &&
193
251
__vmware_platform ())
194
252
return 1 ;
@@ -200,9 +258,9 @@ static uint32_t __init vmware_platform(void)
200
258
static bool __init vmware_legacy_x2apic_available (void )
201
259
{
202
260
uint32_t eax , ebx , ecx , edx ;
203
- VMWARE_PORT (GETVCPU_INFO , eax , ebx , ecx , edx );
204
- return (eax & (1 << VMWARE_PORT_CMD_VCPU_RESERVED )) == 0 &&
205
- (eax & (1 << VMWARE_PORT_CMD_LEGACY_X2APIC )) != 0 ;
261
+ VMWARE_CMD (GETVCPU_INFO , eax , ebx , ecx , edx );
262
+ return (eax & (1 << VMWARE_CMD_VCPU_RESERVED )) == 0 &&
263
+ (eax & (1 << VMWARE_CMD_LEGACY_X2APIC )) != 0 ;
206
264
}
207
265
208
266
const __initconst struct hypervisor_x86 x86_hyper_vmware = {
0 commit comments