diff --git a/sys/dev/hyperv/vmbus/hv_et.c b/sys/dev/hyperv/vmbus/hv_et.c index fe7b33fffda2b5..be725740b56dc2 100644 --- a/sys/dev/hyperv/vmbus/hv_et.c +++ b/sys/dev/hyperv/vmbus/hv_et.c @@ -102,6 +102,12 @@ hv_et_intr(struct trapframe *frame) static void hv_et_identify (driver_t *driver, device_t parent) { + if (vm_guest != VM_GUEST_HV) + return; + + if (!(hv_features & HV_MSR_FEATURE_STIMER)) + return; + if (device_find_child(parent, "hv_et", -1) != NULL) return; diff --git a/sys/dev/hyperv/vmbus/hv_hv.c b/sys/dev/hyperv/vmbus/hv_hv.c index a78f3048ad5328..37f8588e4bd7c4 100644 --- a/sys/dev/hyperv/vmbus/hv_hv.c +++ b/sys/dev/hyperv/vmbus/hv_hv.c @@ -47,6 +47,8 @@ __FBSDID("$FreeBSD$"); #define HV_NANOSECONDS_PER_SEC 1000000000L +uint32_t hv_features; +uint32_t hv_recommendation; static u_int hv_get_timecount(struct timecounter *tc); @@ -76,32 +78,67 @@ hv_vmbus_query_hypervisor_presence(void) } /** - * @brief Get version of the windows hypervisor + * @brief Get information of the hypervisor + * @return 0 if hyperisor info is not present. */ static int -hv_vmbus_get_hypervisor_version(void) +hv_vmbus_get_hypervisor_info(void) { u_int regs[4]; unsigned int maxLeaf; unsigned int op; - /* - * Its assumed that this is called after confirming that - * Viridian is present - * Query id and revision. - */ op = HV_CPU_ID_FUNCTION_HV_VENDOR_AND_MAX_FUNCTION; do_cpuid(op, regs); maxLeaf = regs[0]; op = HV_CPU_ID_FUNCTION_HV_INTERFACE; do_cpuid(op, regs); + if (regs[0] != 0x31237648 /* HV#1 */ + || maxLeaf < HV_CPU_ID_FUNCTION_MS_HV_IMPLEMENTATION_LIMITS) + return (0); if (maxLeaf >= HV_CPU_ID_FUNCTION_MS_HV_VERSION) { - op = HV_CPU_ID_FUNCTION_MS_HV_VERSION; - do_cpuid(op, regs); + op = HV_CPU_ID_FUNCTION_MS_HV_VERSION; + do_cpuid(op, regs); + printf("Hyper-V Version: %d.%d.%d [SP%d]\n", + regs[1] >> 16, regs[1] & 0xffff, regs[0], regs[2]); + } + + if (maxLeaf >= HV_CPU_ID_FUNCTION_MS_HV_FEATURES) { + op = HV_CPU_ID_FUNCTION_MS_HV_FEATURES; + do_cpuid(op, regs); + hv_features = regs[0]; + if (bootverbose) + printf("Hyper-V Features: %08X %08X %08X %08X\n", + regs[0], regs[1], regs[2], regs[3]); + } + + if (maxLeaf >= HV_CPU_ID_FUNCTION_MS_HV_ENLIGHTENMENT_INFORMATION) { + op = HV_CPU_ID_FUNCTION_MS_HV_ENLIGHTENMENT_INFORMATION; + do_cpuid(op, regs); + hv_recommendation = regs[0]; + if (bootverbose) + printf("Hyper-V Recommendations: %08X %08X\n", regs[0], regs[1]); + } + + if (maxLeaf >= HV_CPU_ID_FUNCTION_MS_HV_IMPLEMENTATION_LIMITS) { + op = HV_CPU_ID_FUNCTION_MS_HV_IMPLEMENTATION_LIMITS; + do_cpuid(op, regs); + if (bootverbose) + printf("Hyper-V Limits: Vcpu:%d Lcpu:%d Int:%d\n", + regs[0], regs[1], regs[2]); } - return (maxLeaf); + + if (maxLeaf >= HV_CPU_ID_FUNCTION_MS_HV_HARDWARE_FEATURE) { + op = HV_CPU_ID_FUNCTION_MS_HV_HARDWARE_FEATURE; + do_cpuid(op, regs); + if (bootverbose) + printf("Hyper-V HW Features: %08x AMD: %08x\n", + regs[0], regs[3]); + } + + return (1); } /** @@ -151,14 +188,17 @@ hv_vmbus_do_hypercall(uint64_t control, void* input, void* output) static int hv_vmbus_init(void* context) { - int max_leaf; hv_vmbus_x64_msr_hypercall_contents hypercall_msr; void* virt_addr; if (vm_guest != VM_GUEST_HV) return (ENOTSUP); - max_leaf = hv_vmbus_get_hypervisor_version(); + if (!hv_vmbus_get_hypervisor_info()) + return (ENOTSUP); + + if (!(hv_features & HV_MSR_FEATURE_HYPERCALL)) + return (ENOTSUP); /* * Write our OS info @@ -188,6 +228,11 @@ hv_vmbus_init(void* context) hypercall_page = virt_addr; + if (hv_features & HV_MSR_FEATURE_REF_COUNT) { + /* register virtual timecounter */ + tc_init(&hv_timecounter); + } + return (0); cleanup: @@ -279,16 +324,5 @@ hv_vmbus_signal_event(void *con_id) return (status); } -static void -hv_tc_init(void) -{ - if (vm_guest != VM_GUEST_HV) - return; - - /* register virtual timecounter */ - tc_init(&hv_timecounter); -} - -SYSINIT(hv_tc_init, SI_SUB_HYPERVISOR, SI_ORDER_FIRST, hv_tc_init, NULL); -SYSINIT(hv_init, SI_SUB_HYPERVISOR, SI_ORDER_ANY, hv_vmbus_init, NULL); +SYSINIT(hv_init, SI_SUB_HYPERVISOR, SI_ORDER_FIRST, hv_vmbus_init, NULL); SYSUNINIT(hv_cleanup, SI_SUB_HYPERVISOR, SI_ORDER_ANY, hv_vmbus_cleanup, NULL); diff --git a/sys/dev/hyperv/vmbus/hv_vmbus_priv.h b/sys/dev/hyperv/vmbus/hv_vmbus_priv.h index 5287e63a02e775..ace494d27c9741 100644 --- a/sys/dev/hyperv/vmbus/hv_vmbus_priv.h +++ b/sys/dev/hyperv/vmbus/hv_vmbus_priv.h @@ -469,10 +469,17 @@ typedef enum { HV_CPU_ID_FUNCTION_MS_HV_VERSION = 0x40000002, HV_CPU_ID_FUNCTION_MS_HV_FEATURES = 0x40000003, HV_CPU_ID_FUNCTION_MS_HV_ENLIGHTENMENT_INFORMATION = 0x40000004, - HV_CPU_ID_FUNCTION_MS_HV_IMPLEMENTATION_LIMITS = 0x40000005 + HV_CPU_ID_FUNCTION_MS_HV_IMPLEMENTATION_LIMITS = 0x40000005, + HV_CPU_ID_FUNCTION_MS_HV_HARDWARE_FEATURE = 0x40000006 } hv_vmbus_cpuid_function; +#define HV_MSR_FEATURE_REF_COUNT (1 << 1) +#define HV_MSR_FEATURE_SYNCIC (1 << 2) +#define HV_MSR_FEATURE_STIMER (1 << 3) +#define HV_MSR_FEATURE_APIC (1 << 4) +#define HV_MSR_FEATURE_HYPERCALL (1 << 5) + /* * Define the format of the SIMP register */ @@ -623,6 +630,8 @@ typedef enum { /** * Global variables */ +extern uint32_t hv_features; +extern uint32_t hv_recommendation; extern hv_vmbus_context hv_vmbus_g_context; extern hv_vmbus_connection hv_vmbus_g_connection;