Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 16 Jun 2016 01:57:16 +0000 (UTC)
From:      Sepherosa Ziehau <sephe@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org
Subject:   svn commit: r301942 - stable/10/sys/dev/hyperv/vmbus
Message-ID:  <201606160157.u5G1vGkX020945@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: sephe
Date: Thu Jun 16 01:57:16 2016
New Revision: 301942
URL: https://svnweb.freebsd.org/changeset/base/301942

Log:
  MFC 297802,297803(297481),297804
  
  297802
      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
  
  279803(297481)
      hyperv: Register Hyper-V timer early enough for TSC freq calibration
  
      The i8254 simulation in Hyper-V is kinda broken and is not available
      in Generation 2 Hyper-V VMs, so Hyper-V timer must be registered early
      enough so that it can be used to do the TSC freq calibration.
  
      This fixes the notorious warning like this:
      calcru: runtime went backwards from 50 usec to 25 usec for pid 0 (kernel)
  
      Submitted by:       Dexuan Cui <decui microsoft com>
      Reviewed by:        kib, sephe
      Tested by:  kib, sephe
      MFC after:  1 week
      Sponsored by:       Microsoft OSTC
      Differential Revision:      https://reviews.freebsd.org/D5778
  
      =================
  
      hyperv: Resurrect r297481
  
      This time we make sure that the TIME_REF_COUNT MSR exists.
  
      Submitted by:       Jun Su <junsu microsoft com>
      Reviewed by:        sephe, Dexuan Cui <decui microsoft com>
      MFC after:  1 week
      Sponsored by:       Microsoft OSTC
  
  297804
      hyperv: Declare hyperv_{features,recommends} properly
  
      MFC after:  1 week
      Sponsored by:       Microsoft OSTC

Modified:
  stable/10/sys/dev/hyperv/vmbus/hv_hv.c
  stable/10/sys/dev/hyperv/vmbus/hv_vmbus_priv.h
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/sys/dev/hyperv/vmbus/hv_hv.c
==============================================================================
--- stable/10/sys/dev/hyperv/vmbus/hv_hv.c	Wed Jun 15 23:58:09 2016	(r301941)
+++ stable/10/sys/dev/hyperv/vmbus/hv_hv.c	Thu Jun 16 01:57:16 2016	(r301942)
@@ -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
  */
@@ -207,8 +211,6 @@ hv_vmbus_init(void) 
 
 	hv_vmbus_g_context.hypercall_page = virt_addr;
 
-	tc_init(&hv_timecounter); /* register virtual timecount */
-
 	hv_et_init();
 	
 	return (0);
@@ -423,3 +425,93 @@ 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;
+
+	if (hyperv_features & HV_FEATURE_MSR_TIME_REFCNT) {
+		/* Register virtual timecount */
+		tc_init(&hv_timecounter);
+	}
+}
+SYSINIT(hyperv_initialize, SI_SUB_HYPERVISOR, SI_ORDER_FIRST, hyperv_init, NULL);

Modified: stable/10/sys/dev/hyperv/vmbus/hv_vmbus_priv.h
==============================================================================
--- stable/10/sys/dev/hyperv/vmbus/hv_vmbus_priv.h	Wed Jun 15 23:58:09 2016	(r301941)
+++ stable/10/sys/dev/hyperv/vmbus/hv_vmbus_priv.h	Thu Jun 16 01:57:16 2016	(r301942)
@@ -470,10 +470,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
  */
@@ -627,6 +634,9 @@ typedef enum {
 extern hv_vmbus_context		hv_vmbus_g_context;
 extern hv_vmbus_connection	hv_vmbus_g_connection;
 
+extern u_int			hyperv_features;
+extern u_int			hyperv_recommends;
+
 typedef void (*vmbus_msg_handler)(hv_vmbus_channel_msg_header *msg);
 
 typedef struct hv_vmbus_channel_msg_table_entry {



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201606160157.u5G1vGkX020945>