aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-09-04 14:05:13 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-09-04 14:05:13 -0400
commit05eebfb26bac9215410b70e0f043861aecff896c (patch)
tree3a6f63bad6d7dbc75d66bbb3f8deb4d5e40ef60c /arch/x86
parentcb3e4330e697dffaf3d9cefebc9c7e7d39c89f2e (diff)
parent9df56f19a500bea90d160be1bf77e4fbcd204d3f (diff)
Merge branch 'x86-paravirt-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 paravirt changes from Ingo Molnar: "Hypervisor signature detection cleanup and fixes - the goal is to make KVM guests run better on MS/Hyperv and to generalize and factor out the code a bit" * 'x86-paravirt-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86: Correctly detect hypervisor x86, kvm: Switch to use hypervisor_cpuid_base() xen: Switch to use hypervisor_cpuid_base() x86: Introduce hypervisor_cpuid_base()
Diffstat (limited to 'arch/x86')
-rw-r--r--arch/x86/include/asm/hypervisor.h2
-rw-r--r--arch/x86/include/asm/kvm_para.h24
-rw-r--r--arch/x86/include/asm/processor.h15
-rw-r--r--arch/x86/include/asm/xen/hypervisor.h16
-rw-r--r--arch/x86/kernel/cpu/hypervisor.c15
-rw-r--r--arch/x86/kernel/cpu/mshyperv.c13
-rw-r--r--arch/x86/kernel/cpu/vmware.c8
-rw-r--r--arch/x86/kernel/kvm.c6
-rw-r--r--arch/x86/xen/enlighten.c9
9 files changed, 50 insertions, 58 deletions
diff --git a/arch/x86/include/asm/hypervisor.h b/arch/x86/include/asm/hypervisor.h
index 2d4b5e6107cd..e42f758a0fbd 100644
--- a/arch/x86/include/asm/hypervisor.h
+++ b/arch/x86/include/asm/hypervisor.h
@@ -33,7 +33,7 @@ struct hypervisor_x86 {
33 const char *name; 33 const char *name;
34 34
35 /* Detection routine */ 35 /* Detection routine */
36 bool (*detect)(void); 36 uint32_t (*detect)(void);
37 37
38 /* Adjust CPU feature bits (run once per CPU) */ 38 /* Adjust CPU feature bits (run once per CPU) */
39 void (*set_cpu_features)(struct cpuinfo_x86 *); 39 void (*set_cpu_features)(struct cpuinfo_x86 *);
diff --git a/arch/x86/include/asm/kvm_para.h b/arch/x86/include/asm/kvm_para.h
index 695399f2d5eb..0644129a5333 100644
--- a/arch/x86/include/asm/kvm_para.h
+++ b/arch/x86/include/asm/kvm_para.h
@@ -85,26 +85,20 @@ static inline long kvm_hypercall4(unsigned int nr, unsigned long p1,
85 return ret; 85 return ret;
86} 86}
87 87
88static inline bool kvm_para_available(void) 88static inline uint32_t kvm_cpuid_base(void)
89{ 89{
90 unsigned int eax, ebx, ecx, edx;
91 char signature[13];
92
93 if (boot_cpu_data.cpuid_level < 0) 90 if (boot_cpu_data.cpuid_level < 0)
94 return false; /* So we don't blow up on old processors */ 91 return 0; /* So we don't blow up on old processors */
95 92
96 if (cpu_has_hypervisor) { 93 if (cpu_has_hypervisor)
97 cpuid(KVM_CPUID_SIGNATURE, &eax, &ebx, &ecx, &edx); 94 return hypervisor_cpuid_base("KVMKVMKVM\0\0\0", 0);
98 memcpy(signature + 0, &ebx, 4);
99 memcpy(signature + 4, &ecx, 4);
100 memcpy(signature + 8, &edx, 4);
101 signature[12] = 0;
102 95
103 if (strcmp(signature, "KVMKVMKVM") == 0) 96 return 0;
104 return true; 97}
105 }
106 98
107 return false; 99static inline bool kvm_para_available(void)
100{
101 return kvm_cpuid_base() != 0;
108} 102}
109 103
110static inline unsigned int kvm_arch_para_features(void) 104static inline unsigned int kvm_arch_para_features(void)
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index 4c2d31d941ea..987c75ecc334 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -942,6 +942,21 @@ extern int set_tsc_mode(unsigned int val);
942 942
943extern u16 amd_get_nb_id(int cpu); 943extern u16 amd_get_nb_id(int cpu);
944 944
945static inline uint32_t hypervisor_cpuid_base(const char *sig, uint32_t leaves)
946{
947 uint32_t base, eax, signature[3];
948
949 for (base = 0x40000000; base < 0x40010000; base += 0x100) {
950 cpuid(base, &eax, &signature[0], &signature[1], &signature[2]);
951
952 if (!memcmp(sig, signature, 12) &&
953 (leaves == 0 || ((eax - base) >= leaves)))
954 return base;
955 }
956
957 return 0;
958}
959
945extern unsigned long arch_align_stack(unsigned long sp); 960extern unsigned long arch_align_stack(unsigned long sp);
946extern void free_init_pages(char *what, unsigned long begin, unsigned long end); 961extern void free_init_pages(char *what, unsigned long begin, unsigned long end);
947 962
diff --git a/arch/x86/include/asm/xen/hypervisor.h b/arch/x86/include/asm/xen/hypervisor.h
index 125f344f06a9..d866959e5685 100644
--- a/arch/x86/include/asm/xen/hypervisor.h
+++ b/arch/x86/include/asm/xen/hypervisor.h
@@ -40,21 +40,7 @@ extern struct start_info *xen_start_info;
40 40
41static inline uint32_t xen_cpuid_base(void) 41static inline uint32_t xen_cpuid_base(void)
42{ 42{
43 uint32_t base, eax, ebx, ecx, edx; 43 return hypervisor_cpuid_base("XenVMMXenVMM", 2);
44 char signature[13];
45
46 for (base = 0x40000000; base < 0x40010000; base += 0x100) {
47 cpuid(base, &eax, &ebx, &ecx, &edx);
48 *(uint32_t *)(signature + 0) = ebx;
49 *(uint32_t *)(signature + 4) = ecx;
50 *(uint32_t *)(signature + 8) = edx;
51 signature[12] = 0;
52
53 if (!strcmp("XenVMMXenVMM", signature) && ((eax - base) >= 2))
54 return base;
55 }
56
57 return 0;
58} 44}
59 45
60#ifdef CONFIG_XEN 46#ifdef CONFIG_XEN
diff --git a/arch/x86/kernel/cpu/hypervisor.c b/arch/x86/kernel/cpu/hypervisor.c
index 87279212d318..36ce402a3fa5 100644
--- a/arch/x86/kernel/cpu/hypervisor.c
+++ b/arch/x86/kernel/cpu/hypervisor.c
@@ -25,11 +25,6 @@
25#include <asm/processor.h> 25#include <asm/processor.h>
26#include <asm/hypervisor.h> 26#include <asm/hypervisor.h>
27 27
28/*
29 * Hypervisor detect order. This is specified explicitly here because
30 * some hypervisors might implement compatibility modes for other
31 * hypervisors and therefore need to be detected in specific sequence.
32 */
33static const __initconst struct hypervisor_x86 * const hypervisors[] = 28static const __initconst struct hypervisor_x86 * const hypervisors[] =
34{ 29{
35#ifdef CONFIG_XEN_PVHVM 30#ifdef CONFIG_XEN_PVHVM
@@ -49,15 +44,19 @@ static inline void __init
49detect_hypervisor_vendor(void) 44detect_hypervisor_vendor(void)
50{ 45{
51 const struct hypervisor_x86 *h, * const *p; 46 const struct hypervisor_x86 *h, * const *p;
47 uint32_t pri, max_pri = 0;
52 48
53 for (p = hypervisors; p < hypervisors + ARRAY_SIZE(hypervisors); p++) { 49 for (p = hypervisors; p < hypervisors + ARRAY_SIZE(hypervisors); p++) {
54 h = *p; 50 h = *p;
55 if (h->detect()) { 51 pri = h->detect();
52 if (pri != 0 && pri > max_pri) {
53 max_pri = pri;
56 x86_hyper = h; 54 x86_hyper = h;
57 printk(KERN_INFO "Hypervisor detected: %s\n", h->name);
58 break;
59 } 55 }
60 } 56 }
57
58 if (max_pri)
59 printk(KERN_INFO "Hypervisor detected: %s\n", x86_hyper->name);
61} 60}
62 61
63void init_hypervisor(struct cpuinfo_x86 *c) 62void init_hypervisor(struct cpuinfo_x86 *c)
diff --git a/arch/x86/kernel/cpu/mshyperv.c b/arch/x86/kernel/cpu/mshyperv.c
index 8f4be53ea04b..71a39f3621ba 100644
--- a/arch/x86/kernel/cpu/mshyperv.c
+++ b/arch/x86/kernel/cpu/mshyperv.c
@@ -27,20 +27,23 @@
27struct ms_hyperv_info ms_hyperv; 27struct ms_hyperv_info ms_hyperv;
28EXPORT_SYMBOL_GPL(ms_hyperv); 28EXPORT_SYMBOL_GPL(ms_hyperv);
29 29
30static bool __init ms_hyperv_platform(void) 30static uint32_t __init ms_hyperv_platform(void)
31{ 31{
32 u32 eax; 32 u32 eax;
33 u32 hyp_signature[3]; 33 u32 hyp_signature[3];
34 34
35 if (!boot_cpu_has(X86_FEATURE_HYPERVISOR)) 35 if (!boot_cpu_has(X86_FEATURE_HYPERVISOR))
36 return false; 36 return 0;
37 37
38 cpuid(HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS, 38 cpuid(HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS,
39 &eax, &hyp_signature[0], &hyp_signature[1], &hyp_signature[2]); 39 &eax, &hyp_signature[0], &hyp_signature[1], &hyp_signature[2]);
40 40
41 return eax >= HYPERV_CPUID_MIN && 41 if (eax >= HYPERV_CPUID_MIN &&
42 eax <= HYPERV_CPUID_MAX && 42 eax <= HYPERV_CPUID_MAX &&
43 !memcmp("Microsoft Hv", hyp_signature, 12); 43 !memcmp("Microsoft Hv", hyp_signature, 12))
44 return HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS;
45
46 return 0;
44} 47}
45 48
46static cycle_t read_hv_clock(struct clocksource *arg) 49static cycle_t read_hv_clock(struct clocksource *arg)
diff --git a/arch/x86/kernel/cpu/vmware.c b/arch/x86/kernel/cpu/vmware.c
index 7076878404ec..628a059a9a06 100644
--- a/arch/x86/kernel/cpu/vmware.c
+++ b/arch/x86/kernel/cpu/vmware.c
@@ -93,7 +93,7 @@ static void __init vmware_platform_setup(void)
93 * serial key should be enough, as this will always have a VMware 93 * serial key should be enough, as this will always have a VMware
94 * specific string when running under VMware hypervisor. 94 * specific string when running under VMware hypervisor.
95 */ 95 */
96static bool __init vmware_platform(void) 96static uint32_t __init vmware_platform(void)
97{ 97{
98 if (cpu_has_hypervisor) { 98 if (cpu_has_hypervisor) {
99 unsigned int eax; 99 unsigned int eax;
@@ -102,12 +102,12 @@ static bool __init vmware_platform(void)
102 cpuid(CPUID_VMWARE_INFO_LEAF, &eax, &hyper_vendor_id[0], 102 cpuid(CPUID_VMWARE_INFO_LEAF, &eax, &hyper_vendor_id[0],
103 &hyper_vendor_id[1], &hyper_vendor_id[2]); 103 &hyper_vendor_id[1], &hyper_vendor_id[2]);
104 if (!memcmp(hyper_vendor_id, "VMwareVMware", 12)) 104 if (!memcmp(hyper_vendor_id, "VMwareVMware", 12))
105 return true; 105 return CPUID_VMWARE_INFO_LEAF;
106 } else if (dmi_available && dmi_name_in_serial("VMware") && 106 } else if (dmi_available && dmi_name_in_serial("VMware") &&
107 __vmware_platform()) 107 __vmware_platform())
108 return true; 108 return 1;
109 109
110 return false; 110 return 0;
111} 111}
112 112
113/* 113/*
diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c
index a96d32cc55b8..7817afdac301 100644
--- a/arch/x86/kernel/kvm.c
+++ b/arch/x86/kernel/kvm.c
@@ -498,11 +498,9 @@ void __init kvm_guest_init(void)
498#endif 498#endif
499} 499}
500 500
501static bool __init kvm_detect(void) 501static uint32_t __init kvm_detect(void)
502{ 502{
503 if (!kvm_para_available()) 503 return kvm_cpuid_base();
504 return false;
505 return true;
506} 504}
507 505
508const struct hypervisor_x86 x86_hyper_kvm __refconst = { 506const struct hypervisor_x86 x86_hyper_kvm __refconst = {
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index 193097ef3d7d..2fcaedc0b739 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -1720,15 +1720,12 @@ static void __init xen_hvm_guest_init(void)
1720 xen_hvm_init_mmu_ops(); 1720 xen_hvm_init_mmu_ops();
1721} 1721}
1722 1722
1723static bool __init xen_hvm_platform(void) 1723static uint32_t __init xen_hvm_platform(void)
1724{ 1724{
1725 if (xen_pv_domain()) 1725 if (xen_pv_domain())
1726 return false; 1726 return 0;
1727
1728 if (!xen_cpuid_base())
1729 return false;
1730 1727
1731 return true; 1728 return xen_cpuid_base();
1732} 1729}
1733 1730
1734bool xen_hvm_need_lapic(void) 1731bool xen_hvm_need_lapic(void)