diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-09-04 14:05:13 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-09-04 14:05:13 -0400 |
commit | 05eebfb26bac9215410b70e0f043861aecff896c (patch) | |
tree | 3a6f63bad6d7dbc75d66bbb3f8deb4d5e40ef60c /arch/x86 | |
parent | cb3e4330e697dffaf3d9cefebc9c7e7d39c89f2e (diff) | |
parent | 9df56f19a500bea90d160be1bf77e4fbcd204d3f (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.h | 2 | ||||
-rw-r--r-- | arch/x86/include/asm/kvm_para.h | 24 | ||||
-rw-r--r-- | arch/x86/include/asm/processor.h | 15 | ||||
-rw-r--r-- | arch/x86/include/asm/xen/hypervisor.h | 16 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/hypervisor.c | 15 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/mshyperv.c | 13 | ||||
-rw-r--r-- | arch/x86/kernel/cpu/vmware.c | 8 | ||||
-rw-r--r-- | arch/x86/kernel/kvm.c | 6 | ||||
-rw-r--r-- | arch/x86/xen/enlighten.c | 9 |
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 | ||
88 | static inline bool kvm_para_available(void) | 88 | static 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; | 99 | static inline bool kvm_para_available(void) |
100 | { | ||
101 | return kvm_cpuid_base() != 0; | ||
108 | } | 102 | } |
109 | 103 | ||
110 | static inline unsigned int kvm_arch_para_features(void) | 104 | static 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 | ||
943 | extern u16 amd_get_nb_id(int cpu); | 943 | extern u16 amd_get_nb_id(int cpu); |
944 | 944 | ||
945 | static 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 | |||
945 | extern unsigned long arch_align_stack(unsigned long sp); | 960 | extern unsigned long arch_align_stack(unsigned long sp); |
946 | extern void free_init_pages(char *what, unsigned long begin, unsigned long end); | 961 | extern 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 | ||
41 | static inline uint32_t xen_cpuid_base(void) | 41 | static 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 | */ | ||
33 | static const __initconst struct hypervisor_x86 * const hypervisors[] = | 28 | static 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 | |||
49 | detect_hypervisor_vendor(void) | 44 | detect_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 | ||
63 | void init_hypervisor(struct cpuinfo_x86 *c) | 62 | void 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 @@ | |||
27 | struct ms_hyperv_info ms_hyperv; | 27 | struct ms_hyperv_info ms_hyperv; |
28 | EXPORT_SYMBOL_GPL(ms_hyperv); | 28 | EXPORT_SYMBOL_GPL(ms_hyperv); |
29 | 29 | ||
30 | static bool __init ms_hyperv_platform(void) | 30 | static 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 | ||
46 | static cycle_t read_hv_clock(struct clocksource *arg) | 49 | static 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 | */ |
96 | static bool __init vmware_platform(void) | 96 | static 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 | ||
501 | static bool __init kvm_detect(void) | 501 | static 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 | ||
508 | const struct hypervisor_x86 x86_hyper_kvm __refconst = { | 506 | const 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 | ||
1723 | static bool __init xen_hvm_platform(void) | 1723 | static 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 | ||
1734 | bool xen_hvm_need_lapic(void) | 1731 | bool xen_hvm_need_lapic(void) |