1e83d5887SAndrey Smetanin /* 2e83d5887SAndrey Smetanin * KVM Microsoft Hyper-V emulation 3e83d5887SAndrey Smetanin * 4e83d5887SAndrey Smetanin * derived from arch/x86/kvm/x86.c 5e83d5887SAndrey Smetanin * 6e83d5887SAndrey Smetanin * Copyright (C) 2006 Qumranet, Inc. 7e83d5887SAndrey Smetanin * Copyright (C) 2008 Qumranet, Inc. 8e83d5887SAndrey Smetanin * Copyright IBM Corporation, 2008 9e83d5887SAndrey Smetanin * Copyright 2010 Red Hat, Inc. and/or its affiliates. 10e83d5887SAndrey Smetanin * Copyright (C) 2015 Andrey Smetanin <asmetanin@virtuozzo.com> 11e83d5887SAndrey Smetanin * 12e83d5887SAndrey Smetanin * Authors: 13e83d5887SAndrey Smetanin * Avi Kivity <avi@qumranet.com> 14e83d5887SAndrey Smetanin * Yaniv Kamay <yaniv@qumranet.com> 15e83d5887SAndrey Smetanin * Amit Shah <amit.shah@qumranet.com> 16e83d5887SAndrey Smetanin * Ben-Ami Yassour <benami@il.ibm.com> 17e83d5887SAndrey Smetanin * Andrey Smetanin <asmetanin@virtuozzo.com> 18e83d5887SAndrey Smetanin * 19e83d5887SAndrey Smetanin * This work is licensed under the terms of the GNU GPL, version 2. See 20e83d5887SAndrey Smetanin * the COPYING file in the top-level directory. 21e83d5887SAndrey Smetanin * 22e83d5887SAndrey Smetanin */ 23e83d5887SAndrey Smetanin 24e83d5887SAndrey Smetanin #include "x86.h" 25e83d5887SAndrey Smetanin #include "lapic.h" 26e83d5887SAndrey Smetanin #include "hyperv.h" 27e83d5887SAndrey Smetanin 28e83d5887SAndrey Smetanin #include <linux/kvm_host.h> 29e83d5887SAndrey Smetanin #include <trace/events/kvm.h> 30e83d5887SAndrey Smetanin 31e83d5887SAndrey Smetanin #include "trace.h" 32e83d5887SAndrey Smetanin 33e83d5887SAndrey Smetanin static bool kvm_hv_msr_partition_wide(u32 msr) 34e83d5887SAndrey Smetanin { 35e83d5887SAndrey Smetanin bool r = false; 36e83d5887SAndrey Smetanin 37e83d5887SAndrey Smetanin switch (msr) { 38e83d5887SAndrey Smetanin case HV_X64_MSR_GUEST_OS_ID: 39e83d5887SAndrey Smetanin case HV_X64_MSR_HYPERCALL: 40e83d5887SAndrey Smetanin case HV_X64_MSR_REFERENCE_TSC: 41e83d5887SAndrey Smetanin case HV_X64_MSR_TIME_REF_COUNT: 42e7d9513bSAndrey Smetanin case HV_X64_MSR_CRASH_CTL: 43e7d9513bSAndrey Smetanin case HV_X64_MSR_CRASH_P0 ... HV_X64_MSR_CRASH_P4: 44e516cebbSAndrey Smetanin case HV_X64_MSR_RESET: 45e83d5887SAndrey Smetanin r = true; 46e83d5887SAndrey Smetanin break; 47e83d5887SAndrey Smetanin } 48e83d5887SAndrey Smetanin 49e83d5887SAndrey Smetanin return r; 50e83d5887SAndrey Smetanin } 51e83d5887SAndrey Smetanin 52e7d9513bSAndrey Smetanin static int kvm_hv_msr_get_crash_data(struct kvm_vcpu *vcpu, 53e7d9513bSAndrey Smetanin u32 index, u64 *pdata) 54e7d9513bSAndrey Smetanin { 55e7d9513bSAndrey Smetanin struct kvm_hv *hv = &vcpu->kvm->arch.hyperv; 56e7d9513bSAndrey Smetanin 57e7d9513bSAndrey Smetanin if (WARN_ON_ONCE(index >= ARRAY_SIZE(hv->hv_crash_param))) 58e7d9513bSAndrey Smetanin return -EINVAL; 59e7d9513bSAndrey Smetanin 60e7d9513bSAndrey Smetanin *pdata = hv->hv_crash_param[index]; 61e7d9513bSAndrey Smetanin return 0; 62e7d9513bSAndrey Smetanin } 63e7d9513bSAndrey Smetanin 64e7d9513bSAndrey Smetanin static int kvm_hv_msr_get_crash_ctl(struct kvm_vcpu *vcpu, u64 *pdata) 65e7d9513bSAndrey Smetanin { 66e7d9513bSAndrey Smetanin struct kvm_hv *hv = &vcpu->kvm->arch.hyperv; 67e7d9513bSAndrey Smetanin 68e7d9513bSAndrey Smetanin *pdata = hv->hv_crash_ctl; 69e7d9513bSAndrey Smetanin return 0; 70e7d9513bSAndrey Smetanin } 71e7d9513bSAndrey Smetanin 72e7d9513bSAndrey Smetanin static int kvm_hv_msr_set_crash_ctl(struct kvm_vcpu *vcpu, u64 data, bool host) 73e7d9513bSAndrey Smetanin { 74e7d9513bSAndrey Smetanin struct kvm_hv *hv = &vcpu->kvm->arch.hyperv; 75e7d9513bSAndrey Smetanin 76e7d9513bSAndrey Smetanin if (host) 77e7d9513bSAndrey Smetanin hv->hv_crash_ctl = data & HV_X64_MSR_CRASH_CTL_NOTIFY; 78e7d9513bSAndrey Smetanin 79e7d9513bSAndrey Smetanin if (!host && (data & HV_X64_MSR_CRASH_CTL_NOTIFY)) { 80e7d9513bSAndrey Smetanin 81e7d9513bSAndrey Smetanin vcpu_debug(vcpu, "hv crash (0x%llx 0x%llx 0x%llx 0x%llx 0x%llx)\n", 82e7d9513bSAndrey Smetanin hv->hv_crash_param[0], 83e7d9513bSAndrey Smetanin hv->hv_crash_param[1], 84e7d9513bSAndrey Smetanin hv->hv_crash_param[2], 85e7d9513bSAndrey Smetanin hv->hv_crash_param[3], 86e7d9513bSAndrey Smetanin hv->hv_crash_param[4]); 87e7d9513bSAndrey Smetanin 88e7d9513bSAndrey Smetanin /* Send notification about crash to user space */ 89e7d9513bSAndrey Smetanin kvm_make_request(KVM_REQ_HV_CRASH, vcpu); 90e7d9513bSAndrey Smetanin } 91e7d9513bSAndrey Smetanin 92e7d9513bSAndrey Smetanin return 0; 93e7d9513bSAndrey Smetanin } 94e7d9513bSAndrey Smetanin 95e7d9513bSAndrey Smetanin static int kvm_hv_msr_set_crash_data(struct kvm_vcpu *vcpu, 96e7d9513bSAndrey Smetanin u32 index, u64 data) 97e7d9513bSAndrey Smetanin { 98e7d9513bSAndrey Smetanin struct kvm_hv *hv = &vcpu->kvm->arch.hyperv; 99e7d9513bSAndrey Smetanin 100e7d9513bSAndrey Smetanin if (WARN_ON_ONCE(index >= ARRAY_SIZE(hv->hv_crash_param))) 101e7d9513bSAndrey Smetanin return -EINVAL; 102e7d9513bSAndrey Smetanin 103e7d9513bSAndrey Smetanin hv->hv_crash_param[index] = data; 104e7d9513bSAndrey Smetanin return 0; 105e7d9513bSAndrey Smetanin } 106e7d9513bSAndrey Smetanin 107e7d9513bSAndrey Smetanin static int kvm_hv_set_msr_pw(struct kvm_vcpu *vcpu, u32 msr, u64 data, 108e7d9513bSAndrey Smetanin bool host) 109e83d5887SAndrey Smetanin { 110e83d5887SAndrey Smetanin struct kvm *kvm = vcpu->kvm; 111e83d5887SAndrey Smetanin struct kvm_hv *hv = &kvm->arch.hyperv; 112e83d5887SAndrey Smetanin 113e83d5887SAndrey Smetanin switch (msr) { 114e83d5887SAndrey Smetanin case HV_X64_MSR_GUEST_OS_ID: 115e83d5887SAndrey Smetanin hv->hv_guest_os_id = data; 116e83d5887SAndrey Smetanin /* setting guest os id to zero disables hypercall page */ 117e83d5887SAndrey Smetanin if (!hv->hv_guest_os_id) 118e83d5887SAndrey Smetanin hv->hv_hypercall &= ~HV_X64_MSR_HYPERCALL_ENABLE; 119e83d5887SAndrey Smetanin break; 120e83d5887SAndrey Smetanin case HV_X64_MSR_HYPERCALL: { 121e83d5887SAndrey Smetanin u64 gfn; 122e83d5887SAndrey Smetanin unsigned long addr; 123e83d5887SAndrey Smetanin u8 instructions[4]; 124e83d5887SAndrey Smetanin 125e83d5887SAndrey Smetanin /* if guest os id is not set hypercall should remain disabled */ 126e83d5887SAndrey Smetanin if (!hv->hv_guest_os_id) 127e83d5887SAndrey Smetanin break; 128e83d5887SAndrey Smetanin if (!(data & HV_X64_MSR_HYPERCALL_ENABLE)) { 129e83d5887SAndrey Smetanin hv->hv_hypercall = data; 130e83d5887SAndrey Smetanin break; 131e83d5887SAndrey Smetanin } 132e83d5887SAndrey Smetanin gfn = data >> HV_X64_MSR_HYPERCALL_PAGE_ADDRESS_SHIFT; 133e83d5887SAndrey Smetanin addr = gfn_to_hva(kvm, gfn); 134e83d5887SAndrey Smetanin if (kvm_is_error_hva(addr)) 135e83d5887SAndrey Smetanin return 1; 136e83d5887SAndrey Smetanin kvm_x86_ops->patch_hypercall(vcpu, instructions); 137e83d5887SAndrey Smetanin ((unsigned char *)instructions)[3] = 0xc3; /* ret */ 138e83d5887SAndrey Smetanin if (__copy_to_user((void __user *)addr, instructions, 4)) 139e83d5887SAndrey Smetanin return 1; 140e83d5887SAndrey Smetanin hv->hv_hypercall = data; 141e83d5887SAndrey Smetanin mark_page_dirty(kvm, gfn); 142e83d5887SAndrey Smetanin break; 143e83d5887SAndrey Smetanin } 144e83d5887SAndrey Smetanin case HV_X64_MSR_REFERENCE_TSC: { 145e83d5887SAndrey Smetanin u64 gfn; 146e83d5887SAndrey Smetanin HV_REFERENCE_TSC_PAGE tsc_ref; 147e83d5887SAndrey Smetanin 148e83d5887SAndrey Smetanin memset(&tsc_ref, 0, sizeof(tsc_ref)); 149e83d5887SAndrey Smetanin hv->hv_tsc_page = data; 150e83d5887SAndrey Smetanin if (!(data & HV_X64_MSR_TSC_REFERENCE_ENABLE)) 151e83d5887SAndrey Smetanin break; 152e83d5887SAndrey Smetanin gfn = data >> HV_X64_MSR_TSC_REFERENCE_ADDRESS_SHIFT; 153e83d5887SAndrey Smetanin if (kvm_write_guest( 154e83d5887SAndrey Smetanin kvm, 155e83d5887SAndrey Smetanin gfn << HV_X64_MSR_TSC_REFERENCE_ADDRESS_SHIFT, 156e83d5887SAndrey Smetanin &tsc_ref, sizeof(tsc_ref))) 157e83d5887SAndrey Smetanin return 1; 158e83d5887SAndrey Smetanin mark_page_dirty(kvm, gfn); 159e83d5887SAndrey Smetanin break; 160e83d5887SAndrey Smetanin } 161e7d9513bSAndrey Smetanin case HV_X64_MSR_CRASH_P0 ... HV_X64_MSR_CRASH_P4: 162e7d9513bSAndrey Smetanin return kvm_hv_msr_set_crash_data(vcpu, 163e7d9513bSAndrey Smetanin msr - HV_X64_MSR_CRASH_P0, 164e7d9513bSAndrey Smetanin data); 165e7d9513bSAndrey Smetanin case HV_X64_MSR_CRASH_CTL: 166e7d9513bSAndrey Smetanin return kvm_hv_msr_set_crash_ctl(vcpu, data, host); 167e516cebbSAndrey Smetanin case HV_X64_MSR_RESET: 168e516cebbSAndrey Smetanin if (data == 1) { 169e516cebbSAndrey Smetanin vcpu_debug(vcpu, "hyper-v reset requested\n"); 170e516cebbSAndrey Smetanin kvm_make_request(KVM_REQ_HV_RESET, vcpu); 171e516cebbSAndrey Smetanin } 172e516cebbSAndrey Smetanin break; 173e83d5887SAndrey Smetanin default: 174e83d5887SAndrey Smetanin vcpu_unimpl(vcpu, "Hyper-V uhandled wrmsr: 0x%x data 0x%llx\n", 175e83d5887SAndrey Smetanin msr, data); 176e83d5887SAndrey Smetanin return 1; 177e83d5887SAndrey Smetanin } 178e83d5887SAndrey Smetanin return 0; 179e83d5887SAndrey Smetanin } 180e83d5887SAndrey Smetanin 181*9eec50b8SAndrey Smetanin /* Calculate cpu time spent by current task in 100ns units */ 182*9eec50b8SAndrey Smetanin static u64 current_task_runtime_100ns(void) 183*9eec50b8SAndrey Smetanin { 184*9eec50b8SAndrey Smetanin cputime_t utime, stime; 185*9eec50b8SAndrey Smetanin 186*9eec50b8SAndrey Smetanin task_cputime_adjusted(current, &utime, &stime); 187*9eec50b8SAndrey Smetanin return div_u64(cputime_to_nsecs(utime + stime), 100); 188*9eec50b8SAndrey Smetanin } 189*9eec50b8SAndrey Smetanin 190*9eec50b8SAndrey Smetanin static int kvm_hv_set_msr(struct kvm_vcpu *vcpu, u32 msr, u64 data, bool host) 191e83d5887SAndrey Smetanin { 192e83d5887SAndrey Smetanin struct kvm_vcpu_hv *hv = &vcpu->arch.hyperv; 193e83d5887SAndrey Smetanin 194e83d5887SAndrey Smetanin switch (msr) { 195e83d5887SAndrey Smetanin case HV_X64_MSR_APIC_ASSIST_PAGE: { 196e83d5887SAndrey Smetanin u64 gfn; 197e83d5887SAndrey Smetanin unsigned long addr; 198e83d5887SAndrey Smetanin 199e83d5887SAndrey Smetanin if (!(data & HV_X64_MSR_APIC_ASSIST_PAGE_ENABLE)) { 200e83d5887SAndrey Smetanin hv->hv_vapic = data; 201e83d5887SAndrey Smetanin if (kvm_lapic_enable_pv_eoi(vcpu, 0)) 202e83d5887SAndrey Smetanin return 1; 203e83d5887SAndrey Smetanin break; 204e83d5887SAndrey Smetanin } 205e83d5887SAndrey Smetanin gfn = data >> HV_X64_MSR_APIC_ASSIST_PAGE_ADDRESS_SHIFT; 206e83d5887SAndrey Smetanin addr = kvm_vcpu_gfn_to_hva(vcpu, gfn); 207e83d5887SAndrey Smetanin if (kvm_is_error_hva(addr)) 208e83d5887SAndrey Smetanin return 1; 209e83d5887SAndrey Smetanin if (__clear_user((void __user *)addr, PAGE_SIZE)) 210e83d5887SAndrey Smetanin return 1; 211e83d5887SAndrey Smetanin hv->hv_vapic = data; 212e83d5887SAndrey Smetanin kvm_vcpu_mark_page_dirty(vcpu, gfn); 213e83d5887SAndrey Smetanin if (kvm_lapic_enable_pv_eoi(vcpu, 214e83d5887SAndrey Smetanin gfn_to_gpa(gfn) | KVM_MSR_ENABLED)) 215e83d5887SAndrey Smetanin return 1; 216e83d5887SAndrey Smetanin break; 217e83d5887SAndrey Smetanin } 218e83d5887SAndrey Smetanin case HV_X64_MSR_EOI: 219e83d5887SAndrey Smetanin return kvm_hv_vapic_msr_write(vcpu, APIC_EOI, data); 220e83d5887SAndrey Smetanin case HV_X64_MSR_ICR: 221e83d5887SAndrey Smetanin return kvm_hv_vapic_msr_write(vcpu, APIC_ICR, data); 222e83d5887SAndrey Smetanin case HV_X64_MSR_TPR: 223e83d5887SAndrey Smetanin return kvm_hv_vapic_msr_write(vcpu, APIC_TASKPRI, data); 224*9eec50b8SAndrey Smetanin case HV_X64_MSR_VP_RUNTIME: 225*9eec50b8SAndrey Smetanin if (!host) 226*9eec50b8SAndrey Smetanin return 1; 227*9eec50b8SAndrey Smetanin hv->runtime_offset = data - current_task_runtime_100ns(); 228*9eec50b8SAndrey Smetanin break; 229e83d5887SAndrey Smetanin default: 230e83d5887SAndrey Smetanin vcpu_unimpl(vcpu, "Hyper-V uhandled wrmsr: 0x%x data 0x%llx\n", 231e83d5887SAndrey Smetanin msr, data); 232e83d5887SAndrey Smetanin return 1; 233e83d5887SAndrey Smetanin } 234e83d5887SAndrey Smetanin 235e83d5887SAndrey Smetanin return 0; 236e83d5887SAndrey Smetanin } 237e83d5887SAndrey Smetanin 238e83d5887SAndrey Smetanin static int kvm_hv_get_msr_pw(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata) 239e83d5887SAndrey Smetanin { 240e83d5887SAndrey Smetanin u64 data = 0; 241e83d5887SAndrey Smetanin struct kvm *kvm = vcpu->kvm; 242e83d5887SAndrey Smetanin struct kvm_hv *hv = &kvm->arch.hyperv; 243e83d5887SAndrey Smetanin 244e83d5887SAndrey Smetanin switch (msr) { 245e83d5887SAndrey Smetanin case HV_X64_MSR_GUEST_OS_ID: 246e83d5887SAndrey Smetanin data = hv->hv_guest_os_id; 247e83d5887SAndrey Smetanin break; 248e83d5887SAndrey Smetanin case HV_X64_MSR_HYPERCALL: 249e83d5887SAndrey Smetanin data = hv->hv_hypercall; 250e83d5887SAndrey Smetanin break; 251e83d5887SAndrey Smetanin case HV_X64_MSR_TIME_REF_COUNT: { 252e83d5887SAndrey Smetanin data = 253e83d5887SAndrey Smetanin div_u64(get_kernel_ns() + kvm->arch.kvmclock_offset, 100); 254e83d5887SAndrey Smetanin break; 255e83d5887SAndrey Smetanin } 256e83d5887SAndrey Smetanin case HV_X64_MSR_REFERENCE_TSC: 257e83d5887SAndrey Smetanin data = hv->hv_tsc_page; 258e83d5887SAndrey Smetanin break; 259e7d9513bSAndrey Smetanin case HV_X64_MSR_CRASH_P0 ... HV_X64_MSR_CRASH_P4: 260e7d9513bSAndrey Smetanin return kvm_hv_msr_get_crash_data(vcpu, 261e7d9513bSAndrey Smetanin msr - HV_X64_MSR_CRASH_P0, 262e7d9513bSAndrey Smetanin pdata); 263e7d9513bSAndrey Smetanin case HV_X64_MSR_CRASH_CTL: 264e7d9513bSAndrey Smetanin return kvm_hv_msr_get_crash_ctl(vcpu, pdata); 265e516cebbSAndrey Smetanin case HV_X64_MSR_RESET: 266e516cebbSAndrey Smetanin data = 0; 267e516cebbSAndrey Smetanin break; 268e83d5887SAndrey Smetanin default: 269e83d5887SAndrey Smetanin vcpu_unimpl(vcpu, "Hyper-V unhandled rdmsr: 0x%x\n", msr); 270e83d5887SAndrey Smetanin return 1; 271e83d5887SAndrey Smetanin } 272e83d5887SAndrey Smetanin 273e83d5887SAndrey Smetanin *pdata = data; 274e83d5887SAndrey Smetanin return 0; 275e83d5887SAndrey Smetanin } 276e83d5887SAndrey Smetanin 277e83d5887SAndrey Smetanin static int kvm_hv_get_msr(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata) 278e83d5887SAndrey Smetanin { 279e83d5887SAndrey Smetanin u64 data = 0; 280e83d5887SAndrey Smetanin struct kvm_vcpu_hv *hv = &vcpu->arch.hyperv; 281e83d5887SAndrey Smetanin 282e83d5887SAndrey Smetanin switch (msr) { 283e83d5887SAndrey Smetanin case HV_X64_MSR_VP_INDEX: { 284e83d5887SAndrey Smetanin int r; 285e83d5887SAndrey Smetanin struct kvm_vcpu *v; 286e83d5887SAndrey Smetanin 287e83d5887SAndrey Smetanin kvm_for_each_vcpu(r, v, vcpu->kvm) { 288e83d5887SAndrey Smetanin if (v == vcpu) { 289e83d5887SAndrey Smetanin data = r; 290e83d5887SAndrey Smetanin break; 291e83d5887SAndrey Smetanin } 292e83d5887SAndrey Smetanin } 293e83d5887SAndrey Smetanin break; 294e83d5887SAndrey Smetanin } 295e83d5887SAndrey Smetanin case HV_X64_MSR_EOI: 296e83d5887SAndrey Smetanin return kvm_hv_vapic_msr_read(vcpu, APIC_EOI, pdata); 297e83d5887SAndrey Smetanin case HV_X64_MSR_ICR: 298e83d5887SAndrey Smetanin return kvm_hv_vapic_msr_read(vcpu, APIC_ICR, pdata); 299e83d5887SAndrey Smetanin case HV_X64_MSR_TPR: 300e83d5887SAndrey Smetanin return kvm_hv_vapic_msr_read(vcpu, APIC_TASKPRI, pdata); 301e83d5887SAndrey Smetanin case HV_X64_MSR_APIC_ASSIST_PAGE: 302e83d5887SAndrey Smetanin data = hv->hv_vapic; 303e83d5887SAndrey Smetanin break; 304*9eec50b8SAndrey Smetanin case HV_X64_MSR_VP_RUNTIME: 305*9eec50b8SAndrey Smetanin data = current_task_runtime_100ns() + hv->runtime_offset; 306*9eec50b8SAndrey Smetanin break; 307e83d5887SAndrey Smetanin default: 308e83d5887SAndrey Smetanin vcpu_unimpl(vcpu, "Hyper-V unhandled rdmsr: 0x%x\n", msr); 309e83d5887SAndrey Smetanin return 1; 310e83d5887SAndrey Smetanin } 311e83d5887SAndrey Smetanin *pdata = data; 312e83d5887SAndrey Smetanin return 0; 313e83d5887SAndrey Smetanin } 314e83d5887SAndrey Smetanin 315e7d9513bSAndrey Smetanin int kvm_hv_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data, bool host) 316e83d5887SAndrey Smetanin { 317e83d5887SAndrey Smetanin if (kvm_hv_msr_partition_wide(msr)) { 318e83d5887SAndrey Smetanin int r; 319e83d5887SAndrey Smetanin 320e83d5887SAndrey Smetanin mutex_lock(&vcpu->kvm->lock); 321e7d9513bSAndrey Smetanin r = kvm_hv_set_msr_pw(vcpu, msr, data, host); 322e83d5887SAndrey Smetanin mutex_unlock(&vcpu->kvm->lock); 323e83d5887SAndrey Smetanin return r; 324e83d5887SAndrey Smetanin } else 325*9eec50b8SAndrey Smetanin return kvm_hv_set_msr(vcpu, msr, data, host); 326e83d5887SAndrey Smetanin } 327e83d5887SAndrey Smetanin 328e83d5887SAndrey Smetanin int kvm_hv_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata) 329e83d5887SAndrey Smetanin { 330e83d5887SAndrey Smetanin if (kvm_hv_msr_partition_wide(msr)) { 331e83d5887SAndrey Smetanin int r; 332e83d5887SAndrey Smetanin 333e83d5887SAndrey Smetanin mutex_lock(&vcpu->kvm->lock); 334e83d5887SAndrey Smetanin r = kvm_hv_get_msr_pw(vcpu, msr, pdata); 335e83d5887SAndrey Smetanin mutex_unlock(&vcpu->kvm->lock); 336e83d5887SAndrey Smetanin return r; 337e83d5887SAndrey Smetanin } else 338e83d5887SAndrey Smetanin return kvm_hv_get_msr(vcpu, msr, pdata); 339e83d5887SAndrey Smetanin } 340e83d5887SAndrey Smetanin 341e83d5887SAndrey Smetanin bool kvm_hv_hypercall_enabled(struct kvm *kvm) 342e83d5887SAndrey Smetanin { 343e83d5887SAndrey Smetanin return kvm->arch.hyperv.hv_hypercall & HV_X64_MSR_HYPERCALL_ENABLE; 344e83d5887SAndrey Smetanin } 345e83d5887SAndrey Smetanin 346e83d5887SAndrey Smetanin int kvm_hv_hypercall(struct kvm_vcpu *vcpu) 347e83d5887SAndrey Smetanin { 348e83d5887SAndrey Smetanin u64 param, ingpa, outgpa, ret; 349e83d5887SAndrey Smetanin uint16_t code, rep_idx, rep_cnt, res = HV_STATUS_SUCCESS, rep_done = 0; 350e83d5887SAndrey Smetanin bool fast, longmode; 351e83d5887SAndrey Smetanin 352e83d5887SAndrey Smetanin /* 353e83d5887SAndrey Smetanin * hypercall generates UD from non zero cpl and real mode 354e83d5887SAndrey Smetanin * per HYPER-V spec 355e83d5887SAndrey Smetanin */ 356e83d5887SAndrey Smetanin if (kvm_x86_ops->get_cpl(vcpu) != 0 || !is_protmode(vcpu)) { 357e83d5887SAndrey Smetanin kvm_queue_exception(vcpu, UD_VECTOR); 358e83d5887SAndrey Smetanin return 0; 359e83d5887SAndrey Smetanin } 360e83d5887SAndrey Smetanin 361e83d5887SAndrey Smetanin longmode = is_64_bit_mode(vcpu); 362e83d5887SAndrey Smetanin 363e83d5887SAndrey Smetanin if (!longmode) { 364e83d5887SAndrey Smetanin param = ((u64)kvm_register_read(vcpu, VCPU_REGS_RDX) << 32) | 365e83d5887SAndrey Smetanin (kvm_register_read(vcpu, VCPU_REGS_RAX) & 0xffffffff); 366e83d5887SAndrey Smetanin ingpa = ((u64)kvm_register_read(vcpu, VCPU_REGS_RBX) << 32) | 367e83d5887SAndrey Smetanin (kvm_register_read(vcpu, VCPU_REGS_RCX) & 0xffffffff); 368e83d5887SAndrey Smetanin outgpa = ((u64)kvm_register_read(vcpu, VCPU_REGS_RDI) << 32) | 369e83d5887SAndrey Smetanin (kvm_register_read(vcpu, VCPU_REGS_RSI) & 0xffffffff); 370e83d5887SAndrey Smetanin } 371e83d5887SAndrey Smetanin #ifdef CONFIG_X86_64 372e83d5887SAndrey Smetanin else { 373e83d5887SAndrey Smetanin param = kvm_register_read(vcpu, VCPU_REGS_RCX); 374e83d5887SAndrey Smetanin ingpa = kvm_register_read(vcpu, VCPU_REGS_RDX); 375e83d5887SAndrey Smetanin outgpa = kvm_register_read(vcpu, VCPU_REGS_R8); 376e83d5887SAndrey Smetanin } 377e83d5887SAndrey Smetanin #endif 378e83d5887SAndrey Smetanin 379e83d5887SAndrey Smetanin code = param & 0xffff; 380e83d5887SAndrey Smetanin fast = (param >> 16) & 0x1; 381e83d5887SAndrey Smetanin rep_cnt = (param >> 32) & 0xfff; 382e83d5887SAndrey Smetanin rep_idx = (param >> 48) & 0xfff; 383e83d5887SAndrey Smetanin 384e83d5887SAndrey Smetanin trace_kvm_hv_hypercall(code, fast, rep_cnt, rep_idx, ingpa, outgpa); 385e83d5887SAndrey Smetanin 386e83d5887SAndrey Smetanin switch (code) { 387e83d5887SAndrey Smetanin case HV_X64_HV_NOTIFY_LONG_SPIN_WAIT: 388e83d5887SAndrey Smetanin kvm_vcpu_on_spin(vcpu); 389e83d5887SAndrey Smetanin break; 390e83d5887SAndrey Smetanin default: 391e83d5887SAndrey Smetanin res = HV_STATUS_INVALID_HYPERCALL_CODE; 392e83d5887SAndrey Smetanin break; 393e83d5887SAndrey Smetanin } 394e83d5887SAndrey Smetanin 395e83d5887SAndrey Smetanin ret = res | (((u64)rep_done & 0xfff) << 32); 396e83d5887SAndrey Smetanin if (longmode) { 397e83d5887SAndrey Smetanin kvm_register_write(vcpu, VCPU_REGS_RAX, ret); 398e83d5887SAndrey Smetanin } else { 399e83d5887SAndrey Smetanin kvm_register_write(vcpu, VCPU_REGS_RDX, ret >> 32); 400e83d5887SAndrey Smetanin kvm_register_write(vcpu, VCPU_REGS_RAX, ret & 0xffffffff); 401e83d5887SAndrey Smetanin } 402e83d5887SAndrey Smetanin 403e83d5887SAndrey Smetanin return 1; 404e83d5887SAndrey Smetanin } 405