Page MenuHomeFreeBSD

D35575.id.diff
No OneTemporary

D35575.id.diff

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, &regs[1], 4);
bcopy(bhyve_id + 4, &regs[2], 4);
bcopy(bhyve_id + 8, &regs[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

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)

Event Timeline