diff options
-rw-r--r-- | arch/x86/include/asm/hyperv.h | 5 | ||||
-rw-r--r-- | arch/x86/include/asm/hypervisor.h | 27 | ||||
-rw-r--r-- | arch/x86/include/asm/mshyperv.h | 15 | ||||
-rw-r--r-- | arch/x86/include/asm/processor.h | 7 | ||||
-rw-r--r-- | arch/x86/include/asm/vmware.h | 27 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/hypervisor.c | 56 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/mshyperv.c | 51 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/vmware.c | 36 |
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 | ||
23 | extern void init_hypervisor(struct cpuinfo_x86 *c); | 23 | extern void init_hypervisor(struct cpuinfo_x86 *c); |
24 | extern void init_hypervisor_platform(void); | 24 | extern void init_hypervisor_platform(void); |
25 | 25 | ||
26 | /* | ||
27 | * x86 hypervisor information | ||
28 | */ | ||
29 | struct 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 | |||
43 | extern const struct hypervisor_x86 *x86_hyper; | ||
44 | |||
45 | /* Recognized hypervisors */ | ||
46 | extern const struct hypervisor_x86 x86_hyper_vmware; | ||
47 | extern 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 | ||
4 | int ms_hyperv_platform(void); | 4 | #include <linux/types.h> |
5 | void __cpuinit ms_hyperv_set_feature_bits(struct cpuinfo_x86 *c); | 5 | #include <asm/hyperv.h> |
6 | |||
7 | struct ms_hyperv_info { | ||
8 | u32 features; | ||
9 | u32 hints; | ||
10 | }; | ||
11 | |||
12 | extern 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 | |||
23 | extern void vmware_platform_setup(void); | ||
24 | extern int vmware_platform(void); | ||
25 | extern 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 | ||
29 | static inline void __cpuinit | 27 | /* |
30 | detect_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 | */ | ||
32 | static 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 | ||
40 | static inline void __cpuinit | 38 | const struct hypervisor_x86 *x86_hyper; |
41 | hypervisor_set_feature_bits(struct cpuinfo_x86 *c) | 39 | |
40 | static inline void __init | ||
41 | detect_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 | ||
50 | void __cpuinit init_hypervisor(struct cpuinfo_x86 *c) | 55 | void __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 | ||
56 | void __init init_hypervisor_platform(void) | 61 | void __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 | ||
19 | struct ms_hyperv_info ms_hyperv; | ||
18 | 20 | ||
19 | int ms_hyperv_platform(void) | 21 | static 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 | ||
38 | void __cpuinit ms_hyperv_set_feature_bits(struct cpuinfo_x86 *c) | 37 | static 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 | |||
49 | const __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 | ||
67 | void __init vmware_platform_setup(void) | 67 | static 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 | */ |
85 | int vmware_platform(void) | 85 | static 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 | */ |
117 | void __cpuinit vmware_set_feature_bits(struct cpuinfo_x86 *c) | 114 | static 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 | |||
120 | const __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 | }; | ||