1b7bb4816SSepherosa Ziehau /*- 2b7bb4816SSepherosa Ziehau * Copyright (c) 2009-2012,2016 Microsoft Corp. 3b7bb4816SSepherosa Ziehau * Copyright (c) 2012 NetApp Inc. 4b7bb4816SSepherosa Ziehau * Copyright (c) 2012 Citrix Inc. 5b7bb4816SSepherosa Ziehau * All rights reserved. 6b7bb4816SSepherosa Ziehau * 7b7bb4816SSepherosa Ziehau * Redistribution and use in source and binary forms, with or without 8b7bb4816SSepherosa Ziehau * modification, are permitted provided that the following conditions 9b7bb4816SSepherosa Ziehau * are met: 10b7bb4816SSepherosa Ziehau * 1. Redistributions of source code must retain the above copyright 11b7bb4816SSepherosa Ziehau * notice unmodified, this list of conditions, and the following 12b7bb4816SSepherosa Ziehau * disclaimer. 13b7bb4816SSepherosa Ziehau * 2. Redistributions in binary form must reproduce the above copyright 14b7bb4816SSepherosa Ziehau * notice, this list of conditions and the following disclaimer in the 15b7bb4816SSepherosa Ziehau * documentation and/or other materials provided with the distribution. 16b7bb4816SSepherosa Ziehau * 17b7bb4816SSepherosa Ziehau * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18b7bb4816SSepherosa Ziehau * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19b7bb4816SSepherosa Ziehau * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20b7bb4816SSepherosa Ziehau * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21b7bb4816SSepherosa Ziehau * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22b7bb4816SSepherosa Ziehau * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23b7bb4816SSepherosa Ziehau * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24b7bb4816SSepherosa Ziehau * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25b7bb4816SSepherosa Ziehau * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26b7bb4816SSepherosa Ziehau * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27b7bb4816SSepherosa Ziehau */ 28b7bb4816SSepherosa Ziehau 29b7bb4816SSepherosa Ziehau /** 30b7bb4816SSepherosa Ziehau * Implements low-level interactions with Hypver-V/Azure 31b7bb4816SSepherosa Ziehau */ 32b7bb4816SSepherosa Ziehau #include <sys/cdefs.h> 33b7bb4816SSepherosa Ziehau __FBSDID("$FreeBSD$"); 34b7bb4816SSepherosa Ziehau 35b7bb4816SSepherosa Ziehau #include <sys/param.h> 36b7bb4816SSepherosa Ziehau #include <sys/kernel.h> 37b7bb4816SSepherosa Ziehau #include <sys/malloc.h> 38b7bb4816SSepherosa Ziehau #include <sys/pcpu.h> 39b7bb4816SSepherosa Ziehau #include <sys/timetc.h> 40b7bb4816SSepherosa Ziehau #include <machine/bus.h> 41b7bb4816SSepherosa Ziehau #include <machine/md_var.h> 42b7bb4816SSepherosa Ziehau #include <vm/vm.h> 43b7bb4816SSepherosa Ziehau #include <vm/vm_param.h> 44b7bb4816SSepherosa Ziehau #include <vm/pmap.h> 45b7bb4816SSepherosa Ziehau 46b7bb4816SSepherosa Ziehau #include <dev/hyperv/include/hyperv_busdma.h> 47b7bb4816SSepherosa Ziehau #include <dev/hyperv/vmbus/hv_vmbus_priv.h> 48d8bf5168SSepherosa Ziehau #include <dev/hyperv/vmbus/hyperv_machdep.h> 49b7bb4816SSepherosa Ziehau #include <dev/hyperv/vmbus/hyperv_reg.h> 50b7bb4816SSepherosa Ziehau #include <dev/hyperv/vmbus/hyperv_var.h> 51b7bb4816SSepherosa Ziehau #include <dev/hyperv/vmbus/vmbus_var.h> 52b7bb4816SSepherosa Ziehau 53b7bb4816SSepherosa Ziehau #define HYPERV_FREEBSD_BUILD 0ULL 54b7bb4816SSepherosa Ziehau #define HYPERV_FREEBSD_VERSION ((uint64_t)__FreeBSD_version) 55b7bb4816SSepherosa Ziehau #define HYPERV_FREEBSD_OSID 0ULL 56b7bb4816SSepherosa Ziehau 57b7bb4816SSepherosa Ziehau #define MSR_HV_GUESTID_BUILD_FREEBSD \ 58b7bb4816SSepherosa Ziehau (HYPERV_FREEBSD_BUILD & MSR_HV_GUESTID_BUILD_MASK) 59b7bb4816SSepherosa Ziehau #define MSR_HV_GUESTID_VERSION_FREEBSD \ 60b7bb4816SSepherosa Ziehau ((HYPERV_FREEBSD_VERSION << MSR_HV_GUESTID_VERSION_SHIFT) & \ 61b7bb4816SSepherosa Ziehau MSR_HV_GUESTID_VERSION_MASK) 62b7bb4816SSepherosa Ziehau #define MSR_HV_GUESTID_OSID_FREEBSD \ 63b7bb4816SSepherosa Ziehau ((HYPERV_FREEBSD_OSID << MSR_HV_GUESTID_OSID_SHIFT) & \ 64b7bb4816SSepherosa Ziehau MSR_HV_GUESTID_OSID_MASK) 65b7bb4816SSepherosa Ziehau 66b7bb4816SSepherosa Ziehau #define MSR_HV_GUESTID_FREEBSD \ 67b7bb4816SSepherosa Ziehau (MSR_HV_GUESTID_BUILD_FREEBSD | \ 68b7bb4816SSepherosa Ziehau MSR_HV_GUESTID_VERSION_FREEBSD | \ 69b7bb4816SSepherosa Ziehau MSR_HV_GUESTID_OSID_FREEBSD | \ 70b7bb4816SSepherosa Ziehau MSR_HV_GUESTID_OSTYPE_FREEBSD) 71b7bb4816SSepherosa Ziehau 72b7bb4816SSepherosa Ziehau struct hypercall_ctx { 73b7bb4816SSepherosa Ziehau void *hc_addr; 74b7bb4816SSepherosa Ziehau struct hyperv_dma hc_dma; 75b7bb4816SSepherosa Ziehau }; 76b7bb4816SSepherosa Ziehau 77b7bb4816SSepherosa Ziehau static u_int hyperv_get_timecount(struct timecounter *tc); 78b7bb4816SSepherosa Ziehau 79b7bb4816SSepherosa Ziehau u_int hyperv_features; 80b7bb4816SSepherosa Ziehau u_int hyperv_recommends; 81b7bb4816SSepherosa Ziehau 82b7bb4816SSepherosa Ziehau static u_int hyperv_pm_features; 83b7bb4816SSepherosa Ziehau static u_int hyperv_features3; 84b7bb4816SSepherosa Ziehau 85b7bb4816SSepherosa Ziehau static struct timecounter hyperv_timecounter = { 86b7bb4816SSepherosa Ziehau .tc_get_timecount = hyperv_get_timecount, 87b7bb4816SSepherosa Ziehau .tc_poll_pps = NULL, 88b7bb4816SSepherosa Ziehau .tc_counter_mask = 0xffffffff, 89b7bb4816SSepherosa Ziehau .tc_frequency = HYPERV_TIMER_FREQ, 90b7bb4816SSepherosa Ziehau .tc_name = "Hyper-V", 91b7bb4816SSepherosa Ziehau .tc_quality = 2000, 92b7bb4816SSepherosa Ziehau .tc_flags = 0, 93b7bb4816SSepherosa Ziehau .tc_priv = NULL 94b7bb4816SSepherosa Ziehau }; 95b7bb4816SSepherosa Ziehau 96b7bb4816SSepherosa Ziehau static struct hypercall_ctx hypercall_context; 97b7bb4816SSepherosa Ziehau 98b7bb4816SSepherosa Ziehau static u_int 99b7bb4816SSepherosa Ziehau hyperv_get_timecount(struct timecounter *tc __unused) 100b7bb4816SSepherosa Ziehau { 101b7bb4816SSepherosa Ziehau return rdmsr(MSR_HV_TIME_REF_COUNT); 102b7bb4816SSepherosa Ziehau } 103b7bb4816SSepherosa Ziehau 104b7bb4816SSepherosa Ziehau /** 105b7bb4816SSepherosa Ziehau * @brief Invoke the specified hypercall 106b7bb4816SSepherosa Ziehau */ 107b7bb4816SSepherosa Ziehau static uint64_t 108d8bf5168SSepherosa Ziehau hv_vmbus_do_hypercall(uint64_t value, void *input, void *output) 109b7bb4816SSepherosa Ziehau { 110d8bf5168SSepherosa Ziehau uint64_t in_paddr = 0, out_paddr = 0; 111b7bb4816SSepherosa Ziehau 112d8bf5168SSepherosa Ziehau if (input != NULL) 113d8bf5168SSepherosa Ziehau in_paddr = hv_get_phys_addr(input); 114d8bf5168SSepherosa Ziehau if (output != NULL) 115d8bf5168SSepherosa Ziehau out_paddr = hv_get_phys_addr(output); 116b7bb4816SSepherosa Ziehau 117d8bf5168SSepherosa Ziehau return hypercall_md(hypercall_context.hc_addr, value, 118d8bf5168SSepherosa Ziehau in_paddr, out_paddr); 119b7bb4816SSepherosa Ziehau } 120b7bb4816SSepherosa Ziehau 121*236764b1SSepherosa Ziehau uint64_t 122*236764b1SSepherosa Ziehau hypercall_post_message(bus_addr_t msg_paddr) 123*236764b1SSepherosa Ziehau { 124*236764b1SSepherosa Ziehau return hypercall_md(hypercall_context.hc_addr, 125*236764b1SSepherosa Ziehau HYPERCALL_POST_MESSAGE, msg_paddr, 0); 126*236764b1SSepherosa Ziehau } 127*236764b1SSepherosa Ziehau 128b7bb4816SSepherosa Ziehau /** 129b7bb4816SSepherosa Ziehau * @brief Post a message using the hypervisor message IPC. 130b7bb4816SSepherosa Ziehau * (This involves a hypercall.) 131b7bb4816SSepherosa Ziehau */ 132b7bb4816SSepherosa Ziehau hv_vmbus_status 133b7bb4816SSepherosa Ziehau hv_vmbus_post_msg_via_msg_ipc( 134b7bb4816SSepherosa Ziehau hv_vmbus_connection_id connection_id, 135b7bb4816SSepherosa Ziehau hv_vmbus_msg_type message_type, 136b7bb4816SSepherosa Ziehau void* payload, 137b7bb4816SSepherosa Ziehau size_t payload_size) 138b7bb4816SSepherosa Ziehau { 139b7bb4816SSepherosa Ziehau struct alignedinput { 140b7bb4816SSepherosa Ziehau uint64_t alignment8; 141b7bb4816SSepherosa Ziehau hv_vmbus_input_post_message msg; 142b7bb4816SSepherosa Ziehau }; 143b7bb4816SSepherosa Ziehau 144b7bb4816SSepherosa Ziehau hv_vmbus_input_post_message* aligned_msg; 145b7bb4816SSepherosa Ziehau hv_vmbus_status status; 146b7bb4816SSepherosa Ziehau size_t addr; 147b7bb4816SSepherosa Ziehau 148b7bb4816SSepherosa Ziehau if (payload_size > HV_MESSAGE_PAYLOAD_BYTE_COUNT) 149b7bb4816SSepherosa Ziehau return (EMSGSIZE); 150b7bb4816SSepherosa Ziehau 151b7bb4816SSepherosa Ziehau addr = (size_t) malloc(sizeof(struct alignedinput), M_DEVBUF, 152b7bb4816SSepherosa Ziehau M_ZERO | M_NOWAIT); 153b7bb4816SSepherosa Ziehau KASSERT(addr != 0, 154b7bb4816SSepherosa Ziehau ("Error VMBUS: malloc failed to allocate message buffer!")); 155b7bb4816SSepherosa Ziehau if (addr == 0) 156b7bb4816SSepherosa Ziehau return (ENOMEM); 157b7bb4816SSepherosa Ziehau 158b7bb4816SSepherosa Ziehau aligned_msg = (hv_vmbus_input_post_message*) 159b7bb4816SSepherosa Ziehau (HV_ALIGN_UP(addr, HV_HYPERCALL_PARAM_ALIGN)); 160b7bb4816SSepherosa Ziehau 161b7bb4816SSepherosa Ziehau aligned_msg->connection_id = connection_id; 162b7bb4816SSepherosa Ziehau aligned_msg->message_type = message_type; 163b7bb4816SSepherosa Ziehau aligned_msg->payload_size = payload_size; 164b7bb4816SSepherosa Ziehau memcpy((void*) aligned_msg->payload, payload, payload_size); 165b7bb4816SSepherosa Ziehau 166b7bb4816SSepherosa Ziehau status = hv_vmbus_do_hypercall( 167b7bb4816SSepherosa Ziehau HV_CALL_POST_MESSAGE, aligned_msg, 0) & 0xFFFF; 168b7bb4816SSepherosa Ziehau 169b7bb4816SSepherosa Ziehau free((void *) addr, M_DEVBUF); 170b7bb4816SSepherosa Ziehau return (status); 171b7bb4816SSepherosa Ziehau } 172b7bb4816SSepherosa Ziehau 173b7bb4816SSepherosa Ziehau /** 174b7bb4816SSepherosa Ziehau * @brief Signal an event on the specified connection using the hypervisor 175b7bb4816SSepherosa Ziehau * event IPC. (This involves a hypercall.) 176b7bb4816SSepherosa Ziehau */ 177b7bb4816SSepherosa Ziehau hv_vmbus_status 178b7bb4816SSepherosa Ziehau hv_vmbus_signal_event(void *con_id) 179b7bb4816SSepherosa Ziehau { 180b7bb4816SSepherosa Ziehau hv_vmbus_status status; 181b7bb4816SSepherosa Ziehau 182b7bb4816SSepherosa Ziehau status = hv_vmbus_do_hypercall( 183b7bb4816SSepherosa Ziehau HV_CALL_SIGNAL_EVENT, 184b7bb4816SSepherosa Ziehau con_id, 185b7bb4816SSepherosa Ziehau 0) & 0xFFFF; 186b7bb4816SSepherosa Ziehau 187b7bb4816SSepherosa Ziehau return (status); 188b7bb4816SSepherosa Ziehau } 189b7bb4816SSepherosa Ziehau 190b7bb4816SSepherosa Ziehau int 191b7bb4816SSepherosa Ziehau hyperv_guid2str(const struct hv_guid *guid, char *buf, size_t sz) 192b7bb4816SSepherosa Ziehau { 193b7bb4816SSepherosa Ziehau const uint8_t *d = guid->data; 194b7bb4816SSepherosa Ziehau 195b7bb4816SSepherosa Ziehau return snprintf(buf, sz, "%02x%02x%02x%02x-" 196b7bb4816SSepherosa Ziehau "%02x%02x-%02x%02x-%02x%02x-" 197b7bb4816SSepherosa Ziehau "%02x%02x%02x%02x%02x%02x", 198b7bb4816SSepherosa Ziehau d[3], d[2], d[1], d[0], 199b7bb4816SSepherosa Ziehau d[5], d[4], d[7], d[6], d[8], d[9], 200b7bb4816SSepherosa Ziehau d[10], d[11], d[12], d[13], d[14], d[15]); 201b7bb4816SSepherosa Ziehau } 202b7bb4816SSepherosa Ziehau 203b7bb4816SSepherosa Ziehau static bool 204b7bb4816SSepherosa Ziehau hyperv_identify(void) 205b7bb4816SSepherosa Ziehau { 206b7bb4816SSepherosa Ziehau u_int regs[4]; 207b7bb4816SSepherosa Ziehau unsigned int maxleaf; 208b7bb4816SSepherosa Ziehau 209b7bb4816SSepherosa Ziehau if (vm_guest != VM_GUEST_HV) 210b7bb4816SSepherosa Ziehau return (false); 211b7bb4816SSepherosa Ziehau 212b7bb4816SSepherosa Ziehau do_cpuid(CPUID_LEAF_HV_MAXLEAF, regs); 213b7bb4816SSepherosa Ziehau maxleaf = regs[0]; 214b7bb4816SSepherosa Ziehau if (maxleaf < CPUID_LEAF_HV_LIMITS) 215b7bb4816SSepherosa Ziehau return (false); 216b7bb4816SSepherosa Ziehau 217b7bb4816SSepherosa Ziehau do_cpuid(CPUID_LEAF_HV_INTERFACE, regs); 218b7bb4816SSepherosa Ziehau if (regs[0] != CPUID_HV_IFACE_HYPERV) 219b7bb4816SSepherosa Ziehau return (false); 220b7bb4816SSepherosa Ziehau 221b7bb4816SSepherosa Ziehau do_cpuid(CPUID_LEAF_HV_FEATURES, regs); 222b7bb4816SSepherosa Ziehau if ((regs[0] & CPUID_HV_MSR_HYPERCALL) == 0) { 223b7bb4816SSepherosa Ziehau /* 224b7bb4816SSepherosa Ziehau * Hyper-V w/o Hypercall is impossible; someone 225b7bb4816SSepherosa Ziehau * is faking Hyper-V. 226b7bb4816SSepherosa Ziehau */ 227b7bb4816SSepherosa Ziehau return (false); 228b7bb4816SSepherosa Ziehau } 229b7bb4816SSepherosa Ziehau hyperv_features = regs[0]; 230b7bb4816SSepherosa Ziehau hyperv_pm_features = regs[2]; 231b7bb4816SSepherosa Ziehau hyperv_features3 = regs[3]; 232b7bb4816SSepherosa Ziehau 233b7bb4816SSepherosa Ziehau do_cpuid(CPUID_LEAF_HV_IDENTITY, regs); 234b7bb4816SSepherosa Ziehau printf("Hyper-V Version: %d.%d.%d [SP%d]\n", 235b7bb4816SSepherosa Ziehau regs[1] >> 16, regs[1] & 0xffff, regs[0], regs[2]); 236b7bb4816SSepherosa Ziehau 237b7bb4816SSepherosa Ziehau printf(" Features=0x%b\n", hyperv_features, 238b7bb4816SSepherosa Ziehau "\020" 239b7bb4816SSepherosa Ziehau "\001VPRUNTIME" /* MSR_HV_VP_RUNTIME */ 240b7bb4816SSepherosa Ziehau "\002TMREFCNT" /* MSR_HV_TIME_REF_COUNT */ 241b7bb4816SSepherosa Ziehau "\003SYNIC" /* MSRs for SynIC */ 242b7bb4816SSepherosa Ziehau "\004SYNTM" /* MSRs for SynTimer */ 243b7bb4816SSepherosa Ziehau "\005APIC" /* MSR_HV_{EOI,ICR,TPR} */ 244b7bb4816SSepherosa Ziehau "\006HYPERCALL" /* MSR_HV_{GUEST_OS_ID,HYPERCALL} */ 245b7bb4816SSepherosa Ziehau "\007VPINDEX" /* MSR_HV_VP_INDEX */ 246b7bb4816SSepherosa Ziehau "\010RESET" /* MSR_HV_RESET */ 247b7bb4816SSepherosa Ziehau "\011STATS" /* MSR_HV_STATS_ */ 248b7bb4816SSepherosa Ziehau "\012REFTSC" /* MSR_HV_REFERENCE_TSC */ 249b7bb4816SSepherosa Ziehau "\013IDLE" /* MSR_HV_GUEST_IDLE */ 250b7bb4816SSepherosa Ziehau "\014TMFREQ" /* MSR_HV_{TSC,APIC}_FREQUENCY */ 251b7bb4816SSepherosa Ziehau "\015DEBUG"); /* MSR_HV_SYNTH_DEBUG_ */ 252b7bb4816SSepherosa Ziehau printf(" PM Features=0x%b [C%u]\n", 253b7bb4816SSepherosa Ziehau (hyperv_pm_features & ~CPUPM_HV_CSTATE_MASK), 254b7bb4816SSepherosa Ziehau "\020" 255b7bb4816SSepherosa Ziehau "\005C3HPET", /* HPET is required for C3 state */ 256b7bb4816SSepherosa Ziehau CPUPM_HV_CSTATE(hyperv_pm_features)); 257b7bb4816SSepherosa Ziehau printf(" Features3=0x%b\n", hyperv_features3, 258b7bb4816SSepherosa Ziehau "\020" 259b7bb4816SSepherosa Ziehau "\001MWAIT" /* MWAIT */ 260b7bb4816SSepherosa Ziehau "\002DEBUG" /* guest debug support */ 261b7bb4816SSepherosa Ziehau "\003PERFMON" /* performance monitor */ 262b7bb4816SSepherosa Ziehau "\004PCPUDPE" /* physical CPU dynamic partition event */ 263b7bb4816SSepherosa Ziehau "\005XMMHC" /* hypercall input through XMM regs */ 264b7bb4816SSepherosa Ziehau "\006IDLE" /* guest idle support */ 265b7bb4816SSepherosa Ziehau "\007SLEEP" /* hypervisor sleep support */ 266b7bb4816SSepherosa Ziehau "\010NUMA" /* NUMA distance query support */ 267b7bb4816SSepherosa Ziehau "\011TMFREQ" /* timer frequency query (TSC, LAPIC) */ 268b7bb4816SSepherosa Ziehau "\012SYNCMC" /* inject synthetic machine checks */ 269b7bb4816SSepherosa Ziehau "\013CRASH" /* MSRs for guest crash */ 270b7bb4816SSepherosa Ziehau "\014DEBUGMSR" /* MSRs for guest debug */ 271b7bb4816SSepherosa Ziehau "\015NPIEP" /* NPIEP */ 272b7bb4816SSepherosa Ziehau "\016HVDIS"); /* disabling hypervisor */ 273b7bb4816SSepherosa Ziehau 274b7bb4816SSepherosa Ziehau do_cpuid(CPUID_LEAF_HV_RECOMMENDS, regs); 275b7bb4816SSepherosa Ziehau hyperv_recommends = regs[0]; 276b7bb4816SSepherosa Ziehau if (bootverbose) 277b7bb4816SSepherosa Ziehau printf(" Recommends: %08x %08x\n", regs[0], regs[1]); 278b7bb4816SSepherosa Ziehau 279b7bb4816SSepherosa Ziehau do_cpuid(CPUID_LEAF_HV_LIMITS, regs); 280b7bb4816SSepherosa Ziehau if (bootverbose) { 281b7bb4816SSepherosa Ziehau printf(" Limits: Vcpu:%d Lcpu:%d Int:%d\n", 282b7bb4816SSepherosa Ziehau regs[0], regs[1], regs[2]); 283b7bb4816SSepherosa Ziehau } 284b7bb4816SSepherosa Ziehau 285b7bb4816SSepherosa Ziehau if (maxleaf >= CPUID_LEAF_HV_HWFEATURES) { 286b7bb4816SSepherosa Ziehau do_cpuid(CPUID_LEAF_HV_HWFEATURES, regs); 287b7bb4816SSepherosa Ziehau if (bootverbose) { 288b7bb4816SSepherosa Ziehau printf(" HW Features: %08x, AMD: %08x\n", 289b7bb4816SSepherosa Ziehau regs[0], regs[3]); 290b7bb4816SSepherosa Ziehau } 291b7bb4816SSepherosa Ziehau } 292b7bb4816SSepherosa Ziehau 293b7bb4816SSepherosa Ziehau return (true); 294b7bb4816SSepherosa Ziehau } 295b7bb4816SSepherosa Ziehau 296b7bb4816SSepherosa Ziehau static void 297b7bb4816SSepherosa Ziehau hyperv_init(void *dummy __unused) 298b7bb4816SSepherosa Ziehau { 299b7bb4816SSepherosa Ziehau if (!hyperv_identify()) { 300b7bb4816SSepherosa Ziehau /* Not Hyper-V; reset guest id to the generic one. */ 301b7bb4816SSepherosa Ziehau if (vm_guest == VM_GUEST_HV) 302b7bb4816SSepherosa Ziehau vm_guest = VM_GUEST_VM; 303b7bb4816SSepherosa Ziehau return; 304b7bb4816SSepherosa Ziehau } 305b7bb4816SSepherosa Ziehau 306b7bb4816SSepherosa Ziehau /* Set guest id */ 307b7bb4816SSepherosa Ziehau wrmsr(MSR_HV_GUEST_OS_ID, MSR_HV_GUESTID_FREEBSD); 308b7bb4816SSepherosa Ziehau 309b7bb4816SSepherosa Ziehau if (hyperv_features & CPUID_HV_MSR_TIME_REFCNT) { 310b7bb4816SSepherosa Ziehau /* Register Hyper-V timecounter */ 311b7bb4816SSepherosa Ziehau tc_init(&hyperv_timecounter); 312b7bb4816SSepherosa Ziehau } 313b7bb4816SSepherosa Ziehau } 314b7bb4816SSepherosa Ziehau SYSINIT(hyperv_initialize, SI_SUB_HYPERVISOR, SI_ORDER_FIRST, hyperv_init, 315b7bb4816SSepherosa Ziehau NULL); 316b7bb4816SSepherosa Ziehau 317b7bb4816SSepherosa Ziehau static void 318b7bb4816SSepherosa Ziehau hypercall_memfree(void) 319b7bb4816SSepherosa Ziehau { 320b7bb4816SSepherosa Ziehau hyperv_dmamem_free(&hypercall_context.hc_dma, 321b7bb4816SSepherosa Ziehau hypercall_context.hc_addr); 322b7bb4816SSepherosa Ziehau hypercall_context.hc_addr = NULL; 323b7bb4816SSepherosa Ziehau } 324b7bb4816SSepherosa Ziehau 325b7bb4816SSepherosa Ziehau static void 326b7bb4816SSepherosa Ziehau hypercall_create(void *arg __unused) 327b7bb4816SSepherosa Ziehau { 328b7bb4816SSepherosa Ziehau uint64_t hc, hc_orig; 329b7bb4816SSepherosa Ziehau 330b7bb4816SSepherosa Ziehau if (vm_guest != VM_GUEST_HV) 331b7bb4816SSepherosa Ziehau return; 332b7bb4816SSepherosa Ziehau 333b7bb4816SSepherosa Ziehau hypercall_context.hc_addr = hyperv_dmamem_alloc(NULL, PAGE_SIZE, 0, 334b7bb4816SSepherosa Ziehau PAGE_SIZE, &hypercall_context.hc_dma, BUS_DMA_WAITOK); 335b7bb4816SSepherosa Ziehau if (hypercall_context.hc_addr == NULL) { 336b7bb4816SSepherosa Ziehau printf("hyperv: Hypercall page allocation failed\n"); 337b7bb4816SSepherosa Ziehau /* Can't perform any Hyper-V specific actions */ 338b7bb4816SSepherosa Ziehau vm_guest = VM_GUEST_VM; 339b7bb4816SSepherosa Ziehau return; 340b7bb4816SSepherosa Ziehau } 341b7bb4816SSepherosa Ziehau 342b7bb4816SSepherosa Ziehau /* Get the 'reserved' bits, which requires preservation. */ 343b7bb4816SSepherosa Ziehau hc_orig = rdmsr(MSR_HV_HYPERCALL); 344b7bb4816SSepherosa Ziehau 345b7bb4816SSepherosa Ziehau /* 346b7bb4816SSepherosa Ziehau * Setup the Hypercall page. 347b7bb4816SSepherosa Ziehau * 348b7bb4816SSepherosa Ziehau * NOTE: 'reserved' bits MUST be preserved. 349b7bb4816SSepherosa Ziehau */ 350b7bb4816SSepherosa Ziehau hc = ((hypercall_context.hc_dma.hv_paddr >> PAGE_SHIFT) << 351b7bb4816SSepherosa Ziehau MSR_HV_HYPERCALL_PGSHIFT) | 352b7bb4816SSepherosa Ziehau (hc_orig & MSR_HV_HYPERCALL_RSVD_MASK) | 353b7bb4816SSepherosa Ziehau MSR_HV_HYPERCALL_ENABLE; 354b7bb4816SSepherosa Ziehau wrmsr(MSR_HV_HYPERCALL, hc); 355b7bb4816SSepherosa Ziehau 356b7bb4816SSepherosa Ziehau /* 357b7bb4816SSepherosa Ziehau * Confirm that Hypercall page did get setup. 358b7bb4816SSepherosa Ziehau */ 359b7bb4816SSepherosa Ziehau hc = rdmsr(MSR_HV_HYPERCALL); 360b7bb4816SSepherosa Ziehau if ((hc & MSR_HV_HYPERCALL_ENABLE) == 0) { 361b7bb4816SSepherosa Ziehau printf("hyperv: Hypercall setup failed\n"); 362b7bb4816SSepherosa Ziehau hypercall_memfree(); 363b7bb4816SSepherosa Ziehau /* Can't perform any Hyper-V specific actions */ 364b7bb4816SSepherosa Ziehau vm_guest = VM_GUEST_VM; 365b7bb4816SSepherosa Ziehau return; 366b7bb4816SSepherosa Ziehau } 367b7bb4816SSepherosa Ziehau if (bootverbose) 368b7bb4816SSepherosa Ziehau printf("hyperv: Hypercall created\n"); 369b7bb4816SSepherosa Ziehau } 370b7bb4816SSepherosa Ziehau SYSINIT(hypercall_ctor, SI_SUB_DRIVERS, SI_ORDER_FIRST, hypercall_create, NULL); 371b7bb4816SSepherosa Ziehau 372b7bb4816SSepherosa Ziehau static void 373b7bb4816SSepherosa Ziehau hypercall_destroy(void *arg __unused) 374b7bb4816SSepherosa Ziehau { 375b7bb4816SSepherosa Ziehau uint64_t hc; 376b7bb4816SSepherosa Ziehau 377b7bb4816SSepherosa Ziehau if (hypercall_context.hc_addr == NULL) 378b7bb4816SSepherosa Ziehau return; 379b7bb4816SSepherosa Ziehau 380b7bb4816SSepherosa Ziehau /* Disable Hypercall */ 381b7bb4816SSepherosa Ziehau hc = rdmsr(MSR_HV_HYPERCALL); 382b7bb4816SSepherosa Ziehau wrmsr(MSR_HV_HYPERCALL, (hc & MSR_HV_HYPERCALL_RSVD_MASK)); 383b7bb4816SSepherosa Ziehau hypercall_memfree(); 384b7bb4816SSepherosa Ziehau 385b7bb4816SSepherosa Ziehau if (bootverbose) 386b7bb4816SSepherosa Ziehau printf("hyperv: Hypercall destroyed\n"); 387b7bb4816SSepherosa Ziehau } 388b7bb4816SSepherosa Ziehau SYSUNINIT(hypercall_dtor, SI_SUB_DRIVERS, SI_ORDER_FIRST, hypercall_destroy, 389b7bb4816SSepherosa Ziehau NULL); 390