Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/hyperv/vmbus/hyperv.c
Show All 29 Lines | |||||
* Implements low-level interactions with Hyper-V/Azure | * Implements low-level interactions with Hyper-V/Azure | ||||
*/ | */ | ||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/kernel.h> | #include <sys/kernel.h> | ||||
#include <sys/malloc.h> | #include <sys/malloc.h> | ||||
#include <sys/systm.h> | #include <sys/systm.h> | ||||
#include <sys/timetc.h> | #include <sys/timetc.h> | ||||
#include <sys/cpuset.h> | |||||
#include <vm/vm.h> | #include <vm/vm.h> | ||||
#include <vm/vm_extern.h> | #include <vm/vm_extern.h> | ||||
#include <vm/vm_kern.h> | #include <vm/vm_kern.h> | ||||
#include <vm/pmap.h> | #include <vm/pmap.h> | ||||
#include <dev/hyperv/include/hyperv.h> | #include <dev/hyperv/include/hyperv.h> | ||||
#include <dev/hyperv/include/hyperv_busdma.h> | #include <dev/hyperv/include/hyperv_busdma.h> | ||||
#if defined(__aarch64__) | #if defined(__aarch64__) | ||||
#include <dev/hyperv/vmbus/aarch64/hyperv_machdep.h> | #include <dev/hyperv/vmbus/aarch64/hyperv_machdep.h> | ||||
#include <dev/hyperv/vmbus/aarch64/hyperv_reg.h> | #include <dev/hyperv/vmbus/aarch64/hyperv_reg.h> | ||||
#else | #else | ||||
#include <dev/hyperv/vmbus/x86/hyperv_machdep.h> | #include <dev/hyperv/vmbus/x86/hyperv_machdep.h> | ||||
#include <dev/hyperv/vmbus/x86/hyperv_reg.h> | #include <dev/hyperv/vmbus/x86/hyperv_reg.h> | ||||
#endif | #endif | ||||
#include <dev/hyperv/vmbus/vmbus_var.h> | |||||
#include <dev/hyperv/vmbus/hyperv_common_reg.h> | #include <dev/hyperv/vmbus/hyperv_common_reg.h> | ||||
#include <dev/hyperv/vmbus/hyperv_var.h> | #include <dev/hyperv/vmbus/hyperv_var.h> | ||||
#define HYPERV_FREEBSD_BUILD 0ULL | #define HYPERV_FREEBSD_BUILD 0ULL | ||||
#define HYPERV_FREEBSD_VERSION ((uint64_t)__FreeBSD_version) | #define HYPERV_FREEBSD_VERSION ((uint64_t)__FreeBSD_version) | ||||
#define HYPERV_FREEBSD_OSID 0ULL | #define HYPERV_FREEBSD_OSID 0ULL | ||||
#define MSR_HV_GUESTID_BUILD_FREEBSD \ | #define MSR_HV_GUESTID_BUILD_FREEBSD \ | ||||
(HYPERV_FREEBSD_BUILD & MSR_HV_GUESTID_BUILD_MASK) | (HYPERV_FREEBSD_BUILD & MSR_HV_GUESTID_BUILD_MASK) | ||||
#define MSR_HV_GUESTID_VERSION_FREEBSD \ | #define MSR_HV_GUESTID_VERSION_FREEBSD \ | ||||
((HYPERV_FREEBSD_VERSION << MSR_HV_GUESTID_VERSION_SHIFT) & \ | ((HYPERV_FREEBSD_VERSION << MSR_HV_GUESTID_VERSION_SHIFT) & \ | ||||
MSR_HV_GUESTID_VERSION_MASK) | MSR_HV_GUESTID_VERSION_MASK) | ||||
#define MSR_HV_GUESTID_OSID_FREEBSD \ | #define MSR_HV_GUESTID_OSID_FREEBSD \ | ||||
((HYPERV_FREEBSD_OSID << MSR_HV_GUESTID_OSID_SHIFT) & \ | ((HYPERV_FREEBSD_OSID << MSR_HV_GUESTID_OSID_SHIFT) & \ | ||||
MSR_HV_GUESTID_OSID_MASK) | MSR_HV_GUESTID_OSID_MASK) | ||||
#define MSR_HV_GUESTID_FREEBSD \ | #define MSR_HV_GUESTID_FREEBSD \ | ||||
(MSR_HV_GUESTID_BUILD_FREEBSD | \ | (MSR_HV_GUESTID_BUILD_FREEBSD | \ | ||||
MSR_HV_GUESTID_VERSION_FREEBSD | \ | MSR_HV_GUESTID_VERSION_FREEBSD | \ | ||||
MSR_HV_GUESTID_OSID_FREEBSD | \ | MSR_HV_GUESTID_OSID_FREEBSD | \ | ||||
MSR_HV_GUESTID_OSTYPE_FREEBSD) | MSR_HV_GUESTID_OSTYPE_FREEBSD) | ||||
static bool hyperv_identify(void); | static bool hyperv_identify(void); | ||||
static void hypercall_memfree(void); | static void hypercall_memfree(void); | ||||
static struct hypercall_ctx hypercall_context; | static struct hypercall_ctx hypercall_context; | ||||
uint64_t | uint64_t | ||||
hypercall_post_message(bus_addr_t msg_paddr) | hypercall_post_message(bus_addr_t msg_paddr) | ||||
{ | { | ||||
return hypercall_md(hypercall_context.hc_addr, | return hypercall_md(hypercall_context.hc_addr, | ||||
HYPERCALL_POST_MESSAGE, msg_paddr, 0); | HYPERCALL_POST_MESSAGE, msg_paddr, 0); | ||||
} | } | ||||
uint64_t | uint64_t | ||||
hypercall_signal_event(bus_addr_t monprm_paddr) | hypercall_signal_event(bus_addr_t monprm_paddr) | ||||
{ | { | ||||
return hypercall_md(hypercall_context.hc_addr, | return hypercall_md(hypercall_context.hc_addr, | ||||
HYPERCALL_SIGNAL_EVENT, monprm_paddr, 0); | HYPERCALL_SIGNAL_EVENT, monprm_paddr, 0); | ||||
} | } | ||||
static inline int hv_result(uint64_t status) | |||||
{ | |||||
return status & HV_HYPERCALL_RESULT_MASK; | |||||
} | |||||
static inline bool hv_result_success(uint64_t status) | |||||
{ | |||||
return hv_result(status) == HV_STATUS_SUCCESS; | |||||
} | |||||
static inline unsigned int hv_repcomp(uint64_t status) | |||||
{ | |||||
/* Bits [43:32] of status have 'Reps completed' data. */ | |||||
return (status & HV_HYPERCALL_REP_COMP_MASK) >> | |||||
HV_HYPERCALL_REP_COMP_OFFSET; | |||||
} | |||||
/* | |||||
* Rep hypercalls. Callers of this functions are supposed to ensure that | |||||
* rep_count and varhead_size comply with Hyper-V hypercall definition. | |||||
*/ | |||||
uint64_t | |||||
hv_do_rep_hypercall(uint16_t code, uint16_t rep_count, uint16_t varhead_size, | |||||
uint64_t input, uint64_t output) | |||||
{ | |||||
uint64_t control = code; | |||||
uint64_t status; | |||||
uint16_t rep_comp; | |||||
control |= (uint64_t)varhead_size << HV_HYPERCALL_VARHEAD_OFFSET; | |||||
control |= (uint64_t)rep_count << HV_HYPERCALL_REP_COMP_OFFSET; | |||||
do { | |||||
status = hypercall_do_md(control, input, output); | |||||
if (!hv_result_success(status)) | |||||
return status; | |||||
rep_comp = hv_repcomp(status); | |||||
control &= ~HV_HYPERCALL_REP_START_MASK; | |||||
control |= (uint64_t)rep_comp << HV_HYPERCALL_REP_START_OFFSET; | |||||
} while (rep_comp < rep_count); | |||||
if (hv_result_success(status)) | |||||
return HV_STATUS_SUCCESS; | |||||
return status; | |||||
} | |||||
uint64_t | |||||
hypercall_do_md(uint64_t input_val, uint64_t input_addr, uint64_t out_addr) | |||||
{ | |||||
uint64_t phys_inaddr, phys_outaddr; | |||||
phys_inaddr = input_addr ? vtophys(input_addr) : 0; | |||||
phys_outaddr = out_addr ? vtophys(out_addr) : 0; | |||||
return hypercall_md(hypercall_context.hc_addr, | |||||
input_val, phys_inaddr, phys_outaddr); | |||||
} | |||||
int | int | ||||
hyperv_guid2str(const struct hyperv_guid *guid, char *buf, size_t sz) | hyperv_guid2str(const struct hyperv_guid *guid, char *buf, size_t sz) | ||||
{ | { | ||||
const uint8_t *d = guid->hv_guid; | const uint8_t *d = guid->hv_guid; | ||||
return snprintf(buf, sz, "%02x%02x%02x%02x-" | return snprintf(buf, sz, "%02x%02x%02x%02x-" | ||||
"%02x%02x-%02x%02x-%02x%02x-" | "%02x%02x-%02x%02x-%02x%02x-" | ||||
"%02x%02x%02x%02x%02x%02x", | "%02x%02x%02x%02x%02x%02x", | ||||
▲ Show 20 Lines • Show All 65 Lines • ▼ Show 20 Lines | if (hypercall_context.hc_addr == NULL) | ||||
return; | return; | ||||
hypercall_disable(); | hypercall_disable(); | ||||
hypercall_memfree(); | hypercall_memfree(); | ||||
if (bootverbose) | if (bootverbose) | ||||
printf("hyperv: Hypercall destroyed\n"); | printf("hyperv: Hypercall destroyed\n"); | ||||
} | } | ||||
SYSUNINIT(hypercall_dtor, SI_SUB_DRIVERS, SI_ORDER_FIRST, hypercall_destroy, | SYSUNINIT(hypercall_dtor, SI_SUB_DRIVERS, SI_ORDER_FIRST, hypercall_destroy, | ||||
NULL); | NULL); | ||||