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: 42*e7d9513bSAndrey Smetanin case HV_X64_MSR_CRASH_CTL: 43*e7d9513bSAndrey Smetanin case HV_X64_MSR_CRASH_P0 ... HV_X64_MSR_CRASH_P4: 44e83d5887SAndrey Smetanin r = true; 45e83d5887SAndrey Smetanin break; 46e83d5887SAndrey Smetanin } 47e83d5887SAndrey Smetanin 48e83d5887SAndrey Smetanin return r; 49e83d5887SAndrey Smetanin } 50e83d5887SAndrey Smetanin 51*e7d9513bSAndrey Smetanin static int kvm_hv_msr_get_crash_data(struct kvm_vcpu *vcpu, 52*e7d9513bSAndrey Smetanin u32 index, u64 *pdata) 53*e7d9513bSAndrey Smetanin { 54*e7d9513bSAndrey Smetanin struct kvm_hv *hv = &vcpu->kvm->arch.hyperv; 55*e7d9513bSAndrey Smetanin 56*e7d9513bSAndrey Smetanin if (WARN_ON_ONCE(index >= ARRAY_SIZE(hv->hv_crash_param))) 57*e7d9513bSAndrey Smetanin return -EINVAL; 58*e7d9513bSAndrey Smetanin 59*e7d9513bSAndrey Smetanin *pdata = hv->hv_crash_param[index]; 60*e7d9513bSAndrey Smetanin return 0; 61*e7d9513bSAndrey Smetanin } 62*e7d9513bSAndrey Smetanin 63*e7d9513bSAndrey Smetanin static int kvm_hv_msr_get_crash_ctl(struct kvm_vcpu *vcpu, u64 *pdata) 64*e7d9513bSAndrey Smetanin { 65*e7d9513bSAndrey Smetanin struct kvm_hv *hv = &vcpu->kvm->arch.hyperv; 66*e7d9513bSAndrey Smetanin 67*e7d9513bSAndrey Smetanin *pdata = hv->hv_crash_ctl; 68*e7d9513bSAndrey Smetanin return 0; 69*e7d9513bSAndrey Smetanin } 70*e7d9513bSAndrey Smetanin 71*e7d9513bSAndrey Smetanin static int kvm_hv_msr_set_crash_ctl(struct kvm_vcpu *vcpu, u64 data, bool host) 72*e7d9513bSAndrey Smetanin { 73*e7d9513bSAndrey Smetanin struct kvm_hv *hv = &vcpu->kvm->arch.hyperv; 74*e7d9513bSAndrey Smetanin 75*e7d9513bSAndrey Smetanin if (host) 76*e7d9513bSAndrey Smetanin hv->hv_crash_ctl = data & HV_X64_MSR_CRASH_CTL_NOTIFY; 77*e7d9513bSAndrey Smetanin 78*e7d9513bSAndrey Smetanin if (!host && (data & HV_X64_MSR_CRASH_CTL_NOTIFY)) { 79*e7d9513bSAndrey Smetanin 80*e7d9513bSAndrey Smetanin vcpu_debug(vcpu, "hv crash (0x%llx 0x%llx 0x%llx 0x%llx 0x%llx)\n", 81*e7d9513bSAndrey Smetanin hv->hv_crash_param[0], 82*e7d9513bSAndrey Smetanin hv->hv_crash_param[1], 83*e7d9513bSAndrey Smetanin hv->hv_crash_param[2], 84*e7d9513bSAndrey Smetanin hv->hv_crash_param[3], 85*e7d9513bSAndrey Smetanin hv->hv_crash_param[4]); 86*e7d9513bSAndrey Smetanin 87*e7d9513bSAndrey Smetanin /* Send notification about crash to user space */ 88*e7d9513bSAndrey Smetanin kvm_make_request(KVM_REQ_HV_CRASH, vcpu); 89*e7d9513bSAndrey Smetanin } 90*e7d9513bSAndrey Smetanin 91*e7d9513bSAndrey Smetanin return 0; 92*e7d9513bSAndrey Smetanin } 93*e7d9513bSAndrey Smetanin 94*e7d9513bSAndrey Smetanin static int kvm_hv_msr_set_crash_data(struct kvm_vcpu *vcpu, 95*e7d9513bSAndrey Smetanin u32 index, u64 data) 96*e7d9513bSAndrey Smetanin { 97*e7d9513bSAndrey Smetanin struct kvm_hv *hv = &vcpu->kvm->arch.hyperv; 98*e7d9513bSAndrey Smetanin 99*e7d9513bSAndrey Smetanin if (WARN_ON_ONCE(index >= ARRAY_SIZE(hv->hv_crash_param))) 100*e7d9513bSAndrey Smetanin return -EINVAL; 101*e7d9513bSAndrey Smetanin 102*e7d9513bSAndrey Smetanin hv->hv_crash_param[index] = data; 103*e7d9513bSAndrey Smetanin return 0; 104*e7d9513bSAndrey Smetanin } 105*e7d9513bSAndrey Smetanin 106*e7d9513bSAndrey Smetanin static int kvm_hv_set_msr_pw(struct kvm_vcpu *vcpu, u32 msr, u64 data, 107*e7d9513bSAndrey Smetanin bool host) 108e83d5887SAndrey Smetanin { 109e83d5887SAndrey Smetanin struct kvm *kvm = vcpu->kvm; 110e83d5887SAndrey Smetanin struct kvm_hv *hv = &kvm->arch.hyperv; 111e83d5887SAndrey Smetanin 112e83d5887SAndrey Smetanin switch (msr) { 113e83d5887SAndrey Smetanin case HV_X64_MSR_GUEST_OS_ID: 114e83d5887SAndrey Smetanin hv->hv_guest_os_id = data; 115e83d5887SAndrey Smetanin /* setting guest os id to zero disables hypercall page */ 116e83d5887SAndrey Smetanin if (!hv->hv_guest_os_id) 117e83d5887SAndrey Smetanin hv->hv_hypercall &= ~HV_X64_MSR_HYPERCALL_ENABLE; 118e83d5887SAndrey Smetanin break; 119e83d5887SAndrey Smetanin case HV_X64_MSR_HYPERCALL: { 120e83d5887SAndrey Smetanin u64 gfn; 121e83d5887SAndrey Smetanin unsigned long addr; 122e83d5887SAndrey Smetanin u8 instructions[4]; 123e83d5887SAndrey Smetanin 124e83d5887SAndrey Smetanin /* if guest os id is not set hypercall should remain disabled */ 125e83d5887SAndrey Smetanin if (!hv->hv_guest_os_id) 126e83d5887SAndrey Smetanin break; 127e83d5887SAndrey Smetanin if (!(data & HV_X64_MSR_HYPERCALL_ENABLE)) { 128e83d5887SAndrey Smetanin hv->hv_hypercall = data; 129e83d5887SAndrey Smetanin break; 130e83d5887SAndrey Smetanin } 131e83d5887SAndrey Smetanin gfn = data >> HV_X64_MSR_HYPERCALL_PAGE_ADDRESS_SHIFT; 132e83d5887SAndrey Smetanin addr = gfn_to_hva(kvm, gfn); 133e83d5887SAndrey Smetanin if (kvm_is_error_hva(addr)) 134e83d5887SAndrey Smetanin return 1; 135e83d5887SAndrey Smetanin kvm_x86_ops->patch_hypercall(vcpu, instructions); 136e83d5887SAndrey Smetanin ((unsigned char *)instructions)[3] = 0xc3; /* ret */ 137e83d5887SAndrey Smetanin if (__copy_to_user((void __user *)addr, instructions, 4)) 138e83d5887SAndrey Smetanin return 1; 139e83d5887SAndrey Smetanin hv->hv_hypercall = data; 140e83d5887SAndrey Smetanin mark_page_dirty(kvm, gfn); 141e83d5887SAndrey Smetanin break; 142e83d5887SAndrey Smetanin } 143e83d5887SAndrey Smetanin case HV_X64_MSR_REFERENCE_TSC: { 144e83d5887SAndrey Smetanin u64 gfn; 145e83d5887SAndrey Smetanin HV_REFERENCE_TSC_PAGE tsc_ref; 146e83d5887SAndrey Smetanin 147e83d5887SAndrey Smetanin memset(&tsc_ref, 0, sizeof(tsc_ref)); 148e83d5887SAndrey Smetanin hv->hv_tsc_page = data; 149e83d5887SAndrey Smetanin if (!(data & HV_X64_MSR_TSC_REFERENCE_ENABLE)) 150e83d5887SAndrey Smetanin break; 151e83d5887SAndrey Smetanin gfn = data >> HV_X64_MSR_TSC_REFERENCE_ADDRESS_SHIFT; 152e83d5887SAndrey Smetanin if (kvm_write_guest( 153e83d5887SAndrey Smetanin kvm, 154e83d5887SAndrey Smetanin gfn << HV_X64_MSR_TSC_REFERENCE_ADDRESS_SHIFT, 155e83d5887SAndrey Smetanin &tsc_ref, sizeof(tsc_ref))) 156e83d5887SAndrey Smetanin return 1; 157e83d5887SAndrey Smetanin mark_page_dirty(kvm, gfn); 158e83d5887SAndrey Smetanin break; 159e83d5887SAndrey Smetanin } 160*e7d9513bSAndrey Smetanin case HV_X64_MSR_CRASH_P0 ... HV_X64_MSR_CRASH_P4: 161*e7d9513bSAndrey Smetanin return kvm_hv_msr_set_crash_data(vcpu, 162*e7d9513bSAndrey Smetanin msr - HV_X64_MSR_CRASH_P0, 163*e7d9513bSAndrey Smetanin data); 164*e7d9513bSAndrey Smetanin case HV_X64_MSR_CRASH_CTL: 165*e7d9513bSAndrey Smetanin return kvm_hv_msr_set_crash_ctl(vcpu, data, host); 166e83d5887SAndrey Smetanin default: 167e83d5887SAndrey Smetanin vcpu_unimpl(vcpu, "Hyper-V uhandled wrmsr: 0x%x data 0x%llx\n", 168e83d5887SAndrey Smetanin msr, data); 169e83d5887SAndrey Smetanin return 1; 170e83d5887SAndrey Smetanin } 171e83d5887SAndrey Smetanin return 0; 172e83d5887SAndrey Smetanin } 173e83d5887SAndrey Smetanin 174e83d5887SAndrey Smetanin static int kvm_hv_set_msr(struct kvm_vcpu *vcpu, u32 msr, u64 data) 175e83d5887SAndrey Smetanin { 176e83d5887SAndrey Smetanin struct kvm_vcpu_hv *hv = &vcpu->arch.hyperv; 177e83d5887SAndrey Smetanin 178e83d5887SAndrey Smetanin switch (msr) { 179e83d5887SAndrey Smetanin case HV_X64_MSR_APIC_ASSIST_PAGE: { 180e83d5887SAndrey Smetanin u64 gfn; 181e83d5887SAndrey Smetanin unsigned long addr; 182e83d5887SAndrey Smetanin 183e83d5887SAndrey Smetanin if (!(data & HV_X64_MSR_APIC_ASSIST_PAGE_ENABLE)) { 184e83d5887SAndrey Smetanin hv->hv_vapic = data; 185e83d5887SAndrey Smetanin if (kvm_lapic_enable_pv_eoi(vcpu, 0)) 186e83d5887SAndrey Smetanin return 1; 187e83d5887SAndrey Smetanin break; 188e83d5887SAndrey Smetanin } 189e83d5887SAndrey Smetanin gfn = data >> HV_X64_MSR_APIC_ASSIST_PAGE_ADDRESS_SHIFT; 190e83d5887SAndrey Smetanin addr = kvm_vcpu_gfn_to_hva(vcpu, gfn); 191e83d5887SAndrey Smetanin if (kvm_is_error_hva(addr)) 192e83d5887SAndrey Smetanin return 1; 193e83d5887SAndrey Smetanin if (__clear_user((void __user *)addr, PAGE_SIZE)) 194e83d5887SAndrey Smetanin return 1; 195e83d5887SAndrey Smetanin hv->hv_vapic = data; 196e83d5887SAndrey Smetanin kvm_vcpu_mark_page_dirty(vcpu, gfn); 197e83d5887SAndrey Smetanin if (kvm_lapic_enable_pv_eoi(vcpu, 198e83d5887SAndrey Smetanin gfn_to_gpa(gfn) | KVM_MSR_ENABLED)) 199e83d5887SAndrey Smetanin return 1; 200e83d5887SAndrey Smetanin break; 201e83d5887SAndrey Smetanin } 202e83d5887SAndrey Smetanin case HV_X64_MSR_EOI: 203e83d5887SAndrey Smetanin return kvm_hv_vapic_msr_write(vcpu, APIC_EOI, data); 204e83d5887SAndrey Smetanin case HV_X64_MSR_ICR: 205e83d5887SAndrey Smetanin return kvm_hv_vapic_msr_write(vcpu, APIC_ICR, data); 206e83d5887SAndrey Smetanin case HV_X64_MSR_TPR: 207e83d5887SAndrey Smetanin return kvm_hv_vapic_msr_write(vcpu, APIC_TASKPRI, data); 208e83d5887SAndrey Smetanin default: 209e83d5887SAndrey Smetanin vcpu_unimpl(vcpu, "Hyper-V uhandled wrmsr: 0x%x data 0x%llx\n", 210e83d5887SAndrey Smetanin msr, data); 211e83d5887SAndrey Smetanin return 1; 212e83d5887SAndrey Smetanin } 213e83d5887SAndrey Smetanin 214e83d5887SAndrey Smetanin return 0; 215e83d5887SAndrey Smetanin } 216e83d5887SAndrey Smetanin 217e83d5887SAndrey Smetanin static int kvm_hv_get_msr_pw(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata) 218e83d5887SAndrey Smetanin { 219e83d5887SAndrey Smetanin u64 data = 0; 220e83d5887SAndrey Smetanin struct kvm *kvm = vcpu->kvm; 221e83d5887SAndrey Smetanin struct kvm_hv *hv = &kvm->arch.hyperv; 222e83d5887SAndrey Smetanin 223e83d5887SAndrey Smetanin switch (msr) { 224e83d5887SAndrey Smetanin case HV_X64_MSR_GUEST_OS_ID: 225e83d5887SAndrey Smetanin data = hv->hv_guest_os_id; 226e83d5887SAndrey Smetanin break; 227e83d5887SAndrey Smetanin case HV_X64_MSR_HYPERCALL: 228e83d5887SAndrey Smetanin data = hv->hv_hypercall; 229e83d5887SAndrey Smetanin break; 230e83d5887SAndrey Smetanin case HV_X64_MSR_TIME_REF_COUNT: { 231e83d5887SAndrey Smetanin data = 232e83d5887SAndrey Smetanin div_u64(get_kernel_ns() + kvm->arch.kvmclock_offset, 100); 233e83d5887SAndrey Smetanin break; 234e83d5887SAndrey Smetanin } 235e83d5887SAndrey Smetanin case HV_X64_MSR_REFERENCE_TSC: 236e83d5887SAndrey Smetanin data = hv->hv_tsc_page; 237e83d5887SAndrey Smetanin break; 238*e7d9513bSAndrey Smetanin case HV_X64_MSR_CRASH_P0 ... HV_X64_MSR_CRASH_P4: 239*e7d9513bSAndrey Smetanin return kvm_hv_msr_get_crash_data(vcpu, 240*e7d9513bSAndrey Smetanin msr - HV_X64_MSR_CRASH_P0, 241*e7d9513bSAndrey Smetanin pdata); 242*e7d9513bSAndrey Smetanin case HV_X64_MSR_CRASH_CTL: 243*e7d9513bSAndrey Smetanin return kvm_hv_msr_get_crash_ctl(vcpu, pdata); 244e83d5887SAndrey Smetanin default: 245e83d5887SAndrey Smetanin vcpu_unimpl(vcpu, "Hyper-V unhandled rdmsr: 0x%x\n", msr); 246e83d5887SAndrey Smetanin return 1; 247e83d5887SAndrey Smetanin } 248e83d5887SAndrey Smetanin 249e83d5887SAndrey Smetanin *pdata = data; 250e83d5887SAndrey Smetanin return 0; 251e83d5887SAndrey Smetanin } 252e83d5887SAndrey Smetanin 253e83d5887SAndrey Smetanin static int kvm_hv_get_msr(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata) 254e83d5887SAndrey Smetanin { 255e83d5887SAndrey Smetanin u64 data = 0; 256e83d5887SAndrey Smetanin struct kvm_vcpu_hv *hv = &vcpu->arch.hyperv; 257e83d5887SAndrey Smetanin 258e83d5887SAndrey Smetanin switch (msr) { 259e83d5887SAndrey Smetanin case HV_X64_MSR_VP_INDEX: { 260e83d5887SAndrey Smetanin int r; 261e83d5887SAndrey Smetanin struct kvm_vcpu *v; 262e83d5887SAndrey Smetanin 263e83d5887SAndrey Smetanin kvm_for_each_vcpu(r, v, vcpu->kvm) { 264e83d5887SAndrey Smetanin if (v == vcpu) { 265e83d5887SAndrey Smetanin data = r; 266e83d5887SAndrey Smetanin break; 267e83d5887SAndrey Smetanin } 268e83d5887SAndrey Smetanin } 269e83d5887SAndrey Smetanin break; 270e83d5887SAndrey Smetanin } 271e83d5887SAndrey Smetanin case HV_X64_MSR_EOI: 272e83d5887SAndrey Smetanin return kvm_hv_vapic_msr_read(vcpu, APIC_EOI, pdata); 273e83d5887SAndrey Smetanin case HV_X64_MSR_ICR: 274e83d5887SAndrey Smetanin return kvm_hv_vapic_msr_read(vcpu, APIC_ICR, pdata); 275e83d5887SAndrey Smetanin case HV_X64_MSR_TPR: 276e83d5887SAndrey Smetanin return kvm_hv_vapic_msr_read(vcpu, APIC_TASKPRI, pdata); 277e83d5887SAndrey Smetanin case HV_X64_MSR_APIC_ASSIST_PAGE: 278e83d5887SAndrey Smetanin data = hv->hv_vapic; 279e83d5887SAndrey Smetanin break; 280e83d5887SAndrey Smetanin default: 281e83d5887SAndrey Smetanin vcpu_unimpl(vcpu, "Hyper-V unhandled rdmsr: 0x%x\n", msr); 282e83d5887SAndrey Smetanin return 1; 283e83d5887SAndrey Smetanin } 284e83d5887SAndrey Smetanin *pdata = data; 285e83d5887SAndrey Smetanin return 0; 286e83d5887SAndrey Smetanin } 287e83d5887SAndrey Smetanin 288*e7d9513bSAndrey Smetanin int kvm_hv_set_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 data, bool host) 289e83d5887SAndrey Smetanin { 290e83d5887SAndrey Smetanin if (kvm_hv_msr_partition_wide(msr)) { 291e83d5887SAndrey Smetanin int r; 292e83d5887SAndrey Smetanin 293e83d5887SAndrey Smetanin mutex_lock(&vcpu->kvm->lock); 294*e7d9513bSAndrey Smetanin r = kvm_hv_set_msr_pw(vcpu, msr, data, host); 295e83d5887SAndrey Smetanin mutex_unlock(&vcpu->kvm->lock); 296e83d5887SAndrey Smetanin return r; 297e83d5887SAndrey Smetanin } else 298e83d5887SAndrey Smetanin return kvm_hv_set_msr(vcpu, msr, data); 299e83d5887SAndrey Smetanin } 300e83d5887SAndrey Smetanin 301e83d5887SAndrey Smetanin int kvm_hv_get_msr_common(struct kvm_vcpu *vcpu, u32 msr, u64 *pdata) 302e83d5887SAndrey Smetanin { 303e83d5887SAndrey Smetanin if (kvm_hv_msr_partition_wide(msr)) { 304e83d5887SAndrey Smetanin int r; 305e83d5887SAndrey Smetanin 306e83d5887SAndrey Smetanin mutex_lock(&vcpu->kvm->lock); 307e83d5887SAndrey Smetanin r = kvm_hv_get_msr_pw(vcpu, msr, pdata); 308e83d5887SAndrey Smetanin mutex_unlock(&vcpu->kvm->lock); 309e83d5887SAndrey Smetanin return r; 310e83d5887SAndrey Smetanin } else 311e83d5887SAndrey Smetanin return kvm_hv_get_msr(vcpu, msr, pdata); 312e83d5887SAndrey Smetanin } 313e83d5887SAndrey Smetanin 314e83d5887SAndrey Smetanin bool kvm_hv_hypercall_enabled(struct kvm *kvm) 315e83d5887SAndrey Smetanin { 316e83d5887SAndrey Smetanin return kvm->arch.hyperv.hv_hypercall & HV_X64_MSR_HYPERCALL_ENABLE; 317e83d5887SAndrey Smetanin } 318e83d5887SAndrey Smetanin 319e83d5887SAndrey Smetanin int kvm_hv_hypercall(struct kvm_vcpu *vcpu) 320e83d5887SAndrey Smetanin { 321e83d5887SAndrey Smetanin u64 param, ingpa, outgpa, ret; 322e83d5887SAndrey Smetanin uint16_t code, rep_idx, rep_cnt, res = HV_STATUS_SUCCESS, rep_done = 0; 323e83d5887SAndrey Smetanin bool fast, longmode; 324e83d5887SAndrey Smetanin 325e83d5887SAndrey Smetanin /* 326e83d5887SAndrey Smetanin * hypercall generates UD from non zero cpl and real mode 327e83d5887SAndrey Smetanin * per HYPER-V spec 328e83d5887SAndrey Smetanin */ 329e83d5887SAndrey Smetanin if (kvm_x86_ops->get_cpl(vcpu) != 0 || !is_protmode(vcpu)) { 330e83d5887SAndrey Smetanin kvm_queue_exception(vcpu, UD_VECTOR); 331e83d5887SAndrey Smetanin return 0; 332e83d5887SAndrey Smetanin } 333e83d5887SAndrey Smetanin 334e83d5887SAndrey Smetanin longmode = is_64_bit_mode(vcpu); 335e83d5887SAndrey Smetanin 336e83d5887SAndrey Smetanin if (!longmode) { 337e83d5887SAndrey Smetanin param = ((u64)kvm_register_read(vcpu, VCPU_REGS_RDX) << 32) | 338e83d5887SAndrey Smetanin (kvm_register_read(vcpu, VCPU_REGS_RAX) & 0xffffffff); 339e83d5887SAndrey Smetanin ingpa = ((u64)kvm_register_read(vcpu, VCPU_REGS_RBX) << 32) | 340e83d5887SAndrey Smetanin (kvm_register_read(vcpu, VCPU_REGS_RCX) & 0xffffffff); 341e83d5887SAndrey Smetanin outgpa = ((u64)kvm_register_read(vcpu, VCPU_REGS_RDI) << 32) | 342e83d5887SAndrey Smetanin (kvm_register_read(vcpu, VCPU_REGS_RSI) & 0xffffffff); 343e83d5887SAndrey Smetanin } 344e83d5887SAndrey Smetanin #ifdef CONFIG_X86_64 345e83d5887SAndrey Smetanin else { 346e83d5887SAndrey Smetanin param = kvm_register_read(vcpu, VCPU_REGS_RCX); 347e83d5887SAndrey Smetanin ingpa = kvm_register_read(vcpu, VCPU_REGS_RDX); 348e83d5887SAndrey Smetanin outgpa = kvm_register_read(vcpu, VCPU_REGS_R8); 349e83d5887SAndrey Smetanin } 350e83d5887SAndrey Smetanin #endif 351e83d5887SAndrey Smetanin 352e83d5887SAndrey Smetanin code = param & 0xffff; 353e83d5887SAndrey Smetanin fast = (param >> 16) & 0x1; 354e83d5887SAndrey Smetanin rep_cnt = (param >> 32) & 0xfff; 355e83d5887SAndrey Smetanin rep_idx = (param >> 48) & 0xfff; 356e83d5887SAndrey Smetanin 357e83d5887SAndrey Smetanin trace_kvm_hv_hypercall(code, fast, rep_cnt, rep_idx, ingpa, outgpa); 358e83d5887SAndrey Smetanin 359e83d5887SAndrey Smetanin switch (code) { 360e83d5887SAndrey Smetanin case HV_X64_HV_NOTIFY_LONG_SPIN_WAIT: 361e83d5887SAndrey Smetanin kvm_vcpu_on_spin(vcpu); 362e83d5887SAndrey Smetanin break; 363e83d5887SAndrey Smetanin default: 364e83d5887SAndrey Smetanin res = HV_STATUS_INVALID_HYPERCALL_CODE; 365e83d5887SAndrey Smetanin break; 366e83d5887SAndrey Smetanin } 367e83d5887SAndrey Smetanin 368e83d5887SAndrey Smetanin ret = res | (((u64)rep_done & 0xfff) << 32); 369e83d5887SAndrey Smetanin if (longmode) { 370e83d5887SAndrey Smetanin kvm_register_write(vcpu, VCPU_REGS_RAX, ret); 371e83d5887SAndrey Smetanin } else { 372e83d5887SAndrey Smetanin kvm_register_write(vcpu, VCPU_REGS_RDX, ret >> 32); 373e83d5887SAndrey Smetanin kvm_register_write(vcpu, VCPU_REGS_RAX, ret & 0xffffffff); 374e83d5887SAndrey Smetanin } 375e83d5887SAndrey Smetanin 376e83d5887SAndrey Smetanin return 1; 377e83d5887SAndrey Smetanin } 378