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
This commit is contained in:
Sepherosa Ziehau 2016-06-16 01:57:16 +00:00
parent 239f8613e0
commit 88ac3302e3
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/stable/10/; revision=301942
2 changed files with 106 additions and 4 deletions

View File

@ -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);

View File

@ -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 {