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