diff options
Diffstat (limited to 'arch/x86/kernel/cpu/hypervisor.c')
| -rw-r--r-- | arch/x86/kernel/cpu/hypervisor.c | 84 |
1 files changed, 54 insertions, 30 deletions
diff --git a/arch/x86/kernel/cpu/hypervisor.c b/arch/x86/kernel/cpu/hypervisor.c index 1e7e84a02eba..f3e9219845e8 100644 --- a/arch/x86/kernel/cpu/hypervisor.c +++ b/arch/x86/kernel/cpu/hypervisor.c @@ -21,17 +21,16 @@ * */ -#include <linux/module.h> +#include <linux/init.h> +#include <linux/export.h> #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_PV + &x86_hyper_xen_pv, +#endif #ifdef CONFIG_XEN_PVHVM &x86_hyper_xen_hvm, #endif @@ -40,49 +39,74 @@ static const __initconst struct hypervisor_x86 * const hypervisors[] = #ifdef CONFIG_KVM_GUEST &x86_hyper_kvm, #endif +#ifdef CONFIG_JAILHOUSE_GUEST + &x86_hyper_jailhouse, +#endif +#ifdef CONFIG_ACRN_GUEST + &x86_hyper_acrn, +#endif +#ifdef CONFIG_BHYVE_GUEST + &x86_hyper_bhyve, +#endif }; -const struct hypervisor_x86 *x86_hyper; -EXPORT_SYMBOL(x86_hyper); +enum x86_hypervisor_type x86_hyper_type; +EXPORT_SYMBOL(x86_hyper_type); + +bool __initdata nopv; +static __init int parse_nopv(char *arg) +{ + nopv = true; + return 0; +} +early_param("nopv", parse_nopv); -static inline void __init +static inline const struct hypervisor_x86 * __init detect_hypervisor_vendor(void) { - const struct hypervisor_x86 *h, * const *p; + const struct hypervisor_x86 *h = NULL, * const *p; + uint32_t pri, max_pri = 0; for (p = hypervisors; p < hypervisors + ARRAY_SIZE(hypervisors); p++) { - h = *p; - if (h->detect()) { - x86_hyper = h; - printk(KERN_INFO "Hypervisor detected: %s\n", h->name); - break; + if (unlikely(nopv) && !(*p)->ignore_nopv) + continue; + + pri = (*p)->detect(); + if (pri > max_pri) { + max_pri = pri; + h = *p; } } + + if (h) + pr_info("Hypervisor detected: %s\n", h->name); + + return h; } -void __cpuinit init_hypervisor(struct cpuinfo_x86 *c) +static void __init copy_array(const void *src, void *target, unsigned int size) { - if (x86_hyper && x86_hyper->set_cpu_features) - x86_hyper->set_cpu_features(c); + unsigned int i, n = size / sizeof(void *); + const void * const *from = (const void * const *)src; + const void **to = (const void **)target; + + for (i = 0; i < n; i++) + if (from[i]) + to[i] = from[i]; } void __init init_hypervisor_platform(void) { + const struct hypervisor_x86 *h; - detect_hypervisor_vendor(); + h = detect_hypervisor_vendor(); - if (!x86_hyper) + if (!h) return; - init_hypervisor(&boot_cpu_data); - - if (x86_hyper->init_platform) - x86_hyper->init_platform(); -} + copy_array(&h->init, &x86_init.hyper, sizeof(h->init)); + copy_array(&h->runtime, &x86_platform.hyper, sizeof(h->runtime)); -bool __init hypervisor_x2apic_available(void) -{ - return x86_hyper && - x86_hyper->x2apic_available && - x86_hyper->x2apic_available(); + x86_hyper_type = h->type; + x86_init.hyper.init_platform(); } |
