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 | }; | ||
