mirror of
https://github.com/freebsd/freebsd-src.git
synced 2024-12-03 14:48:57 +00:00
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:
parent
239f8613e0
commit
88ac3302e3
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/stable/10/; revision=301942
@ -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);
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user