mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-14 17:35:42 +00:00
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()
This commit is contained in:
commit
05eebfb26b
@ -33,7 +33,7 @@ struct hypervisor_x86 {
|
|||||||
const char *name;
|
const char *name;
|
||||||
|
|
||||||
/* Detection routine */
|
/* Detection routine */
|
||||||
bool (*detect)(void);
|
uint32_t (*detect)(void);
|
||||||
|
|
||||||
/* Adjust CPU feature bits (run once per CPU) */
|
/* Adjust CPU feature bits (run once per CPU) */
|
||||||
void (*set_cpu_features)(struct cpuinfo_x86 *);
|
void (*set_cpu_features)(struct cpuinfo_x86 *);
|
||||||
|
@ -85,26 +85,20 @@ static inline long kvm_hypercall4(unsigned int nr, unsigned long p1,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline uint32_t kvm_cpuid_base(void)
|
||||||
|
{
|
||||||
|
if (boot_cpu_data.cpuid_level < 0)
|
||||||
|
return 0; /* So we don't blow up on old processors */
|
||||||
|
|
||||||
|
if (cpu_has_hypervisor)
|
||||||
|
return hypervisor_cpuid_base("KVMKVMKVM\0\0\0", 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static inline bool kvm_para_available(void)
|
static inline bool kvm_para_available(void)
|
||||||
{
|
{
|
||||||
unsigned int eax, ebx, ecx, edx;
|
return kvm_cpuid_base() != 0;
|
||||||
char signature[13];
|
|
||||||
|
|
||||||
if (boot_cpu_data.cpuid_level < 0)
|
|
||||||
return false; /* 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 (strcmp(signature, "KVMKVMKVM") == 0)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline unsigned int kvm_arch_para_features(void)
|
static inline unsigned int kvm_arch_para_features(void)
|
||||||
|
@ -942,6 +942,21 @@ extern int set_tsc_mode(unsigned int val);
|
|||||||
|
|
||||||
extern u16 amd_get_nb_id(int cpu);
|
extern u16 amd_get_nb_id(int cpu);
|
||||||
|
|
||||||
|
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 unsigned long arch_align_stack(unsigned long sp);
|
||||||
extern void free_init_pages(char *what, unsigned long begin, unsigned long end);
|
extern void free_init_pages(char *what, unsigned long begin, unsigned long end);
|
||||||
|
|
||||||
|
@ -40,21 +40,7 @@ extern struct start_info *xen_start_info;
|
|||||||
|
|
||||||
static inline uint32_t xen_cpuid_base(void)
|
static inline uint32_t xen_cpuid_base(void)
|
||||||
{
|
{
|
||||||
uint32_t base, eax, ebx, ecx, edx;
|
return hypervisor_cpuid_base("XenVMMXenVMM", 2);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_XEN
|
#ifdef CONFIG_XEN
|
||||||
|
@ -25,11 +25,6 @@
|
|||||||
#include <asm/processor.h>
|
#include <asm/processor.h>
|
||||||
#include <asm/hypervisor.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[] =
|
static const __initconst struct hypervisor_x86 * const hypervisors[] =
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_XEN_PVHVM
|
#ifdef CONFIG_XEN_PVHVM
|
||||||
@ -49,15 +44,19 @@ static inline void __init
|
|||||||
detect_hypervisor_vendor(void)
|
detect_hypervisor_vendor(void)
|
||||||
{
|
{
|
||||||
const struct hypervisor_x86 *h, * const *p;
|
const struct hypervisor_x86 *h, * const *p;
|
||||||
|
uint32_t pri, max_pri = 0;
|
||||||
|
|
||||||
for (p = hypervisors; p < hypervisors + ARRAY_SIZE(hypervisors); p++) {
|
for (p = hypervisors; p < hypervisors + ARRAY_SIZE(hypervisors); p++) {
|
||||||
h = *p;
|
h = *p;
|
||||||
if (h->detect()) {
|
pri = h->detect();
|
||||||
|
if (pri != 0 && pri > max_pri) {
|
||||||
|
max_pri = pri;
|
||||||
x86_hyper = h;
|
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)
|
void init_hypervisor(struct cpuinfo_x86 *c)
|
||||||
|
@ -27,20 +27,23 @@
|
|||||||
struct ms_hyperv_info ms_hyperv;
|
struct ms_hyperv_info ms_hyperv;
|
||||||
EXPORT_SYMBOL_GPL(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 eax;
|
||||||
u32 hyp_signature[3];
|
u32 hyp_signature[3];
|
||||||
|
|
||||||
if (!boot_cpu_has(X86_FEATURE_HYPERVISOR))
|
if (!boot_cpu_has(X86_FEATURE_HYPERVISOR))
|
||||||
return false;
|
return 0;
|
||||||
|
|
||||||
cpuid(HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS,
|
cpuid(HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS,
|
||||||
&eax, &hyp_signature[0], &hyp_signature[1], &hyp_signature[2]);
|
&eax, &hyp_signature[0], &hyp_signature[1], &hyp_signature[2]);
|
||||||
|
|
||||||
return eax >= HYPERV_CPUID_MIN &&
|
if (eax >= HYPERV_CPUID_MIN &&
|
||||||
eax <= HYPERV_CPUID_MAX &&
|
eax <= HYPERV_CPUID_MAX &&
|
||||||
!memcmp("Microsoft Hv", hyp_signature, 12);
|
!memcmp("Microsoft Hv", hyp_signature, 12))
|
||||||
|
return HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS;
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static cycle_t read_hv_clock(struct clocksource *arg)
|
static cycle_t read_hv_clock(struct clocksource *arg)
|
||||||
|
@ -93,7 +93,7 @@ static void __init vmware_platform_setup(void)
|
|||||||
* serial key should be enough, as this will always have a VMware
|
* serial key should be enough, as this will always have a VMware
|
||||||
* specific string when running under VMware hypervisor.
|
* specific string when running under VMware hypervisor.
|
||||||
*/
|
*/
|
||||||
static bool __init vmware_platform(void)
|
static uint32_t __init vmware_platform(void)
|
||||||
{
|
{
|
||||||
if (cpu_has_hypervisor) {
|
if (cpu_has_hypervisor) {
|
||||||
unsigned int eax;
|
unsigned int eax;
|
||||||
@ -102,12 +102,12 @@ static bool __init vmware_platform(void)
|
|||||||
cpuid(CPUID_VMWARE_INFO_LEAF, &eax, &hyper_vendor_id[0],
|
cpuid(CPUID_VMWARE_INFO_LEAF, &eax, &hyper_vendor_id[0],
|
||||||
&hyper_vendor_id[1], &hyper_vendor_id[2]);
|
&hyper_vendor_id[1], &hyper_vendor_id[2]);
|
||||||
if (!memcmp(hyper_vendor_id, "VMwareVMware", 12))
|
if (!memcmp(hyper_vendor_id, "VMwareVMware", 12))
|
||||||
return true;
|
return CPUID_VMWARE_INFO_LEAF;
|
||||||
} else if (dmi_available && dmi_name_in_serial("VMware") &&
|
} else if (dmi_available && dmi_name_in_serial("VMware") &&
|
||||||
__vmware_platform())
|
__vmware_platform())
|
||||||
return true;
|
return 1;
|
||||||
|
|
||||||
return false;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -498,11 +498,9 @@ void __init kvm_guest_init(void)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool __init kvm_detect(void)
|
static uint32_t __init kvm_detect(void)
|
||||||
{
|
{
|
||||||
if (!kvm_para_available())
|
return kvm_cpuid_base();
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct hypervisor_x86 x86_hyper_kvm __refconst = {
|
const struct hypervisor_x86 x86_hyper_kvm __refconst = {
|
||||||
|
@ -1720,15 +1720,12 @@ static void __init xen_hvm_guest_init(void)
|
|||||||
xen_hvm_init_mmu_ops();
|
xen_hvm_init_mmu_ops();
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool __init xen_hvm_platform(void)
|
static uint32_t __init xen_hvm_platform(void)
|
||||||
{
|
{
|
||||||
if (xen_pv_domain())
|
if (xen_pv_domain())
|
||||||
return false;
|
return 0;
|
||||||
|
|
||||||
if (!xen_cpuid_base())
|
return xen_cpuid_base();
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool xen_hvm_need_lapic(void)
|
bool xen_hvm_need_lapic(void)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user