Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/hyperv/vmbus/hv_hv.c
Show First 20 Lines • Show All 61 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
/** | /** | ||||
* Globals | * Globals | ||||
*/ | */ | ||||
hv_vmbus_context hv_vmbus_g_context = { | hv_vmbus_context hv_vmbus_g_context = { | ||||
.syn_ic_initialized = FALSE, | .syn_ic_initialized = FALSE, | ||||
.hypercall_page = NULL, | .hypercall_page = NULL, | ||||
.signal_event_param = NULL, | |||||
.signal_event_buffer = NULL, | |||||
}; | }; | ||||
static struct timecounter hv_timecounter = { | static struct timecounter hv_timecounter = { | ||||
hv_get_timecount, 0, ~0u, HV_NANOSECONDS_PER_SEC/100, "Hyper-V", HV_NANOSECONDS_PER_SEC/100 | hv_get_timecount, 0, ~0u, HV_NANOSECONDS_PER_SEC/100, "Hyper-V", HV_NANOSECONDS_PER_SEC/100 | ||||
}; | }; | ||||
static u_int | static u_int | ||||
hv_get_timecount(struct timecounter *tc) | hv_get_timecount(struct timecounter *tc) | ||||
▲ Show 20 Lines • Show All 171 Lines • ▼ Show 20 Lines | hv_vmbus_init(void) | ||||
hypercall_msr.as_uint64_t = 0; | hypercall_msr.as_uint64_t = 0; | ||||
hypercall_msr.as_uint64_t = rdmsr(HV_X64_MSR_HYPERCALL); | hypercall_msr.as_uint64_t = rdmsr(HV_X64_MSR_HYPERCALL); | ||||
if (!hypercall_msr.u.enable) | if (!hypercall_msr.u.enable) | ||||
goto cleanup; | goto cleanup; | ||||
hv_vmbus_g_context.hypercall_page = virt_addr; | hv_vmbus_g_context.hypercall_page = virt_addr; | ||||
/* | |||||
* Setup the global signal event param for the signal event hypercall | |||||
*/ | |||||
hv_vmbus_g_context.signal_event_buffer = | |||||
malloc(sizeof(hv_vmbus_input_signal_event_buffer), M_DEVBUF, | |||||
M_ZERO | M_NOWAIT); | |||||
KASSERT(hv_vmbus_g_context.signal_event_buffer != NULL, | |||||
("Error VMBUS: Failed to allocate signal_event_buffer\n")); | |||||
if (hv_vmbus_g_context.signal_event_buffer == NULL) | |||||
goto cleanup; | |||||
hv_vmbus_g_context.signal_event_param = | |||||
(hv_vmbus_input_signal_event*) | |||||
(HV_ALIGN_UP((unsigned long) | |||||
hv_vmbus_g_context.signal_event_buffer, | |||||
HV_HYPERCALL_PARAM_ALIGN)); | |||||
hv_vmbus_g_context.signal_event_param->connection_id.as_uint32_t = 0; | |||||
hv_vmbus_g_context.signal_event_param->connection_id.u.id = | |||||
HV_VMBUS_EVENT_CONNECTION_ID; | |||||
hv_vmbus_g_context.signal_event_param->flag_number = 0; | |||||
hv_vmbus_g_context.signal_event_param->rsvd_z = 0; | |||||
tc_init(&hv_timecounter); /* register virtual timecount */ | tc_init(&hv_timecounter); /* register virtual timecount */ | ||||
return (0); | return (0); | ||||
cleanup: | cleanup: | ||||
if (virt_addr != NULL) { | if (virt_addr != NULL) { | ||||
if (hypercall_msr.u.enable) { | if (hypercall_msr.u.enable) { | ||||
hypercall_msr.as_uint64_t = 0; | hypercall_msr.as_uint64_t = 0; | ||||
Show All 9 Lines | |||||
/** | /** | ||||
* @brief Cleanup routine, called normally during driver unloading or exiting | * @brief Cleanup routine, called normally during driver unloading or exiting | ||||
*/ | */ | ||||
void | void | ||||
hv_vmbus_cleanup(void) | hv_vmbus_cleanup(void) | ||||
{ | { | ||||
hv_vmbus_x64_msr_hypercall_contents hypercall_msr; | hv_vmbus_x64_msr_hypercall_contents hypercall_msr; | ||||
if (hv_vmbus_g_context.signal_event_buffer != NULL) { | |||||
free(hv_vmbus_g_context.signal_event_buffer, M_DEVBUF); | |||||
hv_vmbus_g_context.signal_event_buffer = NULL; | |||||
hv_vmbus_g_context.signal_event_param = NULL; | |||||
} | |||||
if (hv_vmbus_g_context.guest_id == HV_FREEBSD_GUEST_ID) { | if (hv_vmbus_g_context.guest_id == HV_FREEBSD_GUEST_ID) { | ||||
if (hv_vmbus_g_context.hypercall_page != NULL) { | if (hv_vmbus_g_context.hypercall_page != NULL) { | ||||
hypercall_msr.as_uint64_t = 0; | hypercall_msr.as_uint64_t = 0; | ||||
wrmsr(HV_X64_MSR_HYPERCALL, | wrmsr(HV_X64_MSR_HYPERCALL, | ||||
hypercall_msr.as_uint64_t); | hypercall_msr.as_uint64_t); | ||||
free(hv_vmbus_g_context.hypercall_page, M_DEVBUF); | free(hv_vmbus_g_context.hypercall_page, M_DEVBUF); | ||||
hv_vmbus_g_context.hypercall_page = NULL; | hv_vmbus_g_context.hypercall_page = NULL; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | hv_vmbus_post_msg_via_msg_ipc( | ||||
return (status); | return (status); | ||||
} | } | ||||
/** | /** | ||||
* @brief Signal an event on the specified connection using the hypervisor | * @brief Signal an event on the specified connection using the hypervisor | ||||
* event IPC. (This involves a hypercall.) | * event IPC. (This involves a hypercall.) | ||||
*/ | */ | ||||
hv_vmbus_status | hv_vmbus_status | ||||
hv_vmbus_signal_event() | hv_vmbus_signal_event(void *con_id) | ||||
{ | { | ||||
hv_vmbus_status status; | hv_vmbus_status status; | ||||
status = hv_vmbus_do_hypercall( | status = hv_vmbus_do_hypercall( | ||||
HV_CALL_SIGNAL_EVENT, | HV_CALL_SIGNAL_EVENT, | ||||
hv_vmbus_g_context.signal_event_param, | con_id, | ||||
0) & 0xFFFF; | 0) & 0xFFFF; | ||||
return (status); | return (status); | ||||
} | } | ||||
/** | /** | ||||
* @brief hv_vmbus_synic_init | * @brief hv_vmbus_synic_init | ||||
*/ | */ | ||||
void | void | ||||
hv_vmbus_synic_init(void *arg) | hv_vmbus_synic_init(void *arg) | ||||
{ | { | ||||
int cpu; | int cpu; | ||||
uint64_t hv_vcpu_index; | |||||
hv_vmbus_synic_simp simp; | hv_vmbus_synic_simp simp; | ||||
hv_vmbus_synic_siefp siefp; | hv_vmbus_synic_siefp siefp; | ||||
hv_vmbus_synic_scontrol sctrl; | hv_vmbus_synic_scontrol sctrl; | ||||
hv_vmbus_synic_sint shared_sint; | hv_vmbus_synic_sint shared_sint; | ||||
uint64_t version; | uint64_t version; | ||||
hv_setup_args* setup_args = (hv_setup_args *)arg; | hv_setup_args* setup_args = (hv_setup_args *)arg; | ||||
cpu = PCPU_GET(cpuid); | cpu = PCPU_GET(cpuid); | ||||
if (hv_vmbus_g_context.hypercall_page == NULL) | if (hv_vmbus_g_context.hypercall_page == NULL) | ||||
return; | return; | ||||
/* | /* | ||||
* KYS: Looks like we can only initialize on cpu0; don't we support | |||||
* SMP guests? | |||||
* | |||||
* TODO: Need to add SMP support for FreeBSD V9 | |||||
*/ | |||||
if (cpu != 0) | |||||
return; | |||||
/* | |||||
* TODO: Check the version | * TODO: Check the version | ||||
*/ | */ | ||||
version = rdmsr(HV_X64_MSR_SVERSION); | version = rdmsr(HV_X64_MSR_SVERSION); | ||||
hv_vmbus_g_context.syn_ic_msg_page[cpu] = | |||||
setup_args->page_buffers[2 * cpu]; | |||||
hv_vmbus_g_context.syn_ic_event_page[cpu] = | |||||
setup_args->page_buffers[2 * cpu + 1]; | |||||
hv_vmbus_g_context.syn_ic_msg_page[cpu] = setup_args->page_buffers[0]; | |||||
hv_vmbus_g_context.syn_ic_event_page[cpu] = setup_args->page_buffers[1]; | |||||
/* | /* | ||||
* Setup the Synic's message page | * Setup the Synic's message page | ||||
*/ | */ | ||||
simp.as_uint64_t = rdmsr(HV_X64_MSR_SIMP); | simp.as_uint64_t = rdmsr(HV_X64_MSR_SIMP); | ||||
simp.u.simp_enabled = 1; | simp.u.simp_enabled = 1; | ||||
simp.u.base_simp_gpa = ((hv_get_phys_addr( | simp.u.base_simp_gpa = ((hv_get_phys_addr( | ||||
hv_vmbus_g_context.syn_ic_msg_page[cpu])) >> PAGE_SHIFT); | hv_vmbus_g_context.syn_ic_msg_page[cpu])) >> PAGE_SHIFT); | ||||
wrmsr(HV_X64_MSR_SIMP, simp.as_uint64_t); | wrmsr(HV_X64_MSR_SIMP, simp.as_uint64_t); | ||||
/* | /* | ||||
* Setup the Synic's event page | * Setup the Synic's event page | ||||
*/ | */ | ||||
siefp.as_uint64_t = rdmsr(HV_X64_MSR_SIEFP); | siefp.as_uint64_t = rdmsr(HV_X64_MSR_SIEFP); | ||||
siefp.u.siefp_enabled = 1; | siefp.u.siefp_enabled = 1; | ||||
siefp.u.base_siefp_gpa = ((hv_get_phys_addr( | siefp.u.base_siefp_gpa = ((hv_get_phys_addr( | ||||
hv_vmbus_g_context.syn_ic_event_page[cpu])) >> PAGE_SHIFT); | hv_vmbus_g_context.syn_ic_event_page[cpu])) >> PAGE_SHIFT); | ||||
wrmsr(HV_X64_MSR_SIEFP, siefp.as_uint64_t); | wrmsr(HV_X64_MSR_SIEFP, siefp.as_uint64_t); | ||||
/*HV_SHARED_SINT_IDT_VECTOR + 0x20; */ | /*HV_SHARED_SINT_IDT_VECTOR + 0x20; */ | ||||
shared_sint.as_uint64_t = 0; | |||||
shared_sint.u.vector = setup_args->vector; | shared_sint.u.vector = setup_args->vector; | ||||
shared_sint.u.masked = FALSE; | shared_sint.u.masked = FALSE; | ||||
shared_sint.u.auto_eoi = FALSE; | shared_sint.u.auto_eoi = TRUE; | ||||
wrmsr(HV_X64_MSR_SINT0 + HV_VMBUS_MESSAGE_SINT, | wrmsr(HV_X64_MSR_SINT0 + HV_VMBUS_MESSAGE_SINT, | ||||
shared_sint.as_uint64_t); | shared_sint.as_uint64_t); | ||||
/* Enable the global synic bit */ | /* Enable the global synic bit */ | ||||
sctrl.as_uint64_t = rdmsr(HV_X64_MSR_SCONTROL); | sctrl.as_uint64_t = rdmsr(HV_X64_MSR_SCONTROL); | ||||
sctrl.u.enable = 1; | sctrl.u.enable = 1; | ||||
wrmsr(HV_X64_MSR_SCONTROL, sctrl.as_uint64_t); | wrmsr(HV_X64_MSR_SCONTROL, sctrl.as_uint64_t); | ||||
hv_vmbus_g_context.syn_ic_initialized = TRUE; | hv_vmbus_g_context.syn_ic_initialized = TRUE; | ||||
/* | |||||
* Set up the cpuid mapping from Hyper-V to FreeBSD. | |||||
* The array is indexed using FreeBSD cpuid. | |||||
*/ | |||||
hv_vcpu_index = rdmsr(HV_X64_MSR_VP_INDEX); | |||||
hv_vmbus_g_context.hv_vcpu_index[cpu] = (uint32_t)hv_vcpu_index; | |||||
return; | return; | ||||
} | } | ||||
/** | /** | ||||
* @brief Cleanup routine for hv_vmbus_synic_init() | * @brief Cleanup routine for hv_vmbus_synic_init() | ||||
*/ | */ | ||||
void hv_vmbus_synic_cleanup(void *arg) | void hv_vmbus_synic_cleanup(void *arg) | ||||
{ | { | ||||
hv_vmbus_synic_sint shared_sint; | hv_vmbus_synic_sint shared_sint; | ||||
hv_vmbus_synic_simp simp; | hv_vmbus_synic_simp simp; | ||||
hv_vmbus_synic_siefp siefp; | hv_vmbus_synic_siefp siefp; | ||||
int cpu = PCPU_GET(cpuid); | |||||
if (!hv_vmbus_g_context.syn_ic_initialized) | if (!hv_vmbus_g_context.syn_ic_initialized) | ||||
return; | return; | ||||
if (cpu != 0) | |||||
return; /* TODO: XXXKYS: SMP? */ | |||||
shared_sint.as_uint64_t = rdmsr( | shared_sint.as_uint64_t = rdmsr( | ||||
HV_X64_MSR_SINT0 + HV_VMBUS_MESSAGE_SINT); | HV_X64_MSR_SINT0 + HV_VMBUS_MESSAGE_SINT); | ||||
shared_sint.u.masked = 1; | shared_sint.u.masked = 1; | ||||
/* | /* | ||||
* Disable the interrupt | * Disable the interrupt | ||||
Show All 18 Lines |