1*fa1d1171SDavid Woodhouse // SPDX-License-Identifier: GPL-2.0 2*fa1d1171SDavid Woodhouse /* 3*fa1d1171SDavid Woodhouse * FreeBSD Bhyve guest enlightenments 4*fa1d1171SDavid Woodhouse * 5*fa1d1171SDavid Woodhouse * Copyright © 2025 Amazon.com, Inc. or its affiliates. 6*fa1d1171SDavid Woodhouse * 7*fa1d1171SDavid Woodhouse * Author: David Woodhouse <dwmw2@infradead.org> 8*fa1d1171SDavid Woodhouse */ 9*fa1d1171SDavid Woodhouse 10*fa1d1171SDavid Woodhouse #include <linux/init.h> 11*fa1d1171SDavid Woodhouse #include <linux/export.h> 12*fa1d1171SDavid Woodhouse #include <asm/processor.h> 13*fa1d1171SDavid Woodhouse #include <asm/hypervisor.h> 14*fa1d1171SDavid Woodhouse 15*fa1d1171SDavid Woodhouse static uint32_t bhyve_cpuid_base; 16*fa1d1171SDavid Woodhouse static uint32_t bhyve_cpuid_max; 17*fa1d1171SDavid Woodhouse 18*fa1d1171SDavid Woodhouse #define BHYVE_SIGNATURE "bhyve bhyve " 19*fa1d1171SDavid Woodhouse 20*fa1d1171SDavid Woodhouse #define CPUID_BHYVE_FEATURES 0x40000001 21*fa1d1171SDavid Woodhouse 22*fa1d1171SDavid Woodhouse /* Features advertised in CPUID_BHYVE_FEATURES %eax */ 23*fa1d1171SDavid Woodhouse 24*fa1d1171SDavid Woodhouse /* MSI Extended Dest ID */ 25*fa1d1171SDavid Woodhouse #define CPUID_BHYVE_FEAT_EXT_DEST_ID (1UL << 0) 26*fa1d1171SDavid Woodhouse bhyve_detect(void)27*fa1d1171SDavid Woodhousestatic uint32_t __init bhyve_detect(void) 28*fa1d1171SDavid Woodhouse { 29*fa1d1171SDavid Woodhouse if (!cpu_feature_enabled(X86_FEATURE_HYPERVISOR)) 30*fa1d1171SDavid Woodhouse return 0; 31*fa1d1171SDavid Woodhouse 32*fa1d1171SDavid Woodhouse bhyve_cpuid_base = cpuid_base_hypervisor(BHYVE_SIGNATURE, 0); 33*fa1d1171SDavid Woodhouse if (!bhyve_cpuid_base) 34*fa1d1171SDavid Woodhouse return 0; 35*fa1d1171SDavid Woodhouse 36*fa1d1171SDavid Woodhouse bhyve_cpuid_max = cpuid_eax(bhyve_cpuid_base); 37*fa1d1171SDavid Woodhouse return bhyve_cpuid_max; 38*fa1d1171SDavid Woodhouse } 39*fa1d1171SDavid Woodhouse bhyve_features(void)40*fa1d1171SDavid Woodhousestatic uint32_t bhyve_features(void) 41*fa1d1171SDavid Woodhouse { 42*fa1d1171SDavid Woodhouse unsigned int cpuid_leaf = bhyve_cpuid_base | CPUID_BHYVE_FEATURES; 43*fa1d1171SDavid Woodhouse 44*fa1d1171SDavid Woodhouse if (bhyve_cpuid_max < cpuid_leaf) 45*fa1d1171SDavid Woodhouse return 0; 46*fa1d1171SDavid Woodhouse 47*fa1d1171SDavid Woodhouse return cpuid_eax(cpuid_leaf); 48*fa1d1171SDavid Woodhouse } 49*fa1d1171SDavid Woodhouse bhyve_ext_dest_id(void)50*fa1d1171SDavid Woodhousestatic bool __init bhyve_ext_dest_id(void) 51*fa1d1171SDavid Woodhouse { 52*fa1d1171SDavid Woodhouse return !!(bhyve_features() & CPUID_BHYVE_FEAT_EXT_DEST_ID); 53*fa1d1171SDavid Woodhouse } 54*fa1d1171SDavid Woodhouse bhyve_x2apic_available(void)55*fa1d1171SDavid Woodhousestatic bool __init bhyve_x2apic_available(void) 56*fa1d1171SDavid Woodhouse { 57*fa1d1171SDavid Woodhouse return true; 58*fa1d1171SDavid Woodhouse } 59*fa1d1171SDavid Woodhouse 60*fa1d1171SDavid Woodhouse const struct hypervisor_x86 x86_hyper_bhyve __refconst = { 61*fa1d1171SDavid Woodhouse .name = "Bhyve", 62*fa1d1171SDavid Woodhouse .detect = bhyve_detect, 63*fa1d1171SDavid Woodhouse .init.init_platform = x86_init_noop, 64*fa1d1171SDavid Woodhouse .init.x2apic_available = bhyve_x2apic_available, 65*fa1d1171SDavid Woodhouse .init.msi_ext_dest_id = bhyve_ext_dest_id, 66*fa1d1171SDavid Woodhouse }; 67