Author: sephe
Date: Mon Apr 11 03:28:17 2016
New Revision: 297802
URL: https://svnweb.freebsd.org/changeset/base/297802

Log:
  hyperv: Identify Hyper-V features and recommends properly
  
  Features bits will be used to detect devices, e.g. timers, which
  do not have corresponding event channels.
  
  Submitted by: Jun Su <junsu microsoft com>
  Reviewed by:  sephe, Dexuan Cui <decui microsoft com>
  Rearranged by:        sephe
  MFC after:    1 week
  Sponsored by: Microsoft OSTC

Modified:
  head/sys/dev/hyperv/vmbus/hv_hv.c
  head/sys/dev/hyperv/vmbus/hv_vmbus_priv.h

Modified: head/sys/dev/hyperv/vmbus/hv_hv.c
==============================================================================
--- head/sys/dev/hyperv/vmbus/hv_hv.c   Mon Apr 11 03:14:28 2016        
(r297801)
+++ head/sys/dev/hyperv/vmbus/hv_hv.c   Mon Apr 11 03:28:17 2016        
(r297802)
@@ -33,6 +33,7 @@
 __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
+#include <sys/kernel.h>
 #include <sys/malloc.h>
 #include <sys/pcpu.h>
 #include <sys/timetc.h>
@@ -50,6 +51,9 @@ __FBSDID("$FreeBSD$");
 
 static u_int hv_get_timecount(struct timecounter *tc);
 
+u_int  hyperv_features;
+u_int  hyperv_recommends;
+
 /**
  * Globals
  */
@@ -393,3 +397,88 @@ void hv_vmbus_synic_cleanup(void *arg)
        wrmsr(HV_X64_MSR_SIEFP, siefp.as_uint64_t);
 }
 
+static bool
+hyperv_identify(void)
+{
+       u_int regs[4];
+       unsigned int maxLeaf;
+       unsigned int op;
+
+       if (vm_guest != VM_GUEST_HV)
+               return (false);
+
+       op = HV_CPU_ID_FUNCTION_HV_VENDOR_AND_MAX_FUNCTION;
+       do_cpuid(op, regs);
+       maxLeaf = regs[0];
+       if (maxLeaf < HV_CPU_ID_FUNCTION_MS_HV_IMPLEMENTATION_LIMITS)
+               return (false);
+
+       op = HV_CPU_ID_FUNCTION_HV_INTERFACE;
+       do_cpuid(op, regs);
+       if (regs[0] != 0x31237648 /* HV#1 */)
+               return (false);
+
+       op = HV_CPU_ID_FUNCTION_MS_HV_FEATURES;
+       do_cpuid(op, regs);
+       if ((regs[0] & HV_FEATURE_MSR_HYPERCALL) == 0) {
+               /*
+                * Hyper-V w/o Hypercall is impossible; someone
+                * is faking Hyper-V.
+                */
+               return (false);
+       }
+       hyperv_features = regs[0];
+
+       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]);
+
+       printf("  Features: 0x%b\n", hyperv_features,
+           "\020"
+           "\001VPRUNTIME"
+           "\002TMREFCNT"
+           "\003SYNCIC"
+           "\004SYNCTM"
+           "\005APIC"
+           "\006HYERCALL"
+           "\007VPINDEX"
+           "\010RESET"
+           "\011STATS"
+           "\012REFTSC"
+           "\013IDLE"
+           "\014TMFREQ"
+           "\015DEBUG");
+
+       op = HV_CPU_ID_FUNCTION_MS_HV_ENLIGHTENMENT_INFORMATION;
+       do_cpuid(op, regs);
+       hyperv_recommends = regs[0];
+       if (bootverbose)
+               printf("  Recommends: %08x %08x\n", regs[0], regs[1]);
+
+       op = HV_CPU_ID_FUNCTION_MS_HV_IMPLEMENTATION_LIMITS;
+       do_cpuid(op, regs);
+       if (bootverbose) {
+               printf("  Limits: Vcpu:%d Lcpu:%d Int:%d\n",
+                   regs[0], regs[1], regs[2]);
+       }
+
+       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("  HW Features: %08x AMD: %08x\n",
+                           regs[0], regs[3]);
+               }
+       }
+
+       return (true);
+}
+
+static void
+hyperv_init(void *dummy __unused)
+{
+       if (!hyperv_identify())
+               return;
+}
+SYSINIT(hyperv_initialize, SI_SUB_HYPERVISOR, SI_ORDER_FIRST, hyperv_init, 
NULL);

Modified: head/sys/dev/hyperv/vmbus/hv_vmbus_priv.h
==============================================================================
--- head/sys/dev/hyperv/vmbus/hv_vmbus_priv.h   Mon Apr 11 03:14:28 2016        
(r297801)
+++ head/sys/dev/hyperv/vmbus/hv_vmbus_priv.h   Mon Apr 11 03:28:17 2016        
(r297802)
@@ -471,10 +471,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_FEATURE_MSR_TIME_REFCNT      (1 << 1)
+#define        HV_FEATURE_MSR_SYNCIC           (1 << 2)
+#define        HV_FEATURE_MSR_STIMER           (1 << 3)
+#define        HV_FEATURE_MSR_APIC             (1 << 4)
+#define        HV_FEATURE_MSR_HYPERCALL        (1 << 5)
+#define        HV_FEATURE_MSR_GUEST_IDLE       (1 << 10)
+
 /*
  * Define the format of the SIMP register
  */
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to