aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/include/asm/hyperv.h5
-rw-r--r--arch/x86/include/asm/hypervisor.h27
-rw-r--r--arch/x86/include/asm/mshyperv.h15
-rw-r--r--arch/x86/include/asm/processor.h7
-rw-r--r--arch/x86/include/asm/vmware.h27
-rw-r--r--arch/x86/kernel/cpu/hypervisor.c56
-rw-r--r--arch/x86/kernel/cpu/mshyperv.c51
-rw-r--r--arch/x86/kernel/cpu/vmware.c36
8 files changed, 117 insertions, 107 deletions
diff --git a/arch/x86/include/asm/hyperv.h b/arch/x86/include/asm/hyperv.h
index 46040473e122..5df477ac3af7 100644
--- a/arch/x86/include/asm/hyperv.h
+++ b/arch/x86/include/asm/hyperv.h
@@ -1,5 +1,5 @@
1#ifndef _ASM_X86_KVM_HYPERV_H 1#ifndef _ASM_X86_HYPERV_H
2#define _ASM_X86_KVM_HYPERV_H 2#define _ASM_X86_HYPERV_H
3 3
4#include <linux/types.h> 4#include <linux/types.h>
5 5
@@ -16,6 +16,7 @@
16 16
17#define HYPERV_HYPERVISOR_PRESENT_BIT 0x80000000 17#define HYPERV_HYPERVISOR_PRESENT_BIT 0x80000000
18#define HYPERV_CPUID_MIN 0x40000005 18#define HYPERV_CPUID_MIN 0x40000005
19#define HYPERV_CPUID_MAX 0x4000ffff
19 20
20/* 21/*
21 * Feature identification. EAX indicates which features are available 22 * Feature identification. EAX indicates which features are available
diff --git a/arch/x86/include/asm/hypervisor.h b/arch/x86/include/asm/hypervisor.h
index b78c0941e422..70abda7058c8 100644
--- a/arch/x86/include/asm/hypervisor.h
+++ b/arch/x86/include/asm/hypervisor.h
@@ -17,10 +17,33 @@
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 * 18 *
19 */ 19 */
20#ifndef ASM_X86__HYPERVISOR_H 20#ifndef _ASM_X86_HYPERVISOR_H
21#define ASM_X86__HYPERVISOR_H 21#define _ASM_X86_HYPERVISOR_H
22 22
23extern void init_hypervisor(struct cpuinfo_x86 *c); 23extern void init_hypervisor(struct cpuinfo_x86 *c);
24extern void init_hypervisor_platform(void); 24extern void init_hypervisor_platform(void);
25 25
26/*
27 * x86 hypervisor information
28 */
29struct hypervisor_x86 {
30 /* Hypervisor name */
31 const char *name;
32
33 /* Detection routine */
34 bool (*detect)(void);
35
36 /* Adjust CPU feature bits (run once per CPU) */
37 void (*set_cpu_features)(struct cpuinfo_x86 *);
38
39 /* Platform setup (run once per boot) */
40 void (*init_platform)(void);
41};
42
43extern const struct hypervisor_x86 *x86_hyper;
44
45/* Recognized hypervisors */
46extern const struct hypervisor_x86 x86_hyper_vmware;
47extern const struct hypervisor_x86 x86_hyper_ms_hyperv;
48
26#endif 49#endif
diff --git a/arch/x86/include/asm/mshyperv.h b/arch/x86/include/asm/mshyperv.h
index 6cd8101d1344..79ce5685ab64 100644
--- a/arch/x86/include/asm/mshyperv.h
+++ b/arch/x86/include/asm/mshyperv.h
@@ -1,7 +1,14 @@
1#ifndef ASM_X86__MSHYPER_H 1#ifndef _ASM_X86_MSHYPER_H
2#define ASM_X86__MSHYPER_H 2#define _ASM_X86_MSHYPER_H
3 3
4int ms_hyperv_platform(void); 4#include <linux/types.h>
5void __cpuinit ms_hyperv_set_feature_bits(struct cpuinfo_x86 *c); 5#include <asm/hyperv.h>
6
7struct ms_hyperv_info {
8 u32 features;
9 u32 hints;
10};
11
12extern struct ms_hyperv_info ms_hyperv;
6 13
7#endif 14#endif
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index 597c041bd124..e4f1dfb2d05b 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -113,9 +113,6 @@ struct cpuinfo_x86 {
113 /* Index into per_cpu list: */ 113 /* Index into per_cpu list: */
114 u16 cpu_index; 114 u16 cpu_index;
115#endif 115#endif
116 unsigned int x86_hyper_vendor;
117 /* The layout of this field is hypervisor specific */
118 unsigned int x86_hyper_features;
119} __attribute__((__aligned__(SMP_CACHE_BYTES))); 116} __attribute__((__aligned__(SMP_CACHE_BYTES)));
120 117
121#define X86_VENDOR_INTEL 0 118#define X86_VENDOR_INTEL 0
@@ -129,10 +126,6 @@ struct cpuinfo_x86 {
129 126
130#define X86_VENDOR_UNKNOWN 0xff 127#define X86_VENDOR_UNKNOWN 0xff
131 128
132#define X86_HYPER_VENDOR_NONE 0
133#define X86_HYPER_VENDOR_VMWARE 1
134#define X86_HYPER_VENDOR_MSFT 2
135
136/* 129/*
137 * capabilities of CPUs 130 * capabilities of CPUs
138 */ 131 */
diff --git a/arch/x86/include/asm/vmware.h b/arch/x86/include/asm/vmware.h
deleted file mode 100644
index e49ed6d2fd4e..000000000000
--- a/arch/x86/include/asm/vmware.h
+++ /dev/null
@@ -1,27 +0,0 @@
1/*
2 * Copyright (C) 2008, VMware, Inc.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
12 * NON INFRINGEMENT. See the GNU General Public License for more
13 * details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 */
20#ifndef ASM_X86__VMWARE_H
21#define ASM_X86__VMWARE_H
22
23extern void vmware_platform_setup(void);
24extern int vmware_platform(void);
25extern void vmware_set_feature_bits(struct cpuinfo_x86 *c);
26
27#endif
diff --git a/arch/x86/kernel/cpu/hypervisor.c b/arch/x86/kernel/cpu/hypervisor.c
index de3f4e0ce8eb..87381759d3cb 100644
--- a/arch/x86/kernel/cpu/hypervisor.c
+++ b/arch/x86/kernel/cpu/hypervisor.c
@@ -22,40 +22,52 @@
22 */ 22 */
23 23
24#include <asm/processor.h> 24#include <asm/processor.h>
25#include <asm/vmware.h>
26#include <asm/mshyperv.h>
27#include <asm/hypervisor.h> 25#include <asm/hypervisor.h>
28 26
29static inline void __cpuinit 27/*
30detect_hypervisor_vendor(struct cpuinfo_x86 *c) 28 * Hypervisor detect order. This is specified explicitly here because
29 * some hypervisors might implement compatibility modes for other
30 * hypervisors and therefore need to be detected in specific sequence.
31 */
32static const __initconst struct hypervisor_x86 * const hypervisors[] =
31{ 33{
32 if (vmware_platform()) 34 &x86_hyper_vmware,
33 c->x86_hyper_vendor = X86_HYPER_VENDOR_VMWARE; 35 &x86_hyper_ms_hyperv,
34 else if (ms_hyperv_platform()) 36};
35 c->x86_hyper_vendor = X86_HYPER_VENDOR_MSFT;
36 else
37 c->x86_hyper_vendor = X86_HYPER_VENDOR_NONE;
38}
39 37
40static inline void __cpuinit 38const struct hypervisor_x86 *x86_hyper;
41hypervisor_set_feature_bits(struct cpuinfo_x86 *c) 39
40static inline void __init
41detect_hypervisor_vendor(void)
42{ 42{
43 if (boot_cpu_data.x86_hyper_vendor == X86_HYPER_VENDOR_VMWARE) 43 const struct hypervisor_x86 *h, * const *p;
44 vmware_set_feature_bits(c); 44
45 else if (boot_cpu_data.x86_hyper_vendor == X86_HYPER_VENDOR_MSFT) 45 for (p = hypervisors; p < hypervisors + ARRAY_SIZE(hypervisors); p++) {
46 ms_hyperv_set_feature_bits(c); 46 h = *p;
47 return; 47 if (h->detect()) {
48 x86_hyper = h;
49 printk(KERN_INFO "Hypervisor detected: %s\n", h->name);
50 break;
51 }
52 }
48} 53}
49 54
50void __cpuinit init_hypervisor(struct cpuinfo_x86 *c) 55void __cpuinit init_hypervisor(struct cpuinfo_x86 *c)
51{ 56{
52 detect_hypervisor_vendor(c); 57 if (x86_hyper && x86_hyper->set_cpu_features)
53 hypervisor_set_feature_bits(c); 58 x86_hyper->set_cpu_features(c);
54} 59}
55 60
56void __init init_hypervisor_platform(void) 61void __init init_hypervisor_platform(void)
57{ 62{
63
64 detect_hypervisor_vendor();
65
66 if (!x86_hyper)
67 return;
68
58 init_hypervisor(&boot_cpu_data); 69 init_hypervisor(&boot_cpu_data);
59 if (boot_cpu_data.x86_hyper_vendor == X86_HYPER_VENDOR_VMWARE) 70
60 vmware_platform_setup(); 71 if (x86_hyper->init_platform)
72 x86_hyper->init_platform();
61} 73}
diff --git a/arch/x86/kernel/cpu/mshyperv.c b/arch/x86/kernel/cpu/mshyperv.c
index a58d8e64fc7c..5969c3ee3186 100644
--- a/arch/x86/kernel/cpu/mshyperv.c
+++ b/arch/x86/kernel/cpu/mshyperv.c
@@ -12,45 +12,42 @@
12 12
13#include <linux/types.h> 13#include <linux/types.h>
14#include <asm/processor.h> 14#include <asm/processor.h>
15#include <asm/hypervisor.h>
15#include <asm/hyperv.h> 16#include <asm/hyperv.h>
16#include <asm/mshyperv.h> 17#include <asm/mshyperv.h>
17 18
19struct ms_hyperv_info ms_hyperv;
18 20
19int ms_hyperv_platform(void) 21static bool __init ms_hyperv_platform(void)
20{ 22{
21 u32 eax, ebx, ecx, edx; 23 u32 eax;
22 char hyp_signature[13]; 24 u32 hyp_signature[3];
23 25
24 cpuid(1, &eax, &ebx, &ecx, &edx); 26 if (!boot_cpu_has(X86_FEATURE_HYPERVISOR))
25 if (!(ecx & HYPERV_HYPERVISOR_PRESENT_BIT)) 27 return false;
26 return 0;
27 28
28 cpuid(HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS, &eax, &ebx, &ecx, &edx); 29 cpuid(HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS,
29 *(u32 *)(hyp_signature + 0) = ebx; 30 &eax, &hyp_signature[0], &hyp_signature[1], &hyp_signature[2]);
30 *(u32 *)(hyp_signature + 4) = ecx;
31 *(u32 *)(hyp_signature + 8) = edx;
32 31
33 if ((eax < HYPERV_CPUID_MIN) || (memcmp("Microsoft Hv", hyp_signature, 12))) 32 return eax >= HYPERV_CPUID_MIN &&
34 return 0; 33 eax <= HYPERV_CPUID_MAX &&
35 return 1; 34 !memcmp("Microsoft Hv", hyp_signature, 12);
36} 35}
37 36
38void __cpuinit ms_hyperv_set_feature_bits(struct cpuinfo_x86 *c) 37static void __init ms_hyperv_init_platform(void)
39{ 38{
40 u32 eax, ebx, ecx, edx;
41
42 c->x86_hyper_features = 0;
43 /* 39 /*
44 * Extract the features, recommendations etc. 40 * Extract the features and hints
45 * The first 9 bits will be used to track hypervisor features.
46 * The next 6 bits will be used to track the hypervisor
47 * recommendations.
48 */ 41 */
49 cpuid(HYPERV_CPUID_FEATURES, &eax, &ebx, &ecx, &edx); 42 ms_hyperv.features = cpuid_eax(HYPERV_CPUID_FEATURES);
50 c->x86_hyper_features |= (eax & 0x1ff); 43 ms_hyperv.hints = cpuid_eax(HYPERV_CPUID_ENLIGHTMENT_INFO);
51 44
52 cpuid(HYPERV_CPUID_ENLIGHTMENT_INFO, &eax, &ebx, &ecx, &edx); 45 printk(KERN_INFO "HyperV: features 0x%x, hints 0x%x\n",
53 c->x86_hyper_features |= ((eax & 0x3f) << 9); 46 ms_hyperv.features, ms_hyperv.hints);
54 printk(KERN_INFO "Detected HyperV with features: %x\n",
55 c->x86_hyper_features);
56} 47}
48
49const __refconst struct hypervisor_x86 x86_hyper_ms_hyperv = {
50 .name = "Microsoft HyperV",
51 .detect = ms_hyperv_platform,
52 .init_platform = ms_hyperv_init_platform,
53};
diff --git a/arch/x86/kernel/cpu/vmware.c b/arch/x86/kernel/cpu/vmware.c
index 1cbed97b59cf..46a5b5d3ba5e 100644
--- a/arch/x86/kernel/cpu/vmware.c
+++ b/arch/x86/kernel/cpu/vmware.c
@@ -23,8 +23,8 @@
23 23
24#include <linux/dmi.h> 24#include <linux/dmi.h>
25#include <asm/div64.h> 25#include <asm/div64.h>
26#include <asm/vmware.h>
27#include <asm/x86_init.h> 26#include <asm/x86_init.h>
27#include <asm/hypervisor.h>
28 28
29#define CPUID_VMWARE_INFO_LEAF 0x40000000 29#define CPUID_VMWARE_INFO_LEAF 0x40000000
30#define VMWARE_HYPERVISOR_MAGIC 0x564D5868 30#define VMWARE_HYPERVISOR_MAGIC 0x564D5868
@@ -64,7 +64,7 @@ static unsigned long vmware_get_tsc_khz(void)
64 return tsc_hz; 64 return tsc_hz;
65} 65}
66 66
67void __init vmware_platform_setup(void) 67static void __init vmware_platform_setup(void)
68{ 68{
69 uint32_t eax, ebx, ecx, edx; 69 uint32_t eax, ebx, ecx, edx;
70 70
@@ -82,24 +82,21 @@ void __init vmware_platform_setup(void)
82 * serial key should be enough, as this will always have a VMware 82 * serial key should be enough, as this will always have a VMware
83 * specific string when running under VMware hypervisor. 83 * specific string when running under VMware hypervisor.
84 */ 84 */
85int vmware_platform(void) 85static bool __init vmware_platform(void)
86{ 86{
87 if (cpu_has_hypervisor) { 87 if (cpu_has_hypervisor) {
88 unsigned int eax, ebx, ecx, edx; 88 unsigned int eax;
89 char hyper_vendor_id[13]; 89 unsigned int hyper_vendor_id[3];
90 90
91 cpuid(CPUID_VMWARE_INFO_LEAF, &eax, &ebx, &ecx, &edx); 91 cpuid(CPUID_VMWARE_INFO_LEAF, &eax, &hyper_vendor_id[0],
92 memcpy(hyper_vendor_id + 0, &ebx, 4); 92 &hyper_vendor_id[1], &hyper_vendor_id[2]);
93 memcpy(hyper_vendor_id + 4, &ecx, 4); 93 if (!memcmp(hyper_vendor_id, "VMwareVMware", 12))
94 memcpy(hyper_vendor_id + 8, &edx, 4); 94 return true;
95 hyper_vendor_id[12] = '\0';
96 if (!strcmp(hyper_vendor_id, "VMwareVMware"))
97 return 1;
98 } else if (dmi_available && dmi_name_in_serial("VMware") && 95 } else if (dmi_available && dmi_name_in_serial("VMware") &&
99 __vmware_platform()) 96 __vmware_platform())
100 return 1; 97 return true;
101 98
102 return 0; 99 return false;
103} 100}
104 101
105/* 102/*
@@ -114,8 +111,15 @@ int vmware_platform(void)
114 * so that the kernel could just trust the hypervisor with providing a 111 * so that the kernel could just trust the hypervisor with providing a
115 * reliable virtual TSC that is suitable for timekeeping. 112 * reliable virtual TSC that is suitable for timekeeping.
116 */ 113 */
117void __cpuinit vmware_set_feature_bits(struct cpuinfo_x86 *c) 114static void __cpuinit vmware_set_cpu_features(struct cpuinfo_x86 *c)
118{ 115{
119 set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC); 116 set_cpu_cap(c, X86_FEATURE_CONSTANT_TSC);
120 set_cpu_cap(c, X86_FEATURE_TSC_RELIABLE); 117 set_cpu_cap(c, X86_FEATURE_TSC_RELIABLE);
121} 118}
119
120const __refconst struct hypervisor_x86 x86_hyper_vmware = {
121 .name = "VMware",
122 .detect = vmware_platform,
123 .set_cpu_features = vmware_set_cpu_features,
124 .init_platform = vmware_platform_setup,
125};