x86/paravirt changes for v3.12
Subsystems (6)
Linus,
Please pull the latest x86-paravirt-for-linus git tree from:
git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git x86-paravirt-for-linus
HEAD: 9df56f19a500bea90d160be1bf77e4fbcd204d3f x86: Correctly detect hypervisor
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.
Thanks,
Ingo
------------------>
Jason Wang (4):
x86: Introduce hypervisor_cpuid_base()
xen: Switch to use hypervisor_cpuid_base() x86, kvm: Switch to use hypervisor_cpuid_base()
x86: Correctly detect hypervisor
arch/x86/include/asm/hypervisor.h | 2 +- arch/x86/include/asm/kvm_para.h | 24 +++++++++--------------- arch/x86/include/asm/processor.h | 15 +++++++++++++++ arch/x86/include/asm/xen/hypervisor.h | 16 +--------------- arch/x86/kernel/cpu/hypervisor.c | 15 +++++++-------- arch/x86/kernel/cpu/mshyperv.c | 13 ++++++++----- arch/x86/kernel/cpu/vmware.c | 8 ++++---- arch/x86/kernel/kvm.c | 6 ++---- arch/x86/xen/enlighten.c | 9 +++------ 9 files changed, 50 insertions(+), 58 deletions(-)
arch/x86/include/asm/hypervisor.h +1 -1
@@ -33,7 +33,7 @@ struct hypervisor_x86 {const char *name;/* Detection routine */ -bool (*detect)(void ); +uint32_t (*detect)(void );/* Adjust CPU feature bits (run once per CPU) */ void (*set_cpu_features)(struct cpuinfo_x86 *);
arch/x86/include/asm/kvm_para.h +9 -15
@@ -85,26 +85,20 @@ static inline long kvm_hypercall4(unsigned int nr, unsigned long p1,return ret; } -static inline bool kvm_para_available (void ) +static inline uint32_t kvm_cpuid_base (void ) { -unsigned int eax, ebx, ecx, edx; -char signature[13 ]; -if (boot_cpu_data.cpuid_level <0 ) -return false;/* So we don't blow up on old processors */ +return 0 ;/* So we don't blow up on old processors */ -if (cpu_has_hypervisor) { -cpuid (KVM_CPUID_SIGNATURE , &eax, &ebx, &ecx, &edx); -memcpy (signature +0 , &ebx,4 ); -memcpy (signature +4 , &ecx,4 ); -memcpy (signature +8 , &edx,4 ); - signature[12 ] =0 ; +if (cpu_has_hypervisor) +return hypervisor_cpuid_base ("KVMKVMKVM\0\0\0" ,0 ); -if (strcmp (signature,"KVMKVMKVM" ) ==0 ) -return true; - } +return 0 ; +} -return false; +static inline bool kvm_para_available (void ) +{ +return kvm_cpuid_base () !=0 ; }static inline unsigned int kvm_arch_para_features (void )
arch/x86/include/asm/processor.h +15 -0
@@ -971,6 +971,21 @@ unsigned long calc_aperfmperf_ratio(struct aperfmperf *old,return ratio; } +static inline uint32_t hypervisor_cpuid_base (const char *sig,uint32_t leaves) +{ +uint32_t base, eax, signature[3 ]; + +for (base =0x40000000 ; base <0x40010000 ; base +=0x100 ) { +cpuid (base, &eax, &signature[0 ], &signature[1 ], &signature[2 ]); + +if (!memcmp (sig, signature,12 ) && + (leaves ==0 || ((eax - base) >= leaves))) +return base; + } + +return 0 ; +} +extern unsigned long arch_align_stack (unsigned long sp);extern void free_init_pages (char *what,unsigned long begin,unsigned long end);
arch/x86/include/asm/xen/hypervisor.h +1 -15
@@ -40,21 +40,7 @@ extern struct start_info *xen_start_info;static inline uint32_t xen_cpuid_base (void ) { -uint32_t base, eax, ebx, ecx, edx; -char signature[13 ]; - -for (base =0x40000000 ; base <0x40010000 ; base +=0x100 ) { -cpuid (base, &eax, &ebx, &ecx, &edx); - *(uint32_t *)(signature +0 ) = ebx; - *(uint32_t *)(signature +4 ) = ecx; - *(uint32_t *)(signature +8 ) = edx; - signature[12 ] =0 ; - -if (!strcmp ("XenVMMXenVMM" , signature) && ((eax - base) >=2 )) -return base; - } - -return 0 ; +return hypervisor_cpuid_base ("XenVMMXenVMM" ,2 ); }#ifdef CONFIG_XEN
arch/x86/kernel/cpu/hypervisor.c +7 -8
@@ -25,11 +25,6 @@#include <asm/processor.h> #include <asm/hypervisor.h> -/* -* Hypervisor detect order. This is specified explicitly here because -* some hypervisors might implement compatibility modes for other -* hypervisors and therefore need to be detected in specific sequence. -*/ static const __initconst struct hypervisor_x86 *const hypervisors[] = { #ifdef CONFIG_XEN_PVHVM
@@ -49,15 +44,19 @@ static inline void __initdetect_hypervisor_vendor (void) {const struct hypervisor_x86 *h, *const *p; +uint32_t pri, max_pri =0 ;for (p = hypervisors; p < hypervisors +ARRAY_SIZE (hypervisors); p++) { h = *p; -if (h->detect ()) { + pri = h->detect (); +if (pri !=0 && pri > max_pri) { + max_pri = pri; x86_hyper = h; -printk (KERN_INFO "Hypervisor detected: %s\n" , h->name); -break ; } } + +if (max_pri) +printk (KERN_INFO "Hypervisor detected: %s\n" , x86_hyper->name); }void init_hypervisor (struct cpuinfo_x86 *c)
arch/x86/kernel/cpu/mshyperv.c +8 -5
@@ -27,20 +27,23 @@struct ms_hyperv_info ms_hyperv;EXPORT_SYMBOL_GPL (ms_hyperv); -static bool __init ms_hyperv_platform (void ) +static uint32_t __init ms_hyperv_platform (void ) {u32 eax;u32 hyp_signature[3 ];if (!boot_cpu_has (X86_FEATURE_HYPERVISOR )) -return false; +return 0 ;cpuid (HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS , &eax, &hyp_signature[0 ], &hyp_signature[1 ], &hyp_signature[2 ]); -return eax >=HYPERV_CPUID_MIN && - eax <=HYPERV_CPUID_MAX && - !memcmp ("Microsoft Hv" , hyp_signature,12 ); +if (eax >=HYPERV_CPUID_MIN && + eax <=HYPERV_CPUID_MAX && + !memcmp ("Microsoft Hv" , hyp_signature,12 )) +return HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS ; + +return 0 ; }static cycle_t read_hv_clock (struct clocksource *arg)
arch/x86/kernel/cpu/vmware.c +4 -4
@@ -93,7 +93,7 @@ static void __init vmware_platform_setup(void)* serial key should be enough, as this will always have a VMware * specific string when running under VMware hypervisor. */ -static bool __init vmware_platform (void ) +static uint32_t __init vmware_platform (void ) {if (cpu_has_hypervisor) {unsigned int eax;
@@ -102,12 +102,12 @@ static bool __init vmware_platform(void)cpuid (CPUID_VMWARE_INFO_LEAF , &eax, &hyper_vendor_id[0 ], &hyper_vendor_id[1 ], &hyper_vendor_id[2 ]);if (!memcmp (hyper_vendor_id,"VMwareVMware" ,12 )) -return true; +return CPUID_VMWARE_INFO_LEAF ; }else if (dmi_available &&dmi_name_in_serial ("VMware" ) &&__vmware_platform ()) -return true; +return 1 ; -return false; +return 0 ; }/*
arch/x86/kernel/kvm.c +2 -4
@@ -498,11 +498,9 @@ void __init kvm_guest_init(void)#endif } -static bool __init kvm_detect (void ) +static uint32_t __init kvm_detect (void ) { -if (!kvm_para_available ()) -return false; -return true; +return kvm_cpuid_base (); }const struct hypervisor_x86 x86_hyper_kvm__refconst = {
arch/x86/xen/enlighten.c +3 -6
@@ -1720,15 +1720,12 @@ static void __init xen_hvm_guest_init(void)xen_hvm_init_mmu_ops (); } -static bool __init xen_hvm_platform (void ) +static uint32_t __init xen_hvm_platform (void ) {if (xen_pv_domain ()) -return false; - -if (!xen_cpuid_base ()) -return false; +return 0 ; -return true; +return xen_cpuid_base (); }bool xen_hvm_need_lapic (void )