Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F144232486
D35575.id.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
8 KB
Referenced Files
None
Subscribers
None
D35575.id.diff
View Options
diff --git a/sys/amd64/vmm/intel/vmx.c b/sys/amd64/vmm/intel/vmx.c
--- a/sys/amd64/vmm/intel/vmx.c
+++ b/sys/amd64/vmm/intel/vmx.c
@@ -292,6 +292,9 @@
SDT_PROBE_DEFINE3(vmm, vmx, exit, vminsn,
"struct vmx *", "int", "struct vm_exit *");
+SDT_PROBE_DEFINE3(vmm, vmx, exit, vmcall,
+ "struct vmx *", "int", "struct vm_exit *");
+
SDT_PROBE_DEFINE4(vmm, vmx, exit, unknown,
"struct vmx *", "int", "struct vm_exit *", "uint32_t");
@@ -2765,7 +2768,6 @@
vmexit->inst_length = 0;
handled = HANDLED;
break;
- case EXIT_REASON_VMCALL:
case EXIT_REASON_VMCLEAR:
case EXIT_REASON_VMLAUNCH:
case EXIT_REASON_VMPTRLD:
@@ -2778,6 +2780,11 @@
SDT_PROBE3(vmm, vmx, exit, vminsn, vmx, vcpu, vmexit);
vmexit->exitcode = VM_EXITCODE_VMINSN;
break;
+ case EXIT_REASON_VMCALL:
+ SDT_PROBE3(vmm, vmx, exit, vmcall, vmx, vcpu, vmexit);
+ vmexit->exitcode = 0;
+ handled = HANDLED;
+ break;
default:
SDT_PROBE4(vmm, vmx, exit, unknown,
vmx, vcpu, vmexit, reason);
diff --git a/sys/amd64/vmm/intel/vmx_msr.c b/sys/amd64/vmm/intel/vmx_msr.c
--- a/sys/amd64/vmm/intel/vmx_msr.c
+++ b/sys/amd64/vmm/intel/vmx_msr.c
@@ -409,6 +409,20 @@
wrmsr(MSR_TSC_AUX, host_aux);
}
+#define HV_X64_MSR_GUEST_OS_ID 0x40000000
+#define HV_X64_MSR_HYPERCALL 0x40000001
+
+/* MSR used to provide vcpu index */
+#define HV_REGISTER_VP_INDEX 0x40000002
+#define HV_X64_MSR_TIME_REF_COUNT 0x40000020
+#define HV_X64_MSR_REFERENCE_TSC 0x40000021
+#define HV_X64_MSR_TSC_FREQUENCY 0x40000022
+
+/* MSR used to retrieve the local APIC timer frequency */
+#define HV_X64_MSR_APIC_FREQUENCY 0x40000023
+
+#define APIC_BUS_FREQUENCY (1000000000ULL)
+
int
vmx_rdmsr(struct vmx *vmx, int vcpuid, u_int num, uint64_t *val, bool *retu)
{
@@ -419,6 +433,21 @@
error = 0;
switch (num) {
+ case HV_X64_MSR_TIME_REF_COUNT: {
+ /* Hyper-V reports time in 100ns units (10 MHz) */
+ uint64_t tsc_per_100ns = (tsc_freq / 10000000UL) ? : 1;
+ *val = (rdtsc() / tsc_per_100ns);
+ break;
+ }
+ case HV_X64_MSR_APIC_FREQUENCY:
+ *val = APIC_BUS_FREQUENCY;
+ break;
+ case HV_REGISTER_VP_INDEX:
+ *val = vcpuid;
+ break;
+ case HV_X64_MSR_TSC_FREQUENCY:
+ *val = tsc_freq;
+ break;
case MSR_MCG_CAP:
case MSR_MCG_STATUS:
*val = 0;
diff --git a/sys/amd64/vmm/x86.c b/sys/amd64/vmm/x86.c
--- a/sys/amd64/vmm/x86.c
+++ b/sys/amd64/vmm/x86.c
@@ -53,7 +53,7 @@
static SYSCTL_NODE(_hw_vmm, OID_AUTO, topology, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
NULL);
-#define CPUID_VM_HIGH 0x40000000
+#define CPUID_VM_HIGH 0x40000005
static const char bhyve_id[12] = "bhyve bhyve ";
@@ -115,8 +115,9 @@
if (func > cpu_exthigh)
func = cpu_exthigh;
} else if (func >= 0x40000000) {
- if (func > CPUID_VM_HIGH)
+ if (func > CPUID_VM_HIGH) {
func = CPUID_VM_HIGH;
+ }
} else if (func > cpu_high) {
func = cpu_high;
}
@@ -605,14 +606,64 @@
regs[2] = 0;
regs[3] = 0;
break;
-
- case 0x40000000:
+#define HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS 0x40000000
+ case HYPERV_CPUID_VENDOR_AND_MAX_FUNCTIONS:
regs[0] = CPUID_VM_HIGH;
bcopy(bhyve_id, ®s[1], 4);
bcopy(bhyve_id + 4, ®s[2], 4);
bcopy(bhyve_id + 8, ®s[3], 4);
break;
+#define HYPERV_CPUID_INTERFACE 0x40000001
+ case HYPERV_CPUID_INTERFACE:
+ /* "Hv#1" signature */
+#define HYPERV_CPUID_SIGNATURE_EAX 0x31237648
+ regs[0] = HYPERV_CPUID_SIGNATURE_EAX;
+ regs[1] = regs[2] = regs[3] = 0;
+ break;
+
+#define HYPERV_CPUID_VERSION 0x40000002
+ case HYPERV_CPUID_VERSION:
+ regs[0] = regs[1] = regs[2] = regs[3] = 0;
+ regs[0] = 0x00003839;
+ regs[1] = 0x000A0000;
+ break;
+
+#define HYPERV_CPUID_FEATURES 0x40000003
+#define HV_MSR_TIME_REF_COUNT_AVAILABLE (1U << 1)
+#define HV_MSR_HYPERCALL_AVAILABLE (1U << 5)
+#define HV_MSR_VP_INDEX_AVAILABLE (1U << 6)
+#define HV_ACCESS_FREQUENCY_MSRS (1U << 11)
+#define HV_MSR_REFERENCE_TSC_AVAILABLE (1U << 9)
+#define HV_FEATURE_FREQUENCY_MSRS_AVAILABLE (1 << 8)
+ case HYPERV_CPUID_FEATURES:
+ regs[0] = regs[1] = regs[2] = regs[3] = 0;
+ regs[0] |= HV_MSR_TIME_REF_COUNT_AVAILABLE;
+ regs[0] |= HV_MSR_HYPERCALL_AVAILABLE;
+ regs[0] |= HV_MSR_VP_INDEX_AVAILABLE;
+ regs[0] |= HV_MSR_REFERENCE_TSC_AVAILABLE;
+ regs[0] |= HV_ACCESS_FREQUENCY_MSRS;
+ regs[3] |= HV_FEATURE_FREQUENCY_MSRS_AVAILABLE;
+ break;
+
+#define HYPERV_CPUID_ENLIGHTMENT_INFO 0x40000004
+#define HYPERV_CPUID_IMPLEMENT_LIMITS 0x40000005
+#define HYPERV_RELAXED_TIMING_RECOMMENDED (1UL << 5)
+ case HYPERV_CPUID_ENLIGHTMENT_INFO:
+ regs[0] = HYPERV_RELAXED_TIMING_RECOMMENDED;
+ regs[1] = 0xffffffff; /* spinlock retry: never notify hypervisor */
+ regs[2] = regs[3] = 0;
+ break;
+ case HYPERV_CPUID_IMPLEMENT_LIMITS:
+ /* Maximum number of virtual processors */
+ regs[0] = VM_MAXCPU;
+
+ /* Maximum number of logical processors */
+ regs[1] = VM_MAXCPU;
+
+ regs[2] = regs[3] = 0;
+ break;
+
default:
default_leaf:
/*
diff --git a/usr.sbin/bhyve/xmsr.c b/usr.sbin/bhyve/xmsr.c
--- a/usr.sbin/bhyve/xmsr.c
+++ b/usr.sbin/bhyve/xmsr.c
@@ -36,21 +36,83 @@
#include <machine/cpufunc.h>
#include <machine/vmm.h>
#include <machine/specialreg.h>
+#include <machine/atomic.h>
#include <vmmapi.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <err.h>
#include "debug.h"
#include "xmsr.h"
static int cpu_vendor_intel, cpu_vendor_amd, cpu_vendor_hygon;
+static uint64_t tsc_ref;
+static uint64_t hypercall;
+static uint64_t guest_os_id;
+static uint64_t freq_khz;
+
+struct ms_hyperv_tsc_page {
+ volatile uint32_t tsc_sequence;
+ uint32_t reserved1;
+ volatile uint64_t tsc_scale;
+ volatile int64_t tsc_offset;
+} __packed;
+
+#define HV_X64_MSR_GUEST_OS_ID 0x40000000
+#define HV_X64_MSR_HYPERCALL 0x40000001
+#define HV_X64_MSR_REFERENCE_TSC 0x40000021
+
+#define HV_X64_MSR_HYPERCALL_ENABLE 0x0001
int
emulate_wrmsr(struct vmctx *ctx, int vcpu, uint32_t num, uint64_t val)
{
+ /* Hyper-V MSR-s */
+ switch (num) {
+ case HV_X64_MSR_HYPERCALL: {
+ void *base;
+ uint64_t gpa = val & (~((1ULL << 12) - 1));
+
+ if (guest_os_id == 0)
+ return (0);
+
+ if (!(val & HV_X64_MSR_HYPERCALL_ENABLE)) {
+ hypercall = val;
+ return (0);
+ }
+
+ base = vm_map_gpa(ctx, gpa, PAGE_SIZE);
+ assert(base != NULL);
+
+ if (cpu_vendor_intel) {
+ const uint8_t hypercall_intel[] = { 0x0F, 0x01, 0xC1, 0xC3 }; /* VMCALL */
+
+ memcpy(base, hypercall_intel, sizeof (hypercall_intel));
+ } else if (cpu_vendor_amd || cpu_vendor_hygon) {
+ const uint8_t hypercall_amd[] = { 0x0F, 0x01, 0xD9, 0xC3 }; /* VMMCALL */;
+
+ memcpy(base, hypercall_amd, sizeof (hypercall_amd));
+ } else {
+ return (-1);
+ }
+ return (0);
+ }
+ case HV_X64_MSR_GUEST_OS_ID:
+ guest_os_id = val;
+ if (guest_os_id == 0) {
+ hypercall &= ~HV_X64_MSR_HYPERCALL_ENABLE;
+ }
+ return (0);
+ default:
+ break;
+ }
+
if (cpu_vendor_intel) {
switch (num) {
@@ -61,6 +123,31 @@
return (0);
case MSR_BIOS_SIGN:
return (0);
+ case HV_X64_MSR_REFERENCE_TSC:
+ {
+ if (val & 0x1) {
+ struct ms_hyperv_tsc_page *tsp;
+ uint64_t gpa;
+ uint32_t seq;
+
+ gpa = val & (~((1ULL << 12) - 1));
+ tsp = vm_map_gpa(ctx, gpa, PAGE_SIZE);
+ assert(tsp != NULL);
+
+ seq = tsp->tsc_sequence;
+ tsp->tsc_sequence = 0;
+ atomic_thread_fence_rel();
+ tsp->tsc_scale = ((10000LL << 32) / freq_khz) << 32;
+ tsp->tsc_offset = 0;
+ atomic_thread_fence_rel();
+ seq++;
+ if (seq == 0xffffffff || seq == 0)
+ seq = 1;
+ tsp->tsc_sequence = seq;
+ }
+ tsc_ref = val;
+ return (0);
+ }
default:
break;
}
@@ -107,6 +194,21 @@
{
int error = 0;
+ /* common case of Hyper-V MSR-s */
+ switch (num) {
+ case HV_X64_MSR_HYPERCALL:
+ *val = hypercall;
+ return (0);
+ case HV_X64_MSR_GUEST_OS_ID:
+ *val = guest_os_id = *val;
+ return (0);
+ case HV_X64_MSR_REFERENCE_TSC:
+ *val = tsc_ref;
+ return (0);
+ default:
+ break;
+ }
+
if (cpu_vendor_intel) {
switch (num) {
case MSR_BIOS_SIGN:
@@ -241,5 +343,18 @@
EPRINTLN("Unknown cpu vendor \"%s\"", cpu_vendor);
error = -1;
}
+
+ if (error == 0) {
+ size_t len = sizeof (freq_khz);
+
+ error = sysctlbyname("machdep.tsc_freq", &freq_khz, &len, NULL, 0);
+ if (error == 0) {
+ freq_khz /= 1000;
+ if (freq_khz == 0) {
+ warnx("CPU freq is too small");
+ error = -1;
+ }
+ }
+ }
return (error);
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Feb 7, 9:18 PM (9 h, 18 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28458644
Default Alt Text
D35575.id.diff (8 KB)
Attached To
Mode
D35575: bhyve: Support Hyper-V (base) and hyperv clock
Attached
Detach File
Event Timeline
Log In to Comment