aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2010-05-07 19:57:28 -0400
committerH. Peter Anvin <hpa@zytor.com>2010-05-07 20:13:04 -0400
commite08cae4181af9483b04ecfac48f01c8e5a5f27bf (patch)
tree2cab8da747a6524694cc19f247d8bc4f157a601c
parent9fa02317429449e8176c9bb6da3ac00eb14d52d3 (diff)
x86: Clean up the hypervisor layer
Clean up the hypervisor layer and the hypervisor drivers, using an ops structure instead of an enumeration with if statements. The identity of the hypervisor, if needed, can be tested by testing the pointer value in x86_hyper. The MS-HyperV private state is moved into a normal global variable (it's per-system state, not per-CPU state). Being a normal bss variable, it will be left at all zero on non-HyperV platforms, and so can generally be tested for HyperV-specific features without additional qualification. Signed-off-by: H. Peter Anvin <hpa@zytor.com> Acked-by: Greg KH <greg@kroah.com> Cc: Hank Janssen <hjanssen@microsoft.com> Cc: Alok Kataria <akataria@vmware.com> Cc: Ky Srinivasan <ksrinivasan@novell.com> LKML-Reference: <4BE49778.6060800@zytor.com>
-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 46040473e12..5df477ac3af 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 b78c0941e42..70abda7058c 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 6cd8101d134..79ce5685ab6 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 597c041bd12..e4f1dfb2d05 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 e49ed6d2fd4..00000000000
--- 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 de3f4e0ce8e..87381759d3c 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 a58d8e64fc7..5969c3ee318 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 1cbed97b59c..46a5b5d3ba5 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};